Euler diff: contracts/modules/Markets.sol

Before: contract 0x12401F97e2264adBF8FF98DA72e3465D97B41477
After: git d7f62927eb58592d82302c87205490c26cccca7c
Files changed (5) hide show
  1. contracts/modules/Markets.sol +23 -2
  2. contracts/BaseLogic.sol +9 -3
  3. contracts/Storage.sol +2 -1
  4. contracts/Events.sol +2 -0
  5. contracts/Constants.sol +5 -0
contracts/modules/Markets.sol CHANGED
@@ -68,8 +68,13 @@
68
68
  assetStorage.underlyingDecimals = decimals;
69
69
  assetStorage.interestRateModel = uint32(MODULEID__IRM_DEFAULT);
70
70
  assetStorage.reserveFee = type(uint32).max; // default
71
71
 
72
+ {
73
+ assetStorage.reserveBalance = encodeSmallAmount(INITIAL_RESERVES);
74
+ assetStorage.totalBalances = encodeAmount(INITIAL_RESERVES);
75
+ }
76
+
72
77
  assetStorage.interestAccumulator = INITIAL_INTEREST_ACCUMULATOR;
73
78
 
74
79
 
75
80
  emit MarketActivated(underlying, childEToken, childDToken);
@@ -148,8 +153,17 @@
148
153
  underlying = eTokenLookup[eToken].underlying;
149
154
  require(underlying != address(0), "e/invalid-etoken");
150
155
  }
151
156
 
157
+ /// @notice Given a DToken address, looks up the associated underlying
158
+ /// @param dToken DToken address
159
+ /// @return underlying Token address
160
+ function dTokenToUnderlying(address dToken) external view returns (address underlying) {
161
+ address eToken = dTokenLookup[dToken];
162
+ require(eToken != address(0), "e/invalid-dtoken");
163
+ return eTokenLookup[eToken].underlying;
164
+ }
165
+
152
166
  /// @notice Given an EToken address, looks up the associated DToken
153
167
  /// @param eToken EToken address
154
168
  /// @return dTokenAddr DToken address
155
169
  function eTokenToDToken(address eToken) external view returns (address dTokenAddr) {
@@ -202,10 +216,10 @@
202
216
  }
203
217
 
204
218
  /// @notice Retrieves the pricing config for an asset
205
219
  /// @param underlying Token address
206
- /// @return pricingType (1=pegged, 2=uniswap3, 3=forwarded)
207
- /// @return pricingParameters If uniswap3 pricingType then this represents the uniswap pool fee used, otherwise unused
220
+ /// @return pricingType (1=pegged, 2=uniswap3, 3=forwarded, 4=chainlink)
221
+ /// @return pricingParameters If uniswap3 pricingType then this represents the uniswap pool fee used, if chainlink pricing type this represents the fallback uniswap pool fee or 0 if none
208
222
  /// @return pricingForwarded If forwarded pricingType then this is the address prices are forwarded to, otherwise address(0)
209
223
  function getPricingConfig(address underlying) external view returns (uint16 pricingType, uint32 pricingParameters, address pricingForwarded) {
210
224
  AssetStorage storage assetStorage = getAssetStorage(underlying);
211
225
 
@@ -214,8 +228,15 @@
214
228
 
215
229
  pricingForwarded = pricingType == PRICINGTYPE__FORWARDED ? pTokenLookup[underlying] : address(0);
216
230
  }
217
231
 
232
+ /// @notice Retrieves the Chainlink price feed config for an asset
233
+ /// @param underlying Token address
234
+ /// @return chainlinkAggregator Chainlink aggregator proxy address
235
+ function getChainlinkPriceFeedConfig(address underlying) external view returns (address chainlinkAggregator) {
236
+ chainlinkAggregator = chainlinkPriceFeedLookup[underlying];
237
+ }
238
+
218
239
 
219
240
  // Enter/exit markets
220
241
 
221
242
  /// @notice Retrieves the list of entered markets for an account (assets enabled for collateral or borrowing)
contracts/BaseLogic.sol CHANGED
@@ -256,13 +256,18 @@
256
256
  }
257
257
  }
258
258
 
259
259
  function loadAssetCacheRO(address underlying, AssetStorage storage assetStorage) internal view returns (AssetCache memory assetCache) {
260
+ require(reentrancyLock == REENTRANCYLOCK__UNLOCKED, "e/ro-reentrancy");
260
261
  initAssetCache(underlying, assetStorage, assetCache);
261
262
  }
262
263
 
264
+ function internalLoadAssetCacheRO(address underlying, AssetStorage storage assetStorage) internal view returns (AssetCache memory assetCache) {
265
+ initAssetCache(underlying, assetStorage, assetCache);
266
+ }
263
267
 
264
268
 
269
+
265
270
  // Utils
266
271
 
267
272
  function decodeExternalAmount(AssetCache memory assetCache, uint externalAmount) internal pure returns (uint scaledAmount) {
268
273
  require(externalAmount <= assetCache.maxExternalAmount, "e/amount-too-large");
@@ -284,10 +289,11 @@
284
289
  return uint144(amount);
285
290
  }
286
291
 
287
292
  function computeExchangeRate(AssetCache memory assetCache) private pure returns (uint) {
288
- if (assetCache.totalBalances == 0) return 1e18;
289
- return (assetCache.poolSize + (assetCache.totalBorrows / INTERNAL_DEBT_PRECISION)) * 1e18 / assetCache.totalBalances;
293
+ uint totalAssets = assetCache.poolSize + (assetCache.totalBorrows / INTERNAL_DEBT_PRECISION);
294
+ if (totalAssets == 0 || assetCache.totalBalances == 0) return 1e18;
295
+ return totalAssets * 1e18 / assetCache.totalBalances;
290
296
  }
291
297
 
292
298
  function underlyingAmountToBalance(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
293
299
  uint exchangeRate = computeExchangeRate(assetCache);
@@ -306,9 +312,9 @@
306
312
 
307
313
  function callBalanceOf(AssetCache memory assetCache, address account) internal view FREEMEM returns (uint) {
308
314
  // We set a gas limit so that a malicious token can't eat up all gas and cause a liquidity check to fail.
309
315
 
310
- (bool success, bytes memory data) = assetCache.underlying.staticcall{gas: 20000}(abi.encodeWithSelector(IERC20.balanceOf.selector, account));
316
+ (bool success, bytes memory data) = assetCache.underlying.staticcall{gas: 200000}(abi.encodeWithSelector(IERC20.balanceOf.selector, account));
311
317
 
312
318
  // If token's balanceOf() call fails for any reason, return 0. This prevents malicious tokens from causing liquidity checks to fail.
313
319
  // If the contract doesn't exist (maybe because selfdestructed), then data.length will be 0 and we will return 0.
314
320
  // Data length > 32 is allowed because some legitimate tokens append extra data that can be safely ignored.
contracts/Storage.sol CHANGED
@@ -6,9 +6,9 @@
6
6
 
7
7
  abstract contract Storage is Constants {
8
8
  // Dispatcher and upgrades
9
9
 
10
- uint reentrancyLock;
10
+ uint internal reentrancyLock;
11
11
 
12
12
  address upgradeAdmin;
13
13
  address governorAdmin;
14
14
 
@@ -91,5 +91,6 @@
91
91
  mapping(address => AssetStorage) internal eTokenLookup; // EToken => AssetStorage
92
92
  mapping(address => address) internal dTokenLookup; // DToken => EToken
93
93
  mapping(address => address) internal pTokenLookup; // PToken => underlying
94
94
  mapping(address => address) internal reversePTokenLookup; // underlying => PToken
95
+ mapping(address => address) internal chainlinkPriceFeedLookup; // underlying => chainlinkAggregator
95
96
  }
contracts/Events.sol CHANGED
@@ -36,8 +36,9 @@
36
36
  event RequestWithdraw(address indexed account, uint amount);
37
37
  event RequestMint(address indexed account, uint amount);
38
38
  event RequestBurn(address indexed account, uint amount);
39
39
  event RequestTransferEToken(address indexed from, address indexed to, uint amount);
40
+ event RequestDonate(address indexed account, uint amount);
40
41
 
41
42
  event RequestBorrow(address indexed account, uint amount);
42
43
  event RequestRepay(address indexed account, uint amount);
43
44
  event RequestTransferDToken(address indexed from, address indexed to, uint amount);
@@ -54,7 +55,8 @@
54
55
  event GovSetIRM(address indexed underlying, uint interestRateModel, bytes resetParams);
55
56
  event GovSetPricingConfig(address indexed underlying, uint16 newPricingType, uint32 newPricingParameter);
56
57
  event GovSetReserveFee(address indexed underlying, uint32 newReserveFee);
57
58
  event GovConvertReserves(address indexed underlying, address indexed recipient, uint amount);
59
+ event GovSetChainlinkPriceFeed(address indexed underlying, address chainlinkAggregator);
58
60
 
59
61
  event RequestSwap(address indexed accountIn, address indexed accountOut, address indexed underlyingIn, address underlyingOut, uint amount, uint swapType);
60
62
  }
contracts/Constants.sol CHANGED
@@ -18,8 +18,9 @@
18
18
  uint internal constant MAX_POSSIBLE_ENTERED_MARKETS = 2**32; // limited by size of AccountStorage.numMarketsEntered
19
19
  uint internal constant CONFIG_FACTOR_SCALE = 4_000_000_000; // must fit into a uint32
20
20
  uint internal constant RESERVE_FEE_SCALE = 4_000_000_000; // must fit into a uint32
21
21
  uint32 internal constant DEFAULT_RESERVE_FEE = uint32(0.23 * 4_000_000_000);
22
+ uint internal constant INITIAL_RESERVES = 1e6;
22
23
  uint internal constant INITIAL_INTEREST_ACCUMULATOR = 1e27;
23
24
  uint internal constant AVERAGE_LIQUIDITY_PERIOD = 24 * 60 * 60;
24
25
  uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 144;
25
26
  uint24 internal constant DEFAULT_TWAP_WINDOW_SECONDS = 30 * 60;
@@ -41,10 +42,14 @@
41
42
 
42
43
  uint16 internal constant PRICINGTYPE__PEGGED = 1;
43
44
  uint16 internal constant PRICINGTYPE__UNISWAP3_TWAP = 2;
44
45
  uint16 internal constant PRICINGTYPE__FORWARDED = 3;
46
+ uint16 internal constant PRICINGTYPE__CHAINLINK = 4;
45
47
 
48
+ // Correct pricing types are always less than this value
49
+ uint16 internal constant PRICINGTYPE__OUT_OF_BOUNDS = 5;
46
50
 
51
+
47
52
  // Modules
48
53
 
49
54
  // Public single-proxy modules
50
55
  uint internal constant MODULEID__INSTALLER = 1;