Skip to content
This repository was archived by the owner on May 24, 2024. It is now read-only.

Commit e3b1e3b

Browse files
committed
Allow multiple overrides to be active with a single liability
1 parent b8ee236 commit e3b1e3b

33 files changed

+2585
-322
lines changed

TODO

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,5 @@
11
Overrides:
2-
* liquidations: will incorrectly calculate liquidatable amount
3-
* verify adding fields to the end of LiquidityStatus doesn't break any ABIs
4-
* view can't correctly query collateral/liability values of individual assets
5-
? fix this in riskManager.computeAssetLiquidities
6-
* make sure user isn't entered into any other markets (with 0 balance)
7-
* attacker could dust their account and force-disable the override
2+
? how is BF=0 handled in liquidations
83

94
Lending logic:
105
g when a token has < 18 decimal places, and a user withdraws their full EToken balance, 0 out the remaining dust so user gets a storage refund

contracts/BaseLogic.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -574,12 +574,13 @@ abstract contract BaseLogic is BaseModule {
574574
return abi.decode(result, (uint));
575575
}
576576

577-
function getAccountLiquidity(address account) internal returns (uint collateralValue, uint liabilityValue) {
577+
function getAccountLiquidity(address account) internal returns (uint collateralValue, uint liabilityValue, uint overrideCollateralValue) {
578578
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER, abi.encodeWithSelector(IRiskManager.computeLiquidity.selector, account));
579579
(IRiskManager.LiquidityStatus memory status) = abi.decode(result, (IRiskManager.LiquidityStatus));
580580

581581
collateralValue = status.collateralValue;
582582
liabilityValue = status.liabilityValue;
583+
overrideCollateralValue = status.overrideCollateralValue;
583584
}
584585

585586
function checkLiquidity(address account) internal {
@@ -603,7 +604,7 @@ abstract contract BaseLogic is BaseModule {
603604
uint currAverageLiquidity;
604605

605606
{
606-
(uint collateralValue, uint liabilityValue) = getAccountLiquidity(account);
607+
(uint collateralValue, uint liabilityValue,) = getAccountLiquidity(account);
607608
currAverageLiquidity = collateralValue > liabilityValue ? collateralValue - liabilityValue : 0;
608609
}
609610

contracts/Constants.sol

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ abstract contract Constants {
2525
uint16 internal constant MIN_UNISWAP3_OBSERVATION_CARDINALITY = 144;
2626
uint24 internal constant DEFAULT_TWAP_WINDOW_SECONDS = 30 * 60;
2727
uint32 internal constant DEFAULT_BORROW_FACTOR = uint32(0.28 * 4_000_000_000);
28-
uint32 internal constant SELF_COLLATERAL_FACTOR = uint32(0.95 * 4_000_000_000);
2928

3029

3130
// Implementation internals

contracts/IRiskManager.sol

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,8 +19,7 @@ interface IRiskManager {
1919
uint liabilityValue;
2020
uint numBorrows;
2121
bool borrowIsolated;
22-
uint numCollaterals;
23-
bool overrideEnabled;
22+
uint overrideCollateralValue;
2423
}
2524

2625
struct AssetLiquidity {
@@ -36,4 +35,6 @@ interface IRiskManager {
3635

3736
function getPrice(address underlying) external view returns (uint twap, uint twapPeriod);
3837
function getPriceFull(address underlying) external view returns (uint twap, uint twapPeriod, uint currPrice);
38+
39+
function selfCollateralFactor() external view returns (uint32);
3940
}

contracts/Storage.sol

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,4 +100,6 @@ abstract contract Storage is Constants {
100100
}
101101

102102
mapping(address => mapping(address => OverrideConfig)) internal overrideLookup; // liability => collateral => OverrideConfig
103+
mapping(address => address[]) internal overrideCollaterals; // liability => collaterals
104+
mapping(address => address[]) internal overrideLiabilities; // collateral => liabilities
103105
}

contracts/modules/EToken.sol

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -167,10 +167,6 @@ contract EToken is BaseLogic {
167167

168168
increaseBalance(assetStorage, assetCache, proxyAddr, account, amountInternal);
169169

170-
// Depositing a token to an account with pre-existing debt in that token creates a self-collateralized loan
171-
// which may result in borrow isolation violation if other tokens are also borrowed on the account
172-
if (assetStorage.users[account].owed != 0) checkLiquidity(account);
173-
174170
logAssetStatus(assetCache);
175171
}
176172

@@ -344,10 +340,6 @@ contract EToken is BaseLogic {
344340

345341
checkLiquidity(from);
346342

347-
// Depositing a token to an account with pre-existing debt in that token creates a self-collateralized loan
348-
// which may result in borrow isolation violation if other tokens are also borrowed on the account
349-
if (assetStorage.users[to].owed != 0) checkLiquidity(to);
350-
351343
logAssetStatus(assetCache);
352344

353345
return true;

contracts/modules/Exec.sol

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ contract Exec is BaseLogic {
5050
/// @notice Compute detailed liquidity for an account, broken down by asset
5151
/// @param account User address
5252
/// @return assets List of user's entered assets and each asset's corresponding liquidity
53-
function detailedLiquidity(address account) public staticDelegate returns (IRiskManager.AssetLiquidity[] memory assets) {
53+
function liquidityPerAsset(address account) public staticDelegate returns (IRiskManager.AssetLiquidity[] memory assets) {
5454
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
5555
abi.encodeWithSelector(IRiskManager.computeAssetLiquidities.selector, account));
5656

@@ -321,4 +321,45 @@ contract Exec is BaseLogic {
321321
if (status == DEFERLIQUIDITY__DIRTY) checkLiquidity(account);
322322
}
323323
}
324+
325+
326+
327+
328+
// Deprecated functions for backward compatibility. May be removed in the future.
329+
330+
struct LegacyLiquidityStatus {
331+
uint collateralValue;
332+
uint liabilityValue;
333+
uint numBorrows;
334+
bool borrowIsolated;
335+
}
336+
struct LegacyAssetLiquidity {
337+
address underlying;
338+
LegacyLiquidityStatus status;
339+
}
340+
341+
// DEPRECATED. Use liquidityPerAsset instead.
342+
function detailedLiquidity(address account) public staticDelegate returns (LegacyAssetLiquidity[] memory) {
343+
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
344+
abi.encodeWithSelector(IRiskManager.computeAssetLiquidities.selector, account));
345+
346+
(IRiskManager.AssetLiquidity[] memory assetLiquidities) = abi.decode(result, (IRiskManager.AssetLiquidity[]));
347+
348+
LegacyAssetLiquidity[] memory assets = new LegacyAssetLiquidity[](assetLiquidities.length);
349+
350+
for (uint i = 0; i < assetLiquidities.length; ++i) {
351+
IRiskManager.LiquidityStatus memory status = assetLiquidities[i].status;
352+
assets[i] = LegacyAssetLiquidity({
353+
underlying: assetLiquidities[i].underlying,
354+
status: LegacyLiquidityStatus({
355+
collateralValue: status.collateralValue,
356+
liabilityValue: status.liabilityValue,
357+
numBorrows: status.numBorrows,
358+
borrowIsolated: status.borrowIsolated
359+
})
360+
});
361+
}
362+
363+
return assets;
364+
}
324365
}

contracts/modules/Governance.sol

Lines changed: 23 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -98,10 +98,6 @@ contract Governance is BaseLogic {
9898

9999
increaseBalance(assetStorage, assetCache, eTokenAddress, recipient, amount);
100100

101-
// Depositing a token to an account with pre-existing debt in that token creates a self-collateralized loan
102-
// which may result in borrow isolation violation if other tokens are also borrowed on the account
103-
if (assetStorage.users[recipient].owed != 0) checkLiquidity(recipient);
104-
105101
logAssetStatus(assetCache);
106102

107103
emit GovConvertReserves(underlying, recipient, balanceToUnderlyingAmount(assetCache, amount));
@@ -118,14 +114,34 @@ contract Governance is BaseLogic {
118114
}
119115

120116
function setOverride(address liability, address collateral, OverrideConfig calldata newOverride) external nonReentrant governorOnly {
121-
require(underlyingLookup[liability].eTokenAddress != address(0), "e/gov/liability-not-activated");
122-
require(underlyingLookup[collateral].eTokenAddress != address(0), "e/gov/collateral-not-activated");
123-
124117
overrideLookup[liability][collateral] = newOverride;
125118

119+
updateOverridesArray(overrideCollaterals[liability], collateral, newOverride);
120+
updateOverridesArray(overrideLiabilities[collateral], liability, newOverride);
121+
126122
emit GovSetOverride(liability, collateral, newOverride);
127123
}
128124

125+
function updateOverridesArray(address[] storage arr, address asset, OverrideConfig calldata newOverride) private {
126+
uint length = arr.length;
127+
if (newOverride.enabled) {
128+
for (uint i = 0; i < length;) {
129+
if (arr[i] == asset) return;
130+
unchecked { ++i; }
131+
}
132+
arr.push(asset);
133+
} else {
134+
for (uint i = 0; i < length;) {
135+
if (arr[i] == asset) {
136+
arr[i] = arr[length - 1];
137+
arr.pop();
138+
return;
139+
}
140+
unchecked { ++i; }
141+
}
142+
}
143+
}
144+
129145
// getters
130146

131147
function getGovernorAdmin() external view returns (address) {

0 commit comments

Comments
 (0)