Euler diff: contracts/modules/Exec.sol

Before: contract 0x14cBaC4eC5673DEFD3968693ebA994F07F8436D2
After: git 1d8c9f1d548570a0235cda39b13a76e658ae37d3
Files changed (7) hide show
  1. contracts/modules/Exec.sol +59 -6
  2. contracts/BaseLogic.sol +1 -1
  3. contracts/IRiskManager.sol +5 -5
  4. contracts/Interfaces.sol +6 -0
  5. contracts/BaseModule.sol +3 -11
  6. contracts/Base.sol +7 -0
  7. contracts/Constants.sol +6 -1
contracts/modules/Exec.sol CHANGED
@@ -33,14 +33,12 @@
33
33
  }
34
34
 
35
35
  // Accessors
36
36
 
37
- // These are not view methods, since they can perform state writes in the uniswap contract while retrieving prices
38
-
39
37
  /// @notice Compute aggregate liquidity for an account
40
38
  /// @param account User address
41
39
  /// @return status Aggregate liquidity (sum of all entered assets)
42
- function liquidity(address account) external nonReentrant returns (IRiskManager.LiquidityStatus memory status) {
40
+ function liquidity(address account) external staticDelegate returns (IRiskManager.LiquidityStatus memory status) {
43
41
  bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
44
42
  abi.encodeWithSelector(IRiskManager.computeLiquidity.selector, account));
45
43
 
46
44
  (status) = abi.decode(result, (IRiskManager.LiquidityStatus));
@@ -48,9 +46,9 @@
48
46
 
49
47
  /// @notice Compute detailed liquidity for an account, broken down by asset
50
48
  /// @param account User address
51
49
  /// @return assets List of user's entered assets and each asset's corresponding liquidity
52
- function detailedLiquidity(address account) public nonReentrant returns (IRiskManager.AssetLiquidity[] memory assets) {
50
+ function detailedLiquidity(address account) public staticDelegate returns (IRiskManager.AssetLiquidity[] memory assets) {
53
51
  bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
54
52
  abi.encodeWithSelector(IRiskManager.computeAssetLiquidities.selector, account));
55
53
 
56
54
  (assets) = abi.decode(result, (IRiskManager.AssetLiquidity[]));
@@ -59,9 +57,9 @@
59
57
  /// @notice Retrieve Euler's view of an asset's price
60
58
  /// @param underlying Token address
61
59
  /// @return twap Time-weighted average price
62
60
  /// @return twapPeriod TWAP duration, either the twapWindow value in AssetConfig, or less if that duration not available
63
- function getPrice(address underlying) external nonReentrant returns (uint twap, uint twapPeriod) {
61
+ function getPrice(address underlying) external staticDelegate returns (uint twap, uint twapPeriod) {
64
62
  bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
65
63
  abi.encodeWithSelector(IRiskManager.getPrice.selector, underlying));
66
64
 
67
65
  (twap, twapPeriod) = abi.decode(result, (uint, uint));
@@ -71,9 +69,9 @@
71
69
  /// @param underlying Token address
72
70
  /// @return twap Time-weighted average price
73
71
  /// @return twapPeriod TWAP duration, either the twapWindow value in AssetConfig, or less if that duration not available
74
72
  /// @return currPrice The current marginal price on uniswap3 (informational: not used anywhere in the Euler protocol)
75
- function getPriceFull(address underlying) external nonReentrant returns (uint twap, uint twapPeriod, uint currPrice) {
73
+ function getPriceFull(address underlying) external staticDelegate returns (uint twap, uint twapPeriod, uint currPrice) {
76
74
  bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
77
75
  abi.encodeWithSelector(IRiskManager.getPriceFull.selector, underlying));
78
76
 
79
77
  (twap, twapPeriod, currPrice) = abi.decode(result, (uint, uint, uint));
@@ -277,5 +275,60 @@
277
275
  require(pTokenAddr != address(0), "e/exec/ptoken-not-found");
278
276
 
279
277
  PToken(pTokenAddr).forceUnwrap(msgSender, amount);
280
278
  }
279
+
280
+ /// @notice Apply EIP2612 signed permit on a target token from sender to euler contract
281
+ /// @param token Token address
282
+ /// @param value Allowance value
283
+ /// @param deadline Permit expiry timestamp
284
+ /// @param v secp256k1 signature v
285
+ /// @param r secp256k1 signature r
286
+ /// @param s secp256k1 signature s
287
+ function usePermit(address token, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external nonReentrant {
288
+ require(underlyingLookup[token].eTokenAddress != address(0), "e/exec/market-not-activated");
289
+ address msgSender = unpackTrailingParamMsgSender();
290
+
291
+ IERC20Permit(token).permit(msgSender, address(this), value, deadline, v, r, s);
292
+ }
293
+
294
+ /// @notice Apply DAI like (allowed) signed permit on a target token from sender to euler contract
295
+ /// @param token Token address
296
+ /// @param nonce Sender nonce
297
+ /// @param expiry Permit expiry timestamp
298
+ /// @param allowed If true, set unlimited allowance, otherwise set zero allowance
299
+ /// @param v secp256k1 signature v
300
+ /// @param r secp256k1 signature r
301
+ /// @param s secp256k1 signature s
302
+ function usePermitAllowed(address token, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external nonReentrant {
303
+ require(underlyingLookup[token].eTokenAddress != address(0), "e/exec/market-not-activated");
304
+ address msgSender = unpackTrailingParamMsgSender();
305
+
306
+ IERC20Permit(token).permit(msgSender, address(this), nonce, expiry, allowed, v, r, s);
307
+ }
308
+
309
+ /// @notice Apply allowance to tokens expecting the signature packed in a single bytes param
310
+ /// @param token Token address
311
+ /// @param value Allowance value
312
+ /// @param deadline Permit expiry timestamp
313
+ /// @param signature secp256k1 signature encoded as rsv
314
+ function usePermitPacked(address token, uint256 value, uint256 deadline, bytes calldata signature) external nonReentrant {
315
+ require(underlyingLookup[token].eTokenAddress != address(0), "e/exec/market-not-activated");
316
+ address msgSender = unpackTrailingParamMsgSender();
317
+
318
+ IERC20Permit(token).permit(msgSender, address(this), value, deadline, signature);
319
+ }
320
+
321
+ /// @notice Execute a staticcall to an arbitrary address with an arbitrary payload.
322
+ /// @param contractAddress Address of the contract to call
323
+ /// @param payload Encoded call payload
324
+ /// @return result Encoded return data
325
+ /// @dev Intended to be used in static-called batches, to e.g. provide detailed information about the impacts of the simulated operation.
326
+ function doStaticCall(address contractAddress, bytes memory payload) external view returns (bytes memory) {
327
+ (bool success, bytes memory result) = contractAddress.staticcall(payload);
328
+ if (!success) revertBytes(result);
329
+
330
+ assembly {
331
+ return(add(32, result), mload(result))
332
+ }
333
+ }
281
334
  }
contracts/BaseLogic.sol CHANGED
@@ -497,9 +497,9 @@
497
497
 
498
498
  if (toOwed == 0) doEnterMarket(to, assetCache.underlying);
499
499
 
500
500
  // If amount was rounded up, transfer exact amount owed
501
- if (amount > fromOwed && amount - fromOwed < INTERNAL_DEBT_PRECISION) amount = fromOwed;
501
+ if (amount > fromOwed && amount - fromOwed < INTERNAL_DEBT_PRECISION * assetCache.underlyingDecimalsScaler) amount = fromOwed;
502
502
 
503
503
  require(fromOwed >= amount, "e/insufficient-balance");
504
504
  unchecked { fromOwed -= amount; }
505
505
 
contracts/IRiskManager.sol CHANGED
@@ -27,11 +27,11 @@
27
27
  }
28
28
 
29
29
  function getNewMarketParameters(address underlying) external returns (NewMarketParameters memory);
30
30
 
31
- function requireLiquidity(address account) external;
32
- function computeLiquidity(address account) external returns (LiquidityStatus memory status);
33
- function computeAssetLiquidities(address account) external returns (AssetLiquidity[] memory assets);
31
+ function requireLiquidity(address account) external view;
32
+ function computeLiquidity(address account) external view returns (LiquidityStatus memory status);
33
+ function computeAssetLiquidities(address account) external view returns (AssetLiquidity[] memory assets);
34
34
 
35
- function getPrice(address underlying) external returns (uint twap, uint twapPeriod);
36
- function getPriceFull(address underlying) external returns (uint twap, uint twapPeriod, uint currPrice);
35
+ function getPrice(address underlying) external view returns (uint twap, uint twapPeriod);
36
+ function getPriceFull(address underlying) external view returns (uint twap, uint twapPeriod, uint currPrice);
37
37
  }
contracts/Interfaces.sol CHANGED
@@ -18,8 +18,14 @@
18
18
  function transfer(address to, uint value) external returns (bool);
19
19
  function transferFrom(address from, address to, uint value) external returns (bool);
20
20
  }
21
21
 
22
+ interface IERC20Permit {
23
+ function permit(address owner, address spender, uint value, uint deadline, uint8 v, bytes32 r, bytes32 s) external;
24
+ function permit(address holder, address spender, uint256 nonce, uint256 expiry, bool allowed, uint8 v, bytes32 r, bytes32 s) external;
25
+ function permit(address owner, address spender, uint value, uint deadline, bytes calldata signature) external;
26
+ }
27
+
22
28
  interface IERC3156FlashBorrower {
23
29
  function onFlashLoan(address initiator, address token, uint256 amount, uint256 fee, bytes calldata data) external returns (bytes32);
24
30
  }
25
31
 
contracts/BaseModule.sol CHANGED
@@ -22,24 +22,16 @@
22
22
  // Accessing parameters
23
23
 
24
24
  function unpackTrailingParamMsgSender() internal pure returns (address msgSender) {
25
25
  assembly {
26
- mstore(0, 0)
27
-
28
- calldatacopy(12, sub(calldatasize(), 40), 20)
29
- msgSender := mload(0)
26
+ msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
30
27
  }
31
28
  }
32
29
 
33
30
  function unpackTrailingParams() internal pure returns (address msgSender, address proxyAddr) {
34
31
  assembly {
35
- mstore(0, 0)
36
-
37
- calldatacopy(12, sub(calldatasize(), 40), 20)
38
- msgSender := mload(0)
39
-
40
- calldatacopy(12, sub(calldatasize(), 20), 20)
41
- proxyAddr := mload(0)
32
+ msgSender := shr(96, calldataload(sub(calldatasize(), 40)))
33
+ proxyAddr := shr(96, calldataload(sub(calldatasize(), 20)))
42
34
  }
43
35
  }
44
36
 
45
37
 
contracts/Base.sol CHANGED
@@ -52,8 +52,15 @@
52
52
  modifier reentrantOK() { // documentation only
53
53
  _;
54
54
  }
55
55
 
56
+ // Used to flag functions which do not modify storage, but do perform a delegate call
57
+ // to a view function, which prohibits a standard view modifier. The flag is used to
58
+ // patch state mutability in compiled ABIs and interfaces.
59
+ modifier staticDelegate() {
60
+ _;
61
+ }
62
+
56
63
  // WARNING: Must be very careful with this modifier. It resets the free memory pointer
57
64
  // to the value it was when the function started. This saves gas if more memory will
58
65
  // be allocated in the future. However, if the memory will be later referenced
59
66
  // (for example because the function has returned a pointer to it) then you cannot
contracts/Constants.sol CHANGED
@@ -20,11 +20,12 @@
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
22
  uint internal constant INITIAL_INTEREST_ACCUMULATOR = 1e27;
23
23
  uint internal constant AVERAGE_LIQUIDITY_PERIOD = 24 * 60 * 60;
24
- uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 10;
24
+ uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 144;
25
25
  uint24 internal constant DEFAULT_TWAP_WINDOW_SECONDS = 30 * 60;
26
26
  uint32 internal constant DEFAULT_BORROW_FACTOR = uint32(0.28 * 4_000_000_000);
27
+ uint32 internal constant SELF_COLLATERAL_FACTOR = uint32(0.95 * 4_000_000_000);
27
28
 
28
29
 
29
30
  // Implementation internals
30
31
 
@@ -74,12 +75,16 @@
74
75
  // Classes
75
76
  uint internal constant MODULEID__IRM_CLASS__STABLE = 2_000_500;
76
77
  uint internal constant MODULEID__IRM_CLASS__MAJOR = 2_000_501;
77
78
  uint internal constant MODULEID__IRM_CLASS__MIDCAP = 2_000_502;
79
+ uint internal constant MODULEID__IRM_CLASS__MEGA = 2_000_503;
78
80
 
79
81
  // Swap types
80
82
  uint internal constant SWAP_TYPE__UNI_EXACT_INPUT_SINGLE = 1;
81
83
  uint internal constant SWAP_TYPE__UNI_EXACT_INPUT = 2;
82
84
  uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE = 3;
83
85
  uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT = 4;
84
86
  uint internal constant SWAP_TYPE__1INCH = 5;
87
+
88
+ uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_SINGLE_REPAY = 6;
89
+ uint internal constant SWAP_TYPE__UNI_EXACT_OUTPUT_REPAY = 7;
85
90
  }