Skip to content

Commit

Permalink
Add Compound Lens (#29)
Browse files Browse the repository at this point in the history
* Add Compound Lens

The Compound Lens is a view contract Compound smart contracts that provides the data dApps need to stay hydrated. Specifically, we wrap the main data that our dApp is asking for. There's probably more bundling we could do, but this already reduces the raw number of calls by 98% (from about 10/s to about 0.2/s).

* Add CompoundLens deployments
  • Loading branch information
hayesgm committed Mar 31, 2020
1 parent 86c0116 commit afbe8a4
Show file tree
Hide file tree
Showing 7 changed files with 195 additions and 5 deletions.
159 changes: 159 additions & 0 deletions contracts/Lens/CompoundLens.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,159 @@
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;

import "../CErc20.sol";
import "../CToken.sol";
import "../Comptroller.sol";
import "../EIP20Interface.sol";

contract CompoundLens {
struct CTokenMetadata {
address cToken;
uint exchangeRateCurrent;
uint supplyRatePerBlock;
uint borrowRatePerBlock;
uint reserveFactorMantissa;
uint totalBorrows;
uint totalReserves;
uint totalSupply;
uint totalCash;
bool isListed;
uint collateralFactorMantissa;
address underlyingAssetAddress;
uint cTokenDecimals;
uint underlyingDecimals;
}

function cTokenMetadata(CToken cToken) public returns (CTokenMetadata memory) {
uint exchangeRateCurrent = cToken.exchangeRateCurrent();
Comptroller comptroller = Comptroller(address(cToken.comptroller()));
(bool isListed, uint collateralFactorMantissa) = comptroller.markets(address(cToken));
address underlyingAssetAddress;
uint underlyingDecimals;

if (compareStrings(cToken.symbol(), "cETH")) {
underlyingAssetAddress = address(0);
underlyingDecimals = 18;
} else {
CErc20 cErc20 = CErc20(address(cToken));
underlyingAssetAddress = cErc20.underlying();
underlyingDecimals = EIP20Interface(cErc20.underlying()).decimals();
}

return CTokenMetadata({
cToken: address(cToken),
exchangeRateCurrent: exchangeRateCurrent,
supplyRatePerBlock: cToken.supplyRatePerBlock(),
borrowRatePerBlock: cToken.borrowRatePerBlock(),
reserveFactorMantissa: cToken.reserveFactorMantissa(),
totalBorrows: cToken.totalBorrows(),
totalReserves: cToken.totalReserves(),
totalSupply: cToken.totalSupply(),
totalCash: cToken.getCash(),
isListed: isListed,
collateralFactorMantissa: collateralFactorMantissa,
underlyingAssetAddress: underlyingAssetAddress,
cTokenDecimals: cToken.decimals(),
underlyingDecimals: underlyingDecimals
});
}

function cTokenMetadataAll(CToken[] calldata cTokens) external returns (CTokenMetadata[] memory) {
uint cTokenCount = cTokens.length;
CTokenMetadata[] memory res = new CTokenMetadata[](cTokenCount);
for (uint i = 0; i < cTokenCount; i++) {
res[i] = cTokenMetadata(cTokens[i]);
}
return res;
}

struct CTokenBalances {
address cToken;
uint balanceOf;
uint borrowBalanceCurrent;
uint balanceOfUnderlying;
uint tokenBalance;
uint tokenAllowance;
}

function cTokenBalances(CToken cToken, address payable account) public returns (CTokenBalances memory) {
uint balanceOf = cToken.balanceOf(account);
uint borrowBalanceCurrent = cToken.borrowBalanceCurrent(account);
uint balanceOfUnderlying = cToken.balanceOfUnderlying(account);
uint tokenBalance;
uint tokenAllowance;

if (compareStrings(cToken.symbol(), "cETH")) {
tokenBalance = account.balance;
tokenAllowance = account.balance;
} else {
CErc20 cErc20 = CErc20(address(cToken));
EIP20Interface underlying = EIP20Interface(cErc20.underlying());
tokenBalance = underlying.balanceOf(account);
tokenAllowance = underlying.allowance(account, address(cToken));
}

return CTokenBalances({
cToken: address(cToken),
balanceOf: balanceOf,
borrowBalanceCurrent: borrowBalanceCurrent,
balanceOfUnderlying: balanceOfUnderlying,
tokenBalance: tokenBalance,
tokenAllowance: tokenAllowance
});
}

function cTokenBalancesAll(CToken[] calldata cTokens, address payable account) external returns (CTokenBalances[] memory) {
uint cTokenCount = cTokens.length;
CTokenBalances[] memory res = new CTokenBalances[](cTokenCount);
for (uint i = 0; i < cTokenCount; i++) {
res[i] = cTokenBalances(cTokens[i], account);
}
return res;
}

struct CTokenUnderlyingPrice {
address cToken;
uint underlyingPrice;
}

function cTokenUnderlyingPrice(CToken cToken) public returns (CTokenUnderlyingPrice memory) {
Comptroller comptroller = Comptroller(address(cToken.comptroller()));
PriceOracle priceOracle = comptroller.oracle();

return CTokenUnderlyingPrice({
cToken: address(cToken),
underlyingPrice: priceOracle.getUnderlyingPrice(cToken)
});
}

function cTokenUnderlyingPriceAll(CToken[] calldata cTokens) external returns (CTokenUnderlyingPrice[] memory) {
uint cTokenCount = cTokens.length;
CTokenUnderlyingPrice[] memory res = new CTokenUnderlyingPrice[](cTokenCount);
for (uint i = 0; i < cTokenCount; i++) {
res[i] = cTokenUnderlyingPrice(cTokens[i]);
}
return res;
}

struct AccountLimits {
CToken[] markets;
uint liquidity;
uint shortfall;
}

function getAccountLimits(Comptroller comptroller, address account) public returns (AccountLimits memory) {
(uint errorCode, uint liquidity, uint shortfall) = comptroller.getAccountLiquidity(account);
require(errorCode == 0);

return AccountLimits({
markets: comptroller.getAssetsIn(account),
liquidity: liquidity,
shortfall: shortfall
});
}

function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
}
}
3 changes: 2 additions & 1 deletion networks/goerli.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"REP": "0x183Faf58c4461972765f3F90c6272A4ecE66Bd96",
"cZRX": "0xA253295eC2157B8b69C44b2cb35360016DAa25b1",
"cWBTC": "0x6CE27497A64fFFb5517AA4aeE908b1E7EB63B9fF",
"USDC": "0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C"
"USDC": "0xD87Ba7A50B2E7E660f678A895E4B72E7CB4CCd9C",
"CompoundLens": "0x05752E558f7141C4b098D9b9B212F4Ea5aff0A3c"
},
"Blocks": {
"ZRX": 1971943,
Expand Down
3 changes: 2 additions & 1 deletion networks/kovan.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,8 @@
"cZRX": "0xC014DC10A57aC78350C5fddB26Bb66f1Cb0960a0",
"cWBTC": "0x3659728876EfB2780f498Ce829C5b076e496E0e3",
"USDC": "0x75B0622Cec14130172EaE9Cf166B92E5C112FaFF",
"Base200bps_Slope222bps_Kink90_Jump10": "0xE057EF4be5c6C712e13E24d4408f5F257fEd4d3f"
"Base200bps_Slope222bps_Kink90_Jump10": "0xE057EF4be5c6C712e13E24d4408f5F257fEd4d3f",
"CompoundLens": "0x6F4853929e4C30Fcd357f36d8d1aa9b5fAC82185"
},
"Blocks": {
"ZRX": 14981231,
Expand Down
3 changes: 2 additions & 1 deletion networks/mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@
"REP": "0x1985365e9f78359a9B6AD760e32412f4a445E862",
"cZRX": "0xB3319f5D18Bc0D84dD1b4825Dcde5d5f7266d407",
"cWBTC": "0xC11b1268C1A384e55C48c2391d8d480264A3A7F4",
"USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48"
"USDC": "0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48",
"CompoundLens": "0xBaaD2b744336D6E4E67Fae2e071C3005b8C17102"
},
"Blocks": {
"cUSDC": 7710760,
Expand Down
3 changes: 2 additions & 1 deletion networks/rinkeby.json
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,8 @@
"REP": "0x6e894660985207feb7cf89Faf048998c71E8EE89",
"cZRX": "0x52201ff1720134bBbBB2f6BC97Bf3715490EC19B",
"cWBTC": "0x0014F450B8Ae7708593F4A46F8fa6E5D50620F96",
"USDC": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b"
"USDC": "0x4DBCdF9B62e891a7cec5A2568C3F4FAF9E8Abe2b",
"CompoundLens": "0x0E01460f00C6B0b66A44D7cF1406Cb2150B718fC"
},
"Blocks": {
"cUSDC": 4319847,
Expand Down
3 changes: 2 additions & 1 deletion networks/ropsten.json
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@
"cZRX": "0x3A728dD027AD6F76Cdea227d5Cf5ba7ce9390A3d",
"cWBTC": "0x4D15eE7DE1f86248c986f5AE7dCE855b1c1A8806",
"TBTC": "0x083f652051b9CdBf65735f98d83cc329725Aa957",
"USDC": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f"
"USDC": "0x8a9447df1FB47209D36204e6D56767a33bf20f9f",
"CompoundLens": "0x1496C81e6DE4928bE5E4e9F83dA575A08B616Ac8"
},
"Blocks": {
"ZRX": 5970747,
Expand Down
26 changes: 26 additions & 0 deletions saddle.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,32 @@ module.exports = {
{unlocked: 0}
]
},
kovan: {
providers: [
{env: "PROVIDER"},
{file: "~/.ethereum/kovan-url"}, // Load from given file with contents as the URL (e.g. https://infura.io/api-key)
{http: "https://kovan-eth.compound.finance"}
],
web3: {
gas: [
{env: "GAS"},
{default: "4600000"}
],
gas_price: [
{env: "GAS_PRICE"},
{default: "12000000000"}
],
options: {
transactionConfirmationBlocks: 1,
transactionBlockTimeout: 5
}
},
accounts: [
{env: "ACCOUNT"},
{file: "~/.ethereum/kovan"}, // Load from given file with contents as the private key (e.g. 0x...)
{unlocked: 0}
]
},
mainnet: {
providers: [
{env: "PROVIDER"},
Expand Down

0 comments on commit afbe8a4

Please sign in to comment.