diff --git a/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol b/src/deployments/contracts/procedures/AaveV3SetupProcedure.sol index 30aeb08d..9852ea88 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..3f69a9c0 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,11 @@ 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 +209,31 @@ 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.rewardsControllerImplementation != address(0), + 'r.rewardsControllerImplementation' + ); + } else { + 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),