From ffd9c3b1dad4f4bd4500f86b6dbb9ae34a1b3aeb Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 21 Aug 2024 09:06:49 +0000 Subject: [PATCH 1/4] feat: add config.incentivesProxy to reuse RewardsController proxy across instances in same EVM network --- .../procedures/AaveV3SetupProcedure.sol | 79 ++++++++++++------- .../interfaces/IMarketReportTypes.sol | 1 + .../batches/AaveV3PeripheryBatch.sol | 11 ++- tests/AaveV3BatchDeployment.t.sol | 23 +++++- tests/AaveV3BatchTests.t.sol | 5 +- tests/DeploymentsGasLimits.t.sol | 3 +- tests/utils/BatchTestProcedures.sol | 26 ++++-- 7 files changed, 102 insertions(+), 46 deletions(-) diff --git a/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol b/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol index 30aeb08d..88b6f8d1 100644 --- a/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol +++ b/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol @@ -12,6 +12,18 @@ import {IEmissionManager} from 'aave-v3-periphery/contracts/rewards/interfaces/I import {IRewardsController} from 'aave-v3-periphery/contracts/rewards/interfaces/IRewardsController.sol'; contract AaveV3SetupProcedure { + struct AddressProviderInput { + InitialReport initialReport; + address poolImplementation; + address poolConfiguratorImplementation; + address protocolDataProvider; + address poolAdmin; + address aaveOracle; + address rewardsControllerProxy; + address rewardsControllerImplementation; + address priceOracleSentinel; + } + function _initialDeployment( address providerRegistry, address marketOwner, @@ -44,14 +56,17 @@ contract AaveV3SetupProcedure { _validateMarketSetup(roles); SetupReport memory report = _setupPoolAddressesProvider( - initialReport, - poolImplementation, - poolConfiguratorImplementation, - protocolDataProvider, - roles.poolAdmin, - aaveOracle, - rewardsControllerImplementation, - priceOracleSentinel + AddressProviderInput( + initialReport, + poolImplementation, + poolConfiguratorImplementation, + protocolDataProvider, + roles.poolAdmin, + aaveOracle, + config.incentivesProxy, + rewardsControllerImplementation, + priceOracleSentinel + ) ); report.aclManager = _setupACL( @@ -90,38 +105,42 @@ contract AaveV3SetupProcedure { } function _setupPoolAddressesProvider( - InitialReport memory initialReport, - address poolImplementation, - address poolConfiguratorImplementation, - address protocolDataProvider, - address poolAdmin, - address aaveOracle, - address rewardsControllerImplementation, - address priceOracleSentinel + AddressProviderInput memory input ) internal returns (SetupReport memory) { SetupReport memory report; - IPoolAddressesProvider provider = IPoolAddressesProvider(initialReport.poolAddressesProvider); - provider.setPriceOracle(aaveOracle); - provider.setPoolImpl(poolImplementation); - provider.setPoolConfiguratorImpl(poolConfiguratorImplementation); - provider.setPoolDataProvider(protocolDataProvider); + IPoolAddressesProvider provider = IPoolAddressesProvider( + input.initialReport.poolAddressesProvider + ); + provider.setPriceOracle(input.aaveOracle); + provider.setPoolImpl(input.poolImplementation); + provider.setPoolConfiguratorImpl(input.poolConfiguratorImplementation); + provider.setPoolDataProvider(input.protocolDataProvider); report.poolProxy = address(provider.getPool()); report.poolConfiguratorProxy = address(provider.getPoolConfigurator()); - if (priceOracleSentinel != address(0)) { - provider.setPriceOracleSentinel(priceOracleSentinel); + if (input.priceOracleSentinel != address(0)) { + provider.setPriceOracleSentinel(input.priceOracleSentinel); } bytes32 controllerId = keccak256('INCENTIVES_CONTROLLER'); - provider.setAddressAsProxy(controllerId, rewardsControllerImplementation); - report.rewardsControllerProxy = provider.getAddress(controllerId); - IEmissionManager emissionManager = IEmissionManager( - IRewardsController(report.rewardsControllerProxy).EMISSION_MANAGER() - ); - emissionManager.setRewardsController(report.rewardsControllerProxy); - IOwnable(address(emissionManager)).transferOwnership(poolAdmin); + if (input.rewardsControllerProxy == address(0)) { + require( + input.rewardsControllerImplementation != address(0), + 'rewardsControllerImplementation must be set' + ); + provider.setAddressAsProxy(controllerId, input.rewardsControllerImplementation); + report.rewardsControllerProxy = provider.getAddress(controllerId); + IEmissionManager emissionManager = IEmissionManager( + IRewardsController(report.rewardsControllerProxy).EMISSION_MANAGER() + ); + emissionManager.setRewardsController(report.rewardsControllerProxy); + IOwnable(address(emissionManager)).transferOwnership(input.poolAdmin); + } else { + provider.setAddress(controllerId, input.rewardsControllerProxy); + report.rewardsControllerProxy = provider.getAddress(controllerId); + } return report; } diff --git a/src/deployments/interfaces/IMarketReportTypes.sol b/src/deployments/interfaces/IMarketReportTypes.sol index df1156cb..93c83f9c 100644 --- a/src/deployments/interfaces/IMarketReportTypes.sol +++ b/src/deployments/interfaces/IMarketReportTypes.sol @@ -123,6 +123,7 @@ struct MarketConfig { address proxyAdmin; uint128 flashLoanPremiumTotal; uint128 flashLoanPremiumToProtocol; + address incentivesProxy; } struct DeployFlags { diff --git a/src/deployments/projects/aave-v3-batched/batches/AaveV3PeripheryBatch.sol b/src/deployments/projects/aave-v3-batched/batches/AaveV3PeripheryBatch.sol index 6c8c5cc7..258d0d6c 100644 --- a/src/deployments/projects/aave-v3-batched/batches/AaveV3PeripheryBatch.sol +++ b/src/deployments/projects/aave-v3-batched/batches/AaveV3PeripheryBatch.sol @@ -5,6 +5,7 @@ import {AaveV3TreasuryProcedure} from '../../../contracts/procedures/AaveV3Treas import {AaveV3OracleProcedure} from '../../../contracts/procedures/AaveV3OracleProcedure.sol'; import {AaveV3IncentiveProcedure} from '../../../contracts/procedures/AaveV3IncentiveProcedure.sol'; import {AaveV3DefaultRateStrategyProcedure} from '../../../contracts/procedures/AaveV3DefaultRateStrategyProcedure.sol'; +import {IOwnable} from 'solidity-utils/contracts/transparent-proxy/interfaces/IOwnable.sol'; import '../../../interfaces/IMarketReportTypes.sol'; contract AaveV3PeripheryBatch is @@ -30,9 +31,13 @@ contract AaveV3PeripheryBatch is _report.treasury = treasuryReport.treasury; _report.treasuryImplementation = treasuryReport.treasuryImplementation; - (_report.emissionManager, _report.rewardsControllerImplementation) = _deployIncentives( - setupBatch - ); + if (config.incentivesProxy == address(0)) { + (_report.emissionManager, _report.rewardsControllerImplementation) = _deployIncentives( + setupBatch + ); + } else { + _report.emissionManager = IRewardsController(config.incentivesProxy).getEmissionManager(); + } } function getPeripheryReport() external view returns (PeripheryReport memory) { diff --git a/tests/AaveV3BatchDeployment.t.sol b/tests/AaveV3BatchDeployment.t.sol index d5af5e2e..b6c89cc0 100644 --- a/tests/AaveV3BatchDeployment.t.sol +++ b/tests/AaveV3BatchDeployment.t.sol @@ -15,6 +15,8 @@ import {IAaveV3ConfigEngine} from 'aave-v3-periphery/contracts/v3-config-engine/ import {IPool} from 'aave-v3-core/contracts/interfaces/IPool.sol'; import {AaveV3ConfigEngine} from 'aave-v3-periphery/contracts/v3-config-engine/AaveV3ConfigEngine.sol'; import {SequencerOracle} from 'aave-v3-core/contracts/mocks/oracle/SequencerOracle.sol'; +import {RewardsController} from 'aave-v3-periphery/contracts/rewards/RewardsController.sol'; +import {EmissionManager} from 'aave-v3-periphery/contracts/rewards/EmissionManager.sol'; contract AaveV3BatchDeployment is BatchTestProcedures { address public marketOwner; @@ -49,7 +51,8 @@ contract AaveV3BatchDeployment is BatchTestProcedures { weth9, address(0), 0.0005e4, - 0.0004e4 + 0.0004e4, + address(0) ); } @@ -61,7 +64,7 @@ contract AaveV3BatchDeployment is BatchTestProcedures { flags, deployedContracts ); - checkFullReport(flags, fullReport); + checkFullReport(config, flags, fullReport); AaveV3TestListing testnetListingPayload = new AaveV3TestListing( IAaveV3ConfigEngine(fullReport.configEngine), @@ -91,7 +94,7 @@ contract AaveV3BatchDeployment is BatchTestProcedures { deployedContracts ); - checkFullReport(flags, fullReport); + checkFullReport(config, flags, fullReport); AaveV3TestListing testnetListingPayload = new AaveV3TestListing( IAaveV3ConfigEngine(fullReport.configEngine), @@ -110,6 +113,20 @@ contract AaveV3BatchDeployment is BatchTestProcedures { function testAaveV3BatchDeploy() public { checkFullReport( + config, + flags, + deployAaveV3Testnet(marketOwner, roles, config, flags, deployedContracts) + ); + } + + function testAaveV3Batch_reuseIncentivesProxy() public { + EmissionManager emissionManager = new EmissionManager(poolAdmin); + RewardsController controller = new RewardsController(address(emissionManager)); + + config.incentivesProxy = address(controller); + + checkFullReport( + config, flags, deployAaveV3Testnet(marketOwner, roles, config, flags, deployedContracts) ); diff --git a/tests/AaveV3BatchTests.t.sol b/tests/AaveV3BatchTests.t.sol index e1969fed..4cf5f0f9 100644 --- a/tests/AaveV3BatchTests.t.sol +++ b/tests/AaveV3BatchTests.t.sol @@ -68,7 +68,8 @@ contract AaveV3BatchTests is BatchTestProcedures { address(new WETH9()), address(0), 0.0005e4, - 0.0004e4 + 0.0004e4, + address(0) ); flags = DeployFlags(false); @@ -111,7 +112,7 @@ contract AaveV3BatchTests is BatchTestProcedures { deployedContracts ); vm.stopPrank(); - checkFullReport(flags, market); + checkFullReport(config, flags, market); } function test0AaveV3SetupDeployment() public { diff --git a/tests/DeploymentsGasLimits.t.sol b/tests/DeploymentsGasLimits.t.sol index 28d5d8e4..b7411c4d 100644 --- a/tests/DeploymentsGasLimits.t.sol +++ b/tests/DeploymentsGasLimits.t.sol @@ -64,7 +64,8 @@ contract DeploymentsGasLimits is BatchTestProcedures { address(new WETH9()), address(0), 0.0005e4, - 0.0004e4 + 0.0004e4, + address(0) ); flags = DeployFlags(true); diff --git a/tests/utils/BatchTestProcedures.sol b/tests/utils/BatchTestProcedures.sol index c704f4de..3f045c58 100644 --- a/tests/utils/BatchTestProcedures.sol +++ b/tests/utils/BatchTestProcedures.sol @@ -12,6 +12,7 @@ import {FfiUtils} from '../../src/deployments/contracts/utilities/FfiUtils.sol'; import {DefaultMarketInput} from '../../src/deployments/inputs/DefaultMarketInput.sol'; import {AaveV3BatchOrchestration} from '../../src/deployments/projects/aave-v3-batched/AaveV3BatchOrchestration.sol'; import {IPoolAddressesProvider} from 'aave-v3-core/contracts/interfaces/IPoolAddressesProvider.sol'; +import {IRewardsController} from 'aave-v3-periphery/contracts/rewards/interfaces/IRewardsController.sol'; import {ACLManager} from 'aave-v3-core/contracts/protocol/configuration/ACLManager.sol'; import {WETH9} from 'aave-v3-core/contracts/dependencies/weth/WETH9.sol'; import 'aave-v3-periphery/contracts/mocks/testnet-helpers/TestnetERC20.sol'; @@ -173,7 +174,7 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput ); } - function checkFullReport(DeployFlags memory flags, MarketReport memory r) internal pure { + function checkFullReport(MarketConfig memory config, DeployFlags memory flags, MarketReport memory r) internal view { assertTrue(r.poolAddressesProviderRegistry != address(0), 'r.poolAddressesProviderRegistry'); assertTrue(r.poolAddressesProvider != address(0), 'report.poolAddressesProvider'); assertTrue(r.poolProxy != address(0), 'report.poolProxy'); @@ -204,12 +205,23 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput assertTrue(r.aToken != address(0), 'report.aToken'); assertTrue(r.variableDebtToken != address(0), 'report.variableDebtToken'); assertTrue(r.stableDebtToken != address(0), 'report.stableDebtToken'); - assertTrue(r.emissionManager != address(0), 'report.emissionManager'); - assertTrue( - r.rewardsControllerImplementation != address(0), - 'r.rewardsControllerImplementation' - ); - assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); + + if (config.incentivesProxy == address(0)) { + assertTrue(r.emissionManager != address(0), 'report.emissionManager'); + assertTrue( + r.rewardsControllerImplementation != address(0), + 'r.rewardsControllerImplementation' + ); + assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); + } else { + assertTrue(r.emissionManager != address(0), 'report.emissionManager'); + assertEq(r.emissionManager, IRewardsController(config.incentivesProxy).getEmissionManager(), 'report.emissionManager should match RewardsController(config.incentivesProxy).getEmissionManager()'); + assertTrue( + r.rewardsControllerImplementation == address(0), + 'r.rewardsControllerImplementation should be empty if incentivesProxy is set' + ); + assertEq(r.rewardsControllerProxy, config.incentivesProxy, 'r.rewardsControllerProxy should match config input'); + } assertTrue(r.configEngine != address(0), 'report.configEngine'); assertTrue( r.staticATokenFactoryImplementation != address(0), From 1e4036a29f91caaa3bc754eb308c25341f7ff281 Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 21 Aug 2024 09:10:42 +0000 Subject: [PATCH 2/4] chore: run lint:fix --- .../procedures/AaveV3SetupProcedure.sol | 4 ++-- tests/utils/BatchTestProcedures.sol | 18 +++++++++++++++--- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol b/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol index 88b6f8d1..9852ea88 100644 --- a/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol +++ b/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol @@ -56,7 +56,7 @@ contract AaveV3SetupProcedure { _validateMarketSetup(roles); SetupReport memory report = _setupPoolAddressesProvider( - AddressProviderInput( + AddressProviderInput( initialReport, poolImplementation, poolConfiguratorImplementation, @@ -109,7 +109,7 @@ contract AaveV3SetupProcedure { ) internal returns (SetupReport memory) { SetupReport memory report; - IPoolAddressesProvider provider = IPoolAddressesProvider( + IPoolAddressesProvider provider = IPoolAddressesProvider( input.initialReport.poolAddressesProvider ); provider.setPriceOracle(input.aaveOracle); diff --git a/tests/utils/BatchTestProcedures.sol b/tests/utils/BatchTestProcedures.sol index 3f045c58..a469f45f 100644 --- a/tests/utils/BatchTestProcedures.sol +++ b/tests/utils/BatchTestProcedures.sol @@ -174,7 +174,11 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput ); } - function checkFullReport(MarketConfig memory config, DeployFlags memory flags, MarketReport memory r) internal view { + function checkFullReport( + MarketConfig memory config, + DeployFlags memory flags, + MarketReport memory r + ) internal view { assertTrue(r.poolAddressesProviderRegistry != address(0), 'r.poolAddressesProviderRegistry'); assertTrue(r.poolAddressesProvider != address(0), 'report.poolAddressesProvider'); assertTrue(r.poolProxy != address(0), 'report.poolProxy'); @@ -215,12 +219,20 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); } else { assertTrue(r.emissionManager != address(0), 'report.emissionManager'); - assertEq(r.emissionManager, IRewardsController(config.incentivesProxy).getEmissionManager(), 'report.emissionManager should match RewardsController(config.incentivesProxy).getEmissionManager()'); + assertEq( + r.emissionManager, + IRewardsController(config.incentivesProxy).getEmissionManager(), + 'report.emissionManager should match RewardsController(config.incentivesProxy).getEmissionManager()' + ); assertTrue( r.rewardsControllerImplementation == address(0), 'r.rewardsControllerImplementation should be empty if incentivesProxy is set' ); - assertEq(r.rewardsControllerProxy, config.incentivesProxy, 'r.rewardsControllerProxy should match config input'); + assertEq( + r.rewardsControllerProxy, + config.incentivesProxy, + 'r.rewardsControllerProxy should match config input' + ); } assertTrue(r.configEngine != address(0), 'report.configEngine'); assertTrue( From 64804c04fb68732ffa685b7c7984c66e2f7b9414 Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 21 Aug 2024 09:57:06 +0000 Subject: [PATCH 3/4] chore: move duplicated check outside if statement at BatchTestProcedures --- tests/utils/BatchTestProcedures.sol | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/utils/BatchTestProcedures.sol b/tests/utils/BatchTestProcedures.sol index a469f45f..754bd8a4 100644 --- a/tests/utils/BatchTestProcedures.sol +++ b/tests/utils/BatchTestProcedures.sol @@ -210,15 +210,15 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput assertTrue(r.variableDebtToken != address(0), 'report.variableDebtToken'); assertTrue(r.stableDebtToken != address(0), 'report.stableDebtToken'); + assertTrue(r.emissionManager != address(0), 'report.emissionManager'); + assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); + if (config.incentivesProxy == address(0)) { - assertTrue(r.emissionManager != address(0), 'report.emissionManager'); assertTrue( r.rewardsControllerImplementation != address(0), 'r.rewardsControllerImplementation' ); - assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); } else { - assertTrue(r.emissionManager != address(0), 'report.emissionManager'); assertEq( r.emissionManager, IRewardsController(config.incentivesProxy).getEmissionManager(), From 8f6cc1e6d4fd635e0c70029c4ed4088d3b45931f Mon Sep 17 00:00:00 2001 From: kartojal Date: Wed, 21 Aug 2024 09:58:49 +0000 Subject: [PATCH 4/4] chore: run lint:fix --- tests/utils/BatchTestProcedures.sol | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/utils/BatchTestProcedures.sol b/tests/utils/BatchTestProcedures.sol index 754bd8a4..3f69a9c0 100644 --- a/tests/utils/BatchTestProcedures.sol +++ b/tests/utils/BatchTestProcedures.sol @@ -212,7 +212,7 @@ contract BatchTestProcedures is Test, DeployUtils, FfiUtils, DefaultMarketInput assertTrue(r.emissionManager != address(0), 'report.emissionManager'); assertTrue(r.rewardsControllerProxy != address(0), 'report.rewardsControllerProxy'); - + if (config.incentivesProxy == address(0)) { assertTrue( r.rewardsControllerImplementation != address(0),