@@ -38,23 +38,30 @@
|
|
38
38
|
(address underlying,,,) = CALLER();
|
39
39
|
return string(abi.encodePacked("d", IERC20(underlying).symbol()));
|
40
40
|
}
|
41
41
|
|
42
|
-
/// @notice Decimals
|
43
|
-
function decimals() external
|
44
|
-
|
42
|
+
/// @notice Decimals of underlying
|
43
|
+
function decimals() external view returns (uint8) {
|
44
|
+
(,AssetStorage storage assetStorage,,) = CALLER();
|
45
|
+
return assetStorage.underlyingDecimals;
|
45
46
|
}
|
46
47
|
|
48
|
+
/// @notice Address of underlying asset
|
49
|
+
function underlyingAsset() external view returns (address) {
|
50
|
+
(address underlying,,,) = CALLER();
|
51
|
+
return underlying;
|
52
|
+
}
|
47
53
|
|
54
|
+
|
48
55
|
/// @notice Sum of all outstanding debts, in underlying units (increases as interest is accrued)
|
49
56
|
function totalSupply() external view returns (uint) {
|
50
57
|
(address underlying, AssetStorage storage assetStorage,,) = CALLER();
|
51
58
|
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
|
52
59
|
|
53
60
|
return assetCache.totalBorrows / INTERNAL_DEBT_PRECISION / assetCache.underlyingDecimalsScaler;
|
54
61
|
}
|
55
62
|
|
56
|
-
/// @notice Sum of all outstanding debts, in underlying units
|
63
|
+
/// @notice Sum of all outstanding debts, in underlying units normalized to 27 decimals (increases as interest is accrued)
|
57
64
|
function totalSupplyExact() external view returns (uint) {
|
58
65
|
(address underlying, AssetStorage storage assetStorage,,) = CALLER();
|
59
66
|
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
|
60
67
|
|
@@ -69,9 +76,9 @@
|
|
69
76
|
|
70
77
|
return getCurrentOwed(assetStorage, assetCache, account) / assetCache.underlyingDecimalsScaler;
|
71
78
|
}
|
72
79
|
|
73
|
-
/// @notice Debt owed by a particular account, in underlying units
|
80
|
+
/// @notice Debt owed by a particular account, in underlying units normalized to 27 decimals
|
74
81
|
function balanceOfExact(address account) external view returns (uint) {
|
75
82
|
(address underlying, AssetStorage storage assetStorage,,) = CALLER();
|
76
83
|
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
|
77
84
|
|
@@ -137,16 +144,19 @@
|
|
137
144
|
|
138
145
|
/// @notice Allow spender to send an amount of dTokens to a particular sub-account
|
139
146
|
/// @param subAccountId 0 for primary, 1-255 for a sub-account
|
140
147
|
/// @param spender Trusted address
|
141
|
-
/// @param amount
|
148
|
+
/// @param amount In underlying units (use max uint256 for "infinite" allowance)
|
142
149
|
function approveDebt(uint subAccountId, address spender, uint amount) public reentrantOK returns (bool) {
|
143
|
-
(, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
|
150
|
+
(address underlying, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
|
144
151
|
address account = getSubAccount(msgSender, subAccountId);
|
145
152
|
|
146
153
|
require(!isSubAccountOf(spender, account), "e/self-approval");
|
147
154
|
|
148
|
-
|
155
|
+
AssetCache memory assetCache = loadAssetCache(underlying, assetStorage);
|
156
|
+
|
157
|
+
assetStorage.dTokenAllowance[account][spender] = amount == type(uint).max ? type(uint).max : decodeExternalAmount(assetCache, amount);
|
158
|
+
|
149
159
|
emitViaProxy_Approval(proxyAddr, account, spender, amount);
|
150
160
|
|
151
161
|
return true;
|
152
162
|
}
|
@@ -154,11 +164,14 @@
|
|
154
164
|
/// @notice Retrieve the current debt allowance
|
155
165
|
/// @param holder Xor with the desired sub-account ID (if applicable)
|
156
166
|
/// @param spender Trusted address
|
157
167
|
function debtAllowance(address holder, address spender) external view returns (uint) {
|
158
|
-
(, AssetStorage storage assetStorage,,) = CALLER();
|
168
|
+
(address underlying, AssetStorage storage assetStorage,,) = CALLER();
|
169
|
+
AssetCache memory assetCache = loadAssetCacheRO(underlying, assetStorage);
|
159
170
|
|
160
|
-
|
171
|
+
uint allowance = assetStorage.dTokenAllowance[holder][spender];
|
172
|
+
|
173
|
+
return allowance == type(uint).max ? type(uint).max : allowance / assetCache.underlyingDecimalsScaler;
|
161
174
|
}
|
162
175
|
|
163
176
|
|
164
177
|
|
@@ -171,9 +184,9 @@
|
|
171
184
|
|
172
185
|
/// @notice Transfer dTokens from one address to another
|
173
186
|
/// @param from Xor with the desired sub-account ID (if applicable)
|
174
187
|
/// @param to This address must've approved the from address, or be a sub-account of msg.sender
|
175
|
-
/// @param amount In underlying. Use max uint256 for full balance.
|
188
|
+
/// @param amount In underlying units. Use max uint256 for full balance.
|
176
189
|
function transferFrom(address from, address to, uint amount) public nonReentrant returns (bool) {
|
177
190
|
(address underlying, AssetStorage storage assetStorage, address proxyAddr, address msgSender) = CALLER();
|
178
191
|
AssetCache memory assetCache = loadAssetCache(underlying, assetStorage);
|
179
192
|
|
@@ -191,9 +204,9 @@
|
|
191
204
|
|
192
205
|
if (!isSubAccountOf(msgSender, to) && assetStorage.dTokenAllowance[to][msgSender] != type(uint).max) {
|
193
206
|
require(assetStorage.dTokenAllowance[to][msgSender] >= amount, "e/insufficient-debt-allowance");
|
194
207
|
unchecked { assetStorage.dTokenAllowance[to][msgSender] -= amount; }
|
195
|
-
emitViaProxy_Approval(proxyAddr, to, msgSender, assetStorage.dTokenAllowance[to][msgSender]);
|
208
|
+
emitViaProxy_Approval(proxyAddr, to, msgSender, assetStorage.dTokenAllowance[to][msgSender] / assetCache.underlyingDecimalsScaler);
|
196
209
|
}
|
197
210
|
|
198
211
|
transferBorrow(assetStorage, assetCache, proxyAddr, from, to, amount);
|
199
212
|
|
@@ -441,13 +441,13 @@
|
|
441
441
|
|
442
442
|
if (owed > prevOwed) {
|
443
443
|
uint change = owed - prevOwed;
|
444
444
|
emit Borrow(assetCache.underlying, account, change);
|
445
|
-
emitViaProxy_Transfer(dTokenAddress, address(0), account, change);
|
445
|
+
emitViaProxy_Transfer(dTokenAddress, address(0), account, change / assetCache.underlyingDecimalsScaler);
|
446
446
|
} else if (prevOwed > owed) {
|
447
447
|
uint change = prevOwed - owed;
|
448
448
|
emit Repay(assetCache.underlying, account, change);
|
449
|
-
emitViaProxy_Transfer(dTokenAddress, account, address(0), change);
|
449
|
+
emitViaProxy_Transfer(dTokenAddress, account, address(0), change / assetCache.underlyingDecimalsScaler);
|
450
450
|
}
|
451
451
|
}
|
452
452
|
|
453
453
|
function increaseBorrow(AssetStorage storage assetStorage, AssetCache memory assetCache, address dTokenAddress, address account, uint amount) internal {
|
@@ -22,24 +22,16 @@
|
|
22
22
|
// Accessing parameters
|
23
23
|
|
24
24
|
function unpackTrailingParamMsgSender() internal pure returns (address msgSender) {
|
25
25
|
assembly {
|
26
|
-
|
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
|
-
|
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
|
|
@@ -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
|
|
@@ -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
|
}
|
@@ -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
|
@@ -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 =
|
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,8 +75,9 @@
|
|
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;
|