forked from CreamFi/compound-protocol
-
Notifications
You must be signed in to change notification settings - Fork 5
/
Copy pathCompoundLens.sol
229 lines (207 loc) · 8.96 KB
/
CompoundLens.sol
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
pragma solidity ^0.5.16;
pragma experimental ABIEncoderV2;
import "../CErc20.sol";
import "../Comptroller.sol";
import "../CToken.sol";
import "../PriceOracle/PriceOracle.sol";
import "../EIP20Interface.sol";
import "../Exponential.sol";
interface CSLPInterface {
function claimSushi(address) external returns (uint256);
}
interface CCTokenInterface {
function claimComp(address) external returns (uint256);
}
contract CompoundLens is Exponential {
struct CTokenMetadata {
address cToken;
uint256 exchangeRateCurrent;
uint256 supplyRatePerBlock;
uint256 borrowRatePerBlock;
uint256 reserveFactorMantissa;
uint256 totalBorrows;
uint256 totalReserves;
uint256 totalSupply;
uint256 totalCash;
uint256 totalCollateralTokens;
bool isListed;
uint256 collateralFactorMantissa;
address underlyingAssetAddress;
uint256 cTokenDecimals;
uint256 underlyingDecimals;
ComptrollerV1Storage.Version version;
uint256 collateralCap;
uint256 underlyingPrice;
bool supplyPaused;
bool borrowPaused;
uint256 supplyCap;
uint256 borrowCap;
}
function cTokenMetadataInternal(
CToken cToken,
Comptroller comptroller,
PriceOracle priceOracle
) internal returns (CTokenMetadata memory) {
uint256 exchangeRateCurrent = cToken.exchangeRateCurrent();
(bool isListed, uint256 collateralFactorMantissa, ComptrollerV1Storage.Version version) = comptroller.markets(
address(cToken)
);
address underlyingAssetAddress;
uint256 underlyingDecimals;
uint256 collateralCap;
uint256 totalCollateralTokens;
if (compareStrings(cToken.symbol(), "crETH")) {
underlyingAssetAddress = address(0);
underlyingDecimals = 18;
} else {
CErc20 cErc20 = CErc20(address(cToken));
underlyingAssetAddress = cErc20.underlying();
underlyingDecimals = EIP20Interface(cErc20.underlying()).decimals();
}
if (version == ComptrollerV1Storage.Version.COLLATERALCAP) {
collateralCap = CCollateralCapErc20Interface(address(cToken)).collateralCap();
totalCollateralTokens = CCollateralCapErc20Interface(address(cToken)).totalCollateralTokens();
} else if (version == ComptrollerV1Storage.Version.WRAPPEDNATIVE) {
collateralCap = CWrappedNativeInterface(address(cToken)).collateralCap();
totalCollateralTokens = CWrappedNativeInterface(address(cToken)).totalCollateralTokens();
}
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(),
totalCollateralTokens: totalCollateralTokens,
isListed: isListed,
collateralFactorMantissa: collateralFactorMantissa,
underlyingAssetAddress: underlyingAssetAddress,
cTokenDecimals: cToken.decimals(),
underlyingDecimals: underlyingDecimals,
version: version,
collateralCap: collateralCap,
underlyingPrice: priceOracle.getUnderlyingPrice(cToken),
supplyPaused: comptroller.mintGuardianPaused(address(cToken)),
borrowPaused: comptroller.borrowGuardianPaused(address(cToken)),
supplyCap: comptroller.supplyCaps(address(cToken)),
borrowCap: comptroller.borrowCaps(address(cToken))
});
}
function cTokenMetadata(CToken cToken) public returns (CTokenMetadata memory) {
Comptroller comptroller = Comptroller(address(cToken.comptroller()));
PriceOracle priceOracle = comptroller.oracle();
return cTokenMetadataInternal(cToken, comptroller, priceOracle);
}
function cTokenMetadataAll(CToken[] calldata cTokens) external returns (CTokenMetadata[] memory) {
uint256 cTokenCount = cTokens.length;
require(cTokenCount > 0, "invalid input");
CTokenMetadata[] memory res = new CTokenMetadata[](cTokenCount);
Comptroller comptroller = Comptroller(address(cTokens[0].comptroller()));
PriceOracle priceOracle = comptroller.oracle();
for (uint256 i = 0; i < cTokenCount; i++) {
require(address(comptroller) == address(cTokens[i].comptroller()), "mismatch comptroller");
res[i] = cTokenMetadataInternal(cTokens[i], comptroller, priceOracle);
}
return res;
}
struct CTokenBalances {
address cToken;
uint256 balanceOf;
uint256 borrowBalanceCurrent;
uint256 balanceOfUnderlying;
uint256 tokenBalance;
uint256 tokenAllowance;
bool collateralEnabled;
uint256 collateralBalance;
uint256 nativeTokenBalance;
}
function cTokenBalances(CToken cToken, address payable account) public returns (CTokenBalances memory) {
address comptroller = address(cToken.comptroller());
bool collateralEnabled = Comptroller(comptroller).checkMembership(account, cToken);
uint256 tokenBalance;
uint256 tokenAllowance;
uint256 collateralBalance;
if (compareStrings(cToken.symbol(), "crETH")) {
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));
}
if (collateralEnabled) {
(, collateralBalance, , ) = cToken.getAccountSnapshot(account);
}
return
CTokenBalances({
cToken: address(cToken),
balanceOf: cToken.balanceOf(account),
borrowBalanceCurrent: cToken.borrowBalanceCurrent(account),
balanceOfUnderlying: cToken.balanceOfUnderlying(account),
tokenBalance: tokenBalance,
tokenAllowance: tokenAllowance,
collateralEnabled: collateralEnabled,
collateralBalance: collateralBalance,
nativeTokenBalance: account.balance
});
}
function cTokenBalancesAll(CToken[] calldata cTokens, address payable account)
external
returns (CTokenBalances[] memory)
{
uint256 cTokenCount = cTokens.length;
CTokenBalances[] memory res = new CTokenBalances[](cTokenCount);
for (uint256 i = 0; i < cTokenCount; i++) {
res[i] = cTokenBalances(cTokens[i], account);
}
return res;
}
struct AccountLimits {
CToken[] markets;
uint256 liquidity;
uint256 shortfall;
}
function getAccountLimits(Comptroller comptroller, address account) public returns (AccountLimits memory) {
(uint256 errorCode, uint256 liquidity, uint256 shortfall) = comptroller.getAccountLiquidity(account);
require(errorCode == 0);
return AccountLimits({markets: comptroller.getAssetsIn(account), liquidity: liquidity, shortfall: shortfall});
}
function getClaimableSushiRewards(
CSLPInterface[] calldata cTokens,
address sushi,
address account
) external returns (uint256[] memory) {
uint256 cTokenCount = cTokens.length;
uint256[] memory rewards = new uint256[](cTokenCount);
for (uint256 i = 0; i < cTokenCount; i++) {
uint256 balanceBefore = EIP20Interface(sushi).balanceOf(account);
cTokens[i].claimSushi(account);
uint256 balanceAfter = EIP20Interface(sushi).balanceOf(account);
rewards[i] = sub_(balanceAfter, balanceBefore);
}
return rewards;
}
function getClaimableCompRewards(
CCTokenInterface[] calldata cTokens,
address comp,
address account
) external returns (uint256[] memory) {
uint256 cTokenCount = cTokens.length;
uint256[] memory rewards = new uint256[](cTokenCount);
for (uint256 i = 0; i < cTokenCount; i++) {
uint256 balanceBefore = EIP20Interface(comp).balanceOf(account);
cTokens[i].claimComp(account);
uint256 balanceAfter = EIP20Interface(comp).balanceOf(account);
rewards[i] = sub_(balanceAfter, balanceBefore);
}
return rewards;
}
function compareStrings(string memory a, string memory b) internal pure returns (bool) {
return (keccak256(abi.encodePacked((a))) == keccak256(abi.encodePacked((b))));
}
}