Euler diff: contracts/modules/EToken.sol

Before: contract 0x196fdd95EAE8c673150e5EFe727F4cC84ED33Cb8
After: git d7f62927eb58592d82302c87205490c26cccca7c
Files changed (5) hide show
  1. contracts/modules/EToken.sol +35 -3
  2. contracts/BaseLogic.sol +4 -3
  3. contracts/Storage.sol +2 -1
  4. contracts/Events.sol +2 -0
  5. contracts/Constants.sol +5 -0
contracts/modules/EToken.sol CHANGED
@@ -273,9 +273,9 @@
273
273
  /// @notice Allow spender to access an amount of your eTokens in a particular sub-account
274
274
  /// @param subAccountId 0 for primary, 1-255 for a sub-account
275
275
  /// @param spender Trusted address
276
276
  /// @param amount Use max uint256 for "infinite" allowance
277
- function approveSubAccount(uint subAccountId, address spender, uint amount) public reentrantOK returns (bool) {
277
+ function approveSubAccount(uint subAccountId, address spender, uint amount) public nonReentrant returns (bool) {
278
278
  (, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
279
279
  address account = getSubAccount(msgSender, subAccountId);
280
280
 
281
281
  require(!isSubAccountOf(spender, account), "e/self-approval");
@@ -300,16 +300,16 @@
300
300
 
301
301
  /// @notice Transfer eTokens to another address (from sub-account 0)
302
302
  /// @param to Xor with the desired sub-account ID (if applicable)
303
303
  /// @param amount In internal book-keeping units (as returned from balanceOf).
304
- function transfer(address to, uint amount) external returns (bool) {
304
+ function transfer(address to, uint amount) external reentrantOK returns (bool) {
305
305
  return transferFrom(address(0), to, amount);
306
306
  }
307
307
 
308
308
  /// @notice Transfer the full eToken balance of an address to another
309
309
  /// @param from This address must've approved the to address, or be a sub-account of msg.sender
310
310
  /// @param to Xor with the desired sub-account ID (if applicable)
311
- function transferFromMax(address from, address to) external returns (bool) {
311
+ function transferFromMax(address from, address to) external reentrantOK returns (bool) {
312
312
  (, AssetStorage storage assetStorage,,) = CALLER();
313
313
 
314
314
  return transferFrom(from, to, assetStorage.users[from].balance);
315
315
  }
@@ -346,5 +346,37 @@
346
346
  logAssetStatus(assetCache);
347
347
 
348
348
  return true;
349
349
  }
350
+
351
+ /// @notice Donate eTokens to the reserves
352
+ /// @param subAccountId 0 for primary, 1-255 for a sub-account
353
+ /// @param amount In internal book-keeping units (as returned from balanceOf).
354
+ function donateToReserves(uint subAccountId, uint amount) external nonReentrant {
355
+ (address underlying, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
356
+ address account = getSubAccount(msgSender, subAccountId);
357
+
358
+ updateAverageLiquidity(account);
359
+ emit RequestDonate(account, amount);
360
+
361
+ AssetCache memory assetCache = loadAssetCache(underlying, assetStorage);
362
+
363
+ uint origBalance = assetStorage.users[account].balance;
364
+ uint newBalance;
365
+
366
+ if (amount == type(uint).max) {
367
+ amount = origBalance;
368
+ newBalance = 0;
369
+ } else {
370
+ require(origBalance >= amount, "e/insufficient-balance");
371
+ unchecked { newBalance = origBalance - amount; }
372
+ }
373
+
374
+ assetStorage.users[account].balance = encodeAmount(newBalance);
375
+ assetStorage.reserveBalance = assetCache.reserveBalance = encodeSmallAmount(assetCache.reserveBalance + amount);
376
+
377
+ emit Withdraw(assetCache.underlying, account, amount);
378
+ emitViaProxy_Transfer(proxyAddr, account, address(0), amount);
379
+
380
+ logAssetStatus(assetCache);
381
+ }
350
382
  }
contracts/BaseLogic.sol CHANGED
@@ -289,10 +289,11 @@
289
289
  return uint144(amount);
290
290
  }
291
291
 
292
292
  function computeExchangeRate(AssetCache memory assetCache) private pure returns (uint) {
293
- if (assetCache.totalBalances == 0) return 1e18;
294
- 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;
295
296
  }
296
297
 
297
298
  function underlyingAmountToBalance(AssetCache memory assetCache, uint amount) internal pure returns (uint) {
298
299
  uint exchangeRate = computeExchangeRate(assetCache);
@@ -311,9 +312,9 @@
311
312
 
312
313
  function callBalanceOf(AssetCache memory assetCache, address account) internal view FREEMEM returns (uint) {
313
314
  // We set a gas limit so that a malicious token can't eat up all gas and cause a liquidity check to fail.
314
315
 
315
- (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));
316
317
 
317
318
  // If token's balanceOf() call fails for any reason, return 0. This prevents malicious tokens from causing liquidity checks to fail.
318
319
  // If the contract doesn't exist (maybe because selfdestructed), then data.length will be 0 and we will return 0.
319
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;