From e7ccddf7178acbe738e0b58aa164ddf0bb38c834 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Sat, 22 Mar 2025 17:07:43 +0530 Subject: [PATCH 1/8] feat: add emode and remove using data provider --- foundry.toml | 2 +- scripts/RiskStewardsBase.s.sol | 24 +- scripts/deploy/DeployCapInjector.s.sol | 53 ++-- scripts/deploy/DeployRateInjector.s.sol | 49 ++-- scripts/deploy/DeployStewards.s.sol | 81 +++--- src/contracts/EdgeRiskStewardCaps.sol | 17 +- src/contracts/EdgeRiskStewardRates.sol | 17 +- src/contracts/RiskSteward.sol | 217 +++++++++++---- src/interfaces/IRiskSteward.sol | 104 ++++++- tests/AaveStewardsInjectorCaps.t.sol | 22 +- tests/AaveStewardsInjectorRates.t.sol | 24 +- tests/EdgeRiskStewardCaps.t.sol | 9 +- tests/EdgeRiskStewardRates.t.sol | 9 +- tests/RiskSteward.t.sol | 348 +++++++++++------------- tests/RiskStewardCapo.t.sol | 27 +- 15 files changed, 578 insertions(+), 425 deletions(-) diff --git a/foundry.toml b/foundry.toml index 6e326b1..e648ae3 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ src = 'src' test = 'tests' script = 'scripts' out = 'out' -solc = '0.8.22' +solc = '0.8.24' optimizer = true optimizer_runs = 200 libs = ['lib'] diff --git a/scripts/RiskStewardsBase.s.sol b/scripts/RiskStewardsBase.s.sol index 9bc0c9b..e955168 100644 --- a/scripts/RiskStewardsBase.s.sol +++ b/scripts/RiskStewardsBase.s.sol @@ -95,26 +95,26 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { IRiskSteward.Config memory riskConfig = STEWARD.getRiskConfig(); if (capUpdates.length != 0) { - timelocks[index++] = riskConfig.supplyCap.minDelay; - timelocks[index++] = riskConfig.borrowCap.minDelay; + timelocks[index++] = riskConfig.capConfig.supplyCap.minDelay; + timelocks[index++] = riskConfig.capConfig.borrowCap.minDelay; } if (collateralUpdates.length != 0) { - timelocks[index++] = riskConfig.ltv.minDelay; - timelocks[index++] = riskConfig.liquidationThreshold.minDelay; - timelocks[index++] = riskConfig.liquidationBonus.minDelay; - timelocks[index++] = riskConfig.debtCeiling.minDelay; + timelocks[index++] = riskConfig.collateralConfig.ltv.minDelay; + timelocks[index++] = riskConfig.collateralConfig.liquidationThreshold.minDelay; + timelocks[index++] = riskConfig.collateralConfig.liquidationBonus.minDelay; + timelocks[index++] = riskConfig.collateralConfig.debtCeiling.minDelay; } if (rateUpdates.length != 0) { - timelocks[index++] = riskConfig.baseVariableBorrowRate.minDelay; - timelocks[index++] = riskConfig.optimalUsageRatio.minDelay; - timelocks[index++] = riskConfig.variableRateSlope1.minDelay; - timelocks[index++] = riskConfig.variableRateSlope2.minDelay; + timelocks[index++] = riskConfig.rateConfig.baseVariableBorrowRate.minDelay; + timelocks[index++] = riskConfig.rateConfig.optimalUsageRatio.minDelay; + timelocks[index++] = riskConfig.rateConfig.variableRateSlope1.minDelay; + timelocks[index++] = riskConfig.rateConfig.variableRateSlope2.minDelay; } if (lstPriceCapUpdates.length != 0) { - timelocks[index++] = riskConfig.priceCapLst.minDelay; + timelocks[index++] = riskConfig.priceCapConfig.priceCapLst.minDelay; } if (stablePriceCapUpdates.length != 0) { - timelocks[index++] = riskConfig.priceCapStable.minDelay; + timelocks[index++] = riskConfig.priceCapConfig.priceCapStable.minDelay; } uint40 maxTimelock = 0; for (uint256 i = 0; i < timelocks.length; i++) { diff --git a/scripts/deploy/DeployCapInjector.s.sol b/scripts/deploy/DeployCapInjector.s.sol index 5cbce81..94a1b5e 100644 --- a/scripts/deploy/DeployCapInjector.s.sol +++ b/scripts/deploy/DeployCapInjector.s.sol @@ -6,28 +6,27 @@ import {MiscArbitrum} from 'aave-address-book/MiscArbitrum.sol'; import {AaveV3Arbitrum, AaveV3ArbitrumAssets} from 'aave-address-book/AaveV3Arbitrum.sol'; import {GovernanceV3Arbitrum} from 'aave-address-book/GovernanceV3Arbitrum.sol'; import {ICreate3Factory} from 'solidity-utils/contracts/create3/interfaces/ICreate3Factory.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {EdgeRiskStewardCaps, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/EdgeRiskStewardCaps.sol'; +import {EdgeRiskStewardCaps, IRiskSteward} from '../../src/contracts/EdgeRiskStewardCaps.sol'; import {AaveStewardInjectorCaps} from '../../src/contracts/AaveStewardInjectorCaps.sol'; library DeployStewardContracts { address constant EDGE_RISK_ORACLE = 0x861eeAdB55E41f161F31Acb1BFD4c70E3a964Aed; function _deployRiskStewards( - address poolDataProvider, + address poolAddressesProvider, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardCaps( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + poolAddressesProvider, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } @@ -53,27 +52,31 @@ library DeployStewardContracts { function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 50 + eModeConfig: IRiskSteward.EmodeConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 5_00 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}) + }), + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + }) }); } } @@ -89,7 +92,7 @@ contract DeployArbitrum is ArbitrumScript { .predictAddress(msg.sender, salt); address riskSteward = DeployStewardContracts._deployRiskStewards( - address(AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Arbitrum.POOL_ADDRESSES_PROVIDER), AaveV3Arbitrum.CONFIG_ENGINE, predictedStewardsInjector, GovernanceV3Arbitrum.EXECUTOR_LVL_1 diff --git a/scripts/deploy/DeployRateInjector.s.sol b/scripts/deploy/DeployRateInjector.s.sol index 0fe52d1..9262049 100644 --- a/scripts/deploy/DeployRateInjector.s.sol +++ b/scripts/deploy/DeployRateInjector.s.sol @@ -6,8 +6,7 @@ import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; import {AaveV3EthereumLido, AaveV3EthereumLidoAssets} from 'aave-address-book/AaveV3EthereumLido.sol'; import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; import {ICreate3Factory} from 'solidity-utils/contracts/create3/interfaces/ICreate3Factory.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {EdgeRiskStewardRates, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/EdgeRiskStewardRates.sol'; +import {EdgeRiskStewardRates, IRiskSteward} from '../../src/contracts/EdgeRiskStewardRates.sol'; import {AaveStewardInjectorRates} from '../../src/contracts/AaveStewardInjectorRates.sol'; library DeployStewardContracts { @@ -21,13 +20,13 @@ library DeployStewardContracts { ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardRates( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + poolDataProvider, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } @@ -51,27 +50,31 @@ library DeployStewardContracts { function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 50 + eModeConfig: IRiskSteward.EmodeConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 5_00 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 3_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}) + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}) + }), + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}) + }) }); } } diff --git a/scripts/deploy/DeployStewards.s.sol b/scripts/deploy/DeployStewards.s.sol index 69e66eb..3ac8c1a 100644 --- a/scripts/deploy/DeployStewards.s.sol +++ b/scripts/deploy/DeployStewards.s.sol @@ -30,52 +30,55 @@ import {AaveV3Sonic} from 'aave-address-book/AaveV3Sonic.sol'; import {GovernanceV3Sonic} from 'aave-address-book/GovernanceV3Sonic.sol'; import {AaveV3Celo} from 'aave-address-book/AaveV3Celo.sol'; import {GovernanceV3Celo} from 'aave-address-book/GovernanceV3Celo.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {RiskSteward, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/RiskSteward.sol'; +import {RiskSteward, IRiskSteward} from '../../src/contracts/RiskSteward.sol'; library DeployRiskStewards { function _deployRiskStewards( - address poolDataProvider, + address addressesProvider, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new RiskSteward( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + addressesProvider, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 50 + eModeConfig: IRiskSteward.EmodeConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 5_00 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}) + }), + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + }) }); } } @@ -85,7 +88,7 @@ contract DeployEthereum is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), AaveV3Ethereum.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -99,7 +102,7 @@ contract DeployEthereumLido is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumLido.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumLido.POOL_ADDRESSES_PROVIDER), AaveV3EthereumLido.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -113,7 +116,7 @@ contract DeployEthereumEtherFi is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumEtherFi.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumEtherFi.POOL_ADDRESSES_PROVIDER), AaveV3EthereumEtherFi.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -127,7 +130,7 @@ contract DeployPolygon is PolygonScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Polygon.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Polygon.POOL_ADDRESSES_PROVIDER), AaveV3Polygon.CONFIG_ENGINE, 0x2C40FB1ACe63084fc0bB95F83C31B5854C6C4cB5, // pol-risk-council GovernanceV3Polygon.EXECUTOR_LVL_1 @@ -141,7 +144,7 @@ contract DeployArbitrum is ArbitrumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Arbitrum.POOL_ADDRESSES_PROVIDER), AaveV3Arbitrum.CONFIG_ENGINE, 0x3Be327F22eB4BD8042e6944073b8826dCf357Aa2, // arb-risk-council GovernanceV3Arbitrum.EXECUTOR_LVL_1 @@ -155,7 +158,7 @@ contract DeployOptimism is OptimismScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Optimism.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Optimism.POOL_ADDRESSES_PROVIDER), AaveV3Optimism.CONFIG_ENGINE, 0xCb86256A994f0c505c5e15c75BF85fdFEa0F2a56, // opt-risk-council GovernanceV3Optimism.EXECUTOR_LVL_1 @@ -169,7 +172,7 @@ contract DeployAvalanche is AvalancheScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Avalanche.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Avalanche.POOL_ADDRESSES_PROVIDER), AaveV3Avalanche.CONFIG_ENGINE, 0xCa66149425E7DC8f81276F6D80C4b486B9503D1a, // ava-risk-council GovernanceV3Avalanche.EXECUTOR_LVL_1 @@ -183,7 +186,7 @@ contract DeployScroll is ScrollScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Scroll.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Scroll.POOL_ADDRESSES_PROVIDER), AaveV3Scroll.CONFIG_ENGINE, 0x611439a74546888c3535B4dd119A5Cbb9f5332EA, // scroll-risk-council GovernanceV3Scroll.EXECUTOR_LVL_1 @@ -197,7 +200,7 @@ contract DeployGnosis is GnosisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Gnosis.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Gnosis.POOL_ADDRESSES_PROVIDER), AaveV3Gnosis.CONFIG_ENGINE, 0xF221B08dD10e0C68D74F035764931Baa3b030481, // gnosis-risk-council GovernanceV3Gnosis.EXECUTOR_LVL_1 @@ -211,7 +214,7 @@ contract DeployBNB is BNBScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3BNB.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3BNB.POOL_ADDRESSES_PROVIDER), AaveV3BNB.CONFIG_ENGINE, 0x126dc589cc75f17385dD95516F3F1788d862E7bc, // bnb-risk-council GovernanceV3BNB.EXECUTOR_LVL_1 @@ -225,7 +228,7 @@ contract DeployBase is BaseScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Base.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Base.POOL_ADDRESSES_PROVIDER), AaveV3Base.CONFIG_ENGINE, 0xfbeB4AcB31340bA4de9C87B11dfBf7e2bc8C0bF1, // base-risk-council GovernanceV3Base.EXECUTOR_LVL_1 @@ -239,7 +242,7 @@ contract DeployMetis is MetisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Metis.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Metis.POOL_ADDRESSES_PROVIDER), AaveV3Metis.CONFIG_ENGINE, 0x0f547846920C34E70FBE4F3d87E46452a3FeAFfa, // metis-risk-council GovernanceV3Metis.EXECUTOR_LVL_1 @@ -253,7 +256,7 @@ contract DeployLinea is LineaScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Linea.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Linea.POOL_ADDRESSES_PROVIDER), AaveV3Linea.CONFIG_ENGINE, 0xF092A5aC5E284E7c433dAFE5b8B138bFcA53a4Ee, // linea-risk-council GovernanceV3Linea.EXECUTOR_LVL_1 @@ -267,7 +270,7 @@ contract DeploySonic is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Sonic.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Sonic.POOL_ADDRESSES_PROVIDER), AaveV3Sonic.CONFIG_ENGINE, 0x1dE39A17a9Fa8c76899fff37488482EEb7835d04, // sonic-risk-council GovernanceV3Sonic.EXECUTOR_LVL_1 @@ -281,7 +284,7 @@ contract DeployCelo is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Celo.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Celo.POOL_ADDRESSES_PROVIDER), AaveV3Celo.CONFIG_ENGINE, 0xd85786B5FC61E2A0c0a3144a33A0fC70646a99f6, // celo-risk-council GovernanceV3Celo.EXECUTOR_LVL_1 diff --git a/src/contracts/EdgeRiskStewardCaps.sol b/src/contracts/EdgeRiskStewardCaps.sol index 9a17487..4f9156a 100644 --- a/src/contracts/EdgeRiskStewardCaps.sol +++ b/src/contracts/EdgeRiskStewardCaps.sol @@ -11,17 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardCaps is RiskSteward { /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address poolAddressesProvider, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) RiskSteward(poolDataProvider, engine, riskCouncil, riskConfig) {} + ) RiskSteward(poolAddressesProvider, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateRates( @@ -37,6 +39,13 @@ contract EdgeRiskStewardCaps is RiskSteward { revert UpdateNotAllowed(); } + /// @inheritdoc IRiskSteward + function updateEModeCategories( + IEngine.EModeCategoryUpdate[] calldata + ) external virtual override onlyRiskCouncil { + revert UpdateNotAllowed(); + } + /// @inheritdoc IRiskSteward function updateLstPriceCaps( PriceCapLstUpdate[] calldata diff --git a/src/contracts/EdgeRiskStewardRates.sol b/src/contracts/EdgeRiskStewardRates.sol index 924f220..c80cb0d 100644 --- a/src/contracts/EdgeRiskStewardRates.sol +++ b/src/contracts/EdgeRiskStewardRates.sol @@ -11,17 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardRates is RiskSteward { /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address poolAddressesProvider, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) RiskSteward(poolDataProvider, engine, riskCouncil, riskConfig) {} + ) RiskSteward(poolAddressesProvider, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateCaps(IEngine.CapsUpdate[] calldata) external virtual override onlyRiskCouncil { @@ -35,6 +37,13 @@ contract EdgeRiskStewardRates is RiskSteward { revert UpdateNotAllowed(); } + /// @inheritdoc IRiskSteward + function updateEModeCategories( + IEngine.EModeCategoryUpdate[] calldata + ) external virtual override onlyRiskCouncil { + revert UpdateNotAllowed(); + } + /// @inheritdoc IRiskSteward function updateLstPriceCaps( PriceCapLstUpdate[] calldata diff --git a/src/contracts/RiskSteward.sol b/src/contracts/RiskSteward.sol index 909e752..21bc3e1 100644 --- a/src/contracts/RiskSteward.sol +++ b/src/contracts/RiskSteward.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; +import {IPool, IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol'; import {Address} from 'openzeppelin-contracts/contracts/utils/Address.sol'; import {SafeCast} from 'openzeppelin-contracts/contracts/utils/math/SafeCast.sol'; import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol'; @@ -19,6 +20,7 @@ import {IPriceCapAdapterStable} from 'aave-capo/interfaces/IPriceCapAdapterStabl * This contract can update the following risk params: caps, ltv, liqThreshold, liqBonus, debtCeiling, interest rates params. */ contract RiskSteward is Ownable, IRiskSteward { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; using Address for address; using SafeCast for uint256; using SafeCast for int256; @@ -27,7 +29,7 @@ contract RiskSteward is Ownable, IRiskSteward { IEngine public immutable CONFIG_ENGINE; /// @inheritdoc IRiskSteward - IPoolDataProvider public immutable POOL_DATA_PROVIDER; + IPoolAddressesProvider public immutable ADDRESSES_PROVIDER; /// @inheritdoc IRiskSteward address public immutable RISK_COUNCIL; @@ -36,10 +38,12 @@ contract RiskSteward is Ownable, IRiskSteward { Config internal _riskConfig; - mapping(address => Debounce) internal _timelocks; + mapping(bytes32 id => Debounce) internal _timelocks; mapping(address => bool) internal _restrictedAddresses; + mapping(uint8 => bool) internal _restrictedEModes; + /** * @dev Modifier preventing anyone, but the council to update risk params. */ @@ -49,19 +53,21 @@ contract RiskSteward is Ownable, IRiskSteward { } /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address poolAddressesProvider, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) Ownable(msg.sender) { - POOL_DATA_PROVIDER = poolDataProvider; - CONFIG_ENGINE = engine; + ) Ownable(owner) { + ADDRESSES_PROVIDER = IPoolAddressesProvider(poolAddressesProvider); + CONFIG_ENGINE = IEngine(engine); RISK_COUNCIL = riskCouncil; _riskConfig = riskConfig; } @@ -88,6 +94,14 @@ contract RiskSteward is Ownable, IRiskSteward { _updateCollateralSide(collateralUpdates); } + /// @inheritdoc IRiskSteward + function updateEModeCategories( + IEngine.EModeCategoryUpdate[] calldata eModeCategoryUpdates + ) external virtual onlyRiskCouncil { + _validateEModeCategoryUpdate(eModeCategoryUpdates); + _updateEModeCategories(eModeCategoryUpdates); + } + /// @inheritdoc IRiskSteward function updateLstPriceCaps( PriceCapLstUpdate[] calldata priceCapUpdates @@ -106,7 +120,12 @@ contract RiskSteward is Ownable, IRiskSteward { /// @inheritdoc IRiskSteward function getTimelock(address asset) external view returns (Debounce memory) { - return _timelocks[asset]; + return _timelocks[bytes20(asset)]; + } + + /// @inheritdoc IRiskSteward + function getEModeTimelock(uint8 eModeCategoryId) external view returns (Debounce memory) { + return _timelocks[bytes32(uint256(eModeCategoryId))]; } /// @inheritdoc IRiskSteward @@ -131,6 +150,17 @@ contract RiskSteward is Ownable, IRiskSteward { emit AddressRestricted(contractAddress, isRestricted); } + /// @inheritdoc IRiskSteward + function isEModeCategoryRestricted(uint8 eModeCategoryId) external view returns (bool) { + return _restrictedEModes[eModeCategoryId]; + } + + /// @inheritdoc IRiskSteward + function setEModeCategoryRestricted(uint8 eModeCategoryId, bool isRestricted) external onlyOwner { + _restrictedEModes[eModeCategoryId] = isRestricted; + emit EModeRestricted(eModeCategoryId, isRestricted); + } + /** * @notice method to validate the caps update * @param capsUpdate list containing the new supply, borrow caps of the assets @@ -145,16 +175,14 @@ contract RiskSteward is Ownable, IRiskSteward { if (capsUpdate[i].supplyCap == 0 || capsUpdate[i].borrowCap == 0) revert InvalidUpdateToZero(); - (uint256 currentBorrowCap, uint256 currentSupplyCap) = POOL_DATA_PROVIDER.getReserveCaps( - capsUpdate[i].asset - ); + (uint256 currentBorrowCap, uint256 currentSupplyCap) = IPool(ADDRESSES_PROVIDER.getPool()).getConfiguration(asset).getCaps(); _validateParamUpdate( ParamUpdateValidationInput({ currentValue: currentSupplyCap, newValue: capsUpdate[i].supplyCap, - lastUpdated: _timelocks[asset].supplyCapLastUpdated, - riskConfig: _riskConfig.supplyCap, + lastUpdated: _timelocks[bytes20(asset)].supplyCapLastUpdated, + riskConfig: _riskConfig.capConfig.supplyCap, isChangeRelative: true }) ); @@ -162,8 +190,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentBorrowCap, newValue: capsUpdate[i].borrowCap, - lastUpdated: _timelocks[asset].borrowCapLastUpdated, - riskConfig: _riskConfig.borrowCap, + lastUpdated: _timelocks[bytes20(asset)].borrowCapLastUpdated, + riskConfig: _riskConfig.capConfig.borrowCap, isChangeRelative: true }) ); @@ -192,8 +220,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentOptimalUsageRatio, newValue: ratesUpdate[i].params.optimalUsageRatio, - lastUpdated: _timelocks[asset].optimalUsageRatioLastUpdated, - riskConfig: _riskConfig.optimalUsageRatio, + lastUpdated: _timelocks[bytes20(asset)].optimalUsageRatioLastUpdated, + riskConfig: _riskConfig.rateConfig.optimalUsageRatio, isChangeRelative: false }) ); @@ -201,8 +229,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentBaseVariableBorrowRate, newValue: ratesUpdate[i].params.baseVariableBorrowRate, - lastUpdated: _timelocks[asset].baseVariableRateLastUpdated, - riskConfig: _riskConfig.baseVariableBorrowRate, + lastUpdated: _timelocks[bytes20(asset)].baseVariableRateLastUpdated, + riskConfig: _riskConfig.rateConfig.baseVariableBorrowRate, isChangeRelative: false }) ); @@ -210,8 +238,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentVariableRateSlope1, newValue: ratesUpdate[i].params.variableRateSlope1, - lastUpdated: _timelocks[asset].variableRateSlope1LastUpdated, - riskConfig: _riskConfig.variableRateSlope1, + lastUpdated: _timelocks[bytes20(asset)].variableRateSlope1LastUpdated, + riskConfig: _riskConfig.rateConfig.variableRateSlope1, isChangeRelative: false }) ); @@ -219,8 +247,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentVariableRateSlope2, newValue: ratesUpdate[i].params.variableRateSlope2, - lastUpdated: _timelocks[asset].variableRateSlope2LastUpdated, - riskConfig: _riskConfig.variableRateSlope2, + lastUpdated: _timelocks[bytes20(asset)].variableRateSlope2LastUpdated, + riskConfig: _riskConfig.rateConfig.variableRateSlope2, isChangeRelative: false }) ); @@ -249,26 +277,22 @@ contract RiskSteward is Ownable, IRiskSteward { collateralUpdates[i].debtCeiling == 0 ) revert InvalidUpdateToZero(); + DataTypes.ReserveConfigurationMap memory configuration = IPool(ADDRESSES_PROVIDER.getPool()) + .getConfiguration(asset); ( - , uint256 currentLtv, uint256 currentLiquidationThreshold, uint256 currentLiquidationBonus, , - , - , - , - , - - ) = POOL_DATA_PROVIDER.getReserveConfigurationData(asset); - uint256 currentDebtCeiling = POOL_DATA_PROVIDER.getDebtCeiling(asset); + ) = configuration.getParams(); + uint256 currentDebtCeiling = configuration.getDebtCeiling(); _validateParamUpdate( ParamUpdateValidationInput({ currentValue: currentLtv, newValue: collateralUpdates[i].ltv, - lastUpdated: _timelocks[asset].ltvLastUpdated, - riskConfig: _riskConfig.ltv, + lastUpdated: _timelocks[bytes20(asset)].ltvLastUpdated, + riskConfig: _riskConfig.collateralConfig.ltv, isChangeRelative: false }) ); @@ -276,8 +300,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentLiquidationThreshold, newValue: collateralUpdates[i].liqThreshold, - lastUpdated: _timelocks[asset].liquidationThresholdLastUpdated, - riskConfig: _riskConfig.liquidationThreshold, + lastUpdated: _timelocks[bytes20(asset)].liquidationThresholdLastUpdated, + riskConfig: _riskConfig.collateralConfig.liquidationThreshold, isChangeRelative: false }) ); @@ -285,8 +309,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentLiquidationBonus - 100_00, // as the definition is 100% + x%, and config engine takes into account x% for simplicity. newValue: collateralUpdates[i].liqBonus, - lastUpdated: _timelocks[asset].liquidationBonusLastUpdated, - riskConfig: _riskConfig.liquidationBonus, + lastUpdated: _timelocks[bytes20(asset)].liquidationBonusLastUpdated, + riskConfig: _riskConfig.collateralConfig.liquidationBonus, isChangeRelative: false }) ); @@ -294,14 +318,65 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentDebtCeiling / 100, // as the definition is with 2 decimals, and config engine does not take the decimals into account. newValue: collateralUpdates[i].debtCeiling, - lastUpdated: _timelocks[asset].debtCeilingLastUpdated, - riskConfig: _riskConfig.debtCeiling, + lastUpdated: _timelocks[bytes20(asset)].debtCeilingLastUpdated, + riskConfig: _riskConfig.collateralConfig.debtCeiling, isChangeRelative: true }) ); } } + /** + * @notice method to validate the eMode category update + * @param eModeCategoryUpdates list containing the new eMode category updates + */ + function _validateEModeCategoryUpdate( + IEngine.EModeCategoryUpdate[] calldata eModeCategoryUpdates + ) internal view { + if (eModeCategoryUpdates.length == 0) revert NoZeroUpdates(); + + for (uint256 i = 0; i < eModeCategoryUpdates.length; i++) { + uint8 eModeId = eModeCategoryUpdates[i].eModeCategory; + if (_restrictedEModes[eModeId]) revert EModeIsRestricted(); + + if ( + eModeCategoryUpdates[i].ltv == 0 || + eModeCategoryUpdates[i].liqThreshold == 0 || + eModeCategoryUpdates[i].liqBonus == 0 + ) revert InvalidUpdateToZero(); + + DataTypes.CollateralConfig memory currentEmodeConfig = IPool(ADDRESSES_PROVIDER.getPool()).getEModeCategoryCollateralConfig(eModeId); + + _validateParamUpdate( + ParamUpdateValidationInput({ + currentValue: currentEmodeConfig.ltv, + newValue: eModeCategoryUpdates[i].ltv, + lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLtvLastUpdated, + riskConfig: _riskConfig.eModeConfig.ltv, + isChangeRelative: false + }) + ); + _validateParamUpdate( + ParamUpdateValidationInput({ + currentValue: currentEmodeConfig.liquidationThreshold, + newValue: eModeCategoryUpdates[i].liqThreshold, + lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLiquidationThresholdLastUpdated, + riskConfig: _riskConfig.eModeConfig.liquidationThreshold, + isChangeRelative: false + }) + ); + _validateParamUpdate( + ParamUpdateValidationInput({ + currentValue: currentEmodeConfig.liquidationBonus - 100_00, // as the definition is 100% + x%, and config engine takes into account x% for simplicity. + newValue: eModeCategoryUpdates[i].liqBonus, + lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLiquidationBonusLastUpdated, + riskConfig: _riskConfig.eModeConfig.liquidationBonus, + isChangeRelative: false + }) + ); + } + } + /** * @notice method to validate the oracle price caps update * @param priceCapsUpdate list containing the new price cap params for the oracles @@ -332,8 +407,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentMaxYearlyGrowthPercent, newValue: priceCapsUpdate[i].priceCapUpdateParams.maxYearlyRatioGrowthPercent, - lastUpdated: _timelocks[oracle].priceCapLastUpdated, - riskConfig: _riskConfig.priceCapLst, + lastUpdated: _timelocks[bytes20(oracle)].priceCapLastUpdated, + riskConfig: _riskConfig.priceCapConfig.priceCapLst, isChangeRelative: true }) ); @@ -362,8 +437,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentPriceCap.toUint256(), newValue: priceCapsUpdate[i].priceCap, - lastUpdated: _timelocks[oracle].priceCapLastUpdated, - riskConfig: _riskConfig.priceCapStable, + lastUpdated: _timelocks[bytes20(oracle)].priceCapLastUpdated, + riskConfig: _riskConfig.priceCapConfig.priceCapStable, isChangeRelative: true }) ); @@ -398,11 +473,11 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = capsUpdate[i].asset; if (capsUpdate[i].supplyCap != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].supplyCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].supplyCapLastUpdated = uint40(block.timestamp); } if (capsUpdate[i].borrowCap != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].borrowCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].borrowCapLastUpdated = uint40(block.timestamp); } } @@ -420,19 +495,19 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = ratesUpdate[i].asset; if (ratesUpdate[i].params.optimalUsageRatio != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].optimalUsageRatioLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].optimalUsageRatioLastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.baseVariableBorrowRate != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].baseVariableRateLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].baseVariableRateLastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.variableRateSlope1 != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].variableRateSlope1LastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].variableRateSlope1LastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.variableRateSlope2 != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].variableRateSlope2LastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].variableRateSlope2LastUpdated = uint40(block.timestamp); } } @@ -450,19 +525,19 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = collateralUpdates[i].asset; if (collateralUpdates[i].ltv != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].ltvLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].ltvLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].liqThreshold != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].liquidationThresholdLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].liquidationThresholdLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].liqBonus != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].liquidationBonusLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].liquidationBonusLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].debtCeiling != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].debtCeilingLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].debtCeilingLastUpdated = uint40(block.timestamp); } } @@ -471,6 +546,32 @@ contract RiskSteward is Ownable, IRiskSteward { ); } + /** + * @notice method to update the eMode category params using the config engine and updates the debounce + * @param eModeCategoryUpdates list containing the new eMode category params of the eMode category id + */ + function _updateEModeCategories(IEngine.EModeCategoryUpdate[] calldata eModeCategoryUpdates) internal { + for (uint256 i = 0; i < eModeCategoryUpdates.length; i++) { + uint8 eModeId = eModeCategoryUpdates[i].eModeCategory; + + if (eModeCategoryUpdates[i].ltv != EngineFlags.KEEP_CURRENT) { + _timelocks[bytes32(uint256(eModeId))].eModeLtvLastUpdated = uint40(block.timestamp); + } + + if (eModeCategoryUpdates[i].liqThreshold != EngineFlags.KEEP_CURRENT) { + _timelocks[bytes32(uint256(eModeId))].eModeLiquidationThresholdLastUpdated = uint40(block.timestamp); + } + + if (eModeCategoryUpdates[i].liqBonus != EngineFlags.KEEP_CURRENT) { + _timelocks[bytes32(uint256(eModeId))].eModeLiquidationBonusLastUpdated = uint40(block.timestamp); + } + } + + address(CONFIG_ENGINE).functionDelegateCall( + abi.encodeWithSelector(CONFIG_ENGINE.updateEModeCategories.selector, eModeCategoryUpdates) + ); + } + /** * @notice method to update the oracle price caps update * @param priceCapsUpdate list containing the new price cap params for the oracles @@ -479,7 +580,7 @@ contract RiskSteward is Ownable, IRiskSteward { for (uint256 i = 0; i < priceCapsUpdate.length; i++) { address oracle = priceCapsUpdate[i].oracle; - _timelocks[oracle].priceCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(oracle)].priceCapLastUpdated = uint40(block.timestamp); IPriceCapAdapter(oracle).setCapParameters(priceCapsUpdate[i].priceCapUpdateParams); @@ -495,7 +596,7 @@ contract RiskSteward is Ownable, IRiskSteward { for (uint256 i = 0; i < priceCapsUpdate.length; i++) { address oracle = priceCapsUpdate[i].oracle; - _timelocks[oracle].priceCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(oracle)].priceCapLastUpdated = uint40(block.timestamp); IPriceCapAdapterStable(oracle).setPriceCap(priceCapsUpdate[i].priceCap.toInt256()); } @@ -521,7 +622,7 @@ contract RiskSteward is Ownable, IRiskSteward { uint256 variableRateSlope2 ) { - address rateStrategyAddress = POOL_DATA_PROVIDER.getInterestRateStrategyAddress(asset); + address rateStrategyAddress = IPool(ADDRESSES_PROVIDER.getPool()).getReserveData(asset).interestRateStrategyAddress; IDefaultInterestRateStrategyV2.InterestRateData memory interestRateData = IDefaultInterestRateStrategyV2(rateStrategyAddress) .getInterestRateDataBps(asset); diff --git a/src/interfaces/IRiskSteward.sol b/src/interfaces/IRiskSteward.sol index d233e3b..af4d061 100644 --- a/src/interfaces/IRiskSteward.sol +++ b/src/interfaces/IRiskSteward.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {IPoolDataProvider, IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol'; import {IAaveV3ConfigEngine as IEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol'; import {IPriceCapAdapter} from 'aave-capo/interfaces/IPriceCapAdapter.sol'; @@ -46,6 +46,11 @@ interface IRiskSteward { */ error AssetIsRestricted(); + /** + * @notice The steward does not allow updates of risk param of a restricted eMode + */ + error EModeIsRestricted(); + /** * @notice The steward does not allow updates of cap param of a restricted oracle */ @@ -68,6 +73,13 @@ interface IRiskSteward { */ event AddressRestricted(address indexed contractAddress, bool indexed isRestricted); + /** + * @notice Emitted when the owner configures an eMode categoryId as restricted to be used by steward + * @param eModeCategoryId the id of the eMode category + * @param isRestricted true if eModeCategoryId is set as restricted, false otherwise + */ + event EModeRestricted(uint8 indexed eModeCategoryId, bool indexed isRestricted); + /** * @notice Emitted when the risk configuration for the risk params has been set * @param riskConfig struct containing the risk configurations @@ -78,17 +90,20 @@ interface IRiskSteward { * @notice Struct storing the last update by the steward of each risk param */ struct Debounce { - uint40 supplyCapLastUpdated; - uint40 borrowCapLastUpdated; uint40 ltvLastUpdated; uint40 liquidationBonusLastUpdated; uint40 liquidationThresholdLastUpdated; - uint40 debtCeilingLastUpdated; + uint40 eModeLtvLastUpdated; + uint40 eModeLiquidationBonusLastUpdated; + uint40 eModeLiquidationThresholdLastUpdated; + uint40 optimalUsageRatioLastUpdated; uint40 baseVariableRateLastUpdated; uint40 variableRateSlope1LastUpdated; uint40 variableRateSlope2LastUpdated; - uint40 optimalUsageRatioLastUpdated; + uint40 debtCeilingLastUpdated; uint40 priceCapLastUpdated; + uint40 supplyCapLastUpdated; + uint40 borrowCapLastUpdated; } /** @@ -119,16 +134,54 @@ interface IRiskSteward { * @notice Struct storing the risk configuration for all the risk param */ struct Config { + CollateralConfig collateralConfig; + EmodeConfig eModeConfig; + RateConfig rateConfig; + CapConfig capConfig; + PriceCapConfig priceCapConfig; + } + + /** + * @notice Struct storing the risk configuration for collateral side param + */ + struct CollateralConfig { RiskParamConfig ltv; RiskParamConfig liquidationThreshold; RiskParamConfig liquidationBonus; - RiskParamConfig supplyCap; - RiskParamConfig borrowCap; RiskParamConfig debtCeiling; + } + + /** + * @notice Struct storing the risk configuration for emode category param + */ + struct EmodeConfig { + RiskParamConfig ltv; + RiskParamConfig liquidationThreshold; + RiskParamConfig liquidationBonus; + } + + /** + * @notice Struct storing the risk configuration for rate param + */ + struct RateConfig { RiskParamConfig baseVariableBorrowRate; RiskParamConfig variableRateSlope1; RiskParamConfig variableRateSlope2; RiskParamConfig optimalUsageRatio; + } + + /** + * @notice Struct storing the risk configuration for cap param + */ + struct CapConfig { + RiskParamConfig supplyCap; + RiskParamConfig borrowCap; + } + + /** + * @notice Struct storing the risk configuration for price cap param + */ + struct PriceCapConfig { RiskParamConfig priceCapLst; RiskParamConfig priceCapStable; } @@ -155,9 +208,9 @@ interface IRiskSteward { function CONFIG_ENGINE() external view returns (IEngine); /** - * @notice The pool data provider of the POOL the steward controls + * @notice The aave addresses provider of the instance steward controls */ - function POOL_DATA_PROVIDER() external view returns (IPoolDataProvider); + function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); /** * @notice The safe controlling the steward @@ -188,6 +241,14 @@ interface IRiskSteward { */ function updateCollateralSide(IEngine.CollateralUpdate[] calldata collateralUpdates) external; + /** + * @notice Allows updating eMode category params across multiple eMode ids + * @dev A eMode category update is only possible after minDelay has passed after last update + * @dev A eMode category increase / decrease is only allowed by a magnitude of maxPercentChange + * @param eModeCategoryUpdates struct containing new eMode category params to be updated + */ + function updateEModeCategories(IEngine.EModeCategoryUpdate[] calldata eModeCategoryUpdates) external; + /** * @notice Allows updating lst price cap params across multiple oracles * @dev A price cap update is only possible after minDelay has passed after last update @@ -211,6 +272,13 @@ interface IRiskSteward { */ function isAddressRestricted(address contractAddress) external view returns (bool); + /** + * @notice method to check if an eMode category id is restricted to be used by the risk stewards + * @param eModeCategoryId the id of the eMode category + * @return bool if eModeCategoryId is restricted or not + */ + function isEModeCategoryRestricted(uint8 eModeCategoryId) external view returns (bool); + /** * @notice method called by the owner to set an asset/oracle as restricted * @param contractAddress address of the underlying asset or oracle @@ -218,13 +286,29 @@ interface IRiskSteward { */ function setAddressRestricted(address contractAddress, bool isRestricted) external; + /** + * @notice method called by the owner to set an eMode category as restricted + * @param eModeCategoryId the id of the eMode category + * @param isRestricted true if eModeCategoryId needs to be restricted, false otherwise + */ + function setEModeCategoryRestricted(uint8 eModeCategoryId, bool isRestricted) external; + /** * @notice Returns the timelock for a specific asset i.e the last updated timestamp * @param asset for which to fetch the timelock - * @return struct containing the latest updated timestamps of all the risk params by the steward + * @return struct containing the latest updated timestamps of all the risk params by the steward except eMode + * @dev the emode timelock params of the struct returned will be unused */ function getTimelock(address asset) external view returns (Debounce memory); + /** + * @notice Returns the timelock for a specific eMode category id i.e the last updated timestamp + * @param eModeCategoryId the eMode category for which to fetch the timelock + * @return struct containing the latest updated timestamps of eMode risk params by the steward + * @dev the non-emode timelock params of the struct returned will be unused + */ + function getEModeTimelock(uint8 eModeCategoryId) external view returns (Debounce memory); + /** * @notice method to get the risk configuration set for all the risk params * @return struct containing the risk configurations diff --git a/tests/AaveStewardsInjectorCaps.t.sol b/tests/AaveStewardsInjectorCaps.t.sol index a2a273b..1b11cfa 100644 --- a/tests/AaveStewardsInjectorCaps.t.sol +++ b/tests/AaveStewardsInjectorCaps.t.sol @@ -18,20 +18,9 @@ contract AaveStewardsInjectorCaps_Test is AaveStewardsInjectorBaseTest { minDelay: 3 days, maxPercentChange: 100_00 }); - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); + IRiskSteward.Config memory riskConfig; + riskConfig.capConfig.supplyCap = defaultRiskParamConfig; + riskConfig.capConfig.borrowCap = defaultRiskParamConfig; // setup risk oracle vm.startPrank(_riskOracleOwner); @@ -61,9 +50,10 @@ contract AaveStewardsInjectorCaps_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - contracts.protocolDataProvider, - IEngine(report.configEngine), + address(contracts.poolAddressesProvider), + report.configEngine, address(_stewardInjector), + address(this), riskConfig ); vm.assertEq(computedRiskStewardAddress, address(_riskSteward)); diff --git a/tests/AaveStewardsInjectorRates.t.sol b/tests/AaveStewardsInjectorRates.t.sol index dd6e921..a836a18 100644 --- a/tests/AaveStewardsInjectorRates.t.sol +++ b/tests/AaveStewardsInjectorRates.t.sol @@ -12,20 +12,11 @@ contract AaveStewardsInjectorRates_Test is AaveStewardsInjectorBaseTest { minDelay: 3 days, maxPercentChange: 5_00 // 5% }); - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); + IRiskSteward.Config memory riskConfig; + riskConfig.rateConfig.baseVariableBorrowRate = defaultRiskParamConfig; + riskConfig.rateConfig.variableRateSlope1 = defaultRiskParamConfig; + riskConfig.rateConfig.variableRateSlope2 = defaultRiskParamConfig; + riskConfig.rateConfig.optimalUsageRatio = defaultRiskParamConfig; // setup risk oracle vm.startPrank(_riskOracleOwner); @@ -54,9 +45,10 @@ contract AaveStewardsInjectorRates_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - contracts.protocolDataProvider, - IEngine(report.configEngine), + address(contracts.poolAddressesProvider), + report.configEngine, address(_stewardInjector), + address(this), riskConfig ); diff --git a/tests/EdgeRiskStewardCaps.t.sol b/tests/EdgeRiskStewardCaps.t.sol index 52458be..376e00b 100644 --- a/tests/EdgeRiskStewardCaps.t.sol +++ b/tests/EdgeRiskStewardCaps.t.sol @@ -9,15 +9,16 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { function setUp() public override { super.setUp(); - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new EdgeRiskStewardCaps( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Rates Tests ----------------------------- */ diff --git a/tests/EdgeRiskStewardRates.t.sol b/tests/EdgeRiskStewardRates.t.sol index dc69453..0287ee0 100644 --- a/tests/EdgeRiskStewardRates.t.sol +++ b/tests/EdgeRiskStewardRates.t.sol @@ -9,15 +9,16 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { function setUp() public override { super.setUp(); - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new EdgeRiskStewardRates( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Caps Tests ----------------------------- */ diff --git a/tests/RiskSteward.t.sol b/tests/RiskSteward.t.sol index 5994c16..3dcc2f8 100644 --- a/tests/RiskSteward.t.sol +++ b/tests/RiskSteward.t.sol @@ -11,56 +11,31 @@ import {IAaveV3ConfigEngine as IEngine} from 'aave-v3-origin/src/contracts/exten import {GovV3Helpers} from 'aave-helpers/src/GovV3Helpers.sol'; import {ConfigEngineDeployer} from './utils/ConfigEngineDeployer.sol'; import {Ownable} from 'openzeppelin-contracts/contracts/access/Ownable.sol'; +import {DeployRiskStewards} from '../scripts/deploy/DeployStewards.s.sol'; contract RiskSteward_Test is Test { address public constant riskCouncil = address(42); IRiskSteward public steward; - address public configEngine; - IRiskSteward.RiskParamConfig public defaultRiskParamConfig; IRiskSteward.Config public riskConfig; event AddressRestricted(address indexed contractAddress, bool indexed isRestricted); - event RiskConfigSet(IRiskSteward.Config indexed riskConfig); function setUp() public virtual { vm.createSelectFork(vm.rpcUrl('mainnet'), 21974363); - configEngine = AaveV3Ethereum.CONFIG_ENGINE; - - defaultRiskParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, - maxPercentChange: 10_00 // 10% - }); - IRiskSteward.RiskParamConfig memory liquidationBonusParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, - maxPercentChange: 2_00 // 2% - }); - - riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: liquidationBonusParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); + riskConfig = DeployRiskStewards._getRiskConfig(); - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Caps Tests ----------------------------- */ @@ -93,7 +68,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.borrowCapLastUpdated, block.timestamp); // after min time passed test caps decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); (daiBorrowCapBefore, daiSupplyCapBefore) = AaveV3Ethereum .AAVE_PROTOCOL_DATA_PROVIDER .getReserveCaps(AaveV3EthereumAssets.DAI_UNDERLYING); @@ -122,19 +97,31 @@ contract RiskSteward_Test is Test { IEngine.CapsUpdate[] memory capUpdates = new IEngine.CapsUpdate[](1); capUpdates[0] = IEngine.CapsUpdate( AaveV3EthereumAssets.DAI_UNDERLYING, - (daiSupplyCapBefore * 120) / 100, // 20% relative increase (current maxChangePercent configured is 10%) - (daiBorrowCapBefore * 120) / 100 // 20% relative increase + (daiSupplyCapBefore * 210) / 100, // 110% relative increase (current maxChangePercent configured is 100%) + (daiBorrowCapBefore * 210) / 100 // 110% relative increase ); - vm.startPrank(riskCouncil); + vm.prank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); steward.updateCaps(capUpdates); + IRiskSteward.RiskParamConfig memory newConfig = IRiskSteward.RiskParamConfig({ + minDelay: 3 days, + maxPercentChange: 10_00 + }); + IRiskSteward.Config memory config = riskConfig; + config.capConfig.supplyCap = newConfig; + config.capConfig.borrowCap = newConfig; + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setRiskConfig(config); + capUpdates[0] = IEngine.CapsUpdate( AaveV3EthereumAssets.DAI_UNDERLYING, (daiSupplyCapBefore * 80) / 100, // 20% relative decrease (daiBorrowCapBefore * 80) / 100 // 20% relative decrease ); + vm.prank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); steward.updateCaps(capUpdates); @@ -248,12 +235,12 @@ contract RiskSteward_Test is Test { function test_updateCaps_toValueZeroNotAllowed() public virtual { // set risk config to allow 100% cap change to 0 IRiskSteward.RiskParamConfig memory capsParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, + minDelay: 3 days, maxPercentChange: 100_00 // 100% relative change }); - riskConfig.supplyCap = capsParamConfig; - riskConfig.borrowCap = capsParamConfig; + riskConfig.capConfig.supplyCap = capsParamConfig; + riskConfig.capConfig.borrowCap = capsParamConfig; vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(riskConfig); @@ -284,10 +271,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase + optimalUsageRatio: beforeOptimalUsageRatio + 3_00, // 3% absolute increase + baseVariableBorrowRate: beforeBaseVariableBorrowRate + 1_00, // 1% absolute increase + variableRateSlope1: beforeVariableRateSlope1 + 1_00, // 1% absolute increase + variableRateSlope2: beforeVariableRateSlope2 + 20_00 // 20% absolute increase }) }); @@ -315,7 +302,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.variableRateSlope2LastUpdated, block.timestamp); // after min time passed test rates decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); ( beforeOptimalUsageRatio, @@ -327,10 +314,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio - 10_00, // 10% decrease + optimalUsageRatio: beforeOptimalUsageRatio - 3_00, // 3% decrease baseVariableBorrowRate: beforeBaseVariableBorrowRate - 1_00, // 1% decrease variableRateSlope1: beforeVariableRateSlope1 - 1_00, // 1% decrease - variableRateSlope2: beforeVariableRateSlope2 - 10_00 // 10% absolute decrease + variableRateSlope2: beforeVariableRateSlope2 - 20_00 // 20% absolute decrease }) }); steward.updateRates(rateUpdates); @@ -392,10 +379,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase + optimalUsageRatio: beforeOptimalUsageRatio + 3_00, // 3% absolute increase + baseVariableBorrowRate: beforeBaseVariableBorrowRate + 1_00, // 1% absolute increase + variableRateSlope1: beforeVariableRateSlope1 + 1_00, // 1% absolute increase + variableRateSlope2: beforeVariableRateSlope2 + 20_00 // 20% absolute increase }) }); @@ -548,10 +535,10 @@ contract RiskSteward_Test is Test { IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase + ltv: ltvBefore + 50, // 0.5% absolute increase + liqThreshold: ltBefore + 50, // 0.5% absolute increase + liqBonus: (lbBefore - 100_00) + 50, // 0.5% absolute increase + debtCeiling: (debtCeilingBefore * 120) / 100, // 20% relative increase liqProtocolFee: EngineFlags.KEEP_CURRENT }); @@ -581,7 +568,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.debtCeilingLastUpdated, block.timestamp); // after min time passed test collateral update decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); (, ltvBefore, ltBefore, lbBefore, , , , , , ) = AaveV3Ethereum .AAVE_PROTOCOL_DATA_PROVIDER @@ -595,10 +582,10 @@ contract RiskSteward_Test is Test { collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore - 10_00, // 10% absolute decrease - liqThreshold: ltBefore - 10_00, // 10% absolute decrease - liqBonus: (lbBefore - 100_00) - 2_00, // 2% absolute decrease - debtCeiling: (debtCeilingBefore * 90) / 100, // 10% relative decrease + ltv: ltvBefore - 50, // 0.5% absolute decrease + liqThreshold: ltBefore - 50, // 0.5% absolute decrease + liqBonus: (lbBefore - 100_00) - 50, // 0.5% absolute decrease + debtCeiling: (debtCeilingBefore * 80) / 100, // 20% relative decrease liqProtocolFee: EngineFlags.KEEP_CURRENT }); steward.updateCollateralSide(collateralUpdates); @@ -649,7 +636,7 @@ contract RiskSteward_Test is Test { steward.updateCollateralSide(collateralUpdates); // after min time passed test collateral update decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, @@ -763,14 +750,14 @@ contract RiskSteward_Test is Test { function test_updateCollateralSide_toValueZeroNotAllowed() public virtual { // set risk config to allow 100% collateral param change to 0 IRiskSteward.RiskParamConfig memory collateralParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, + minDelay: 3 days, maxPercentChange: 100_00 // 100% relative change }); - riskConfig.ltv = collateralParamConfig; - riskConfig.liquidationThreshold = collateralParamConfig; - riskConfig.liquidationBonus = collateralParamConfig; - riskConfig.debtCeiling = collateralParamConfig; + riskConfig.collateralConfig.ltv = collateralParamConfig; + riskConfig.collateralConfig.liquidationThreshold = collateralParamConfig; + riskConfig.collateralConfig.liquidationBonus = collateralParamConfig; + riskConfig.collateralConfig.debtCeiling = collateralParamConfig; vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(riskConfig); @@ -942,18 +929,31 @@ contract RiskSteward_Test is Test { }); IRiskSteward.Config memory initialRiskConfig = IRiskSteward.Config({ - ltv: newRiskParamConfig, - liquidationThreshold: newRiskParamConfig, - liquidationBonus: newRiskParamConfig, - supplyCap: newRiskParamConfig, - borrowCap: newRiskParamConfig, - debtCeiling: newRiskParamConfig, - baseVariableBorrowRate: newRiskParamConfig, - variableRateSlope1: newRiskParamConfig, - variableRateSlope2: newRiskParamConfig, - optimalUsageRatio: newRiskParamConfig, - priceCapLst: newRiskParamConfig, - priceCapStable: newRiskParamConfig + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: newRiskParamConfig, + liquidationThreshold: newRiskParamConfig, + liquidationBonus: newRiskParamConfig, + debtCeiling: newRiskParamConfig + }), + eModeConfig: IRiskSteward.EmodeConfig({ + ltv: newRiskParamConfig, + liquidationThreshold: newRiskParamConfig, + liquidationBonus: newRiskParamConfig + }), + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: newRiskParamConfig, + variableRateSlope1: newRiskParamConfig, + variableRateSlope2: newRiskParamConfig, + optimalUsageRatio: newRiskParamConfig + }), + capConfig: IRiskSteward.CapConfig({ + supplyCap: newRiskParamConfig, + borrowCap: newRiskParamConfig + }), + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: newRiskParamConfig, + priceCapStable: newRiskParamConfig + }) }); vm.expectEmit(); @@ -962,121 +962,89 @@ contract RiskSteward_Test is Test { vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(initialRiskConfig); - _validateRiskConfig(initialRiskConfig, steward.getRiskConfig()); + // _validateRiskConfig(initialRiskConfig, steward.getRiskConfig()); } - function test_constructor() public { - riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); - - steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), - riskCouncil, - riskConfig - ); - - assertEq( - address(steward.POOL_DATA_PROVIDER()), - address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER) - ); - assertEq(address(steward.CONFIG_ENGINE()), address(IEngine(configEngine))); - assertEq(steward.RISK_COUNCIL(), riskCouncil); - _validateRiskConfig(riskConfig, steward.getRiskConfig()); - } - - function _validateRiskConfig( - IRiskSteward.Config memory initialRiskConfig, - IRiskSteward.Config memory updatedRiskConfig - ) internal pure { - assertEq(initialRiskConfig.ltv.minDelay, updatedRiskConfig.ltv.minDelay); - assertEq(initialRiskConfig.ltv.maxPercentChange, updatedRiskConfig.ltv.maxPercentChange); - assertEq( - initialRiskConfig.liquidationThreshold.minDelay, - updatedRiskConfig.liquidationThreshold.minDelay - ); - assertEq( - initialRiskConfig.liquidationThreshold.maxPercentChange, - updatedRiskConfig.liquidationThreshold.maxPercentChange - ); - assertEq( - initialRiskConfig.liquidationBonus.minDelay, - updatedRiskConfig.liquidationBonus.minDelay - ); - assertEq( - initialRiskConfig.liquidationBonus.maxPercentChange, - updatedRiskConfig.liquidationBonus.maxPercentChange - ); - assertEq(initialRiskConfig.supplyCap.minDelay, updatedRiskConfig.supplyCap.minDelay); - assertEq( - initialRiskConfig.supplyCap.maxPercentChange, - updatedRiskConfig.supplyCap.maxPercentChange - ); - assertEq(initialRiskConfig.borrowCap.minDelay, updatedRiskConfig.borrowCap.minDelay); - assertEq( - initialRiskConfig.borrowCap.maxPercentChange, - updatedRiskConfig.borrowCap.maxPercentChange - ); - assertEq(initialRiskConfig.debtCeiling.minDelay, updatedRiskConfig.debtCeiling.minDelay); - assertEq( - initialRiskConfig.debtCeiling.maxPercentChange, - updatedRiskConfig.debtCeiling.maxPercentChange - ); - assertEq( - initialRiskConfig.baseVariableBorrowRate.minDelay, - updatedRiskConfig.baseVariableBorrowRate.minDelay - ); - assertEq( - initialRiskConfig.baseVariableBorrowRate.maxPercentChange, - updatedRiskConfig.baseVariableBorrowRate.maxPercentChange - ); - assertEq( - initialRiskConfig.variableRateSlope1.minDelay, - updatedRiskConfig.variableRateSlope1.minDelay - ); - assertEq( - initialRiskConfig.variableRateSlope1.maxPercentChange, - updatedRiskConfig.variableRateSlope1.maxPercentChange - ); - assertEq( - initialRiskConfig.variableRateSlope2.minDelay, - updatedRiskConfig.variableRateSlope2.minDelay - ); - assertEq( - initialRiskConfig.variableRateSlope2.maxPercentChange, - updatedRiskConfig.variableRateSlope2.maxPercentChange - ); - assertEq( - initialRiskConfig.optimalUsageRatio.minDelay, - updatedRiskConfig.optimalUsageRatio.minDelay - ); - assertEq( - initialRiskConfig.optimalUsageRatio.maxPercentChange, - updatedRiskConfig.optimalUsageRatio.maxPercentChange - ); - assertEq( - initialRiskConfig.priceCapLst.maxPercentChange, - updatedRiskConfig.priceCapLst.maxPercentChange - ); - assertEq(initialRiskConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapLst.minDelay); - assertEq( - initialRiskConfig.priceCapStable.maxPercentChange, - updatedRiskConfig.priceCapStable.maxPercentChange - ); - assertEq(initialRiskConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapStable.minDelay); - } + // function _validateRiskConfig( + // IRiskSteward.Config memory initialRiskConfig, + // IRiskSteward.Config memory updatedRiskConfig + // ) internal pure { + // assertEq(initialRiskConfig.ltv.minDelay, updatedRiskConfig.ltv.minDelay); + // assertEq(initialRiskConfig.ltv.maxPercentChange, updatedRiskConfig.ltv.maxPercentChange); + // assertEq( + // initialRiskConfig.liquidationThreshold.minDelay, + // updatedRiskConfig.liquidationThreshold.minDelay + // ); + // assertEq( + // initialRiskConfig.liquidationThreshold.maxPercentChange, + // updatedRiskConfig.liquidationThreshold.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.liquidationBonus.minDelay, + // updatedRiskConfig.liquidationBonus.minDelay + // ); + // assertEq( + // initialRiskConfig.liquidationBonus.maxPercentChange, + // updatedRiskConfig.liquidationBonus.maxPercentChange + // ); + // assertEq(initialRiskConfig.supplyCap.minDelay, updatedRiskConfig.supplyCap.minDelay); + // assertEq( + // initialRiskConfig.supplyCap.maxPercentChange, + // updatedRiskConfig.supplyCap.maxPercentChange + // ); + // assertEq(initialRiskConfig.borrowCap.minDelay, updatedRiskConfig.borrowCap.minDelay); + // assertEq( + // initialRiskConfig.borrowCap.maxPercentChange, + // updatedRiskConfig.borrowCap.maxPercentChange + // ); + // assertEq(initialRiskConfig.debtCeiling.minDelay, updatedRiskConfig.debtCeiling.minDelay); + // assertEq( + // initialRiskConfig.debtCeiling.maxPercentChange, + // updatedRiskConfig.debtCeiling.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.baseVariableBorrowRate.minDelay, + // updatedRiskConfig.baseVariableBorrowRate.minDelay + // ); + // assertEq( + // initialRiskConfig.baseVariableBorrowRate.maxPercentChange, + // updatedRiskConfig.baseVariableBorrowRate.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.variableRateSlope1.minDelay, + // updatedRiskConfig.variableRateSlope1.minDelay + // ); + // assertEq( + // initialRiskConfig.variableRateSlope1.maxPercentChange, + // updatedRiskConfig.variableRateSlope1.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.variableRateSlope2.minDelay, + // updatedRiskConfig.variableRateSlope2.minDelay + // ); + // assertEq( + // initialRiskConfig.variableRateSlope2.maxPercentChange, + // updatedRiskConfig.variableRateSlope2.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.optimalUsageRatio.minDelay, + // updatedRiskConfig.optimalUsageRatio.minDelay + // ); + // assertEq( + // initialRiskConfig.optimalUsageRatio.maxPercentChange, + // updatedRiskConfig.optimalUsageRatio.maxPercentChange + // ); + // assertEq( + // initialRiskConfig.priceCapLst.maxPercentChange, + // updatedRiskConfig.priceCapLst.maxPercentChange + // ); + // assertEq(initialRiskConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapLst.minDelay); + // assertEq( + // initialRiskConfig.priceCapStable.maxPercentChange, + // updatedRiskConfig.priceCapStable.maxPercentChange + // ); + // assertEq(initialRiskConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapStable.minDelay); + // } function _getInterestRatesForAsset( address asset diff --git a/tests/RiskStewardCapo.t.sol b/tests/RiskStewardCapo.t.sol index 0506ea5..1499dca 100644 --- a/tests/RiskStewardCapo.t.sol +++ b/tests/RiskStewardCapo.t.sol @@ -32,31 +32,20 @@ contract RiskSteward_Capo_Test is Test { minDelay: 5 days, maxPercentChange: 10_00 // 10% }); + IRiskSteward.Config memory riskConfig; + riskConfig.priceCapConfig.priceCapLst = defaultRiskParamConfig; + riskConfig.priceCapConfig.priceCapStable = defaultRiskParamConfig; - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); - - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(AaveV3Ethereum.CONFIG_ENGINE), + address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); currentRatio = IPriceCapAdapter(AaveV3EthereumAssets.wstETH_ORACLE) .getRatio() From d8b5eca145c5fe9293b3a27f6e930520771340d1 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Sat, 22 Mar 2025 19:06:01 +0530 Subject: [PATCH 2/8] test: emode updates --- tests/EdgeRiskStewardCaps.t.sol | 72 ++--- tests/EdgeRiskStewardRates.t.sol | 65 ++--- tests/RiskSteward.t.sol | 484 +++++++++++++++++++++++++------ 3 files changed, 448 insertions(+), 173 deletions(-) diff --git a/tests/EdgeRiskStewardCaps.t.sol b/tests/EdgeRiskStewardCaps.t.sol index 376e00b..8df5fed 100644 --- a/tests/EdgeRiskStewardCaps.t.sol +++ b/tests/EdgeRiskStewardCaps.t.sol @@ -24,23 +24,7 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { /* ----------------------------- Rates Tests ----------------------------- */ function test_updateRates() public override { - ( - uint256 beforeOptimalUsageRatio, - uint256 beforeBaseVariableBorrowRate, - uint256 beforeVariableRateSlope1, - uint256 beforeVariableRateSlope2 - ) = _getInterestRatesForAsset(AaveV3EthereumAssets.WETH_UNDERLYING); - IEngine.RateStrategyUpdate[] memory rateUpdates = new IEngine.RateStrategyUpdate[](1); - rateUpdates[0] = IEngine.RateStrategyUpdate({ - asset: AaveV3EthereumAssets.WETH_UNDERLYING, - params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -62,24 +46,7 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { /* ----------------------------- Collateral Tests ----------------------------- */ function test_updateCollateralSide() public override { - (, uint256 ltvBefore, uint256 ltBefore, uint256 lbBefore, , , , , , ) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveConfigurationData(AaveV3EthereumAssets.UNI_UNDERLYING); - - // as the definition is with 2 decimals, and config engine does not take the decimals into account, so we divide by 100. - uint256 debtCeilingBefore = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getDebtCeiling( - AaveV3EthereumAssets.UNI_UNDERLYING - ) / 100; - IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); - collateralUpdates[0] = IEngine.CollateralUpdate({ - asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase - liqProtocolFee: EngineFlags.KEEP_CURRENT - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -102,20 +69,38 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { function test_updateCollaterals_sameUpdate() public override {} + /* ----------------------------- EMode Category Update Tests ----------------------------- */ + + function test_updateEModeCategories() public override { + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + + vm.startPrank(riskCouncil); + vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_outOfRange() public override {} + + function test_updateEModeCategories_debounceNotRespected() public override {} + + function test_updateEModeCategories_eModeDoesNotExist() public override {} + + function test_updateEModeCategories_eModeRestricted() public override {} + + function test_updateEModeCategories_toValueZeroNotAllowed() public override {} + + function test_updateEModeCategories_allKeepCurrent() public override {} + + function test_updateEModeCategories_sameUpdate() public override {} + + function test_updateEModeCategories_onlyLabelChange() public override {} + /* ----------------------------- LST Price Cap Tests ----------------------------- */ function test_updateLstPriceCap() public { IRiskSteward.PriceCapLstUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapLstUpdate[]( 1 ); - priceCapUpdates[0] = IRiskSteward.PriceCapLstUpdate({ - oracle: AaveV3EthereumAssets.wstETH_ORACLE, - priceCapUpdateParams: IPriceCapAdapter.PriceCapUpdateParams({ - snapshotTimestamp: uint48(block.timestamp - 2), - snapshotRatio: 1.1e18, - maxYearlyRatioGrowthPercent: 9_68 - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -128,11 +113,6 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { IRiskSteward.PriceCapStableUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapStableUpdate[](1); - priceCapUpdates[0] = IRiskSteward.PriceCapStableUpdate({ - oracle: AaveV3EthereumAssets.USDT_ORACLE, - priceCap: 1060000 - }); - vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); steward.updateStablePriceCaps(priceCapUpdates); diff --git a/tests/EdgeRiskStewardRates.t.sol b/tests/EdgeRiskStewardRates.t.sol index 0287ee0..235e967 100644 --- a/tests/EdgeRiskStewardRates.t.sol +++ b/tests/EdgeRiskStewardRates.t.sol @@ -24,16 +24,7 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { /* ----------------------------- Caps Tests ----------------------------- */ function test_updateCaps() public override { - (uint256 daiBorrowCapBefore, uint256 daiSupplyCapBefore) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveCaps(AaveV3EthereumAssets.DAI_UNDERLYING); - IEngine.CapsUpdate[] memory capUpdates = new IEngine.CapsUpdate[](1); - capUpdates[0] = IEngine.CapsUpdate( - AaveV3EthereumAssets.DAI_UNDERLYING, - (daiSupplyCapBefore * 110) / 100, // 10% relative increase - (daiBorrowCapBefore * 110) / 100 // 10% relative increase - ); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -57,24 +48,7 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { /* ----------------------------- Collateral Tests ----------------------------- */ function test_updateCollateralSide() public override { - (, uint256 ltvBefore, uint256 ltBefore, uint256 lbBefore, , , , , , ) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveConfigurationData(AaveV3EthereumAssets.UNI_UNDERLYING); - - // as the definition is with 2 decimals, and config engine does not take the decimals into account, so we divide by 100. - uint256 debtCeilingBefore = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getDebtCeiling( - AaveV3EthereumAssets.UNI_UNDERLYING - ) / 100; - IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); - collateralUpdates[0] = IEngine.CollateralUpdate({ - asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase - liqProtocolFee: EngineFlags.KEEP_CURRENT - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -97,20 +71,38 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { function test_updateCollaterals_sameUpdate() public override {} + /* ----------------------------- EMode Category Update Tests ----------------------------- */ + + function test_updateEModeCategories() public override { + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + + vm.startPrank(riskCouncil); + vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_outOfRange() public override {} + + function test_updateEModeCategories_debounceNotRespected() public override {} + + function test_updateEModeCategories_eModeDoesNotExist() public override {} + + function test_updateEModeCategories_eModeRestricted() public override {} + + function test_updateEModeCategories_toValueZeroNotAllowed() public override {} + + function test_updateEModeCategories_allKeepCurrent() public override {} + + function test_updateEModeCategories_sameUpdate() public override {} + + function test_updateEModeCategories_onlyLabelChange() public override {} + /* ----------------------------- LST Price Cap Tests ----------------------------- */ function test_updateLstPriceCap() public { IRiskSteward.PriceCapLstUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapLstUpdate[]( 1 ); - priceCapUpdates[0] = IRiskSteward.PriceCapLstUpdate({ - oracle: AaveV3EthereumAssets.wstETH_ORACLE, - priceCapUpdateParams: IPriceCapAdapter.PriceCapUpdateParams({ - snapshotTimestamp: uint48(block.timestamp - 2), - snapshotRatio: 1.1e18, - maxYearlyRatioGrowthPercent: 9_68 - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -123,11 +115,6 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { IRiskSteward.PriceCapStableUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapStableUpdate[](1); - priceCapUpdates[0] = IRiskSteward.PriceCapStableUpdate({ - oracle: AaveV3EthereumAssets.USDT_ORACLE, - priceCap: 1060000 - }); - vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); steward.updateStablePriceCaps(priceCapUpdates); diff --git a/tests/RiskSteward.t.sol b/tests/RiskSteward.t.sol index 3dcc2f8..14e457e 100644 --- a/tests/RiskSteward.t.sol +++ b/tests/RiskSteward.t.sol @@ -2,6 +2,7 @@ pragma solidity ^0.8.0; import 'forge-std/Test.sol'; +import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; import {IACLManager, IPoolConfigurator, IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; import {IDefaultInterestRateStrategyV2} from 'aave-v3-origin/src/contracts/interfaces/IDefaultInterestRateStrategyV2.sol'; import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; @@ -14,13 +15,12 @@ import {Ownable} from 'openzeppelin-contracts/contracts/access/Ownable.sol'; import {DeployRiskStewards} from '../scripts/deploy/DeployStewards.s.sol'; contract RiskSteward_Test is Test { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + address public constant riskCouncil = address(42); IRiskSteward public steward; IRiskSteward.Config public riskConfig; - event AddressRestricted(address indexed contractAddress, bool indexed isRestricted); - event RiskConfigSet(IRiskSteward.Config indexed riskConfig); - function setUp() public virtual { vm.createSelectFork(vm.rpcUrl('mainnet'), 21974363); @@ -851,6 +851,280 @@ contract RiskSteward_Test is Test { assertEq(debtCeilingBefore, debtCeilingAfter); } + /* ----------------------------- EMode Category Update Tests ----------------------------- */ + + function test_updateEModeCategories() public virtual { + uint8 eModeId = 1; + DataTypes.CollateralConfig memory currentEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + string memory label = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: currentEmodeConfig.ltv + 50, // 0.5% absolute increase + liqThreshold: currentEmodeConfig.liquidationThreshold + 50, // 0.5% absolute increase + liqBonus: (currentEmodeConfig.liquidationBonus - 100_00) + 50, // 0.5% absolute increase + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + + RiskSteward.Debounce memory lastUpdated = steward.getEModeTimelock(eModeId); + + DataTypes.CollateralConfig memory afterEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + string memory afterLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + assertEq(afterEmodeConfig.ltv, eModeCategoryUpdates[0].ltv); + assertEq(afterEmodeConfig.liquidationThreshold, eModeCategoryUpdates[0].liqThreshold); + assertEq(afterEmodeConfig.liquidationBonus - 100_00, eModeCategoryUpdates[0].liqBonus); + assertEq(afterLabel, label); + + assertEq(lastUpdated.eModeLtvLastUpdated, block.timestamp); + assertEq(lastUpdated.eModeLiquidationThresholdLastUpdated, block.timestamp); + assertEq(lastUpdated.eModeLiquidationBonusLastUpdated, block.timestamp); + + // after min time passed test eMode update decrease + vm.warp(block.timestamp + 3 days + 1); + + currentEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: currentEmodeConfig.ltv - 50, // 0.5% absolute increase + liqThreshold: currentEmodeConfig.liquidationThreshold - 50, // 0.5% absolute increase + liqBonus: (currentEmodeConfig.liquidationBonus - 100_00) - 50, // 0.5% absolute increase + label: EngineFlags.KEEP_CURRENT_STRING + }); + steward.updateEModeCategories(eModeCategoryUpdates); + + afterEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + afterLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + assertEq(afterEmodeConfig.ltv, eModeCategoryUpdates[0].ltv); + assertEq(afterEmodeConfig.liquidationThreshold, eModeCategoryUpdates[0].liqThreshold); + assertEq(afterEmodeConfig.liquidationBonus - 100_00, eModeCategoryUpdates[0].liqBonus); + assertEq(afterLabel, label); + + lastUpdated = steward.getEModeTimelock(eModeId); + + assertEq(lastUpdated.eModeLtvLastUpdated, block.timestamp); + assertEq(lastUpdated.eModeLiquidationThresholdLastUpdated, block.timestamp); + assertEq(lastUpdated.eModeLiquidationBonusLastUpdated, block.timestamp); + } + + function test_updateEModeCategories_outOfRange() public virtual { + uint8 eModeId = 1; + DataTypes.CollateralConfig memory currentEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: currentEmodeConfig.ltv + 51, // 0.5% absolute increase + liqThreshold: currentEmodeConfig.liquidationThreshold + 51, // 0.51% absolute increase + liqBonus: (currentEmodeConfig.liquidationBonus - 100_00) + 51, // 0.51% absolute increase + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + + // after min time passed test eMode update decrease + vm.warp(block.timestamp + 3 days + 1); + + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: currentEmodeConfig.ltv - 51, // 0.51% absolute increase + liqThreshold: currentEmodeConfig.liquidationThreshold - 51, // 0.51% absolute increase + liqBonus: (currentEmodeConfig.liquidationBonus - 100_00) - 51, // 0.51% absolute increase + label: EngineFlags.KEEP_CURRENT_STRING + }); + vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_debounceNotRespected() public virtual { + uint8 eModeId = 1; + DataTypes.CollateralConfig memory currentEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: currentEmodeConfig.ltv + 50, // 0.5% absolute increase + liqThreshold: currentEmodeConfig.liquidationThreshold + 50, // 0.5% absolute increase + liqBonus: (currentEmodeConfig.liquidationBonus - 100_00) + 50, // 0.5% absolute increase + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + + vm.warp(block.timestamp + 1 days); + + // expect revert as minimum time has not passed for next update + vm.expectRevert(IRiskSteward.DebounceNotRespected.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_eModeDoesNotExist() public virtual { + uint8 eModeId = 100; + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: 50, + liqThreshold: 50, + liqBonus: 100_00, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + vm.expectRevert(); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_eModeRestricted() public virtual { + uint8 eModeCategoryId = 1; + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setEModeCategoryRestricted(eModeCategoryId, true); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeCategoryId, + ltv: 50, + liqThreshold: 50, + liqBonus: 100_00, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.prank(riskCouncil); + vm.expectRevert(IRiskSteward.EModeIsRestricted.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_toValueZeroNotAllowed() public virtual { + // set risk config to allow 100% collateral param change to 0 + IRiskSteward.RiskParamConfig memory eModeParamConfig = IRiskSteward.RiskParamConfig({ + minDelay: 3 days, + maxPercentChange: 100_00 // 100% relative change + }); + IRiskSteward.Config memory config; + config.eModeConfig.ltv = eModeParamConfig; + config.eModeConfig.liquidationThreshold = eModeParamConfig; + config.eModeConfig.liquidationBonus = eModeParamConfig; + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setRiskConfig(config); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: 1, + ltv: 0, + liqThreshold: 0, + liqBonus: 0, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + vm.expectRevert(IRiskSteward.InvalidUpdateToZero.selector); + steward.updateEModeCategories(eModeCategoryUpdates); + } + + function test_updateEModeCategories_allKeepCurrent() public virtual { + uint8 eModeId = 1; + DataTypes.CollateralConfig memory prevEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + string memory prevLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + RiskSteward.Debounce memory prevLastUpdated = steward.getEModeTimelock(eModeId); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: EngineFlags.KEEP_CURRENT, + liqBonus: EngineFlags.KEEP_CURRENT, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + + DataTypes.CollateralConfig memory afterEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + RiskSteward.Debounce memory afterLastUpdated = steward.getEModeTimelock(eModeId); + string memory afterLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + assertEq(afterEmodeConfig.ltv, prevEmodeConfig.ltv); + assertEq(afterEmodeConfig.liquidationThreshold, prevEmodeConfig.liquidationThreshold); + assertEq(afterEmodeConfig.liquidationBonus, prevEmodeConfig.liquidationBonus); + assertEq(afterLabel, prevLabel); + + assertEq(prevLastUpdated.eModeLtvLastUpdated, afterLastUpdated.eModeLtvLastUpdated); + assertEq(prevLastUpdated.eModeLiquidationThresholdLastUpdated, afterLastUpdated.eModeLiquidationThresholdLastUpdated); + assertEq(prevLastUpdated.eModeLiquidationBonusLastUpdated, afterLastUpdated.eModeLiquidationBonusLastUpdated); + } + + function test_updateEModeCategories_sameUpdate() public virtual { + uint8 eModeId = 1; + DataTypes.CollateralConfig memory prevEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + string memory prevLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: prevEmodeConfig.ltv, + liqThreshold: prevEmodeConfig.liquidationThreshold, + liqBonus: prevEmodeConfig.liquidationBonus - 100_00, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + + DataTypes.CollateralConfig memory afterEmodeConfig = AaveV3Ethereum.POOL.getEModeCategoryCollateralConfig(eModeId); + RiskSteward.Debounce memory afterLastUpdated = steward.getEModeTimelock(eModeId); + string memory afterLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + + assertEq(afterEmodeConfig.ltv, prevEmodeConfig.ltv); + assertEq(afterEmodeConfig.liquidationThreshold, prevEmodeConfig.liquidationThreshold); + assertEq(afterEmodeConfig.liquidationBonus, prevEmodeConfig.liquidationBonus); + assertEq(afterLabel, prevLabel); + + assertEq(afterLastUpdated.eModeLtvLastUpdated, block.timestamp); + assertEq(afterLastUpdated.eModeLiquidationThresholdLastUpdated, block.timestamp); + assertEq(afterLastUpdated.eModeLiquidationBonusLastUpdated, block.timestamp); + } + + function test_updateEModeCategories_onlyLabelChange() public virtual { + uint8 eModeId = 1; + string memory newLabel = 'NEW_EMODE_LABEL'; + + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: EngineFlags.KEEP_CURRENT, + liqBonus: EngineFlags.KEEP_CURRENT, + label: newLabel + }); + + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + + string memory afterLabel = AaveV3Ethereum.POOL.getEModeCategoryLabel(eModeId); + assertEq(newLabel, afterLabel); + + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: eModeId, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: EngineFlags.KEEP_CURRENT, + liqBonus: EngineFlags.KEEP_CURRENT, + label: 'LABEL_CHANGE_AGAIN' + }); + + // no timelock for label change + vm.startPrank(riskCouncil); + steward.updateEModeCategories(eModeCategoryUpdates); + } + /* ----------------------------- MISC ----------------------------- */ function test_invalidCaller(address caller) public { @@ -884,6 +1158,15 @@ contract RiskSteward_Test is Test { }) }); + IEngine.EModeCategoryUpdate[] memory eModeCategoryUpdates = new IEngine.EModeCategoryUpdate[](1); + eModeCategoryUpdates[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: 1, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: EngineFlags.KEEP_CURRENT, + liqBonus: EngineFlags.KEEP_CURRENT, + label: EngineFlags.KEEP_CURRENT_STRING + }); + vm.startPrank(caller); vm.expectRevert(IRiskSteward.InvalidCaller.selector); @@ -893,7 +1176,10 @@ contract RiskSteward_Test is Test { steward.updateCollateralSide(collateralUpdates); vm.expectRevert(IRiskSteward.InvalidCaller.selector); - steward.updateRates(rateStrategyUpdate); + steward.updateCollateralSide(collateralUpdates); + + vm.expectRevert(IRiskSteward.InvalidCaller.selector); + steward.updateEModeCategories(eModeCategoryUpdates); vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, caller)); steward.setRiskConfig(riskConfig); @@ -901,12 +1187,15 @@ contract RiskSteward_Test is Test { vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, caller)); steward.setAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); + vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, caller)); + steward.setEModeCategoryRestricted(1, true); + vm.stopPrank(); } function test_assetRestricted() public { vm.expectEmit(); - emit AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); + emit IRiskSteward.AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); @@ -914,7 +1203,7 @@ contract RiskSteward_Test is Test { assertTrue(steward.isAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING)); vm.expectEmit(); - emit AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); + emit IRiskSteward.AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); @@ -922,6 +1211,25 @@ contract RiskSteward_Test is Test { assertFalse(steward.isAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING)); } + function test_eModeCategoryRestricted() public { + uint8 eModeId = 1; + vm.expectEmit(); + emit IRiskSteward.EModeRestricted(eModeId, true); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setEModeCategoryRestricted(eModeId, true); + + assertTrue(steward.isEModeCategoryRestricted(eModeId)); + + vm.expectEmit(); + emit IRiskSteward.EModeRestricted(eModeId, false); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setEModeCategoryRestricted(eModeId, false); + + assertFalse(steward.isEModeCategoryRestricted(eModeId)); + } + function test_setRiskConfig() public { IRiskSteward.RiskParamConfig memory newRiskParamConfig = IRiskSteward.RiskParamConfig({ minDelay: 10 days, @@ -957,94 +1265,94 @@ contract RiskSteward_Test is Test { }); vm.expectEmit(); - emit RiskConfigSet(initialRiskConfig); + emit IRiskSteward.RiskConfigSet(initialRiskConfig); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(initialRiskConfig); - // _validateRiskConfig(initialRiskConfig, steward.getRiskConfig()); + _validateRiskConfig(initialRiskConfig, steward.getRiskConfig()); } - // function _validateRiskConfig( - // IRiskSteward.Config memory initialRiskConfig, - // IRiskSteward.Config memory updatedRiskConfig - // ) internal pure { - // assertEq(initialRiskConfig.ltv.minDelay, updatedRiskConfig.ltv.minDelay); - // assertEq(initialRiskConfig.ltv.maxPercentChange, updatedRiskConfig.ltv.maxPercentChange); - // assertEq( - // initialRiskConfig.liquidationThreshold.minDelay, - // updatedRiskConfig.liquidationThreshold.minDelay - // ); - // assertEq( - // initialRiskConfig.liquidationThreshold.maxPercentChange, - // updatedRiskConfig.liquidationThreshold.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.liquidationBonus.minDelay, - // updatedRiskConfig.liquidationBonus.minDelay - // ); - // assertEq( - // initialRiskConfig.liquidationBonus.maxPercentChange, - // updatedRiskConfig.liquidationBonus.maxPercentChange - // ); - // assertEq(initialRiskConfig.supplyCap.minDelay, updatedRiskConfig.supplyCap.minDelay); - // assertEq( - // initialRiskConfig.supplyCap.maxPercentChange, - // updatedRiskConfig.supplyCap.maxPercentChange - // ); - // assertEq(initialRiskConfig.borrowCap.minDelay, updatedRiskConfig.borrowCap.minDelay); - // assertEq( - // initialRiskConfig.borrowCap.maxPercentChange, - // updatedRiskConfig.borrowCap.maxPercentChange - // ); - // assertEq(initialRiskConfig.debtCeiling.minDelay, updatedRiskConfig.debtCeiling.minDelay); - // assertEq( - // initialRiskConfig.debtCeiling.maxPercentChange, - // updatedRiskConfig.debtCeiling.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.baseVariableBorrowRate.minDelay, - // updatedRiskConfig.baseVariableBorrowRate.minDelay - // ); - // assertEq( - // initialRiskConfig.baseVariableBorrowRate.maxPercentChange, - // updatedRiskConfig.baseVariableBorrowRate.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.variableRateSlope1.minDelay, - // updatedRiskConfig.variableRateSlope1.minDelay - // ); - // assertEq( - // initialRiskConfig.variableRateSlope1.maxPercentChange, - // updatedRiskConfig.variableRateSlope1.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.variableRateSlope2.minDelay, - // updatedRiskConfig.variableRateSlope2.minDelay - // ); - // assertEq( - // initialRiskConfig.variableRateSlope2.maxPercentChange, - // updatedRiskConfig.variableRateSlope2.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.optimalUsageRatio.minDelay, - // updatedRiskConfig.optimalUsageRatio.minDelay - // ); - // assertEq( - // initialRiskConfig.optimalUsageRatio.maxPercentChange, - // updatedRiskConfig.optimalUsageRatio.maxPercentChange - // ); - // assertEq( - // initialRiskConfig.priceCapLst.maxPercentChange, - // updatedRiskConfig.priceCapLst.maxPercentChange - // ); - // assertEq(initialRiskConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapLst.minDelay); - // assertEq( - // initialRiskConfig.priceCapStable.maxPercentChange, - // updatedRiskConfig.priceCapStable.maxPercentChange - // ); - // assertEq(initialRiskConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapStable.minDelay); - // } + function _validateRiskConfig( + IRiskSteward.Config memory initialRiskConfig, + IRiskSteward.Config memory updatedRiskConfig + ) internal pure { + assertEq(initialRiskConfig.collateralConfig.ltv.minDelay, updatedRiskConfig.collateralConfig.ltv.minDelay); + assertEq(initialRiskConfig.collateralConfig.ltv.maxPercentChange, updatedRiskConfig.collateralConfig.ltv.maxPercentChange); + assertEq( + initialRiskConfig.collateralConfig.liquidationThreshold.minDelay, + updatedRiskConfig.collateralConfig.liquidationThreshold.minDelay + ); + assertEq( + initialRiskConfig.collateralConfig.liquidationThreshold.maxPercentChange, + updatedRiskConfig.collateralConfig.liquidationThreshold.maxPercentChange + ); + assertEq( + initialRiskConfig.collateralConfig.liquidationBonus.minDelay, + updatedRiskConfig.collateralConfig.liquidationBonus.minDelay + ); + assertEq( + initialRiskConfig.collateralConfig.liquidationBonus.maxPercentChange, + updatedRiskConfig.collateralConfig.liquidationBonus.maxPercentChange + ); + assertEq(initialRiskConfig.capConfig.supplyCap.minDelay, updatedRiskConfig.capConfig.supplyCap.minDelay); + assertEq( + initialRiskConfig.capConfig.supplyCap.maxPercentChange, + updatedRiskConfig.capConfig.supplyCap.maxPercentChange + ); + assertEq(initialRiskConfig.capConfig.borrowCap.minDelay, updatedRiskConfig.capConfig.borrowCap.minDelay); + assertEq( + initialRiskConfig.capConfig.borrowCap.maxPercentChange, + updatedRiskConfig.capConfig.borrowCap.maxPercentChange + ); + assertEq(initialRiskConfig.collateralConfig.debtCeiling.minDelay, updatedRiskConfig.collateralConfig.debtCeiling.minDelay); + assertEq( + initialRiskConfig.collateralConfig.debtCeiling.maxPercentChange, + updatedRiskConfig.collateralConfig.debtCeiling.maxPercentChange + ); + assertEq( + initialRiskConfig.rateConfig.baseVariableBorrowRate.minDelay, + updatedRiskConfig.rateConfig.baseVariableBorrowRate.minDelay + ); + assertEq( + initialRiskConfig.rateConfig.baseVariableBorrowRate.maxPercentChange, + updatedRiskConfig.rateConfig.baseVariableBorrowRate.maxPercentChange + ); + assertEq( + initialRiskConfig.rateConfig.variableRateSlope1.minDelay, + updatedRiskConfig.rateConfig.variableRateSlope1.minDelay + ); + assertEq( + initialRiskConfig.rateConfig.variableRateSlope1.maxPercentChange, + updatedRiskConfig.rateConfig.variableRateSlope1.maxPercentChange + ); + assertEq( + initialRiskConfig.rateConfig.variableRateSlope2.minDelay, + updatedRiskConfig.rateConfig.variableRateSlope2.minDelay + ); + assertEq( + initialRiskConfig.rateConfig.variableRateSlope2.maxPercentChange, + updatedRiskConfig.rateConfig.variableRateSlope2.maxPercentChange + ); + assertEq( + initialRiskConfig.rateConfig.optimalUsageRatio.minDelay, + updatedRiskConfig.rateConfig.optimalUsageRatio.minDelay + ); + assertEq( + initialRiskConfig.rateConfig.optimalUsageRatio.maxPercentChange, + updatedRiskConfig.rateConfig.optimalUsageRatio.maxPercentChange + ); + assertEq( + initialRiskConfig.priceCapConfig.priceCapLst.maxPercentChange, + updatedRiskConfig.priceCapConfig.priceCapLst.maxPercentChange + ); + assertEq(initialRiskConfig.priceCapConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapConfig.priceCapLst.minDelay); + assertEq( + initialRiskConfig.priceCapConfig.priceCapStable.maxPercentChange, + updatedRiskConfig.priceCapConfig.priceCapStable.maxPercentChange + ); + assertEq(initialRiskConfig.priceCapConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapConfig.priceCapStable.minDelay); + } function _getInterestRatesForAsset( address asset From da9ac080c996d3bc1b69b1977e5386b61f92be1b Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Tue, 25 Mar 2025 19:59:37 +0530 Subject: [PATCH 3/8] fix: use bytes20 for timelock --- src/contracts/RiskSteward.sol | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/contracts/RiskSteward.sol b/src/contracts/RiskSteward.sol index 21bc3e1..d088048 100644 --- a/src/contracts/RiskSteward.sol +++ b/src/contracts/RiskSteward.sol @@ -38,7 +38,7 @@ contract RiskSteward is Ownable, IRiskSteward { Config internal _riskConfig; - mapping(bytes32 id => Debounce) internal _timelocks; + mapping(bytes20 id => Debounce) internal _timelocks; mapping(address => bool) internal _restrictedAddresses; @@ -125,7 +125,7 @@ contract RiskSteward is Ownable, IRiskSteward { /// @inheritdoc IRiskSteward function getEModeTimelock(uint8 eModeCategoryId) external view returns (Debounce memory) { - return _timelocks[bytes32(uint256(eModeCategoryId))]; + return _timelocks[bytes20(uint160(eModeCategoryId))]; } /// @inheritdoc IRiskSteward @@ -351,7 +351,7 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentEmodeConfig.ltv, newValue: eModeCategoryUpdates[i].ltv, - lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLtvLastUpdated, + lastUpdated: _timelocks[bytes20(uint160(eModeId))].eModeLtvLastUpdated, riskConfig: _riskConfig.eModeConfig.ltv, isChangeRelative: false }) @@ -360,7 +360,7 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentEmodeConfig.liquidationThreshold, newValue: eModeCategoryUpdates[i].liqThreshold, - lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLiquidationThresholdLastUpdated, + lastUpdated: _timelocks[bytes20(uint160(eModeId))].eModeLiquidationThresholdLastUpdated, riskConfig: _riskConfig.eModeConfig.liquidationThreshold, isChangeRelative: false }) @@ -369,7 +369,7 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentEmodeConfig.liquidationBonus - 100_00, // as the definition is 100% + x%, and config engine takes into account x% for simplicity. newValue: eModeCategoryUpdates[i].liqBonus, - lastUpdated: _timelocks[bytes32(uint256(eModeId))].eModeLiquidationBonusLastUpdated, + lastUpdated: _timelocks[bytes20(uint160(eModeId))].eModeLiquidationBonusLastUpdated, riskConfig: _riskConfig.eModeConfig.liquidationBonus, isChangeRelative: false }) @@ -555,15 +555,15 @@ contract RiskSteward is Ownable, IRiskSteward { uint8 eModeId = eModeCategoryUpdates[i].eModeCategory; if (eModeCategoryUpdates[i].ltv != EngineFlags.KEEP_CURRENT) { - _timelocks[bytes32(uint256(eModeId))].eModeLtvLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(uint160(eModeId))].eModeLtvLastUpdated = uint40(block.timestamp); } if (eModeCategoryUpdates[i].liqThreshold != EngineFlags.KEEP_CURRENT) { - _timelocks[bytes32(uint256(eModeId))].eModeLiquidationThresholdLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(uint160(eModeId))].eModeLiquidationThresholdLastUpdated = uint40(block.timestamp); } if (eModeCategoryUpdates[i].liqBonus != EngineFlags.KEEP_CURRENT) { - _timelocks[bytes32(uint256(eModeId))].eModeLiquidationBonusLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(uint160(eModeId))].eModeLiquidationBonusLastUpdated = uint40(block.timestamp); } } From 603319de84fbb3374df8ee479993c0d6a31f9707 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Tue, 25 Mar 2025 20:56:08 +0530 Subject: [PATCH 4/8] feat: add generator for emode updates --- generator/cli.ts | 4 +- generator/common.ts | 9 +- .../__snapshots__/eModeUpdates.spec.ts.snap | 102 ++++++++++++++++++ generator/features/eModeUpdates.spec.ts | 37 +++++++ generator/features/eModeUpdates.ts | 82 ++++++++++++++ generator/features/mocks/configs.ts | 12 ++- generator/features/types.ts | 9 ++ generator/prompts.ts | 15 +-- generator/types.ts | 1 + scripts/RiskStewardsBase.s.sol | 27 ++++- 10 files changed, 280 insertions(+), 18 deletions(-) create mode 100644 generator/features/__snapshots__/eModeUpdates.spec.ts.snap create mode 100644 generator/features/eModeUpdates.spec.ts create mode 100644 generator/features/eModeUpdates.ts diff --git a/generator/cli.ts b/generator/cli.ts index 1bc77bb..fbbf93c 100644 --- a/generator/cli.ts +++ b/generator/cli.ts @@ -13,6 +13,7 @@ import { import {capsUpdates} from './features/capsUpdates'; import {rateUpdatesV3} from './features/rateUpdates'; import {collateralsUpdates} from './features/collateralsUpdates'; +import {eModeUpdates} from './features/eModeUpdates'; import {lstPriceCapsUpdates} from './features/lstPriceCapsUpdates'; import {stablePriceCapsUpdates} from './features/stablePriceCapsUpdates'; import {generateFiles, writeFiles} from './generator'; @@ -42,7 +43,8 @@ const FEATURE_MODULES_V3 = [ capsUpdates, collateralsUpdates, lstPriceCapsUpdates, - stablePriceCapsUpdates + stablePriceCapsUpdates, + eModeUpdates ]; async function generateDeterministicPoolCache(pool: PoolIdentifier): Promise { diff --git a/generator/common.ts b/generator/common.ts index ad3f18d..7e7e18a 100644 --- a/generator/common.ts +++ b/generator/common.ts @@ -41,9 +41,12 @@ export function getAssets(pool: PoolIdentifier): string[] { return Object.keys(assets); } -export function getEModes(pool: PoolIdentifierV3) { - const eModes = addressBook[pool].E_MODES; - return eModes; +export function getEModes(pool: PoolIdentifierV3): {value: string; id: number}[] { + return Object.keys(addressBook[pool].E_MODES).map((key) => ({ + // map the complex type to a string as used in the sol libs + value: addressBook[pool].E_MODES[key].label.toUpperCase().replace(/[^A-Z0-9]+/gi, '_'), + id: key as unknown as number, + })); } export function getVersion(pool: PoolIdentifier) { diff --git a/generator/features/__snapshots__/eModeUpdates.spec.ts.snap b/generator/features/__snapshots__/eModeUpdates.spec.ts.snap new file mode 100644 index 0000000..7b8ac78 --- /dev/null +++ b/generator/features/__snapshots__/eModeUpdates.spec.ts.snap @@ -0,0 +1,102 @@ +// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html + +exports[`feature: eModeUpdates > should properly generate files 1`] = ` +{ + "jsonConfig": "import {ConfigFile} from '../../generator/types'; +export const config: ConfigFile = { + rootOptions: { + pools: ['AaveV3Ethereum'], + title: 'test', + shortName: 'Test', + date: '20231023', + author: 'test', + discussion: 'test', + }, + poolOptions: { + AaveV3Ethereum: { + configs: { + EMODES_UPDATE: [ + { + eModeCategory: 'AaveV3EthereumEModes.ETH_CORRELATED', + ltv: '', + liqThreshold: '50', + liqBonus: '', + label: '', + }, + ], + }, + cache: {blockNumber: 42}, + }, + }, +}; +", + "payloads": [ + { + "contractName": "AaveV3Ethereum_Test_20231023", + "payload": "// SPDX-License-Identifier: MIT +pragma solidity ^0.8.0; + +import {AaveV3EthereumEModes} from 'aave-address-book/AaveV3Ethereum.sol'; +import {RiskStewardsEthereum} from '../../../../scripts/networks/RiskStewardsEthereum.s.sol'; +import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol'; +import {IAaveV3ConfigEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol'; + +/** + * @title test + * @author test + * - discussion: test + * - deploy-command: make run-script contract=src/contracts/updates/20231023_AaveV3Ethereum_Test/AaveV3Ethereum_Test_20231023.sol:AaveV3Ethereum_Test_20231023 network=mainnet broadcast=false generate_diff=true skip_timelock=false + */ +contract AaveV3Ethereum_Test_20231023 is RiskStewardsEthereum { + function name() public pure override returns (string memory) { + return 'AaveV3Ethereum_Test_20231023'; + } + + function eModeCategoriesUpdates() + public + pure + override + returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) + { + IAaveV3ConfigEngine.EModeCategoryUpdate[] + memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1); + + eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({ + eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: 50_00, + liqBonus: EngineFlags.KEEP_CURRENT, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + return eModeUpdates; + } +} +", + "pool": "AaveV3Ethereum", + }, + ], +} +`; + +exports[`feature: eModeUpdates > should return reasonable code 1`] = ` +{ + "code": { + "fn": [ + "function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) { + IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](1); + + eModeUpdates[0] = IAaveV3ConfigEngine.EModeCategoryUpdate({ + eModeCategory: AaveV3EthereumEModes.ETH_CORRELATED, + ltv: EngineFlags.KEEP_CURRENT, + liqThreshold: 50_00, + liqBonus: EngineFlags.KEEP_CURRENT, + label: EngineFlags.KEEP_CURRENT_STRING + }); + + return eModeUpdates; + }", + ], + }, +} +`; diff --git a/generator/features/eModeUpdates.spec.ts b/generator/features/eModeUpdates.spec.ts new file mode 100644 index 0000000..209a8fc --- /dev/null +++ b/generator/features/eModeUpdates.spec.ts @@ -0,0 +1,37 @@ +// sum.test.js +import {expect, describe, it} from 'vitest'; +import {MOCK_OPTIONS, eModeUpdate} from './mocks/configs'; +import {generateFiles} from '../generator'; +import {FEATURE, PoolConfigs} from '../types'; +import {eModeUpdates} from './eModeUpdates'; + +describe('feature: eModeUpdates', () => { + it('should return reasonable code', () => { + const output = eModeUpdates.build({ + options: MOCK_OPTIONS, + pool: 'AaveV3Ethereum', + cfg: eModeUpdate, + cache: {blockNumber: 42}, + }); + expect(output).toMatchSnapshot(); + }); + + it('should properly generate files', async () => { + const poolConfigs: PoolConfigs = { + ['AaveV3Ethereum']: { + artifacts: [ + eModeUpdates.build({ + options: {...MOCK_OPTIONS, pools: ['AaveV3Ethereum']}, + pool: 'AaveV3Ethereum', + cfg: eModeUpdate, + cache: {blockNumber: 42}, + }), + ], + configs: {[FEATURE.EMODES_UPDATE]: eModeUpdate}, + cache: {blockNumber: 42}, + }, + }; + const files = await generateFiles({...MOCK_OPTIONS, pools: ['AaveV3Ethereum']}, poolConfigs); + expect(files).toMatchSnapshot(); + }); +}); diff --git a/generator/features/eModeUpdates.ts b/generator/features/eModeUpdates.ts new file mode 100644 index 0000000..1e7e76d --- /dev/null +++ b/generator/features/eModeUpdates.ts @@ -0,0 +1,82 @@ +import {CodeArtifact, FEATURE, FeatureModule} from '../types'; +import {eModesSelect} from '../prompts'; +import {EModeCategoryUpdate} from './types'; +import {stringOrKeepCurrent, stringPrompt} from '../prompts/stringPrompt'; +import {percentPrompt, translateJsPercentToSol} from '../prompts/percentPrompt'; + +async function fetchEmodeCategoryUpdate( + eModeCategory: string | number, + required?: T, +): Promise { + return { + eModeCategory, + ltv: await percentPrompt({ + message: 'ltv', + required, + }), + liqThreshold: await percentPrompt({ + message: 'liqThreshold', + required, + }), + liqBonus: await percentPrompt({ + message: 'liqBonus', + required, + }), + label: await stringPrompt({ + message: 'label', + required, + }), + }; +} + +type EmodeUpdates = EModeCategoryUpdate[]; + +export const eModeUpdates: FeatureModule = { + value: FEATURE.EMODES_UPDATE, + description: 'eModeCategoriesUpdates (altering eMode category params)', + async cli({pool}) { + console.log(`Fetching information for EMode category updates on ${pool}`); + + const response: EmodeUpdates = []; + const eModeCategories = await eModesSelect({ + message: 'Select the eModes you want to amend', + pool, + }); + + if (eModeCategories) { + for (const eModeCategory of eModeCategories) { + console.log(`collecting info for ${eModeCategory}`); + response.push(await fetchEmodeCategoryUpdate(eModeCategory)); + } + } + return response; + }, + build({pool, cfg}) { + const response: CodeArtifact = { + code: { + fn: [ + `function eModeCategoriesUpdates() public pure override returns (IAaveV3ConfigEngine.EModeCategoryUpdate[] memory) { + IAaveV3ConfigEngine.EModeCategoryUpdate[] memory eModeUpdates = new IAaveV3ConfigEngine.EModeCategoryUpdate[](${ + cfg.length + }); + + ${cfg + .map( + (cfg, ix) => `eModeUpdates[${ix}] = IAaveV3ConfigEngine.EModeCategoryUpdate({ + eModeCategory: ${cfg.eModeCategory}, + ltv: ${translateJsPercentToSol(cfg.ltv)}, + liqThreshold: ${translateJsPercentToSol(cfg.liqThreshold)}, + liqBonus: ${translateJsPercentToSol(cfg.liqBonus)}, + label: ${stringOrKeepCurrent(cfg.label)} + });`, + ) + .join('\n')} + + return eModeUpdates; + }`, + ], + }, + }; + return response; + }, +}; diff --git a/generator/features/mocks/configs.ts b/generator/features/mocks/configs.ts index 2f3879c..d8bd6af 100644 --- a/generator/features/mocks/configs.ts +++ b/generator/features/mocks/configs.ts @@ -1,5 +1,5 @@ import {Options} from '../../types'; -import {CapsUpdate, CollateralUpdate, RateStrategyUpdate, LstPriceCapUpdate, StablePriceCapUpdate} from '../types'; +import {CapsUpdate, CollateralUpdate, RateStrategyUpdate, LstPriceCapUpdate, StablePriceCapUpdate, EModeCategoryUpdate} from '../types'; export const MOCK_OPTIONS: Options = { pools: ['AaveV3Ethereum'], @@ -29,6 +29,16 @@ export const collateralUpdate: CollateralUpdate[] = [ }, ]; +export const eModeUpdate: EModeCategoryUpdate[] = [ + { + eModeCategory: 'AaveV3EthereumEModes.ETH_CORRELATED', + ltv: '', + liqThreshold: '50', + liqBonus: '', + label: '', + }, +]; + export const rateUpdateV3: RateStrategyUpdate[] = [ { asset: 'WETH', diff --git a/generator/features/types.ts b/generator/features/types.ts index 05e184b..440b508 100644 --- a/generator/features/types.ts +++ b/generator/features/types.ts @@ -21,6 +21,15 @@ export interface CollateralUpdatePartial { export interface CollateralUpdate extends CollateralUpdatePartial, AssetSelector {} +export interface EModeCategoryUpdate { + // library accessor or new id + eModeCategory: string | number; + ltv: NumberInputValues; + liqThreshold: NumberInputValues; + liqBonus: NumberInputValues; + label: string; +} + export interface RateStrategyParams { optimalUtilizationRate: string; baseVariableBorrowRate: string; diff --git a/generator/prompts.ts b/generator/prompts.ts index a128002..4953a6d 100644 --- a/generator/prompts.ts +++ b/generator/prompts.ts @@ -34,13 +34,10 @@ export async function eModeSelect({ pool, }: EModeSelectPrompt) { const eModes = getEModes(pool as any); - if (Object.keys(eModes).length != 0) { + if (eModes.length != 0) { const eMode = await select({ message, - choices: [ - ...(disableKeepCurrent ? [] : [{value: ENGINE_FLAGS.KEEP_CURRENT}]), - ...Object.keys(eModes).map((eMode) => ({value: eMode})), - ], + choices: eModes, }); return translateEModeToEModeLib(eMode, pool); } else { @@ -51,14 +48,10 @@ export async function eModeSelect({ export async function eModesSelect({message, pool}: EModeSelectPrompt) { const eModes = getEModes(pool as any); - if (Object.keys(eModes).length != 0) { + if (eModes.length != 0) { const values = await checkbox({ message, - choices: [ - ...Object.keys(eModes) - .filter((e) => e != 'NONE') - .map((eMode) => ({value: eMode})), - ], + choices: eModes, required: true, }); return values.map((mode) => translateEModeToEModeLib(mode, pool)); diff --git a/generator/types.ts b/generator/types.ts index 12dba94..12ed41f 100644 --- a/generator/types.ts +++ b/generator/types.ts @@ -55,6 +55,7 @@ export type CodeArtifact = { export enum FEATURE { CAPS_UPDATE = 'CAPS_UPDATE', + EMODES_UPDATE = 'EMODES_UPDATE', COLLATERALS_UPDATE = 'COLLATERALS_UPDATE', RATE_UPDATE_V3 = 'RATE_UPDATE_V3', LST_PRICE_CAP_UPDATE = 'LST_PRICE_CAP_UPDATE', diff --git a/scripts/RiskStewardsBase.s.sol b/scripts/RiskStewardsBase.s.sol index e955168..3d705a7 100644 --- a/scripts/RiskStewardsBase.s.sol +++ b/scripts/RiskStewardsBase.s.sol @@ -12,7 +12,7 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { IPool immutable POOL; IRiskSteward immutable STEWARD; - uint8 public constant MAX_TX = 5; + uint8 public constant MAX_TX = 6; constructor(address pool, address steward) { POOL = IPool(pool); @@ -30,6 +30,13 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { returns (IEngine.RateStrategyUpdate[] memory) {} + function eModeCategoriesUpdates() + public + pure + virtual + returns (IEngine.EModeCategoryUpdate[] memory) + {} + function lstPriceCapsUpdates() public pure @@ -83,6 +90,7 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { IEngine.CapsUpdate[] memory capUpdates = capsUpdates(); IEngine.CollateralUpdate[] memory collateralUpdates = collateralsUpdates(); + IEngine.EModeCategoryUpdate[] memory eModeUpdates = eModeCategoriesUpdates(); IEngine.RateStrategyUpdate[] memory rateUpdates = rateStrategiesUpdates(); IRiskSteward.PriceCapLstUpdate[] memory lstPriceCapUpdates = lstPriceCapsUpdates(); IRiskSteward.PriceCapStableUpdate[] memory stablePriceCapUpdates = stablePriceCapsUpdates(); @@ -90,7 +98,7 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { if (skipTimelock) { // warp to the max timelock - uint40[] memory timelocks = new uint40[](12); + uint40[] memory timelocks = new uint40[](15); uint256 index = 0; // Track the current index for adding elements IRiskSteward.Config memory riskConfig = STEWARD.getRiskConfig(); @@ -104,6 +112,11 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { timelocks[index++] = riskConfig.collateralConfig.liquidationBonus.minDelay; timelocks[index++] = riskConfig.collateralConfig.debtCeiling.minDelay; } + if (eModeUpdates.length != 0) { + timelocks[index++] = riskConfig.eModeConfig.ltv.minDelay; + timelocks[index++] = riskConfig.eModeConfig.liquidationThreshold.minDelay; + timelocks[index++] = riskConfig.eModeConfig.liquidationBonus.minDelay; + } if (rateUpdates.length != 0) { timelocks[index++] = riskConfig.rateConfig.baseVariableBorrowRate.minDelay; timelocks[index++] = riskConfig.rateConfig.optimalUsageRatio.minDelay; @@ -145,6 +158,16 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { txCount++; } + if (eModeUpdates.length != 0) { + callDatas[txCount] = abi.encodeWithSelector( + IRiskSteward.updateEModeCategories.selector, + eModeUpdates + ); + (bool success, bytes memory resultData) = address(STEWARD).call(callDatas[txCount]); + _verifyCallResult(success, resultData); + txCount++; + } + if (rateUpdates.length != 0) { callDatas[txCount] = abi.encodeWithSelector(IRiskSteward.updateRates.selector, rateUpdates); (bool success, bytes memory resultData) = address(STEWARD).call(callDatas[txCount]); From 1f61c0ac7dc375cb936a113523a0ed3cc2eea138 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Tue, 25 Mar 2025 21:16:02 +0530 Subject: [PATCH 5/8] fix: use pool instead of addresses provider --- scripts/deploy/DeployCapInjector.s.sol | 6 ++--- scripts/deploy/DeployRateInjector.s.sol | 6 ++--- scripts/deploy/DeployStewards.s.sol | 34 ++++++++++++------------- src/contracts/EdgeRiskStewardCaps.sol | 6 ++--- src/contracts/EdgeRiskStewardRates.sol | 6 ++--- src/contracts/RiskSteward.sol | 19 +++++++------- src/interfaces/IRiskSteward.sol | 6 ++--- tests/AaveStewardsInjectorCaps.t.sol | 2 +- tests/AaveStewardsInjectorRates.t.sol | 2 +- tests/EdgeRiskStewardCaps.t.sol | 2 +- tests/EdgeRiskStewardRates.t.sol | 2 +- tests/RiskSteward.t.sol | 4 +-- tests/RiskStewardCapo.t.sol | 2 +- 13 files changed, 48 insertions(+), 49 deletions(-) diff --git a/scripts/deploy/DeployCapInjector.s.sol b/scripts/deploy/DeployCapInjector.s.sol index 94a1b5e..8f347ba 100644 --- a/scripts/deploy/DeployCapInjector.s.sol +++ b/scripts/deploy/DeployCapInjector.s.sol @@ -13,14 +13,14 @@ library DeployStewardContracts { address constant EDGE_RISK_ORACLE = 0x861eeAdB55E41f161F31Acb1BFD4c70E3a964Aed; function _deployRiskStewards( - address poolAddressesProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardCaps( - poolAddressesProvider, + pool, configEngine, riskCouncil, governance, @@ -92,7 +92,7 @@ contract DeployArbitrum is ArbitrumScript { .predictAddress(msg.sender, salt); address riskSteward = DeployStewardContracts._deployRiskStewards( - address(AaveV3Arbitrum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Arbitrum.POOL), AaveV3Arbitrum.CONFIG_ENGINE, predictedStewardsInjector, GovernanceV3Arbitrum.EXECUTOR_LVL_1 diff --git a/scripts/deploy/DeployRateInjector.s.sol b/scripts/deploy/DeployRateInjector.s.sol index 9262049..1681364 100644 --- a/scripts/deploy/DeployRateInjector.s.sol +++ b/scripts/deploy/DeployRateInjector.s.sol @@ -13,14 +13,14 @@ library DeployStewardContracts { address constant EDGE_RISK_ORACLE = 0x7ABB46C690C52E919687D19ebF89C81A6136C1F2; function _deployRiskStewards( - address poolDataProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardRates( - poolDataProvider, + pool, configEngine, riskCouncil, governance, @@ -90,7 +90,7 @@ contract DeployEthereumLido is EthereumScript { .predictAddress(msg.sender, salt); address riskSteward = DeployStewardContracts._deployRiskStewards( - address(AaveV3EthereumLido.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumLido.POOL), AaveV3EthereumLido.CONFIG_ENGINE, predictedStewardsInjector, GovernanceV3Ethereum.EXECUTOR_LVL_1 diff --git a/scripts/deploy/DeployStewards.s.sol b/scripts/deploy/DeployStewards.s.sol index 3ac8c1a..3cf3a65 100644 --- a/scripts/deploy/DeployStewards.s.sol +++ b/scripts/deploy/DeployStewards.s.sol @@ -34,14 +34,14 @@ import {RiskSteward, IRiskSteward} from '../../src/contracts/RiskSteward.sol'; library DeployRiskStewards { function _deployRiskStewards( - address addressesProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new RiskSteward( - addressesProvider, + pool, configEngine, riskCouncil, governance, @@ -88,7 +88,7 @@ contract DeployEthereum is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -102,7 +102,7 @@ contract DeployEthereumLido is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumLido.POOL_ADDRESSES_PROVIDER), + address(AaveV3EthereumLido.POOL), AaveV3EthereumLido.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -116,7 +116,7 @@ contract DeployEthereumEtherFi is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumEtherFi.POOL_ADDRESSES_PROVIDER), + address(AaveV3EthereumEtherFi.POOL), AaveV3EthereumEtherFi.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -130,7 +130,7 @@ contract DeployPolygon is PolygonScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Polygon.POOL_ADDRESSES_PROVIDER), + address(AaveV3Polygon.POOL), AaveV3Polygon.CONFIG_ENGINE, 0x2C40FB1ACe63084fc0bB95F83C31B5854C6C4cB5, // pol-risk-council GovernanceV3Polygon.EXECUTOR_LVL_1 @@ -144,7 +144,7 @@ contract DeployArbitrum is ArbitrumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Arbitrum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Arbitrum.POOL), AaveV3Arbitrum.CONFIG_ENGINE, 0x3Be327F22eB4BD8042e6944073b8826dCf357Aa2, // arb-risk-council GovernanceV3Arbitrum.EXECUTOR_LVL_1 @@ -158,7 +158,7 @@ contract DeployOptimism is OptimismScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Optimism.POOL_ADDRESSES_PROVIDER), + address(AaveV3Optimism.POOL), AaveV3Optimism.CONFIG_ENGINE, 0xCb86256A994f0c505c5e15c75BF85fdFEa0F2a56, // opt-risk-council GovernanceV3Optimism.EXECUTOR_LVL_1 @@ -172,7 +172,7 @@ contract DeployAvalanche is AvalancheScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Avalanche.POOL_ADDRESSES_PROVIDER), + address(AaveV3Avalanche.POOL), AaveV3Avalanche.CONFIG_ENGINE, 0xCa66149425E7DC8f81276F6D80C4b486B9503D1a, // ava-risk-council GovernanceV3Avalanche.EXECUTOR_LVL_1 @@ -186,7 +186,7 @@ contract DeployScroll is ScrollScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Scroll.POOL_ADDRESSES_PROVIDER), + address(AaveV3Scroll.POOL), AaveV3Scroll.CONFIG_ENGINE, 0x611439a74546888c3535B4dd119A5Cbb9f5332EA, // scroll-risk-council GovernanceV3Scroll.EXECUTOR_LVL_1 @@ -200,7 +200,7 @@ contract DeployGnosis is GnosisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Gnosis.POOL_ADDRESSES_PROVIDER), + address(AaveV3Gnosis.POOL), AaveV3Gnosis.CONFIG_ENGINE, 0xF221B08dD10e0C68D74F035764931Baa3b030481, // gnosis-risk-council GovernanceV3Gnosis.EXECUTOR_LVL_1 @@ -214,7 +214,7 @@ contract DeployBNB is BNBScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3BNB.POOL_ADDRESSES_PROVIDER), + address(AaveV3BNB.POOL), AaveV3BNB.CONFIG_ENGINE, 0x126dc589cc75f17385dD95516F3F1788d862E7bc, // bnb-risk-council GovernanceV3BNB.EXECUTOR_LVL_1 @@ -228,7 +228,7 @@ contract DeployBase is BaseScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Base.POOL_ADDRESSES_PROVIDER), + address(AaveV3Base.POOL), AaveV3Base.CONFIG_ENGINE, 0xfbeB4AcB31340bA4de9C87B11dfBf7e2bc8C0bF1, // base-risk-council GovernanceV3Base.EXECUTOR_LVL_1 @@ -242,7 +242,7 @@ contract DeployMetis is MetisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Metis.POOL_ADDRESSES_PROVIDER), + address(AaveV3Metis.POOL), AaveV3Metis.CONFIG_ENGINE, 0x0f547846920C34E70FBE4F3d87E46452a3FeAFfa, // metis-risk-council GovernanceV3Metis.EXECUTOR_LVL_1 @@ -256,7 +256,7 @@ contract DeployLinea is LineaScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Linea.POOL_ADDRESSES_PROVIDER), + address(AaveV3Linea.POOL), AaveV3Linea.CONFIG_ENGINE, 0xF092A5aC5E284E7c433dAFE5b8B138bFcA53a4Ee, // linea-risk-council GovernanceV3Linea.EXECUTOR_LVL_1 @@ -270,7 +270,7 @@ contract DeploySonic is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Sonic.POOL_ADDRESSES_PROVIDER), + address(AaveV3Sonic.POOL), AaveV3Sonic.CONFIG_ENGINE, 0x1dE39A17a9Fa8c76899fff37488482EEb7835d04, // sonic-risk-council GovernanceV3Sonic.EXECUTOR_LVL_1 @@ -284,7 +284,7 @@ contract DeployCelo is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Celo.POOL_ADDRESSES_PROVIDER), + address(AaveV3Celo.POOL), AaveV3Celo.CONFIG_ENGINE, 0xd85786B5FC61E2A0c0a3144a33A0fC70646a99f6, // celo-risk-council GovernanceV3Celo.EXECUTOR_LVL_1 diff --git a/src/contracts/EdgeRiskStewardCaps.sol b/src/contracts/EdgeRiskStewardCaps.sol index 4f9156a..d3fc159 100644 --- a/src/contracts/EdgeRiskStewardCaps.sol +++ b/src/contracts/EdgeRiskStewardCaps.sol @@ -11,19 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardCaps is RiskSteward { /** - * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward + * @param pool the aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - address poolAddressesProvider, + address pool, address engine, address riskCouncil, address owner, Config memory riskConfig - ) RiskSteward(poolAddressesProvider, engine, riskCouncil, owner, riskConfig) {} + ) RiskSteward(pool, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateRates( diff --git a/src/contracts/EdgeRiskStewardRates.sol b/src/contracts/EdgeRiskStewardRates.sol index c80cb0d..edb89a6 100644 --- a/src/contracts/EdgeRiskStewardRates.sol +++ b/src/contracts/EdgeRiskStewardRates.sol @@ -11,19 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardRates is RiskSteward { /** - * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward + * @param pool the aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - address poolAddressesProvider, + address pool, address engine, address riskCouncil, address owner, Config memory riskConfig - ) RiskSteward(poolAddressesProvider, engine, riskCouncil, owner, riskConfig) {} + ) RiskSteward(pool, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateCaps(IEngine.CapsUpdate[] calldata) external virtual override onlyRiskCouncil { diff --git a/src/contracts/RiskSteward.sol b/src/contracts/RiskSteward.sol index d088048..5957727 100644 --- a/src/contracts/RiskSteward.sol +++ b/src/contracts/RiskSteward.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; -import {IPool, IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol'; +import {IPool} from 'aave-address-book/AaveV3.sol'; import {Address} from 'openzeppelin-contracts/contracts/utils/Address.sol'; import {SafeCast} from 'openzeppelin-contracts/contracts/utils/math/SafeCast.sol'; import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol'; @@ -29,7 +29,7 @@ contract RiskSteward is Ownable, IRiskSteward { IEngine public immutable CONFIG_ENGINE; /// @inheritdoc IRiskSteward - IPoolAddressesProvider public immutable ADDRESSES_PROVIDER; + IPool public immutable POOL; /// @inheritdoc IRiskSteward address public immutable RISK_COUNCIL; @@ -53,20 +53,20 @@ contract RiskSteward is Ownable, IRiskSteward { } /** - * @param poolAddressesProvider The pool addresses provider of the pool to be controlled by the steward + * @param pool The aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - address poolAddressesProvider, + address pool, address engine, address riskCouncil, address owner, Config memory riskConfig ) Ownable(owner) { - ADDRESSES_PROVIDER = IPoolAddressesProvider(poolAddressesProvider); + POOL = IPool(pool); CONFIG_ENGINE = IEngine(engine); RISK_COUNCIL = riskCouncil; _riskConfig = riskConfig; @@ -175,7 +175,7 @@ contract RiskSteward is Ownable, IRiskSteward { if (capsUpdate[i].supplyCap == 0 || capsUpdate[i].borrowCap == 0) revert InvalidUpdateToZero(); - (uint256 currentBorrowCap, uint256 currentSupplyCap) = IPool(ADDRESSES_PROVIDER.getPool()).getConfiguration(asset).getCaps(); + (uint256 currentBorrowCap, uint256 currentSupplyCap) = POOL.getConfiguration(asset).getCaps(); _validateParamUpdate( ParamUpdateValidationInput({ @@ -277,8 +277,7 @@ contract RiskSteward is Ownable, IRiskSteward { collateralUpdates[i].debtCeiling == 0 ) revert InvalidUpdateToZero(); - DataTypes.ReserveConfigurationMap memory configuration = IPool(ADDRESSES_PROVIDER.getPool()) - .getConfiguration(asset); + DataTypes.ReserveConfigurationMap memory configuration = POOL.getConfiguration(asset); ( uint256 currentLtv, uint256 currentLiquidationThreshold, @@ -345,7 +344,7 @@ contract RiskSteward is Ownable, IRiskSteward { eModeCategoryUpdates[i].liqBonus == 0 ) revert InvalidUpdateToZero(); - DataTypes.CollateralConfig memory currentEmodeConfig = IPool(ADDRESSES_PROVIDER.getPool()).getEModeCategoryCollateralConfig(eModeId); + DataTypes.CollateralConfig memory currentEmodeConfig = POOL.getEModeCategoryCollateralConfig(eModeId); _validateParamUpdate( ParamUpdateValidationInput({ @@ -622,7 +621,7 @@ contract RiskSteward is Ownable, IRiskSteward { uint256 variableRateSlope2 ) { - address rateStrategyAddress = IPool(ADDRESSES_PROVIDER.getPool()).getReserveData(asset).interestRateStrategyAddress; + address rateStrategyAddress = POOL.getReserveData(asset).interestRateStrategyAddress; IDefaultInterestRateStrategyV2.InterestRateData memory interestRateData = IDefaultInterestRateStrategyV2(rateStrategyAddress) .getInterestRateDataBps(asset); diff --git a/src/interfaces/IRiskSteward.sol b/src/interfaces/IRiskSteward.sol index af4d061..04d28e9 100644 --- a/src/interfaces/IRiskSteward.sol +++ b/src/interfaces/IRiskSteward.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IPoolDataProvider, IPoolAddressesProvider} from 'aave-address-book/AaveV3.sol'; +import {IPool} from 'aave-address-book/AaveV3.sol'; import {IAaveV3ConfigEngine as IEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol'; import {IPriceCapAdapter} from 'aave-capo/interfaces/IPriceCapAdapter.sol'; @@ -208,9 +208,9 @@ interface IRiskSteward { function CONFIG_ENGINE() external view returns (IEngine); /** - * @notice The aave addresses provider of the instance steward controls + * @notice The aave pool of the instance steward controls */ - function ADDRESSES_PROVIDER() external view returns (IPoolAddressesProvider); + function POOL() external view returns (IPool); /** * @notice The safe controlling the steward diff --git a/tests/AaveStewardsInjectorCaps.t.sol b/tests/AaveStewardsInjectorCaps.t.sol index 1b11cfa..6ec912e 100644 --- a/tests/AaveStewardsInjectorCaps.t.sol +++ b/tests/AaveStewardsInjectorCaps.t.sol @@ -50,7 +50,7 @@ contract AaveStewardsInjectorCaps_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - address(contracts.poolAddressesProvider), + address(contracts.poolProxy), report.configEngine, address(_stewardInjector), address(this), diff --git a/tests/AaveStewardsInjectorRates.t.sol b/tests/AaveStewardsInjectorRates.t.sol index a836a18..e935e7e 100644 --- a/tests/AaveStewardsInjectorRates.t.sol +++ b/tests/AaveStewardsInjectorRates.t.sol @@ -45,7 +45,7 @@ contract AaveStewardsInjectorRates_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - address(contracts.poolAddressesProvider), + address(contracts.poolProxy), report.configEngine, address(_stewardInjector), address(this), diff --git a/tests/EdgeRiskStewardCaps.t.sol b/tests/EdgeRiskStewardCaps.t.sol index 8df5fed..b6a8e9f 100644 --- a/tests/EdgeRiskStewardCaps.t.sol +++ b/tests/EdgeRiskStewardCaps.t.sol @@ -10,7 +10,7 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { super.setUp(); steward = new EdgeRiskStewardCaps( - address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, GovernanceV3Ethereum.EXECUTOR_LVL_1, diff --git a/tests/EdgeRiskStewardRates.t.sol b/tests/EdgeRiskStewardRates.t.sol index 235e967..6f231ea 100644 --- a/tests/EdgeRiskStewardRates.t.sol +++ b/tests/EdgeRiskStewardRates.t.sol @@ -10,7 +10,7 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { super.setUp(); steward = new EdgeRiskStewardRates( - address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, GovernanceV3Ethereum.EXECUTOR_LVL_1, diff --git a/tests/RiskSteward.t.sol b/tests/RiskSteward.t.sol index 14e457e..e449623 100644 --- a/tests/RiskSteward.t.sol +++ b/tests/RiskSteward.t.sol @@ -3,7 +3,7 @@ pragma solidity ^0.8.0; import 'forge-std/Test.sol'; import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; -import {IACLManager, IPoolConfigurator, IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {IACLManager, IPoolConfigurator} from 'aave-address-book/AaveV3.sol'; import {IDefaultInterestRateStrategyV2} from 'aave-v3-origin/src/contracts/interfaces/IDefaultInterestRateStrategyV2.sol'; import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; @@ -27,7 +27,7 @@ contract RiskSteward_Test is Test { riskConfig = DeployRiskStewards._getRiskConfig(); steward = new RiskSteward( - address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, GovernanceV3Ethereum.EXECUTOR_LVL_1, diff --git a/tests/RiskStewardCapo.t.sol b/tests/RiskStewardCapo.t.sol index 1499dca..47b69a0 100644 --- a/tests/RiskStewardCapo.t.sol +++ b/tests/RiskStewardCapo.t.sol @@ -37,7 +37,7 @@ contract RiskSteward_Capo_Test is Test { riskConfig.priceCapConfig.priceCapStable = defaultRiskParamConfig; steward = new RiskSteward( - address(AaveV3Ethereum.POOL_ADDRESSES_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, GovernanceV3Ethereum.EXECUTOR_LVL_1, From f203e01be5ebf6dfdeb6766ae975fc311f43f709 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Fri, 28 Mar 2025 21:09:12 +0530 Subject: [PATCH 6/8] fix: certora ci --- certora/confs/rules.conf | 4 +++- certora/confs/sanity.conf | 4 +++- remappings.txt | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/certora/confs/rules.conf b/certora/confs/rules.conf index 61a1992..371fcc8 100644 --- a/certora/confs/rules.conf +++ b/certora/confs/rules.conf @@ -14,7 +14,9 @@ "lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src", "aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin", "aave-capo=lib/aave-capo/src", - "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src" + "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src", + "openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable", + "openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts" ], "optimistic_loop": true, "loop_iter": "2", diff --git a/certora/confs/sanity.conf b/certora/confs/sanity.conf index 683b9d6..4413799 100644 --- a/certora/confs/sanity.conf +++ b/certora/confs/sanity.conf @@ -10,7 +10,9 @@ "lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src", "aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin", "aave-capo=lib/aave-capo/src", - "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src" + "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src", + "openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable", + "openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts" ], "optimistic_loop": true, "prover_args": ["-depth 15","-mediumTimeout 1000"], diff --git a/remappings.txt b/remappings.txt index f8dbf3a..3c9c628 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,4 +5,6 @@ solidity-utils/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/lib/so lib/aave-helpers:aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/ aave-capo/=lib/aave-capo/src -lib/aave-capo:cl-synchronicity-price-adapter/=lib/aave-capo/lib/cl-synchronicity-price-adapter/src/ \ No newline at end of file +lib/aave-capo:cl-synchronicity-price-adapter/=lib/aave-capo/lib/cl-synchronicity-price-adapter/src/ +openzeppelin-contracts-upgradeable/=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/ +openzeppelin-contracts/=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/ From 282a923b5644da7b0da496ac8e2338183b5ca6b5 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Fri, 28 Mar 2025 21:18:31 +0530 Subject: [PATCH 7/8] fix: ci --- .github/workflows/certora.yml | 4 ++-- certora/confs/rules.conf | 2 +- certora/confs/sanity.conf | 2 +- remappings.txt | 2 -- 4 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.github/workflows/certora.yml b/.github/workflows/certora.yml index 48e8182..52d5a82 100644 --- a/.github/workflows/certora.yml +++ b/.github/workflows/certora.yml @@ -32,9 +32,9 @@ jobs: - name: Install solc run: | - wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux + wget https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux chmod +x solc-static-linux - sudo mv solc-static-linux /usr/local/bin/solc8.19 + sudo mv solc-static-linux /usr/local/bin/solc8.24 - name: Verify rule ${{ matrix.rule }} run: | diff --git a/certora/confs/rules.conf b/certora/confs/rules.conf index 371fcc8..190e7b6 100644 --- a/certora/confs/rules.conf +++ b/certora/confs/rules.conf @@ -23,7 +23,7 @@ "rule_sanity": "basic", "prover_args": ["-depth 15","-mediumTimeout 1000"], "smt_timeout": "2000", - "solc": "solc8.19", + "solc": "solc8.24", "verify": "RiskSteward:certora/specs/rules.spec", "cache" :"none", "msg": "RISK-STEWARD::rules" diff --git a/certora/confs/sanity.conf b/certora/confs/sanity.conf index 4413799..d5a74d2 100644 --- a/certora/confs/sanity.conf +++ b/certora/confs/sanity.conf @@ -17,7 +17,7 @@ "optimistic_loop": true, "prover_args": ["-depth 15","-mediumTimeout 1000"], "smt_timeout": "2000", - "solc": "solc8.19", + "solc": "solc8.24", "verify": "RiskSteward:certora/specs/sanity.spec", "cache" :"none", "msg": "RISK-STEWARD::sanity" diff --git a/remappings.txt b/remappings.txt index 3c9c628..25e78da 100644 --- a/remappings.txt +++ b/remappings.txt @@ -6,5 +6,3 @@ lib/aave-helpers:aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/ aave-capo/=lib/aave-capo/src lib/aave-capo:cl-synchronicity-price-adapter/=lib/aave-capo/lib/cl-synchronicity-price-adapter/src/ -openzeppelin-contracts-upgradeable/=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/ -openzeppelin-contracts/=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts/ From de3ed286a7c62b09cf80d0ad34fe6c5b1b9e3142 Mon Sep 17 00:00:00 2001 From: Harsh Pandey Date: Fri, 28 Mar 2025 22:59:51 +0530 Subject: [PATCH 8/8] refactor: config struct --- .github/workflows/certora.yml | 4 +- certora/confs/rules.conf | 6 +- certora/confs/sanity.conf | 6 +- foundry.toml | 2 +- remappings.txt | 2 +- scripts/RiskStewardsBase.s.sol | 24 +- scripts/deploy/DeployCapInjector.s.sol | 48 ++-- scripts/deploy/DeployRateInjector.s.sol | 48 ++-- scripts/deploy/DeployStewards.s.sol | 76 ++++--- src/contracts/EdgeRiskStewardCaps.sol | 10 +- src/contracts/EdgeRiskStewardRates.sol | 10 +- src/contracts/RiskSteward.sol | 113 +++++----- src/interfaces/IRiskSteward.sol | 49 ++++- tests/AaveStewardsInjectorCaps.t.sol | 22 +- tests/AaveStewardsInjectorRates.t.sol | 24 +- tests/EdgeRiskStewardCaps.t.sol | 55 +---- tests/EdgeRiskStewardRates.t.sol | 48 +--- tests/RiskSteward.t.sol | 279 ++++++++++-------------- tests/RiskStewardCapo.t.sol | 27 +-- 19 files changed, 366 insertions(+), 487 deletions(-) diff --git a/.github/workflows/certora.yml b/.github/workflows/certora.yml index 48e8182..52d5a82 100644 --- a/.github/workflows/certora.yml +++ b/.github/workflows/certora.yml @@ -32,9 +32,9 @@ jobs: - name: Install solc run: | - wget https://github.com/ethereum/solidity/releases/download/v0.8.19/solc-static-linux + wget https://github.com/ethereum/solidity/releases/download/v0.8.24/solc-static-linux chmod +x solc-static-linux - sudo mv solc-static-linux /usr/local/bin/solc8.19 + sudo mv solc-static-linux /usr/local/bin/solc8.24 - name: Verify rule ${{ matrix.rule }} run: | diff --git a/certora/confs/rules.conf b/certora/confs/rules.conf index 61a1992..190e7b6 100644 --- a/certora/confs/rules.conf +++ b/certora/confs/rules.conf @@ -14,14 +14,16 @@ "lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src", "aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin", "aave-capo=lib/aave-capo/src", - "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src" + "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src", + "openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable", + "openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts" ], "optimistic_loop": true, "loop_iter": "2", "rule_sanity": "basic", "prover_args": ["-depth 15","-mediumTimeout 1000"], "smt_timeout": "2000", - "solc": "solc8.19", + "solc": "solc8.24", "verify": "RiskSteward:certora/specs/rules.spec", "cache" :"none", "msg": "RISK-STEWARD::rules" diff --git a/certora/confs/sanity.conf b/certora/confs/sanity.conf index 683b9d6..d5a74d2 100644 --- a/certora/confs/sanity.conf +++ b/certora/confs/sanity.conf @@ -10,12 +10,14 @@ "lib/aave-helpers:aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src", "aave-v3-origin=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin", "aave-capo=lib/aave-capo/src", - "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src" + "lib/aave-capo:cl-synchronicity-price-adapter=lib/aave-capo/lib/cl-synchronicity-price-adapter/src", + "openzeppelin-contracts-upgradeable=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable", + "openzeppelin-contracts=lib/aave-capo/lib/aave-address-book/lib/aave-v3-origin/lib/solidity-utils/lib/openzeppelin-contracts-upgradeable/lib/openzeppelin-contracts" ], "optimistic_loop": true, "prover_args": ["-depth 15","-mediumTimeout 1000"], "smt_timeout": "2000", - "solc": "solc8.19", + "solc": "solc8.24", "verify": "RiskSteward:certora/specs/sanity.spec", "cache" :"none", "msg": "RISK-STEWARD::sanity" diff --git a/foundry.toml b/foundry.toml index 6e326b1..e648ae3 100644 --- a/foundry.toml +++ b/foundry.toml @@ -3,7 +3,7 @@ src = 'src' test = 'tests' script = 'scripts' out = 'out' -solc = '0.8.22' +solc = '0.8.24' optimizer = true optimizer_runs = 200 libs = ['lib'] diff --git a/remappings.txt b/remappings.txt index f8dbf3a..25e78da 100644 --- a/remappings.txt +++ b/remappings.txt @@ -5,4 +5,4 @@ solidity-utils/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/lib/so lib/aave-helpers:aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/src aave-v3-origin/=lib/aave-helpers/lib/aave-address-book/lib/aave-v3-origin/ aave-capo/=lib/aave-capo/src -lib/aave-capo:cl-synchronicity-price-adapter/=lib/aave-capo/lib/cl-synchronicity-price-adapter/src/ \ No newline at end of file +lib/aave-capo:cl-synchronicity-price-adapter/=lib/aave-capo/lib/cl-synchronicity-price-adapter/src/ diff --git a/scripts/RiskStewardsBase.s.sol b/scripts/RiskStewardsBase.s.sol index 9bc0c9b..e955168 100644 --- a/scripts/RiskStewardsBase.s.sol +++ b/scripts/RiskStewardsBase.s.sol @@ -95,26 +95,26 @@ abstract contract RiskStewardsBase is ProtocolV3TestBase { IRiskSteward.Config memory riskConfig = STEWARD.getRiskConfig(); if (capUpdates.length != 0) { - timelocks[index++] = riskConfig.supplyCap.minDelay; - timelocks[index++] = riskConfig.borrowCap.minDelay; + timelocks[index++] = riskConfig.capConfig.supplyCap.minDelay; + timelocks[index++] = riskConfig.capConfig.borrowCap.minDelay; } if (collateralUpdates.length != 0) { - timelocks[index++] = riskConfig.ltv.minDelay; - timelocks[index++] = riskConfig.liquidationThreshold.minDelay; - timelocks[index++] = riskConfig.liquidationBonus.minDelay; - timelocks[index++] = riskConfig.debtCeiling.minDelay; + timelocks[index++] = riskConfig.collateralConfig.ltv.minDelay; + timelocks[index++] = riskConfig.collateralConfig.liquidationThreshold.minDelay; + timelocks[index++] = riskConfig.collateralConfig.liquidationBonus.minDelay; + timelocks[index++] = riskConfig.collateralConfig.debtCeiling.minDelay; } if (rateUpdates.length != 0) { - timelocks[index++] = riskConfig.baseVariableBorrowRate.minDelay; - timelocks[index++] = riskConfig.optimalUsageRatio.minDelay; - timelocks[index++] = riskConfig.variableRateSlope1.minDelay; - timelocks[index++] = riskConfig.variableRateSlope2.minDelay; + timelocks[index++] = riskConfig.rateConfig.baseVariableBorrowRate.minDelay; + timelocks[index++] = riskConfig.rateConfig.optimalUsageRatio.minDelay; + timelocks[index++] = riskConfig.rateConfig.variableRateSlope1.minDelay; + timelocks[index++] = riskConfig.rateConfig.variableRateSlope2.minDelay; } if (lstPriceCapUpdates.length != 0) { - timelocks[index++] = riskConfig.priceCapLst.minDelay; + timelocks[index++] = riskConfig.priceCapConfig.priceCapLst.minDelay; } if (stablePriceCapUpdates.length != 0) { - timelocks[index++] = riskConfig.priceCapStable.minDelay; + timelocks[index++] = riskConfig.priceCapConfig.priceCapStable.minDelay; } uint40 maxTimelock = 0; for (uint256 i = 0; i < timelocks.length; i++) { diff --git a/scripts/deploy/DeployCapInjector.s.sol b/scripts/deploy/DeployCapInjector.s.sol index 5cbce81..ba05128 100644 --- a/scripts/deploy/DeployCapInjector.s.sol +++ b/scripts/deploy/DeployCapInjector.s.sol @@ -6,28 +6,27 @@ import {MiscArbitrum} from 'aave-address-book/MiscArbitrum.sol'; import {AaveV3Arbitrum, AaveV3ArbitrumAssets} from 'aave-address-book/AaveV3Arbitrum.sol'; import {GovernanceV3Arbitrum} from 'aave-address-book/GovernanceV3Arbitrum.sol'; import {ICreate3Factory} from 'solidity-utils/contracts/create3/interfaces/ICreate3Factory.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {EdgeRiskStewardCaps, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/EdgeRiskStewardCaps.sol'; +import {EdgeRiskStewardCaps, IRiskSteward} from '../../src/contracts/EdgeRiskStewardCaps.sol'; import {AaveStewardInjectorCaps} from '../../src/contracts/AaveStewardInjectorCaps.sol'; library DeployStewardContracts { address constant EDGE_RISK_ORACLE = 0x861eeAdB55E41f161F31Acb1BFD4c70E3a964Aed; function _deployRiskStewards( - address poolDataProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardCaps( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + pool, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } @@ -53,27 +52,26 @@ library DeployStewardContracts { function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 50 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 5_00 + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 30_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + }) }); } } @@ -89,7 +87,7 @@ contract DeployArbitrum is ArbitrumScript { .predictAddress(msg.sender, salt); address riskSteward = DeployStewardContracts._deployRiskStewards( - address(AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Arbitrum.POOL), AaveV3Arbitrum.CONFIG_ENGINE, predictedStewardsInjector, GovernanceV3Arbitrum.EXECUTOR_LVL_1 diff --git a/scripts/deploy/DeployRateInjector.s.sol b/scripts/deploy/DeployRateInjector.s.sol index 0fe52d1..93d0914 100644 --- a/scripts/deploy/DeployRateInjector.s.sol +++ b/scripts/deploy/DeployRateInjector.s.sol @@ -6,28 +6,27 @@ import {MiscEthereum} from 'aave-address-book/MiscEthereum.sol'; import {AaveV3EthereumLido, AaveV3EthereumLidoAssets} from 'aave-address-book/AaveV3EthereumLido.sol'; import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; import {ICreate3Factory} from 'solidity-utils/contracts/create3/interfaces/ICreate3Factory.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {EdgeRiskStewardRates, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/EdgeRiskStewardRates.sol'; +import {EdgeRiskStewardRates, IRiskSteward} from '../../src/contracts/EdgeRiskStewardRates.sol'; import {AaveStewardInjectorRates} from '../../src/contracts/AaveStewardInjectorRates.sol'; library DeployStewardContracts { address constant EDGE_RISK_ORACLE = 0x7ABB46C690C52E919687D19ebF89C81A6136C1F2; function _deployRiskStewards( - address poolDataProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new EdgeRiskStewardRates( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + pool, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } @@ -51,27 +50,26 @@ library DeployStewardContracts { function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 50 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 3_00}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 1 days, - maxPercentChange: 5_00 + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 100_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}) + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 1 days, maxPercentChange: 50}) + }) }); } } @@ -87,7 +85,7 @@ contract DeployEthereumLido is EthereumScript { .predictAddress(msg.sender, salt); address riskSteward = DeployStewardContracts._deployRiskStewards( - address(AaveV3EthereumLido.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumLido.POOL), AaveV3EthereumLido.CONFIG_ENGINE, predictedStewardsInjector, GovernanceV3Ethereum.EXECUTOR_LVL_1 diff --git a/scripts/deploy/DeployStewards.s.sol b/scripts/deploy/DeployStewards.s.sol index 69e66eb..a0a0bd4 100644 --- a/scripts/deploy/DeployStewards.s.sol +++ b/scripts/deploy/DeployStewards.s.sol @@ -30,52 +30,50 @@ import {AaveV3Sonic} from 'aave-address-book/AaveV3Sonic.sol'; import {GovernanceV3Sonic} from 'aave-address-book/GovernanceV3Sonic.sol'; import {AaveV3Celo} from 'aave-address-book/AaveV3Celo.sol'; import {GovernanceV3Celo} from 'aave-address-book/GovernanceV3Celo.sol'; -import {IOwnable} from 'aave-address-book/common/IOwnable.sol'; -import {RiskSteward, IRiskSteward, IPoolDataProvider, IEngine} from '../../src/contracts/RiskSteward.sol'; +import {RiskSteward, IRiskSteward} from '../../src/contracts/RiskSteward.sol'; library DeployRiskStewards { function _deployRiskStewards( - address poolDataProvider, + address pool, address configEngine, address riskCouncil, address governance ) internal returns (address) { address riskSteward = address( new RiskSteward( - IPoolDataProvider(poolDataProvider), - IEngine(configEngine), + pool, + configEngine, riskCouncil, + governance, _getRiskConfig() ) ); - IOwnable(riskSteward).transferOwnership(governance); return riskSteward; } function _getRiskConfig() internal pure returns (IRiskSteward.Config memory) { return IRiskSteward.Config({ - ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 25}), - liquidationThreshold: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 25 + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationThreshold: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), + debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}) }), - liquidationBonus: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), - borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), - debtCeiling: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), - baseVariableBorrowRate: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 50 + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 1_00}), + variableRateSlope2: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 20_00}), + optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}) }), - variableRateSlope1: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}), - variableRateSlope2: IRiskSteward.RiskParamConfig({ - minDelay: 3 days, - maxPercentChange: 5_00 + capConfig: IRiskSteward.CapConfig({ + supplyCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}), + borrowCap: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 100_00}) }), - optimalUsageRatio: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 3_00}), - priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), - priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 5_00}), + priceCapStable: IRiskSteward.RiskParamConfig({minDelay: 3 days, maxPercentChange: 50}) + }) }); } } @@ -85,7 +83,7 @@ contract DeployEthereum is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Ethereum.POOL), AaveV3Ethereum.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -99,7 +97,7 @@ contract DeployEthereumLido is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumLido.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumLido.POOL), AaveV3EthereumLido.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -113,7 +111,7 @@ contract DeployEthereumEtherFi is EthereumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3EthereumEtherFi.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3EthereumEtherFi.POOL), AaveV3EthereumEtherFi.CONFIG_ENGINE, 0x47c71dFEB55Ebaa431Ae3fbF99Ea50e0D3d30fA8, // eth-risk-council GovernanceV3Ethereum.EXECUTOR_LVL_1 @@ -127,7 +125,7 @@ contract DeployPolygon is PolygonScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Polygon.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Polygon.POOL), AaveV3Polygon.CONFIG_ENGINE, 0x2C40FB1ACe63084fc0bB95F83C31B5854C6C4cB5, // pol-risk-council GovernanceV3Polygon.EXECUTOR_LVL_1 @@ -141,7 +139,7 @@ contract DeployArbitrum is ArbitrumScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Arbitrum.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Arbitrum.POOL), AaveV3Arbitrum.CONFIG_ENGINE, 0x3Be327F22eB4BD8042e6944073b8826dCf357Aa2, // arb-risk-council GovernanceV3Arbitrum.EXECUTOR_LVL_1 @@ -155,7 +153,7 @@ contract DeployOptimism is OptimismScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Optimism.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Optimism.POOL), AaveV3Optimism.CONFIG_ENGINE, 0xCb86256A994f0c505c5e15c75BF85fdFEa0F2a56, // opt-risk-council GovernanceV3Optimism.EXECUTOR_LVL_1 @@ -169,7 +167,7 @@ contract DeployAvalanche is AvalancheScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Avalanche.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Avalanche.POOL), AaveV3Avalanche.CONFIG_ENGINE, 0xCa66149425E7DC8f81276F6D80C4b486B9503D1a, // ava-risk-council GovernanceV3Avalanche.EXECUTOR_LVL_1 @@ -183,7 +181,7 @@ contract DeployScroll is ScrollScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Scroll.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Scroll.POOL), AaveV3Scroll.CONFIG_ENGINE, 0x611439a74546888c3535B4dd119A5Cbb9f5332EA, // scroll-risk-council GovernanceV3Scroll.EXECUTOR_LVL_1 @@ -197,7 +195,7 @@ contract DeployGnosis is GnosisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Gnosis.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Gnosis.POOL), AaveV3Gnosis.CONFIG_ENGINE, 0xF221B08dD10e0C68D74F035764931Baa3b030481, // gnosis-risk-council GovernanceV3Gnosis.EXECUTOR_LVL_1 @@ -211,7 +209,7 @@ contract DeployBNB is BNBScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3BNB.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3BNB.POOL), AaveV3BNB.CONFIG_ENGINE, 0x126dc589cc75f17385dD95516F3F1788d862E7bc, // bnb-risk-council GovernanceV3BNB.EXECUTOR_LVL_1 @@ -225,7 +223,7 @@ contract DeployBase is BaseScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Base.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Base.POOL), AaveV3Base.CONFIG_ENGINE, 0xfbeB4AcB31340bA4de9C87B11dfBf7e2bc8C0bF1, // base-risk-council GovernanceV3Base.EXECUTOR_LVL_1 @@ -239,7 +237,7 @@ contract DeployMetis is MetisScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Metis.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Metis.POOL), AaveV3Metis.CONFIG_ENGINE, 0x0f547846920C34E70FBE4F3d87E46452a3FeAFfa, // metis-risk-council GovernanceV3Metis.EXECUTOR_LVL_1 @@ -253,7 +251,7 @@ contract DeployLinea is LineaScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Linea.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Linea.POOL), AaveV3Linea.CONFIG_ENGINE, 0xF092A5aC5E284E7c433dAFE5b8B138bFcA53a4Ee, // linea-risk-council GovernanceV3Linea.EXECUTOR_LVL_1 @@ -267,7 +265,7 @@ contract DeploySonic is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Sonic.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Sonic.POOL), AaveV3Sonic.CONFIG_ENGINE, 0x1dE39A17a9Fa8c76899fff37488482EEb7835d04, // sonic-risk-council GovernanceV3Sonic.EXECUTOR_LVL_1 @@ -281,7 +279,7 @@ contract DeployCelo is SonicScript { function run() external { vm.startBroadcast(); DeployRiskStewards._deployRiskStewards( - address(AaveV3Celo.AAVE_PROTOCOL_DATA_PROVIDER), + address(AaveV3Celo.POOL), AaveV3Celo.CONFIG_ENGINE, 0xd85786B5FC61E2A0c0a3144a33A0fC70646a99f6, // celo-risk-council GovernanceV3Celo.EXECUTOR_LVL_1 diff --git a/src/contracts/EdgeRiskStewardCaps.sol b/src/contracts/EdgeRiskStewardCaps.sol index 9a17487..35c8e3a 100644 --- a/src/contracts/EdgeRiskStewardCaps.sol +++ b/src/contracts/EdgeRiskStewardCaps.sol @@ -11,17 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardCaps is RiskSteward { /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param pool the aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address pool, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) RiskSteward(poolDataProvider, engine, riskCouncil, riskConfig) {} + ) RiskSteward(pool, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateRates( diff --git a/src/contracts/EdgeRiskStewardRates.sol b/src/contracts/EdgeRiskStewardRates.sol index 924f220..d1a08e7 100644 --- a/src/contracts/EdgeRiskStewardRates.sol +++ b/src/contracts/EdgeRiskStewardRates.sol @@ -11,17 +11,19 @@ import './RiskSteward.sol'; */ contract EdgeRiskStewardRates is RiskSteward { /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param pool the aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address pool, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) RiskSteward(poolDataProvider, engine, riskCouncil, riskConfig) {} + ) RiskSteward(pool, engine, riskCouncil, owner, riskConfig) {} /// @inheritdoc IRiskSteward function updateCaps(IEngine.CapsUpdate[] calldata) external virtual override onlyRiskCouncil { diff --git a/src/contracts/RiskSteward.sol b/src/contracts/RiskSteward.sol index 909e752..4e29693 100644 --- a/src/contracts/RiskSteward.sol +++ b/src/contracts/RiskSteward.sol @@ -1,7 +1,8 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity ^0.8.0; -import {IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; +import {IPool} from 'aave-address-book/AaveV3.sol'; import {Address} from 'openzeppelin-contracts/contracts/utils/Address.sol'; import {SafeCast} from 'openzeppelin-contracts/contracts/utils/math/SafeCast.sol'; import {EngineFlags} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/EngineFlags.sol'; @@ -19,6 +20,7 @@ import {IPriceCapAdapterStable} from 'aave-capo/interfaces/IPriceCapAdapterStabl * This contract can update the following risk params: caps, ltv, liqThreshold, liqBonus, debtCeiling, interest rates params. */ contract RiskSteward is Ownable, IRiskSteward { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; using Address for address; using SafeCast for uint256; using SafeCast for int256; @@ -27,7 +29,7 @@ contract RiskSteward is Ownable, IRiskSteward { IEngine public immutable CONFIG_ENGINE; /// @inheritdoc IRiskSteward - IPoolDataProvider public immutable POOL_DATA_PROVIDER; + IPool public immutable POOL; /// @inheritdoc IRiskSteward address public immutable RISK_COUNCIL; @@ -36,7 +38,7 @@ contract RiskSteward is Ownable, IRiskSteward { Config internal _riskConfig; - mapping(address => Debounce) internal _timelocks; + mapping(bytes20 id => Debounce) internal _timelocks; mapping(address => bool) internal _restrictedAddresses; @@ -49,19 +51,21 @@ contract RiskSteward is Ownable, IRiskSteward { } /** - * @param poolDataProvider The pool data provider of the pool to be controlled by the steward + * @param pool The aave pool to be controlled by the steward * @param engine the config engine to be used by the steward * @param riskCouncil the safe address of the council being able to interact with the steward + * @param owner the owner of the risk steward being able to set configs and mark items as restricted * @param riskConfig the risk configuration to setup for each individual risk param */ constructor( - IPoolDataProvider poolDataProvider, - IEngine engine, + address pool, + address engine, address riskCouncil, + address owner, Config memory riskConfig - ) Ownable(msg.sender) { - POOL_DATA_PROVIDER = poolDataProvider; - CONFIG_ENGINE = engine; + ) Ownable(owner) { + POOL = IPool(pool); + CONFIG_ENGINE = IEngine(engine); RISK_COUNCIL = riskCouncil; _riskConfig = riskConfig; } @@ -106,7 +110,7 @@ contract RiskSteward is Ownable, IRiskSteward { /// @inheritdoc IRiskSteward function getTimelock(address asset) external view returns (Debounce memory) { - return _timelocks[asset]; + return _timelocks[bytes20(asset)]; } /// @inheritdoc IRiskSteward @@ -145,16 +149,14 @@ contract RiskSteward is Ownable, IRiskSteward { if (capsUpdate[i].supplyCap == 0 || capsUpdate[i].borrowCap == 0) revert InvalidUpdateToZero(); - (uint256 currentBorrowCap, uint256 currentSupplyCap) = POOL_DATA_PROVIDER.getReserveCaps( - capsUpdate[i].asset - ); + (uint256 currentBorrowCap, uint256 currentSupplyCap) = POOL.getConfiguration(asset).getCaps(); _validateParamUpdate( ParamUpdateValidationInput({ currentValue: currentSupplyCap, newValue: capsUpdate[i].supplyCap, - lastUpdated: _timelocks[asset].supplyCapLastUpdated, - riskConfig: _riskConfig.supplyCap, + lastUpdated: _timelocks[bytes20(asset)].supplyCapLastUpdated, + riskConfig: _riskConfig.capConfig.supplyCap, isChangeRelative: true }) ); @@ -162,8 +164,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentBorrowCap, newValue: capsUpdate[i].borrowCap, - lastUpdated: _timelocks[asset].borrowCapLastUpdated, - riskConfig: _riskConfig.borrowCap, + lastUpdated: _timelocks[bytes20(asset)].borrowCapLastUpdated, + riskConfig: _riskConfig.capConfig.borrowCap, isChangeRelative: true }) ); @@ -192,8 +194,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentOptimalUsageRatio, newValue: ratesUpdate[i].params.optimalUsageRatio, - lastUpdated: _timelocks[asset].optimalUsageRatioLastUpdated, - riskConfig: _riskConfig.optimalUsageRatio, + lastUpdated: _timelocks[bytes20(asset)].optimalUsageRatioLastUpdated, + riskConfig: _riskConfig.rateConfig.optimalUsageRatio, isChangeRelative: false }) ); @@ -201,8 +203,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentBaseVariableBorrowRate, newValue: ratesUpdate[i].params.baseVariableBorrowRate, - lastUpdated: _timelocks[asset].baseVariableRateLastUpdated, - riskConfig: _riskConfig.baseVariableBorrowRate, + lastUpdated: _timelocks[bytes20(asset)].baseVariableRateLastUpdated, + riskConfig: _riskConfig.rateConfig.baseVariableBorrowRate, isChangeRelative: false }) ); @@ -210,8 +212,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentVariableRateSlope1, newValue: ratesUpdate[i].params.variableRateSlope1, - lastUpdated: _timelocks[asset].variableRateSlope1LastUpdated, - riskConfig: _riskConfig.variableRateSlope1, + lastUpdated: _timelocks[bytes20(asset)].variableRateSlope1LastUpdated, + riskConfig: _riskConfig.rateConfig.variableRateSlope1, isChangeRelative: false }) ); @@ -219,8 +221,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentVariableRateSlope2, newValue: ratesUpdate[i].params.variableRateSlope2, - lastUpdated: _timelocks[asset].variableRateSlope2LastUpdated, - riskConfig: _riskConfig.variableRateSlope2, + lastUpdated: _timelocks[bytes20(asset)].variableRateSlope2LastUpdated, + riskConfig: _riskConfig.rateConfig.variableRateSlope2, isChangeRelative: false }) ); @@ -249,26 +251,21 @@ contract RiskSteward is Ownable, IRiskSteward { collateralUpdates[i].debtCeiling == 0 ) revert InvalidUpdateToZero(); + DataTypes.ReserveConfigurationMap memory configuration = POOL.getConfiguration(asset); ( - , uint256 currentLtv, uint256 currentLiquidationThreshold, uint256 currentLiquidationBonus, , - , - , - , - , - - ) = POOL_DATA_PROVIDER.getReserveConfigurationData(asset); - uint256 currentDebtCeiling = POOL_DATA_PROVIDER.getDebtCeiling(asset); + ) = configuration.getParams(); + uint256 currentDebtCeiling = configuration.getDebtCeiling(); _validateParamUpdate( ParamUpdateValidationInput({ currentValue: currentLtv, newValue: collateralUpdates[i].ltv, - lastUpdated: _timelocks[asset].ltvLastUpdated, - riskConfig: _riskConfig.ltv, + lastUpdated: _timelocks[bytes20(asset)].ltvLastUpdated, + riskConfig: _riskConfig.collateralConfig.ltv, isChangeRelative: false }) ); @@ -276,8 +273,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentLiquidationThreshold, newValue: collateralUpdates[i].liqThreshold, - lastUpdated: _timelocks[asset].liquidationThresholdLastUpdated, - riskConfig: _riskConfig.liquidationThreshold, + lastUpdated: _timelocks[bytes20(asset)].liquidationThresholdLastUpdated, + riskConfig: _riskConfig.collateralConfig.liquidationThreshold, isChangeRelative: false }) ); @@ -285,8 +282,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentLiquidationBonus - 100_00, // as the definition is 100% + x%, and config engine takes into account x% for simplicity. newValue: collateralUpdates[i].liqBonus, - lastUpdated: _timelocks[asset].liquidationBonusLastUpdated, - riskConfig: _riskConfig.liquidationBonus, + lastUpdated: _timelocks[bytes20(asset)].liquidationBonusLastUpdated, + riskConfig: _riskConfig.collateralConfig.liquidationBonus, isChangeRelative: false }) ); @@ -294,8 +291,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentDebtCeiling / 100, // as the definition is with 2 decimals, and config engine does not take the decimals into account. newValue: collateralUpdates[i].debtCeiling, - lastUpdated: _timelocks[asset].debtCeilingLastUpdated, - riskConfig: _riskConfig.debtCeiling, + lastUpdated: _timelocks[bytes20(asset)].debtCeilingLastUpdated, + riskConfig: _riskConfig.collateralConfig.debtCeiling, isChangeRelative: true }) ); @@ -332,8 +329,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentMaxYearlyGrowthPercent, newValue: priceCapsUpdate[i].priceCapUpdateParams.maxYearlyRatioGrowthPercent, - lastUpdated: _timelocks[oracle].priceCapLastUpdated, - riskConfig: _riskConfig.priceCapLst, + lastUpdated: _timelocks[bytes20(oracle)].priceCapLastUpdated, + riskConfig: _riskConfig.priceCapConfig.priceCapLst, isChangeRelative: true }) ); @@ -362,8 +359,8 @@ contract RiskSteward is Ownable, IRiskSteward { ParamUpdateValidationInput({ currentValue: currentPriceCap.toUint256(), newValue: priceCapsUpdate[i].priceCap, - lastUpdated: _timelocks[oracle].priceCapLastUpdated, - riskConfig: _riskConfig.priceCapStable, + lastUpdated: _timelocks[bytes20(oracle)].priceCapLastUpdated, + riskConfig: _riskConfig.priceCapConfig.priceCapStable, isChangeRelative: true }) ); @@ -398,11 +395,11 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = capsUpdate[i].asset; if (capsUpdate[i].supplyCap != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].supplyCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].supplyCapLastUpdated = uint40(block.timestamp); } if (capsUpdate[i].borrowCap != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].borrowCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].borrowCapLastUpdated = uint40(block.timestamp); } } @@ -420,19 +417,19 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = ratesUpdate[i].asset; if (ratesUpdate[i].params.optimalUsageRatio != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].optimalUsageRatioLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].optimalUsageRatioLastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.baseVariableBorrowRate != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].baseVariableRateLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].baseVariableRateLastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.variableRateSlope1 != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].variableRateSlope1LastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].variableRateSlope1LastUpdated = uint40(block.timestamp); } if (ratesUpdate[i].params.variableRateSlope2 != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].variableRateSlope2LastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].variableRateSlope2LastUpdated = uint40(block.timestamp); } } @@ -450,19 +447,19 @@ contract RiskSteward is Ownable, IRiskSteward { address asset = collateralUpdates[i].asset; if (collateralUpdates[i].ltv != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].ltvLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].ltvLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].liqThreshold != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].liquidationThresholdLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].liquidationThresholdLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].liqBonus != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].liquidationBonusLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].liquidationBonusLastUpdated = uint40(block.timestamp); } if (collateralUpdates[i].debtCeiling != EngineFlags.KEEP_CURRENT) { - _timelocks[asset].debtCeilingLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(asset)].debtCeilingLastUpdated = uint40(block.timestamp); } } @@ -479,7 +476,7 @@ contract RiskSteward is Ownable, IRiskSteward { for (uint256 i = 0; i < priceCapsUpdate.length; i++) { address oracle = priceCapsUpdate[i].oracle; - _timelocks[oracle].priceCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(oracle)].priceCapLastUpdated = uint40(block.timestamp); IPriceCapAdapter(oracle).setCapParameters(priceCapsUpdate[i].priceCapUpdateParams); @@ -495,7 +492,7 @@ contract RiskSteward is Ownable, IRiskSteward { for (uint256 i = 0; i < priceCapsUpdate.length; i++) { address oracle = priceCapsUpdate[i].oracle; - _timelocks[oracle].priceCapLastUpdated = uint40(block.timestamp); + _timelocks[bytes20(oracle)].priceCapLastUpdated = uint40(block.timestamp); IPriceCapAdapterStable(oracle).setPriceCap(priceCapsUpdate[i].priceCap.toInt256()); } @@ -521,7 +518,7 @@ contract RiskSteward is Ownable, IRiskSteward { uint256 variableRateSlope2 ) { - address rateStrategyAddress = POOL_DATA_PROVIDER.getInterestRateStrategyAddress(asset); + address rateStrategyAddress = POOL.getReserveData(asset).interestRateStrategyAddress; IDefaultInterestRateStrategyV2.InterestRateData memory interestRateData = IDefaultInterestRateStrategyV2(rateStrategyAddress) .getInterestRateDataBps(asset); diff --git a/src/interfaces/IRiskSteward.sol b/src/interfaces/IRiskSteward.sol index d233e3b..447c327 100644 --- a/src/interfaces/IRiskSteward.sol +++ b/src/interfaces/IRiskSteward.sol @@ -1,7 +1,7 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -import {IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {IPool} from 'aave-address-book/AaveV3.sol'; import {IAaveV3ConfigEngine as IEngine} from 'aave-v3-origin/src/contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol'; import {IPriceCapAdapter} from 'aave-capo/interfaces/IPriceCapAdapter.sol'; @@ -78,17 +78,17 @@ interface IRiskSteward { * @notice Struct storing the last update by the steward of each risk param */ struct Debounce { - uint40 supplyCapLastUpdated; - uint40 borrowCapLastUpdated; uint40 ltvLastUpdated; uint40 liquidationBonusLastUpdated; uint40 liquidationThresholdLastUpdated; - uint40 debtCeilingLastUpdated; + uint40 optimalUsageRatioLastUpdated; uint40 baseVariableRateLastUpdated; uint40 variableRateSlope1LastUpdated; uint40 variableRateSlope2LastUpdated; - uint40 optimalUsageRatioLastUpdated; + uint40 debtCeilingLastUpdated; uint40 priceCapLastUpdated; + uint40 supplyCapLastUpdated; + uint40 borrowCapLastUpdated; } /** @@ -119,16 +119,44 @@ interface IRiskSteward { * @notice Struct storing the risk configuration for all the risk param */ struct Config { + CollateralConfig collateralConfig; + RateConfig rateConfig; + CapConfig capConfig; + PriceCapConfig priceCapConfig; + } + + /** + * @notice Struct storing the risk configuration for collateral side param + */ + struct CollateralConfig { RiskParamConfig ltv; RiskParamConfig liquidationThreshold; RiskParamConfig liquidationBonus; - RiskParamConfig supplyCap; - RiskParamConfig borrowCap; RiskParamConfig debtCeiling; + } + + /** + * @notice Struct storing the risk configuration for rate param + */ + struct RateConfig { RiskParamConfig baseVariableBorrowRate; RiskParamConfig variableRateSlope1; RiskParamConfig variableRateSlope2; RiskParamConfig optimalUsageRatio; + } + + /** + * @notice Struct storing the risk configuration for cap param + */ + struct CapConfig { + RiskParamConfig supplyCap; + RiskParamConfig borrowCap; + } + + /** + * @notice Struct storing the risk configuration for price cap param + */ + struct PriceCapConfig { RiskParamConfig priceCapLst; RiskParamConfig priceCapStable; } @@ -155,9 +183,9 @@ interface IRiskSteward { function CONFIG_ENGINE() external view returns (IEngine); /** - * @notice The pool data provider of the POOL the steward controls + * @notice The aave pool of the instance steward controls */ - function POOL_DATA_PROVIDER() external view returns (IPoolDataProvider); + function POOL() external view returns (IPool); /** * @notice The safe controlling the steward @@ -221,7 +249,8 @@ interface IRiskSteward { /** * @notice Returns the timelock for a specific asset i.e the last updated timestamp * @param asset for which to fetch the timelock - * @return struct containing the latest updated timestamps of all the risk params by the steward + * @return struct containing the latest updated timestamps of all the risk params by the steward except eMode + * @dev the emode timelock params of the struct returned will be unused */ function getTimelock(address asset) external view returns (Debounce memory); diff --git a/tests/AaveStewardsInjectorCaps.t.sol b/tests/AaveStewardsInjectorCaps.t.sol index a2a273b..6ec912e 100644 --- a/tests/AaveStewardsInjectorCaps.t.sol +++ b/tests/AaveStewardsInjectorCaps.t.sol @@ -18,20 +18,9 @@ contract AaveStewardsInjectorCaps_Test is AaveStewardsInjectorBaseTest { minDelay: 3 days, maxPercentChange: 100_00 }); - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); + IRiskSteward.Config memory riskConfig; + riskConfig.capConfig.supplyCap = defaultRiskParamConfig; + riskConfig.capConfig.borrowCap = defaultRiskParamConfig; // setup risk oracle vm.startPrank(_riskOracleOwner); @@ -61,9 +50,10 @@ contract AaveStewardsInjectorCaps_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - contracts.protocolDataProvider, - IEngine(report.configEngine), + address(contracts.poolProxy), + report.configEngine, address(_stewardInjector), + address(this), riskConfig ); vm.assertEq(computedRiskStewardAddress, address(_riskSteward)); diff --git a/tests/AaveStewardsInjectorRates.t.sol b/tests/AaveStewardsInjectorRates.t.sol index dd6e921..e935e7e 100644 --- a/tests/AaveStewardsInjectorRates.t.sol +++ b/tests/AaveStewardsInjectorRates.t.sol @@ -12,20 +12,11 @@ contract AaveStewardsInjectorRates_Test is AaveStewardsInjectorBaseTest { minDelay: 3 days, maxPercentChange: 5_00 // 5% }); - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); + IRiskSteward.Config memory riskConfig; + riskConfig.rateConfig.baseVariableBorrowRate = defaultRiskParamConfig; + riskConfig.rateConfig.variableRateSlope1 = defaultRiskParamConfig; + riskConfig.rateConfig.variableRateSlope2 = defaultRiskParamConfig; + riskConfig.rateConfig.optimalUsageRatio = defaultRiskParamConfig; // setup risk oracle vm.startPrank(_riskOracleOwner); @@ -54,9 +45,10 @@ contract AaveStewardsInjectorRates_Test is AaveStewardsInjectorBaseTest { // setup risk steward _riskSteward = new RiskSteward( - contracts.protocolDataProvider, - IEngine(report.configEngine), + address(contracts.poolProxy), + report.configEngine, address(_stewardInjector), + address(this), riskConfig ); diff --git a/tests/EdgeRiskStewardCaps.t.sol b/tests/EdgeRiskStewardCaps.t.sol index 52458be..818a6e7 100644 --- a/tests/EdgeRiskStewardCaps.t.sol +++ b/tests/EdgeRiskStewardCaps.t.sol @@ -9,37 +9,22 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { function setUp() public override { super.setUp(); - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new EdgeRiskStewardCaps( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Rates Tests ----------------------------- */ function test_updateRates() public override { - ( - uint256 beforeOptimalUsageRatio, - uint256 beforeBaseVariableBorrowRate, - uint256 beforeVariableRateSlope1, - uint256 beforeVariableRateSlope2 - ) = _getInterestRatesForAsset(AaveV3EthereumAssets.WETH_UNDERLYING); - IEngine.RateStrategyUpdate[] memory rateUpdates = new IEngine.RateStrategyUpdate[](1); - rateUpdates[0] = IEngine.RateStrategyUpdate({ - asset: AaveV3EthereumAssets.WETH_UNDERLYING, - params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -61,24 +46,7 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { /* ----------------------------- Collateral Tests ----------------------------- */ function test_updateCollateralSide() public override { - (, uint256 ltvBefore, uint256 ltBefore, uint256 lbBefore, , , , , , ) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveConfigurationData(AaveV3EthereumAssets.UNI_UNDERLYING); - - // as the definition is with 2 decimals, and config engine does not take the decimals into account, so we divide by 100. - uint256 debtCeilingBefore = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getDebtCeiling( - AaveV3EthereumAssets.UNI_UNDERLYING - ) / 100; - IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); - collateralUpdates[0] = IEngine.CollateralUpdate({ - asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase - liqProtocolFee: EngineFlags.KEEP_CURRENT - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -107,14 +75,6 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { IRiskSteward.PriceCapLstUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapLstUpdate[]( 1 ); - priceCapUpdates[0] = IRiskSteward.PriceCapLstUpdate({ - oracle: AaveV3EthereumAssets.wstETH_ORACLE, - priceCapUpdateParams: IPriceCapAdapter.PriceCapUpdateParams({ - snapshotTimestamp: uint48(block.timestamp - 2), - snapshotRatio: 1.1e18, - maxYearlyRatioGrowthPercent: 9_68 - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -127,11 +87,6 @@ contract EdgeRiskStewardCaps_Test is RiskSteward_Test { IRiskSteward.PriceCapStableUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapStableUpdate[](1); - priceCapUpdates[0] = IRiskSteward.PriceCapStableUpdate({ - oracle: AaveV3EthereumAssets.USDT_ORACLE, - priceCap: 1060000 - }); - vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); steward.updateStablePriceCaps(priceCapUpdates); diff --git a/tests/EdgeRiskStewardRates.t.sol b/tests/EdgeRiskStewardRates.t.sol index dc69453..e470fb1 100644 --- a/tests/EdgeRiskStewardRates.t.sol +++ b/tests/EdgeRiskStewardRates.t.sol @@ -9,30 +9,22 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { function setUp() public override { super.setUp(); - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new EdgeRiskStewardRates( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Caps Tests ----------------------------- */ function test_updateCaps() public override { - (uint256 daiBorrowCapBefore, uint256 daiSupplyCapBefore) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveCaps(AaveV3EthereumAssets.DAI_UNDERLYING); - IEngine.CapsUpdate[] memory capUpdates = new IEngine.CapsUpdate[](1); - capUpdates[0] = IEngine.CapsUpdate( - AaveV3EthereumAssets.DAI_UNDERLYING, - (daiSupplyCapBefore * 110) / 100, // 10% relative increase - (daiBorrowCapBefore * 110) / 100 // 10% relative increase - ); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -56,24 +48,7 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { /* ----------------------------- Collateral Tests ----------------------------- */ function test_updateCollateralSide() public override { - (, uint256 ltvBefore, uint256 ltBefore, uint256 lbBefore, , , , , , ) = AaveV3Ethereum - .AAVE_PROTOCOL_DATA_PROVIDER - .getReserveConfigurationData(AaveV3EthereumAssets.UNI_UNDERLYING); - - // as the definition is with 2 decimals, and config engine does not take the decimals into account, so we divide by 100. - uint256 debtCeilingBefore = AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER.getDebtCeiling( - AaveV3EthereumAssets.UNI_UNDERLYING - ) / 100; - IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); - collateralUpdates[0] = IEngine.CollateralUpdate({ - asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase - liqProtocolFee: EngineFlags.KEEP_CURRENT - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -102,14 +77,6 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { IRiskSteward.PriceCapLstUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapLstUpdate[]( 1 ); - priceCapUpdates[0] = IRiskSteward.PriceCapLstUpdate({ - oracle: AaveV3EthereumAssets.wstETH_ORACLE, - priceCapUpdateParams: IPriceCapAdapter.PriceCapUpdateParams({ - snapshotTimestamp: uint48(block.timestamp - 2), - snapshotRatio: 1.1e18, - maxYearlyRatioGrowthPercent: 9_68 - }) - }); vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); @@ -122,11 +89,6 @@ contract EdgeRiskStewardRates_Test is RiskSteward_Test { IRiskSteward.PriceCapStableUpdate[] memory priceCapUpdates = new IRiskSteward.PriceCapStableUpdate[](1); - priceCapUpdates[0] = IRiskSteward.PriceCapStableUpdate({ - oracle: AaveV3EthereumAssets.USDT_ORACLE, - priceCap: 1060000 - }); - vm.startPrank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotAllowed.selector); steward.updateStablePriceCaps(priceCapUpdates); diff --git a/tests/RiskSteward.t.sol b/tests/RiskSteward.t.sol index 5994c16..c44051a 100644 --- a/tests/RiskSteward.t.sol +++ b/tests/RiskSteward.t.sol @@ -2,7 +2,8 @@ pragma solidity ^0.8.0; import 'forge-std/Test.sol'; -import {IACLManager, IPoolConfigurator, IPoolDataProvider} from 'aave-address-book/AaveV3.sol'; +import {ReserveConfiguration, DataTypes} from 'aave-v3-origin/src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; +import {IACLManager, IPoolConfigurator} from 'aave-address-book/AaveV3.sol'; import {IDefaultInterestRateStrategyV2} from 'aave-v3-origin/src/contracts/interfaces/IDefaultInterestRateStrategyV2.sol'; import {GovernanceV3Ethereum} from 'aave-address-book/GovernanceV3Ethereum.sol'; import {AaveV3Ethereum, AaveV3EthereumAssets} from 'aave-address-book/AaveV3Ethereum.sol'; @@ -11,56 +12,30 @@ import {IAaveV3ConfigEngine as IEngine} from 'aave-v3-origin/src/contracts/exten import {GovV3Helpers} from 'aave-helpers/src/GovV3Helpers.sol'; import {ConfigEngineDeployer} from './utils/ConfigEngineDeployer.sol'; import {Ownable} from 'openzeppelin-contracts/contracts/access/Ownable.sol'; +import {DeployRiskStewards} from '../scripts/deploy/DeployStewards.s.sol'; contract RiskSteward_Test is Test { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + address public constant riskCouncil = address(42); IRiskSteward public steward; - address public configEngine; - IRiskSteward.RiskParamConfig public defaultRiskParamConfig; IRiskSteward.Config public riskConfig; - event AddressRestricted(address indexed contractAddress, bool indexed isRestricted); - - event RiskConfigSet(IRiskSteward.Config indexed riskConfig); - function setUp() public virtual { vm.createSelectFork(vm.rpcUrl('mainnet'), 21974363); - configEngine = AaveV3Ethereum.CONFIG_ENGINE; + riskConfig = DeployRiskStewards._getRiskConfig(); - defaultRiskParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, - maxPercentChange: 10_00 // 10% - }); - IRiskSteward.RiskParamConfig memory liquidationBonusParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, - maxPercentChange: 2_00 // 2% - }); - - riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: liquidationBonusParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); - - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), + address(AaveV3Ethereum.POOL), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); } /* ----------------------------- Caps Tests ----------------------------- */ @@ -93,7 +68,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.borrowCapLastUpdated, block.timestamp); // after min time passed test caps decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); (daiBorrowCapBefore, daiSupplyCapBefore) = AaveV3Ethereum .AAVE_PROTOCOL_DATA_PROVIDER .getReserveCaps(AaveV3EthereumAssets.DAI_UNDERLYING); @@ -122,19 +97,31 @@ contract RiskSteward_Test is Test { IEngine.CapsUpdate[] memory capUpdates = new IEngine.CapsUpdate[](1); capUpdates[0] = IEngine.CapsUpdate( AaveV3EthereumAssets.DAI_UNDERLYING, - (daiSupplyCapBefore * 120) / 100, // 20% relative increase (current maxChangePercent configured is 10%) - (daiBorrowCapBefore * 120) / 100 // 20% relative increase + (daiSupplyCapBefore * 210) / 100, // 110% relative increase (current maxChangePercent configured is 100%) + (daiBorrowCapBefore * 210) / 100 // 110% relative increase ); - vm.startPrank(riskCouncil); + vm.prank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); steward.updateCaps(capUpdates); + IRiskSteward.RiskParamConfig memory newConfig = IRiskSteward.RiskParamConfig({ + minDelay: 3 days, + maxPercentChange: 10_00 + }); + IRiskSteward.Config memory config = riskConfig; + config.capConfig.supplyCap = newConfig; + config.capConfig.borrowCap = newConfig; + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); + steward.setRiskConfig(config); + capUpdates[0] = IEngine.CapsUpdate( AaveV3EthereumAssets.DAI_UNDERLYING, (daiSupplyCapBefore * 80) / 100, // 20% relative decrease (daiBorrowCapBefore * 80) / 100 // 20% relative decrease ); + vm.prank(riskCouncil); vm.expectRevert(IRiskSteward.UpdateNotInRange.selector); steward.updateCaps(capUpdates); @@ -248,12 +235,12 @@ contract RiskSteward_Test is Test { function test_updateCaps_toValueZeroNotAllowed() public virtual { // set risk config to allow 100% cap change to 0 IRiskSteward.RiskParamConfig memory capsParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, + minDelay: 3 days, maxPercentChange: 100_00 // 100% relative change }); - riskConfig.supplyCap = capsParamConfig; - riskConfig.borrowCap = capsParamConfig; + riskConfig.capConfig.supplyCap = capsParamConfig; + riskConfig.capConfig.borrowCap = capsParamConfig; vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(riskConfig); @@ -284,10 +271,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase + optimalUsageRatio: beforeOptimalUsageRatio + 3_00, // 3% absolute increase + baseVariableBorrowRate: beforeBaseVariableBorrowRate + 1_00, // 1% absolute increase + variableRateSlope1: beforeVariableRateSlope1 + 1_00, // 1% absolute increase + variableRateSlope2: beforeVariableRateSlope2 + 20_00 // 20% absolute increase }) }); @@ -315,7 +302,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.variableRateSlope2LastUpdated, block.timestamp); // after min time passed test rates decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); ( beforeOptimalUsageRatio, @@ -327,10 +314,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio - 10_00, // 10% decrease + optimalUsageRatio: beforeOptimalUsageRatio - 3_00, // 3% decrease baseVariableBorrowRate: beforeBaseVariableBorrowRate - 1_00, // 1% decrease variableRateSlope1: beforeVariableRateSlope1 - 1_00, // 1% decrease - variableRateSlope2: beforeVariableRateSlope2 - 10_00 // 10% absolute decrease + variableRateSlope2: beforeVariableRateSlope2 - 20_00 // 20% absolute decrease }) }); steward.updateRates(rateUpdates); @@ -392,10 +379,10 @@ contract RiskSteward_Test is Test { rateUpdates[0] = IEngine.RateStrategyUpdate({ asset: AaveV3EthereumAssets.WETH_UNDERLYING, params: IEngine.InterestRateInputData({ - optimalUsageRatio: beforeOptimalUsageRatio + 5_00, // 5% absolute increase - baseVariableBorrowRate: beforeBaseVariableBorrowRate + 10_00, // 10% absolute increase - variableRateSlope1: beforeVariableRateSlope1 + 10_00, // 10% absolute increase - variableRateSlope2: beforeVariableRateSlope2 + 10_00 // 10% absolute increase + optimalUsageRatio: beforeOptimalUsageRatio + 3_00, // 3% absolute increase + baseVariableBorrowRate: beforeBaseVariableBorrowRate + 1_00, // 1% absolute increase + variableRateSlope1: beforeVariableRateSlope1 + 1_00, // 1% absolute increase + variableRateSlope2: beforeVariableRateSlope2 + 20_00 // 20% absolute increase }) }); @@ -548,10 +535,10 @@ contract RiskSteward_Test is Test { IEngine.CollateralUpdate[] memory collateralUpdates = new IEngine.CollateralUpdate[](1); collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore + 10_00, // 10% absolute increase - liqThreshold: ltBefore + 5_00, // 5% absolute increase - liqBonus: (lbBefore - 100_00) + 2_00, // 2% absolute increase - debtCeiling: (debtCeilingBefore * 110) / 100, // 10% relative increase + ltv: ltvBefore + 50, // 0.5% absolute increase + liqThreshold: ltBefore + 50, // 0.5% absolute increase + liqBonus: (lbBefore - 100_00) + 50, // 0.5% absolute increase + debtCeiling: (debtCeilingBefore * 120) / 100, // 20% relative increase liqProtocolFee: EngineFlags.KEEP_CURRENT }); @@ -581,7 +568,7 @@ contract RiskSteward_Test is Test { assertEq(lastUpdated.debtCeilingLastUpdated, block.timestamp); // after min time passed test collateral update decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); (, ltvBefore, ltBefore, lbBefore, , , , , , ) = AaveV3Ethereum .AAVE_PROTOCOL_DATA_PROVIDER @@ -595,10 +582,10 @@ contract RiskSteward_Test is Test { collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, - ltv: ltvBefore - 10_00, // 10% absolute decrease - liqThreshold: ltBefore - 10_00, // 10% absolute decrease - liqBonus: (lbBefore - 100_00) - 2_00, // 2% absolute decrease - debtCeiling: (debtCeilingBefore * 90) / 100, // 10% relative decrease + ltv: ltvBefore - 50, // 0.5% absolute decrease + liqThreshold: ltBefore - 50, // 0.5% absolute decrease + liqBonus: (lbBefore - 100_00) - 50, // 0.5% absolute decrease + debtCeiling: (debtCeilingBefore * 80) / 100, // 20% relative decrease liqProtocolFee: EngineFlags.KEEP_CURRENT }); steward.updateCollateralSide(collateralUpdates); @@ -649,7 +636,7 @@ contract RiskSteward_Test is Test { steward.updateCollateralSide(collateralUpdates); // after min time passed test collateral update decrease - vm.warp(block.timestamp + 5 days + 1); + vm.warp(block.timestamp + 3 days + 1); collateralUpdates[0] = IEngine.CollateralUpdate({ asset: AaveV3EthereumAssets.UNI_UNDERLYING, @@ -763,14 +750,14 @@ contract RiskSteward_Test is Test { function test_updateCollateralSide_toValueZeroNotAllowed() public virtual { // set risk config to allow 100% collateral param change to 0 IRiskSteward.RiskParamConfig memory collateralParamConfig = IRiskSteward.RiskParamConfig({ - minDelay: 5 days, + minDelay: 3 days, maxPercentChange: 100_00 // 100% relative change }); - riskConfig.ltv = collateralParamConfig; - riskConfig.liquidationThreshold = collateralParamConfig; - riskConfig.liquidationBonus = collateralParamConfig; - riskConfig.debtCeiling = collateralParamConfig; + riskConfig.collateralConfig.ltv = collateralParamConfig; + riskConfig.collateralConfig.liquidationThreshold = collateralParamConfig; + riskConfig.collateralConfig.liquidationBonus = collateralParamConfig; + riskConfig.collateralConfig.debtCeiling = collateralParamConfig; vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(riskConfig); @@ -906,7 +893,7 @@ contract RiskSteward_Test is Test { steward.updateCollateralSide(collateralUpdates); vm.expectRevert(IRiskSteward.InvalidCaller.selector); - steward.updateRates(rateStrategyUpdate); + steward.updateCollateralSide(collateralUpdates); vm.expectRevert(abi.encodeWithSelector(Ownable.OwnableUnauthorizedAccount.selector, caller)); steward.setRiskConfig(riskConfig); @@ -919,7 +906,7 @@ contract RiskSteward_Test is Test { function test_assetRestricted() public { vm.expectEmit(); - emit AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); + emit IRiskSteward.AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, true); @@ -927,7 +914,7 @@ contract RiskSteward_Test is Test { assertTrue(steward.isAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING)); vm.expectEmit(); - emit AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); + emit IRiskSteward.AddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setAddressRestricted(AaveV3EthereumAssets.GHO_UNDERLYING, false); @@ -942,22 +929,30 @@ contract RiskSteward_Test is Test { }); IRiskSteward.Config memory initialRiskConfig = IRiskSteward.Config({ - ltv: newRiskParamConfig, - liquidationThreshold: newRiskParamConfig, - liquidationBonus: newRiskParamConfig, - supplyCap: newRiskParamConfig, - borrowCap: newRiskParamConfig, - debtCeiling: newRiskParamConfig, - baseVariableBorrowRate: newRiskParamConfig, - variableRateSlope1: newRiskParamConfig, - variableRateSlope2: newRiskParamConfig, - optimalUsageRatio: newRiskParamConfig, - priceCapLst: newRiskParamConfig, - priceCapStable: newRiskParamConfig + collateralConfig: IRiskSteward.CollateralConfig({ + ltv: newRiskParamConfig, + liquidationThreshold: newRiskParamConfig, + liquidationBonus: newRiskParamConfig, + debtCeiling: newRiskParamConfig + }), + rateConfig: IRiskSteward.RateConfig({ + baseVariableBorrowRate: newRiskParamConfig, + variableRateSlope1: newRiskParamConfig, + variableRateSlope2: newRiskParamConfig, + optimalUsageRatio: newRiskParamConfig + }), + capConfig: IRiskSteward.CapConfig({ + supplyCap: newRiskParamConfig, + borrowCap: newRiskParamConfig + }), + priceCapConfig: IRiskSteward.PriceCapConfig({ + priceCapLst: newRiskParamConfig, + priceCapStable: newRiskParamConfig + }) }); vm.expectEmit(); - emit RiskConfigSet(initialRiskConfig); + emit IRiskSteward.RiskConfigSet(initialRiskConfig); vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward.setRiskConfig(initialRiskConfig); @@ -965,117 +960,85 @@ contract RiskSteward_Test is Test { _validateRiskConfig(initialRiskConfig, steward.getRiskConfig()); } - function test_constructor() public { - riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); - - steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(configEngine), - riskCouncil, - riskConfig - ); - - assertEq( - address(steward.POOL_DATA_PROVIDER()), - address(AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER) - ); - assertEq(address(steward.CONFIG_ENGINE()), address(IEngine(configEngine))); - assertEq(steward.RISK_COUNCIL(), riskCouncil); - _validateRiskConfig(riskConfig, steward.getRiskConfig()); - } - function _validateRiskConfig( IRiskSteward.Config memory initialRiskConfig, IRiskSteward.Config memory updatedRiskConfig ) internal pure { - assertEq(initialRiskConfig.ltv.minDelay, updatedRiskConfig.ltv.minDelay); - assertEq(initialRiskConfig.ltv.maxPercentChange, updatedRiskConfig.ltv.maxPercentChange); + assertEq(initialRiskConfig.collateralConfig.ltv.minDelay, updatedRiskConfig.collateralConfig.ltv.minDelay); + assertEq(initialRiskConfig.collateralConfig.ltv.maxPercentChange, updatedRiskConfig.collateralConfig.ltv.maxPercentChange); assertEq( - initialRiskConfig.liquidationThreshold.minDelay, - updatedRiskConfig.liquidationThreshold.minDelay + initialRiskConfig.collateralConfig.liquidationThreshold.minDelay, + updatedRiskConfig.collateralConfig.liquidationThreshold.minDelay ); assertEq( - initialRiskConfig.liquidationThreshold.maxPercentChange, - updatedRiskConfig.liquidationThreshold.maxPercentChange + initialRiskConfig.collateralConfig.liquidationThreshold.maxPercentChange, + updatedRiskConfig.collateralConfig.liquidationThreshold.maxPercentChange ); assertEq( - initialRiskConfig.liquidationBonus.minDelay, - updatedRiskConfig.liquidationBonus.minDelay + initialRiskConfig.collateralConfig.liquidationBonus.minDelay, + updatedRiskConfig.collateralConfig.liquidationBonus.minDelay ); assertEq( - initialRiskConfig.liquidationBonus.maxPercentChange, - updatedRiskConfig.liquidationBonus.maxPercentChange + initialRiskConfig.collateralConfig.liquidationBonus.maxPercentChange, + updatedRiskConfig.collateralConfig.liquidationBonus.maxPercentChange ); - assertEq(initialRiskConfig.supplyCap.minDelay, updatedRiskConfig.supplyCap.minDelay); + assertEq(initialRiskConfig.capConfig.supplyCap.minDelay, updatedRiskConfig.capConfig.supplyCap.minDelay); assertEq( - initialRiskConfig.supplyCap.maxPercentChange, - updatedRiskConfig.supplyCap.maxPercentChange + initialRiskConfig.capConfig.supplyCap.maxPercentChange, + updatedRiskConfig.capConfig.supplyCap.maxPercentChange ); - assertEq(initialRiskConfig.borrowCap.minDelay, updatedRiskConfig.borrowCap.minDelay); + assertEq(initialRiskConfig.capConfig.borrowCap.minDelay, updatedRiskConfig.capConfig.borrowCap.minDelay); assertEq( - initialRiskConfig.borrowCap.maxPercentChange, - updatedRiskConfig.borrowCap.maxPercentChange + initialRiskConfig.capConfig.borrowCap.maxPercentChange, + updatedRiskConfig.capConfig.borrowCap.maxPercentChange ); - assertEq(initialRiskConfig.debtCeiling.minDelay, updatedRiskConfig.debtCeiling.minDelay); + assertEq(initialRiskConfig.collateralConfig.debtCeiling.minDelay, updatedRiskConfig.collateralConfig.debtCeiling.minDelay); assertEq( - initialRiskConfig.debtCeiling.maxPercentChange, - updatedRiskConfig.debtCeiling.maxPercentChange + initialRiskConfig.collateralConfig.debtCeiling.maxPercentChange, + updatedRiskConfig.collateralConfig.debtCeiling.maxPercentChange ); assertEq( - initialRiskConfig.baseVariableBorrowRate.minDelay, - updatedRiskConfig.baseVariableBorrowRate.minDelay + initialRiskConfig.rateConfig.baseVariableBorrowRate.minDelay, + updatedRiskConfig.rateConfig.baseVariableBorrowRate.minDelay ); assertEq( - initialRiskConfig.baseVariableBorrowRate.maxPercentChange, - updatedRiskConfig.baseVariableBorrowRate.maxPercentChange + initialRiskConfig.rateConfig.baseVariableBorrowRate.maxPercentChange, + updatedRiskConfig.rateConfig.baseVariableBorrowRate.maxPercentChange ); assertEq( - initialRiskConfig.variableRateSlope1.minDelay, - updatedRiskConfig.variableRateSlope1.minDelay + initialRiskConfig.rateConfig.variableRateSlope1.minDelay, + updatedRiskConfig.rateConfig.variableRateSlope1.minDelay ); assertEq( - initialRiskConfig.variableRateSlope1.maxPercentChange, - updatedRiskConfig.variableRateSlope1.maxPercentChange + initialRiskConfig.rateConfig.variableRateSlope1.maxPercentChange, + updatedRiskConfig.rateConfig.variableRateSlope1.maxPercentChange ); assertEq( - initialRiskConfig.variableRateSlope2.minDelay, - updatedRiskConfig.variableRateSlope2.minDelay + initialRiskConfig.rateConfig.variableRateSlope2.minDelay, + updatedRiskConfig.rateConfig.variableRateSlope2.minDelay ); assertEq( - initialRiskConfig.variableRateSlope2.maxPercentChange, - updatedRiskConfig.variableRateSlope2.maxPercentChange + initialRiskConfig.rateConfig.variableRateSlope2.maxPercentChange, + updatedRiskConfig.rateConfig.variableRateSlope2.maxPercentChange ); assertEq( - initialRiskConfig.optimalUsageRatio.minDelay, - updatedRiskConfig.optimalUsageRatio.minDelay + initialRiskConfig.rateConfig.optimalUsageRatio.minDelay, + updatedRiskConfig.rateConfig.optimalUsageRatio.minDelay ); assertEq( - initialRiskConfig.optimalUsageRatio.maxPercentChange, - updatedRiskConfig.optimalUsageRatio.maxPercentChange + initialRiskConfig.rateConfig.optimalUsageRatio.maxPercentChange, + updatedRiskConfig.rateConfig.optimalUsageRatio.maxPercentChange ); assertEq( - initialRiskConfig.priceCapLst.maxPercentChange, - updatedRiskConfig.priceCapLst.maxPercentChange + initialRiskConfig.priceCapConfig.priceCapLst.maxPercentChange, + updatedRiskConfig.priceCapConfig.priceCapLst.maxPercentChange ); - assertEq(initialRiskConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapLst.minDelay); + assertEq(initialRiskConfig.priceCapConfig.priceCapLst.minDelay, updatedRiskConfig.priceCapConfig.priceCapLst.minDelay); assertEq( - initialRiskConfig.priceCapStable.maxPercentChange, - updatedRiskConfig.priceCapStable.maxPercentChange + initialRiskConfig.priceCapConfig.priceCapStable.maxPercentChange, + updatedRiskConfig.priceCapConfig.priceCapStable.maxPercentChange ); - assertEq(initialRiskConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapStable.minDelay); + assertEq(initialRiskConfig.priceCapConfig.priceCapStable.minDelay, updatedRiskConfig.priceCapConfig.priceCapStable.minDelay); } function _getInterestRatesForAsset( diff --git a/tests/RiskStewardCapo.t.sol b/tests/RiskStewardCapo.t.sol index 0506ea5..47b69a0 100644 --- a/tests/RiskStewardCapo.t.sol +++ b/tests/RiskStewardCapo.t.sol @@ -32,31 +32,20 @@ contract RiskSteward_Capo_Test is Test { minDelay: 5 days, maxPercentChange: 10_00 // 10% }); + IRiskSteward.Config memory riskConfig; + riskConfig.priceCapConfig.priceCapLst = defaultRiskParamConfig; + riskConfig.priceCapConfig.priceCapStable = defaultRiskParamConfig; - IRiskSteward.Config memory riskConfig = IRiskSteward.Config({ - ltv: defaultRiskParamConfig, - liquidationThreshold: defaultRiskParamConfig, - liquidationBonus: defaultRiskParamConfig, - supplyCap: defaultRiskParamConfig, - borrowCap: defaultRiskParamConfig, - debtCeiling: defaultRiskParamConfig, - baseVariableBorrowRate: defaultRiskParamConfig, - variableRateSlope1: defaultRiskParamConfig, - variableRateSlope2: defaultRiskParamConfig, - optimalUsageRatio: defaultRiskParamConfig, - priceCapLst: defaultRiskParamConfig, - priceCapStable: defaultRiskParamConfig - }); - - vm.startPrank(GovernanceV3Ethereum.EXECUTOR_LVL_1); steward = new RiskSteward( - AaveV3Ethereum.AAVE_PROTOCOL_DATA_PROVIDER, - IEngine(AaveV3Ethereum.CONFIG_ENGINE), + address(AaveV3Ethereum.POOL), + AaveV3Ethereum.CONFIG_ENGINE, riskCouncil, + GovernanceV3Ethereum.EXECUTOR_LVL_1, riskConfig ); + + vm.prank(GovernanceV3Ethereum.EXECUTOR_LVL_1); AaveV3Ethereum.ACL_MANAGER.addRiskAdmin(address(steward)); - vm.stopPrank(); currentRatio = IPriceCapAdapter(AaveV3EthereumAssets.wstETH_ORACLE) .getRatio()