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

Commit

Permalink
Allow multiple overrides to be active with a single liability
Browse files Browse the repository at this point in the history
  • Loading branch information
dglowinski committed Mar 10, 2023
1 parent b8ee236 commit b835b05
Show file tree
Hide file tree
Showing 33 changed files with 2,592 additions and 318 deletions.
7 changes: 1 addition & 6 deletions TODO
Original file line number Diff line number Diff line change
@@ -1,10 +1,5 @@
Overrides:
* liquidations: will incorrectly calculate liquidatable amount
* verify adding fields to the end of LiquidityStatus doesn't break any ABIs
* view can't correctly query collateral/liability values of individual assets
? fix this in riskManager.computeAssetLiquidities
* make sure user isn't entered into any other markets (with 0 balance)
* attacker could dust their account and force-disable the override
? how is BF=0 handled in liquidations

Lending logic:
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
Expand Down
1 change: 1 addition & 0 deletions addresses/euler-addresses-mainnet.json
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@
"SwapHandlerUniswapV3": "0x7527E082300fb8D189B3c07dB3BEcc990B5037E7"
},
"eulerGeneralView": "0xACC25c4d40651676FEEd43a3467F3169e3E68e42",
"eulerLensV1": "0xACC25c4d40651676FEEd43a3467F3169e3E68e42",
"eulerSimpleLens": "0x5077B7642abF198b4a5b7C4BdCE4f03016C7089C",
"euler": "0x27182842E098f60e3D576794A5bFFb0777E025d3",
"installer": "0x055DE1CCbCC9Bc5291569a0b6aFFdF8b5707aB16",
Expand Down
5 changes: 3 additions & 2 deletions contracts/BaseLogic.sol
Original file line number Diff line number Diff line change
Expand Up @@ -574,12 +574,13 @@ abstract contract BaseLogic is BaseModule {
return abi.decode(result, (uint));
}

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

collateralValue = status.collateralValue;
liabilityValue = status.liabilityValue;
overrideCollateralValue = status.overrideCollateralValue;
}

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

{
(uint collateralValue, uint liabilityValue) = getAccountLiquidity(account);
(uint collateralValue, uint liabilityValue,) = getAccountLiquidity(account);
currAverageLiquidity = collateralValue > liabilityValue ? collateralValue - liabilityValue : 0;
}

Expand Down
3 changes: 1 addition & 2 deletions contracts/IRiskManager.sol
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@ interface IRiskManager {
uint liabilityValue;
uint numBorrows;
bool borrowIsolated;
uint numCollaterals;
bool overrideEnabled;
uint overrideCollateralValue;
}

struct AssetLiquidity {
Expand Down
2 changes: 2 additions & 0 deletions contracts/Storage.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,6 @@ abstract contract Storage is Constants {
}

mapping(address => mapping(address => OverrideConfig)) internal overrideLookup; // liability => collateral => OverrideConfig
mapping(address => address[]) internal overrideCollaterals; // liability => collaterals
mapping(address => address[]) internal overrideLiabilities; // collateral => liabilities
}
8 changes: 0 additions & 8 deletions contracts/modules/EToken.sol
Original file line number Diff line number Diff line change
Expand Up @@ -167,10 +167,6 @@ contract EToken is BaseLogic {

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

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

logAssetStatus(assetCache);
}

Expand Down Expand Up @@ -344,10 +340,6 @@ contract EToken is BaseLogic {

checkLiquidity(from);

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

logAssetStatus(assetCache);

return true;
Expand Down
43 changes: 42 additions & 1 deletion contracts/modules/Exec.sol
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ contract Exec is BaseLogic {
/// @notice Compute detailed liquidity for an account, broken down by asset
/// @param account User address
/// @return assets List of user's entered assets and each asset's corresponding liquidity
function detailedLiquidity(address account) public staticDelegate returns (IRiskManager.AssetLiquidity[] memory assets) {
function liquidityPerAsset(address account) public staticDelegate returns (IRiskManager.AssetLiquidity[] memory assets) {
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
abi.encodeWithSelector(IRiskManager.computeAssetLiquidities.selector, account));

Expand Down Expand Up @@ -321,4 +321,45 @@ contract Exec is BaseLogic {
if (status == DEFERLIQUIDITY__DIRTY) checkLiquidity(account);
}
}




// Deprecated functions for backward compatibility. May be removed in the future.

struct LegacyLiquidityStatus {
uint collateralValue;
uint liabilityValue;
uint numBorrows;
bool borrowIsolated;
}
struct LegacyAssetLiquidity {
address underlying;
LegacyLiquidityStatus status;
}

// DEPRECATED. Use liquidityPerAsset instead.
function detailedLiquidity(address account) public staticDelegate returns (LegacyAssetLiquidity[] memory) {
bytes memory result = callInternalModule(MODULEID__RISK_MANAGER,
abi.encodeWithSelector(IRiskManager.computeAssetLiquidities.selector, account));

(IRiskManager.AssetLiquidity[] memory assetLiquidities) = abi.decode(result, (IRiskManager.AssetLiquidity[]));

LegacyAssetLiquidity[] memory assets = new LegacyAssetLiquidity[](assetLiquidities.length);

for (uint i = 0; i < assetLiquidities.length; ++i) {
IRiskManager.LiquidityStatus memory status = assetLiquidities[i].status;
assets[i] = LegacyAssetLiquidity({
underlying: assetLiquidities[i].underlying,
status: LegacyLiquidityStatus({
collateralValue: status.collateralValue,
liabilityValue: status.liabilityValue,
numBorrows: status.numBorrows,
borrowIsolated: status.borrowIsolated
})
});
}

return assets;
}
}
30 changes: 23 additions & 7 deletions contracts/modules/Governance.sol
Original file line number Diff line number Diff line change
Expand Up @@ -98,10 +98,6 @@ contract Governance is BaseLogic {

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

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

logAssetStatus(assetCache);

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

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

overrideLookup[liability][collateral] = newOverride;

updateOverridesArray(overrideCollaterals[liability], collateral, newOverride);
updateOverridesArray(overrideLiabilities[collateral], liability, newOverride);

emit GovSetOverride(liability, collateral, newOverride);
}

function updateOverridesArray(address[] storage arr, address asset, OverrideConfig calldata newOverride) private {
uint length = arr.length;
if (newOverride.enabled) {
for (uint i = 0; i < length;) {
if (arr[i] == asset) return;
unchecked { ++i; }
}
arr.push(asset);
} else {
for (uint i = 0; i < length;) {
if (arr[i] == asset) {
arr[i] = arr[length - 1];
arr.pop();
return;
}
unchecked { ++i; }
}
}
}

// getters

function getGovernorAdmin() external view returns (address) {
Expand Down
Loading

0 comments on commit b835b05

Please sign in to comment.