diff --git a/Makefile b/Makefile index 4b7d2ea7..533d76a5 100644 --- a/Makefile +++ b/Makefile @@ -92,6 +92,14 @@ deploy-liquidation-data-provider :; --sig "run(address,address)" ${pool} ${addressesProvider} \ --verify --broadcast +# Deploys payload to list phase two assets. `make deploy-phase-two-payload CHAIN=mainnet ACCOUNT=` +deploy-phase-two-payload :; + FOUNDRY_PROFILE=${CHAIN} forge script scripts/misc/DeployHorizonPhaseTwoPayload.sol:DeployHorizonPhaseTwoPayload \ + --rpc-url ${CHAIN} --account ${ACCOUNT} --slow --gas-estimate-multiplier 150 \ + --chain ${CHAIN} --verifier-url ${VERIFIER_URL} \ + --sig "run()" \ + --verify --broadcast \ + # Invariants echidna: echidna tests/invariants/Tester.t.sol --contract Tester --config ./tests/invariants/_config/echidna_config.yaml --corpus-dir ./tests/invariants/_corpus/echidna/default/_data/corpus diff --git a/foundry.toml b/foundry.toml index 070765e7..0da1df00 100644 --- a/foundry.toml +++ b/foundry.toml @@ -43,6 +43,7 @@ base = "${RPC_BASE}" metis = "${RPC_METIS}" linea = "${RPC_LINEA}" sepolia = "${RPC_SEPOLIA}" +vtestnet = "${RPC_VTESTNET}" [etherscan] mainnet = { key = "${ETHERSCAN_API_KEY}", chainId = 1 } diff --git a/scripts/misc/DeployHorizonPhaseTwoPayload.sol b/scripts/misc/DeployHorizonPhaseTwoPayload.sol new file mode 100644 index 00000000..6fa39ff1 --- /dev/null +++ b/scripts/misc/DeployHorizonPhaseTwoPayload.sol @@ -0,0 +1,31 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {AaveV3EthereumHorizonCustom} from 'tests/horizon/utils/AaveV3EthereumHorizonCustom.sol'; +import {HorizonPhaseTwoListing} from 'src/deployments/inputs/HorizonPhaseTwoListing.sol'; +import {AaveV3HelpersBatchOne} from 'src/deployments/projects/aave-v3-batched/batches/AaveV3HelpersBatchOne.sol'; +import {AaveV3ConfigEngine} from 'src/contracts/extensions/v3-config-engine/AaveV3ConfigEngine.sol'; +import {Script} from 'forge-std/Script.sol'; + +contract DeployHorizonPhaseTwoPayload is Script { + function run() public returns (address, address) { + vm.startBroadcast(); + AaveV3HelpersBatchOne helpersBatchOne = new AaveV3HelpersBatchOne( + AaveV3EthereumHorizonCustom.POOL, + AaveV3EthereumHorizonCustom.POOL_CONFIGURATOR, + AaveV3EthereumHorizonCustom.DEFAULT_INTEREST_RATE_STRATEGY, + AaveV3EthereumHorizonCustom.AAVE_ORACLE, + AaveV3EthereumHorizonCustom.REWARDS_CONTROLLER, + AaveV3EthereumHorizonCustom.REVENUE_SPLITTER, + AaveV3EthereumHorizonCustom.ATOKEN_IMPL, + AaveV3EthereumHorizonCustom.VARIABLE_DEBT_TOKEN_IMPL + ); + + HorizonPhaseTwoListing horizonPhaseTwoListing = new HorizonPhaseTwoListing( + helpersBatchOne.getConfigEngineReport().configEngine + ); + vm.stopBroadcast(); + + return (address(helpersBatchOne), address(horizonPhaseTwoListing)); + } +} diff --git a/src/deployments/inputs/HorizonPhaseTwoListing.sol b/src/deployments/inputs/HorizonPhaseTwoListing.sol new file mode 100644 index 00000000..a7336b72 --- /dev/null +++ b/src/deployments/inputs/HorizonPhaseTwoListing.sol @@ -0,0 +1,101 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {IAaveV3ConfigEngine as IEngine} from '../../contracts/extensions/v3-config-engine/IAaveV3ConfigEngine.sol'; +import {EngineFlags} from '../../contracts/extensions/v3-config-engine/EngineFlags.sol'; +import {AaveV3Payload} from '../../contracts/extensions/v3-config-engine/AaveV3Payload.sol'; + +import {AaveV3EthereumHorizonCustom} from 'tests/horizon/utils/AaveV3EthereumHorizonCustom.sol'; + +contract HorizonPhaseTwoListing is AaveV3Payload { + constructor(address configEngine) AaveV3Payload(IEngine(configEngine)) {} + + function eModeCategoriesUpdates() + public + pure + override + returns (IEngine.EModeCategoryUpdate[] memory) + { + IEngine.EModeCategoryUpdate[] memory eModeCategories = new IEngine.EModeCategoryUpdate[](1); + + // VBILL GHO + eModeCategories[0] = IEngine.EModeCategoryUpdate({ + eModeCategory: 1, // overwrite previous empty eMode category + ltv: 84_00, + liqThreshold: 89_00, + liqBonus: 3_00, + label: 'VBILL GHO' + }); + + return eModeCategories; + } + + function newListingsCustom() + public + view + override + returns (IEngine.ListingWithCustomImpl[] memory) + { + IEngine.ListingWithCustomImpl[] memory listingsCustom = new IEngine.ListingWithCustomImpl[](1); + + listingsCustom[0] = IEngine.ListingWithCustomImpl( + IEngine.Listing({ + asset: AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, + assetSymbol: 'VBILL', + priceFeed: AaveV3EthereumHorizonCustom.VBILL_PRICE_FEED, + rateStrategyParams: IEngine.InterestRateInputData({ + optimalUsageRatio: 99_00, + baseVariableBorrowRate: 0, + variableRateSlope1: 0, + variableRateSlope2: 0 + }), + enabledToBorrow: EngineFlags.DISABLED, + borrowableInIsolation: EngineFlags.DISABLED, + withSiloedBorrowing: EngineFlags.DISABLED, + flashloanable: EngineFlags.DISABLED, + ltv: 83_00, + liqThreshold: 88_00, + liqBonus: 3_00, + reserveFactor: EngineFlags.KEEP_CURRENT, + supplyCap: 15_000_000, + borrowCap: 0, + debtCeiling: 0, + liqProtocolFee: 0 + }), + IEngine.TokenImplementations({ + aToken: AaveV3EthereumHorizonCustom.RWA_ATOKEN_IMPL, + vToken: AaveV3EthereumHorizonCustom.VARIABLE_DEBT_TOKEN_IMPL + }) + ); + + return listingsCustom; + } + + function assetsEModeUpdates() public view override returns (IEngine.AssetEModeUpdate[] memory) { + IEngine.AssetEModeUpdate[] memory assetsEMode = new IEngine.AssetEModeUpdate[](2); + + uint256 index = 0; + + // Overwrite empty eMode category 1 + assetsEMode[index++] = IEngine.AssetEModeUpdate({ + asset: AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, + eModeCategory: 1, + collateral: EngineFlags.ENABLED, + borrowable: EngineFlags.DISABLED + }); + assetsEMode[index++] = IEngine.AssetEModeUpdate({ + asset: AaveV3EthereumHorizonCustom.GHO_UNDERLYING, + eModeCategory: 1, + collateral: EngineFlags.DISABLED, + borrowable: EngineFlags.ENABLED + }); + + assert(index == assetsEMode.length); + + return assetsEMode; + } + + function getPoolContext() public pure override returns (IEngine.PoolContext memory) { + return IEngine.PoolContext({networkName: 'Horizon RWA', networkAbbreviation: 'HorRwa'}); + } +} diff --git a/tests/deployments/HorizonBase.t.sol b/tests/deployments/HorizonBase.t.sol new file mode 100644 index 00000000..e348bf7c --- /dev/null +++ b/tests/deployments/HorizonBase.t.sol @@ -0,0 +1,437 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import {console2 as console} from 'forge-std/console2.sol'; + +import {Test, Vm} from 'forge-std/Test.sol'; +import {DataTypes} from '../../src/contracts/protocol/libraries/types/DataTypes.sol'; +import {MarketReport} from '../../src/deployments/interfaces/IMarketReportTypes.sol'; +import {Default} from '../../scripts/DeployAaveV3MarketBatched.sol'; +import {DeployHorizonPhaseOnePayload} from '../../scripts/misc/DeployHorizonPhaseOnePayload.sol'; +import {ReserveConfiguration} from '../../src/contracts/protocol/libraries/configuration/ReserveConfiguration.sol'; +import {EModeConfiguration} from '../../src/contracts/protocol/libraries/configuration/EModeConfiguration.sol'; +import {PercentageMath} from '../../src/contracts/protocol/libraries/math/PercentageMath.sol'; +import {IMetadataReporter} from '../../src/deployments/interfaces/IMetadataReporter.sol'; +import {IRevenueSplitter} from '../../src/contracts/treasury/IRevenueSplitter.sol'; +import {IDefaultInterestRateStrategyV2} from '../../src/contracts/interfaces/IDefaultInterestRateStrategyV2.sol'; +import {IERC20Detailed, IERC20} from '../../src/contracts/dependencies/openzeppelin/contracts/IERC20Detailed.sol'; +import {IAccessControl} from '../../src/contracts/dependencies/openzeppelin/contracts/IAccessControl.sol'; +import {AggregatorInterface} from '../../src/contracts/dependencies/chainlink/AggregatorInterface.sol'; +import {IScaledPriceAdapter} from '../../src/contracts/interfaces/IScaledPriceAdapter.sol'; +import {IAaveOracle} from '../../src/contracts/interfaces/IAaveOracle.sol'; +import {IACLManager} from '../../src/contracts/interfaces/IACLManager.sol'; +import {IAToken} from '../../src/contracts/interfaces/IAToken.sol'; +import {IPool} from '../../src/contracts/interfaces/IPool.sol'; +import {IPoolConfigurator} from '../../src/contracts/interfaces/IPoolConfigurator.sol'; +import {Errors} from '../../src/contracts/protocol/libraries/helpers/Errors.sol'; +import {ProxyHelpers} from '../utils/ProxyHelpers.sol'; +import {IRwaOracleParameterRegistry} from '../horizon/dependencies/IRwaOracleParameterRegistry.sol'; +import {AaveV3EthereumHorizonCustom} from '../horizon/utils/AaveV3EthereumHorizonCustom.sol'; + +abstract contract HorizonBaseTest is Test { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using EModeConfiguration for uint128; + using PercentageMath for uint256; + + IPool internal pool; + IRevenueSplitter internal revenueSplitter; + IDefaultInterestRateStrategyV2 internal defaultInterestRateStrategy; + address internal rwaATokenManager; + address internal aTokenImpl; + address internal rwaATokenImpl; + address internal variableDebtTokenImpl; + address internal poolAdmin; + + address internal alice = makeAddr('alice'); + address internal bob = makeAddr('bob'); + + bytes32 internal constant ATOKEN_ADMIN_ROLE = keccak256('ATOKEN_ADMIN'); + + struct DeploymentInfo { + address pool; + address revenueSplitter; + address defaultInterestRateStrategy; + address rwaATokenManager; + address aTokenImpl; + address rwaATokenImpl; + address variableDebtTokenImpl; + address poolAdmin; + } + + struct TokenListingParams { + bool isRwa; + bool hasPriceAdapter; + address oracle; + address underlyingPriceFeed; // if no price adapter, this is the same as oracle + string aTokenName; + string aTokenSymbol; + string variableDebtTokenName; + string variableDebtTokenSymbol; + uint256 supplyCap; + uint256 borrowCap; + uint256 reserveFactor; + bool enabledToBorrow; + bool borrowableInIsolation; + bool withSiloedBorrowing; + bool flashloanable; + uint256 ltv; + uint256 liquidationThreshold; + uint256 liquidationBonus; // includes 100_00 base, so 103_00 = 3_00 bonus + uint256 debtCeiling; + uint256 liqProtocolFee; + IDefaultInterestRateStrategyV2.InterestRateDataRay interestRateData; + uint256 initialDeposit; + } + + struct EModeCategoryParams { + uint256 ltv; + uint256 liquidationThreshold; + uint256 liquidationBonus; + string label; + address[] collateralAssets; + address[] borrowableAssets; + } + + function initEnvironment() internal virtual { + pool = IPool(AaveV3EthereumHorizonCustom.POOL); + revenueSplitter = IRevenueSplitter(AaveV3EthereumHorizonCustom.REVENUE_SPLITTER); + defaultInterestRateStrategy = IDefaultInterestRateStrategyV2( + AaveV3EthereumHorizonCustom.DEFAULT_INTEREST_RATE_STRATEGY + ); + aTokenImpl = AaveV3EthereumHorizonCustom.ATOKEN_IMPL; + variableDebtTokenImpl = AaveV3EthereumHorizonCustom.VARIABLE_DEBT_TOKEN_IMPL; + rwaATokenImpl = AaveV3EthereumHorizonCustom.RWA_ATOKEN_IMPL; + } + + function test_listing(address token, TokenListingParams memory params) internal virtual { + test_getConfiguration(token, params); + test_interestRateStrategy(token, params); + test_aToken(token, params); + test_variableDebtToken(token, params); + test_priceFeed(token, params); + } + + function test_eMode( + uint8 eModeCategory, + EModeCategoryParams memory params, + bool dealCollateral + ) internal { + test_eMode_configuration(eModeCategory, params); + test_eMode_collateralization(eModeCategory, params, true); + } + + function test_getConfiguration(address token, TokenListingParams memory params) internal view { + DataTypes.ReserveConfigurationMap memory config = pool.getConfiguration(token); + assertEq(config.getSupplyCap(), params.supplyCap, 'supplyCap'); + assertEq(config.getBorrowCap(), params.borrowCap, 'borrowCap'); + assertEq(config.getIsVirtualAccActive(), true, 'isVirtualAccActive'); + assertEq(config.getBorrowingEnabled(), params.enabledToBorrow, 'borrowingEnabled'); + assertEq( + config.getBorrowableInIsolation(), + params.borrowableInIsolation, + 'borrowableInIsolation' + ); + assertEq(config.getSiloedBorrowing(), params.withSiloedBorrowing, 'siloedBorrowing'); + assertEq(config.getFlashLoanEnabled(), params.flashloanable, 'flashloanable'); + assertEq(config.getReserveFactor(), params.reserveFactor, 'reserveFactor'); + assertEq(config.getLtv(), params.ltv, 'ltv'); + assertEq(config.getLiquidationThreshold(), params.liquidationThreshold, 'liquidationThreshold'); + assertEq(config.getLiquidationBonus(), params.liquidationBonus, 'liquidationBonus'); + assertEq(config.getDebtCeiling(), params.debtCeiling, 'debtCeiling'); + assertEq(config.getLiquidationProtocolFee(), params.liqProtocolFee, 'liqProtocolFee'); + assertEq(config.getPaused(), false, 'paused'); + } + + function test_interestRateStrategy( + address token, + TokenListingParams memory params + ) internal view { + assertEq( + pool.getReserveData(token).interestRateStrategyAddress, + address(defaultInterestRateStrategy), + 'interestRateStrategyAddress' + ); + assertEq(defaultInterestRateStrategy.getInterestRateData(token), params.interestRateData); + } + + function test_aToken(address token, TokenListingParams memory params) internal { + address aToken = pool.getReserveAToken(token); + assertEq(IERC20Detailed(aToken).name(), params.aTokenName, 'aTokenName'); + assertEq(IERC20Detailed(aToken).symbol(), params.aTokenSymbol, 'aTokenSymbol'); + assertEq( + IAToken(aToken).RESERVE_TREASURY_ADDRESS(), + address(revenueSplitter), + 'reserveTreasuryAddress' + ); + + address currentATokenImpl = ProxyHelpers.getInitializableAdminUpgradeabilityProxyImplementation( + vm, + aToken + ); + if (params.isRwa) { + assertEq(currentATokenImpl, rwaATokenImpl, 'rwaATokenImpl'); + vm.expectRevert(bytes(Errors.OPERATION_NOT_SUPPORTED)); + IAToken(aToken).approve(address(0), 0); + } else { + assertEq(currentATokenImpl, aTokenImpl, 'aTokenImpl'); + IAToken(aToken).approve(makeAddr('randomAddress'), 1); + } + } + + function test_variableDebtToken(address token, TokenListingParams memory params) private view { + address variableDebtToken = pool.getReserveVariableDebtToken(token); + assertEq( + IERC20Detailed(variableDebtToken).name(), + params.variableDebtTokenName, + 'variableDebtTokenName' + ); + assertEq( + IERC20Detailed(variableDebtToken).symbol(), + params.variableDebtTokenSymbol, + 'variableDebtTokenSymbol' + ); + assertEq( + ProxyHelpers.getInitializableAdminUpgradeabilityProxyImplementation(vm, variableDebtToken), + variableDebtTokenImpl, + 'variableDebtTokenImpl' + ); + } + + function test_priceFeed(address token, TokenListingParams memory params) private view { + IAaveOracle oracle = IAaveOracle(pool.ADDRESSES_PROVIDER().getPriceOracle()); + + AggregatorInterface oracleSource = AggregatorInterface(oracle.getSourceOfAsset(token)); + assertEq(oracleSource.decimals(), 8, 'oracleSource.decimals'); + + assertEq(address(oracleSource), params.oracle, 'oracleSource'); + + AggregatorInterface priceFeed = oracleSource; + if (params.hasPriceAdapter) { + priceFeed = AggregatorInterface(IScaledPriceAdapter(address(oracleSource)).source()); + assertEq( + priceFeed.latestAnswer() * int256(10 ** (8 - priceFeed.decimals())), + oracleSource.latestAnswer(), + 'priceFeed.latestAnswer' + ); + } + + assertEq(address(priceFeed), params.underlyingPriceFeed, 'priceFeed'); + } + + function test_eMode_configuration( + uint8 eModeCategory, + EModeCategoryParams memory params + ) private view { + assertEq(pool.getEModeCategoryCollateralConfig(eModeCategory).ltv, params.ltv, 'emode.ltv'); + assertEq( + pool.getEModeCategoryCollateralConfig(eModeCategory).liquidationThreshold, + params.liquidationThreshold, + 'emode.liquidationThreshold' + ); + assertEq( + pool.getEModeCategoryCollateralConfig(eModeCategory).liquidationBonus, + params.liquidationBonus, + 'emode.liquidationBonus' + ); + assertEq(pool.getEModeCategoryLabel(eModeCategory), params.label, 'emode.label'); + + uint128 collateralBitmap = pool.getEModeCategoryCollateralBitmap(eModeCategory); + uint128 recoveredCollateralBitmap = 0; + for (uint256 i = 0; i < params.collateralAssets.length; i++) { + uint256 reserveId = pool.getReserveData(params.collateralAssets[i]).id; + assertEq( + collateralBitmap.isReserveEnabledOnBitmap(reserveId), + true, + string.concat('emode.collateralAsset ', vm.toString(params.collateralAssets[i])) + ); + recoveredCollateralBitmap = recoveredCollateralBitmap.setReserveBitmapBit(reserveId, true); + } + assertEq(collateralBitmap, recoveredCollateralBitmap, 'emode.collateralBitmap'); + + uint128 borrowableBitmap = pool.getEModeCategoryBorrowableBitmap(eModeCategory); + uint128 recoveredBorrowableBitmap = 0; + for (uint256 i = 0; i < params.borrowableAssets.length; i++) { + uint256 reserveId = pool.getReserveData(params.borrowableAssets[i]).id; + assertEq( + borrowableBitmap.isReserveEnabledOnBitmap(reserveId), + true, + string.concat('emode.borrowableAsset ', vm.toString(params.borrowableAssets[i])) + ); + recoveredBorrowableBitmap = recoveredBorrowableBitmap.setReserveBitmapBit(reserveId, true); + } + assertEq(borrowableBitmap, recoveredBorrowableBitmap, 'emode.borrowableBitmap'); + } + + function test_eMode_collateralization( + uint8 eModeCategory, + EModeCategoryParams memory params, + bool dealCollateral + ) internal { + address poolConfigurator = pool.ADDRESSES_PROVIDER().getPoolConfigurator(); + + vm.prank(alice); + pool.setUserEMode(eModeCategory); + + IAaveOracle oracle = IAaveOracle(pool.ADDRESSES_PROVIDER().getPriceOracle()); + for (uint256 i = 0; i < params.collateralAssets.length; i++) { + uint256 amountInBaseCurrency = 1e5 * 1e8; + + uint256 supplyAmount = (amountInBaseCurrency * + 10 ** IERC20Detailed(params.collateralAssets[i]).decimals()) / + oracle.getAssetPrice(params.collateralAssets[i]) + + 1; + address collateralAsset = params.collateralAssets[i]; + if (dealCollateral) { + deal(collateralAsset, alice, supplyAmount); + } + + vm.startPrank(alice); + IERC20Detailed(collateralAsset).approve(address(pool), supplyAmount); + pool.supply(collateralAsset, supplyAmount, alice, 0); + vm.stopPrank(); + + for (uint256 j = 0; j < params.borrowableAssets.length; j++) { + address borrowAsset = params.borrowableAssets[j]; + uint256 borrowAmount = (amountInBaseCurrency.percentMul(params.ltv) * + 10 ** IERC20Detailed(borrowAsset).decimals()) / + oracle.getAssetPrice(borrowAsset) - + 1; + + deal(borrowAsset, bob, borrowAmount); + + vm.startPrank(bob); + IERC20Detailed(borrowAsset).approve(address(pool), borrowAmount); + pool.supply(borrowAsset, borrowAmount, bob, 0); + vm.stopPrank(); + + vm.prank(alice); + pool.borrow(borrowAsset, borrowAmount, 2, 0, alice); + + vm.startPrank(alice); + IERC20Detailed(borrowAsset).approve(address(pool), borrowAmount); + pool.repay(borrowAsset, borrowAmount, 2, alice); + vm.stopPrank(); + + vm.prank(bob); + pool.withdraw(borrowAsset, borrowAmount, bob); + } + + vm.prank(alice); + pool.withdraw(collateralAsset, supplyAmount, alice); + } + } + + function test_nonEMode_collateralization( + address token, + TokenListingParams memory params, + address[] memory borrowableAssets, + bool dealCollateral + ) internal { + address poolConfigurator = pool.ADDRESSES_PROVIDER().getPoolConfigurator(); + + IAaveOracle oracle = IAaveOracle(pool.ADDRESSES_PROVIDER().getPriceOracle()); + uint256 amountInBaseCurrency = 1e5 * 1e8; + + uint256 supplyAmount = (amountInBaseCurrency * 10 ** IERC20Detailed(token).decimals()) / + oracle.getAssetPrice(token) + + 1; + + if (dealCollateral) { + deal(token, alice, supplyAmount); + } + + vm.startPrank(alice); + IERC20Detailed(token).approve(address(pool), supplyAmount); + pool.supply(token, supplyAmount, alice, 0); + vm.stopPrank(); + + for (uint256 j = 0; j < borrowableAssets.length; j++) { + address borrowAsset = borrowableAssets[j]; + uint256 borrowAmount = (amountInBaseCurrency.percentMul(params.ltv) * + 10 ** IERC20Detailed(borrowAsset).decimals()) / + oracle.getAssetPrice(borrowAsset) - + 1; + + deal(borrowAsset, bob, borrowAmount); + + vm.startPrank(bob); + IERC20Detailed(borrowAsset).approve(address(pool), borrowAmount); + pool.supply(borrowAsset, borrowAmount, bob, 0); + vm.stopPrank(); + + vm.prank(alice); + pool.borrow(borrowAsset, borrowAmount, 2, 0, alice); + + vm.startPrank(alice); + IERC20Detailed(borrowAsset).approve(address(pool), borrowAmount); + pool.repay(borrowAsset, borrowAmount, 2, alice); + vm.stopPrank(); + + vm.prank(bob); + pool.withdraw(borrowAsset, borrowAmount, bob); + } + + vm.prank(alice); + pool.withdraw(token, supplyAmount, alice); + } + + function assertEq( + IDefaultInterestRateStrategyV2.InterestRateDataRay memory a, + IDefaultInterestRateStrategyV2.InterestRateDataRay memory b + ) internal pure { + assertEq( + a.optimalUsageRatio, + b.optimalUsageRatio, + 'assertEq(interestRateData): optimalUsageRatio' + ); + assertEq( + a.baseVariableBorrowRate, + b.baseVariableBorrowRate, + 'assertEq(interestRateData): baseVariableBorrowRate' + ); + assertEq( + a.variableRateSlope1, + b.variableRateSlope1, + 'assertEq(interestRateData): variableRateSlope1' + ); + assertEq( + a.variableRateSlope2, + b.variableRateSlope2, + 'assertEq(interestRateData): variableRateSlope2' + ); + assertEq(abi.encode(a), abi.encode(b), 'assertEq(interestRateData): all fields'); + } + + // check current emode category label is empty so it can be overridden + function _checkExistingEModeCategory(uint8 eModeCategory) internal virtual { + DataTypes.EModeCategoryLegacy memory eModeCategoryData = pool.getEModeCategoryData( + eModeCategory + ); + assertEq(eModeCategoryData.label, '', 'EMode category does not exist'); + } + + function _toDynamicAddressArray(address a) internal pure returns (address[] memory) { + address[] memory array = new address[](1); + array[0] = a; + return array; + } + + function _toDynamicAddressArray(address a, address b) internal pure returns (address[] memory) { + address[] memory array = new address[](2); + array[0] = a; + array[1] = b; + return array; + } + + function _toDynamicAddressArray( + address a, + address b, + address c + ) internal pure returns (address[] memory) { + address[] memory array = new address[](3); + array[0] = a; + array[1] = b; + array[2] = c; + return array; + } +} diff --git a/tests/deployments/HorizonPhaseTwoListing.t.sol b/tests/deployments/HorizonPhaseTwoListing.t.sol new file mode 100644 index 00000000..ca2fb1be --- /dev/null +++ b/tests/deployments/HorizonPhaseTwoListing.t.sol @@ -0,0 +1,241 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity ^0.8.0; + +import './HorizonBase.t.sol'; +import {DeployHorizonPhaseTwoPayload} from '../../scripts/misc/DeployHorizonPhaseTwoPayload.sol'; + +/// forge-config: default.evm_version = "cancun" +contract HorizonPhaseTwoListingTest is HorizonBaseTest { + using ReserveConfiguration for DataTypes.ReserveConfigurationMap; + using EModeConfiguration for uint128; + using PercentageMath for uint256; + + TokenListingParams internal VBILL_TOKEN_LISTING_PARAMS = + TokenListingParams({ + aTokenName: 'Aave Horizon RWA VBILL', + aTokenSymbol: 'aHorRwaVBILL', + variableDebtTokenName: 'Aave Horizon RWA Variable Debt VBILL', + variableDebtTokenSymbol: 'variableDebtHorRwaVBILL', + isRwa: true, + hasPriceAdapter: false, + oracle: AaveV3EthereumHorizonCustom.VBILL_PRICE_FEED, + underlyingPriceFeed: AaveV3EthereumHorizonCustom.VBILL_PRICE_FEED, + supplyCap: 15_000_000, + borrowCap: 0, + reserveFactor: 0, + enabledToBorrow: false, + borrowableInIsolation: false, + withSiloedBorrowing: false, + flashloanable: false, + ltv: 83_00, + liquidationThreshold: 88_00, + liquidationBonus: 100_00 + 3_00, + debtCeiling: 0, + liqProtocolFee: 0, + interestRateData: IDefaultInterestRateStrategyV2.InterestRateDataRay({ + optimalUsageRatio: 0.99e27, + baseVariableBorrowRate: 0, + variableRateSlope1: 0, + variableRateSlope2: 0 + }), + initialDeposit: 0 + }); + + EModeCategoryParams internal VBILL_GHO_EMODE_PARAMS = + EModeCategoryParams({ + ltv: 84_00, + liquidationThreshold: 89_00, + liquidationBonus: 100_00 + 3_00, + label: 'VBILL GHO', + collateralAssets: _toDynamicAddressArray(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING), + borrowableAssets: _toDynamicAddressArray(AaveV3EthereumHorizonCustom.GHO_UNDERLYING) + }); + + uint8 internal constant VBILL_GHO_EMODE_CATEGORY = 1; + + function setUp() public virtual { + vm.createSelectFork('mainnet', 23690478); + + initEnvironment(); + _checkExistingEModeCategory(VBILL_GHO_EMODE_CATEGORY); + _loadDeployment(); + + _whitelistVbillRwa(alice); + _whitelistVbillRwa(pool.getReserveAToken(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING)); + + _transferVBILLTo(alice, 1_000_000e6); + } + + function test_listing_VBILL() public { + test_listing(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, VBILL_TOKEN_LISTING_PARAMS); + } + + function test_eMode_VBILL_GHO() public { + test_eMode({ + eModeCategory: VBILL_GHO_EMODE_CATEGORY, + params: VBILL_GHO_EMODE_PARAMS, + dealCollateral: false + }); + } + + function test_param_registry_VBILL() public view { + assertEq( + IRwaOracleParameterRegistry(AaveV3EthereumHorizonCustom.RWA_ORACLE_PARAMS_REGISTRY) + .assetExists(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING), + true, + 'assetExists' + ); + } + + // fund accounts by transferring existing VBILL, as `deal` causes issues on token contract accounting + function _transferVBILLTo(address user, uint256 amount) internal virtual { + vm.prank(0x5E6c2AD8376A9E5E857B1d91643399E9aB65ff8c); // on-chain holder, ~25M VBILL balance + IERC20(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING).transfer(user, amount); + } + + function test_listing(address token, TokenListingParams memory params) internal virtual override { + super.test_listing(token, params); + if (params.isRwa) { + test_nonEMode_collateralization({ + token: token, + params: params, + borrowableAssets: _toDynamicAddressArray( + AaveV3EthereumHorizonCustom.USDC_UNDERLYING, + AaveV3EthereumHorizonCustom.GHO_UNDERLYING + ), + dealCollateral: false + }); + } + } + + function _loadDeployment() internal virtual { + (, address horizonPhaseTwoListing) = new DeployHorizonPhaseTwoPayload().run(); + + vm.startPrank(AaveV3EthereumHorizonCustom.HORIZON_EMERGENCY); + (bool success, bytes memory returnData) = AaveV3EthereumHorizonCustom.HORIZON_EXECUTOR.call( + abi.encodeWithSignature( + 'executeTransaction(address,uint256,string,bytes,bool)', + address(horizonPhaseTwoListing), // target + 0, // value + 'execute()', // signature + '', // data + true // withDelegatecall + ) + ); + vm.stopPrank(); + require(success, 'Failed to execute transaction'); + } + + function _whitelistVbillRwa(address addressToWhitelist) internal virtual { + (bool success, bytes memory data) = AaveV3EthereumHorizonCustom.VBILL_UNDERLYING.call( + abi.encodeWithSignature('REGISTRY_SERVICE()') + ); + require(success, 'Failed to call REGISTRY_SERVICE()'); + (success, data) = AaveV3EthereumHorizonCustom.VBILL_UNDERLYING.call( + abi.encodeWithSignature('getDSService(uint256)', abi.decode(data, (uint256))) + ); + require(success, 'Failed to call getDSService()'); + address registryService = abi.decode(data, (address)); + + address admin = 0xDA8e2d926D28a86aeE933d928357583aae5D3b85; // retrieved onchain + (success, data) = AaveV3EthereumHorizonCustom.VBILL_UNDERLYING.call( + abi.encodeWithSignature('TRUST_SERVICE()') + ); + require(success, 'Failed to call TRUST_SERVICE()'); + (success, data) = AaveV3EthereumHorizonCustom.VBILL_UNDERLYING.call( + abi.encodeWithSignature('getDSService(uint256)', abi.decode(data, (uint256))) + ); + address trustService = abi.decode(data, (address)); + (success, data) = trustService.call(abi.encodeWithSignature('getRole(address)', admin)); + require(success, 'Failed to call getRole()'); + require(abi.decode(data, (uint8)) != 0, 'Admin does not have role'); + + vm.prank(admin); + (success, ) = registryService.call( + abi.encodeWithSignature( + 'addWallet(address,string)', + addressToWhitelist, + 'f27e20ca73314651b387da0aa9116f30' // retrieved from on-chain tx + ) + ); + require(success, 'Failed to call addWallet()'); + } + + function _supplyAndBorrow(address user) internal virtual { + vm.startPrank(user); + IERC20(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING).approve(address(pool), 100e6); + pool.supply(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, 100e6, user, 0); + pool.borrow(AaveV3EthereumHorizonCustom.USDC_UNDERLYING, 50e6, 2, 0, user); + vm.stopPrank(); + } +} + +/// forge-config: default.evm_version = "cancun" +contract HorizonPhaseTwoListingVTestnetTest is HorizonPhaseTwoListingTest { + function setUp() public virtual override { + vm.skip(true, 'vtestnet with VBILL listed'); + vm.createSelectFork('vtestnet'); + + initEnvironment(); + + _whitelistVbillRwa(alice); + _transferVBILLTo(alice, 1_000_000e6); + } + + function test_actions() public { + // test users from tenderly vtestnet, already whitelisted and seeded with VBILL + address testUser1 = 0xabCa9b6E08dC6C031880f515Ec0cf9e395D0d6B8; + address testUser2 = 0x66C1d4c6195D587C99aCc4256EbaC0a8D0AB9f64; + address testUser3 = 0xd22eefD49B81e078f576Dbb4A804aa250cB3A291; + + _supplyAndBorrow(testUser1); + _supplyAndBorrow(testUser2); + _supplyAndBorrow(testUser3); + } +} + +/// forge-config: default.evm_version = "cancun" +contract HorizonPhaseTwoListingPostDeploymentForkTest is HorizonPhaseTwoListingTest { + function setUp() public virtual override { + vm.createSelectFork('mainnet', 23693075); + + initEnvironment(); + _checkExistingEModeCategory(VBILL_GHO_EMODE_CATEGORY); + _loadDeployment(); + + _whitelistVbillRwa(alice); + _whitelistVbillRwa(pool.getReserveAToken(AaveV3EthereumHorizonCustom.VBILL_UNDERLYING)); + + _transferVBILLTo(alice, 1_000_000e6); + } + + function _loadDeployment() internal virtual override { + address horizonPhaseTwoListing = 0xA9ce8c46F6119410BBF5C797233f5494C7b3E7E5; // fill in with deployed payload address + + vm.startPrank(AaveV3EthereumHorizonCustom.HORIZON_EMERGENCY); + (bool success, bytes memory returnData) = AaveV3EthereumHorizonCustom.HORIZON_EXECUTOR.call( + abi.encodeWithSignature( + 'executeTransaction(address,uint256,string,bytes,bool)', + address(horizonPhaseTwoListing), // target + 0, // value + 'execute()', // signature + '', // data + true // withDelegatecall + ) + ); + vm.stopPrank(); + require(success, 'Failed to execute transaction'); + } +} + +/// forge-config: default.evm_version = "cancun" +contract HorizonPhaseTwoListingPostExecutionForkTest is HorizonPhaseTwoListingTest { + function setUp() public virtual override { + vm.createSelectFork('mainnet', 23726548); + + initEnvironment(); + + _whitelistVbillRwa(alice); + _transferVBILLTo(alice, 1_000_000e6); + } +} diff --git a/tests/horizon/OracleDynamicBounds.t.sol b/tests/horizon/OracleDynamicBounds.t.sol index cf527cb9..1a9dd909 100644 --- a/tests/horizon/OracleDynamicBounds.t.sol +++ b/tests/horizon/OracleDynamicBounds.t.sol @@ -8,9 +8,9 @@ import {IAaveOracle} from '../../src/contracts/interfaces/IAaveOracle.sol'; import {IPool} from '../../src/contracts/interfaces/IPool.sol'; import {AggregatorInterface} from '../../src/contracts/dependencies/chainlink/AggregatorInterface.sol'; -import {AaveV3HorizonEthereum} from './utils/AaveV3HorizonEthereum.sol'; +import {AaveV3EthereumHorizonCustom} from './utils/AaveV3EthereumHorizonCustom.sol'; -import {IParameterRegistry} from './dependencies/IParameterRegistry.sol'; +import {IRwaOracleParameterRegistry} from './dependencies/IRwaOracleParameterRegistry.sol'; abstract contract OracleDynamicBoundsTestBase is Test { address constant USTB_NEW_AGGREGATOR = 0x267D0DD05fbc989565C521e0B8882f61027FF32A; @@ -39,9 +39,11 @@ abstract contract OracleDynamicBoundsTestBase is Test { mapping(address => NewAggregator) internal newAggregators; // asset => new aggregator IAaveOracle internal aaveOracle; - IParameterRegistry internal parameterRegistry; + IRwaOracleParameterRegistry internal parameterRegistry; function setUp() public virtual { - parameterRegistry = IParameterRegistry(AaveV3HorizonEthereum.RWA_ORACLE_PARAMS_REGISTRY); + parameterRegistry = IRwaOracleParameterRegistry( + AaveV3EthereumHorizonCustom.RWA_ORACLE_PARAMS_REGISTRY + ); } function test_asset(address asset, address oracleSource, bool isAdapter) internal { @@ -241,71 +243,77 @@ contract OracleDynamicBoundsTest is OracleDynamicBoundsTestBase { }); function _initEnvironment() internal virtual { - expectedParams[AaveV3HorizonEthereum.USTB_ADDRESS] = USTB_EXPECTED_PARAMS; - expectedParams[AaveV3HorizonEthereum.USCC_ADDRESS] = USCC_EXPECTED_PARAMS; - expectedParams[AaveV3HorizonEthereum.USYC_ADDRESS] = USYC_EXPECTED_PARAMS; - expectedParams[AaveV3HorizonEthereum.JTRSY_ADDRESS] = JTRSY_EXPECTED_PARAMS; - expectedParams[AaveV3HorizonEthereum.JAAA_ADDRESS] = JAAA_EXPECTED_PARAMS; - expectedParams[AaveV3HorizonEthereum.VBILL_ADDRESS] = VBILL_EXPECTED_PARAMS; - - newAggregators[AaveV3HorizonEthereum.USTB_ADDRESS] = NewAggregator({ + expectedParams[AaveV3EthereumHorizonCustom.USTB_UNDERLYING] = USTB_EXPECTED_PARAMS; + expectedParams[AaveV3EthereumHorizonCustom.USCC_UNDERLYING] = USCC_EXPECTED_PARAMS; + expectedParams[AaveV3EthereumHorizonCustom.USYC_UNDERLYING] = USYC_EXPECTED_PARAMS; + expectedParams[AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING] = JTRSY_EXPECTED_PARAMS; + expectedParams[AaveV3EthereumHorizonCustom.JAAA_UNDERLYING] = JAAA_EXPECTED_PARAMS; + expectedParams[AaveV3EthereumHorizonCustom.VBILL_UNDERLYING] = VBILL_EXPECTED_PARAMS; + + newAggregators[AaveV3EthereumHorizonCustom.USTB_UNDERLYING] = NewAggregator({ aggregator: USTB_NEW_AGGREGATOR }); - newAggregators[AaveV3HorizonEthereum.USCC_ADDRESS] = NewAggregator({ + newAggregators[AaveV3EthereumHorizonCustom.USCC_UNDERLYING] = NewAggregator({ aggregator: USCC_NEW_AGGREGATOR }); - newAggregators[AaveV3HorizonEthereum.USYC_ADDRESS] = NewAggregator({ + newAggregators[AaveV3EthereumHorizonCustom.USYC_UNDERLYING] = NewAggregator({ aggregator: USYC_NEW_AGGREGATOR }); - newAggregators[AaveV3HorizonEthereum.JTRSY_ADDRESS] = NewAggregator({ + newAggregators[AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING] = NewAggregator({ aggregator: JTRSY_NEW_AGGREGATOR }); - newAggregators[AaveV3HorizonEthereum.JAAA_ADDRESS] = NewAggregator({ + newAggregators[AaveV3EthereumHorizonCustom.JAAA_UNDERLYING] = NewAggregator({ aggregator: JAAA_NEW_AGGREGATOR }); - newAggregators[AaveV3HorizonEthereum.VBILL_ADDRESS] = NewAggregator({ + newAggregators[AaveV3EthereumHorizonCustom.VBILL_UNDERLYING] = NewAggregator({ aggregator: VBILL_NEW_AGGREGATOR }); aaveOracle = IAaveOracle( - IPool(AaveV3HorizonEthereum.POOL).ADDRESSES_PROVIDER().getPriceOracle() + IPool(AaveV3EthereumHorizonCustom.POOL).ADDRESSES_PROVIDER().getPriceOracle() ); } // check that param registry admin are set properly function test_registry_admin() external { - assertEq(parameterRegistry.owner(), AaveV3HorizonEthereum.HORIZON_OPS, 'owner'); - assertEq(parameterRegistry.updater(), AaveV3HorizonEthereum.HORIZON_OPS, 'updater'); + assertEq(parameterRegistry.owner(), AaveV3EthereumHorizonCustom.HORIZON_OPS, 'owner'); + assertEq(parameterRegistry.updater(), AaveV3EthereumHorizonCustom.HORIZON_OPS, 'updater'); } function test_ustb() external virtual { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USTB_ADDRESS); - test_asset(AaveV3HorizonEthereum.USTB_ADDRESS, oracleSource, true); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USTB_UNDERLYING); + test_asset(AaveV3EthereumHorizonCustom.USTB_UNDERLYING, oracleSource, true); } function test_uscc() external virtual { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USCC_ADDRESS); - test_asset(AaveV3HorizonEthereum.USCC_ADDRESS, oracleSource, true); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USCC_UNDERLYING); + test_asset(AaveV3EthereumHorizonCustom.USCC_UNDERLYING, oracleSource, true); } function test_usyc() external virtual { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USYC_ADDRESS); - test_asset(AaveV3HorizonEthereum.USYC_ADDRESS, oracleSource, false); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USYC_UNDERLYING); + test_asset(AaveV3EthereumHorizonCustom.USYC_UNDERLYING, oracleSource, false); } function test_jtrsy() external virtual { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.JTRSY_ADDRESS); - test_asset(AaveV3HorizonEthereum.JTRSY_ADDRESS, oracleSource, true); + address oracleSource = aaveOracle.getSourceOfAsset( + AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING + ); + test_asset(AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING, oracleSource, true); } function test_jaaa() external virtual { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.JAAA_ADDRESS); - test_asset(AaveV3HorizonEthereum.JAAA_ADDRESS, oracleSource, true); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.JAAA_UNDERLYING); + test_asset(AaveV3EthereumHorizonCustom.JAAA_UNDERLYING, oracleSource, true); } function test_vbill() external virtual { // VBILL not deployed yet, get price feed directly from lib - test_asset(AaveV3HorizonEthereum.VBILL_ADDRESS, AaveV3HorizonEthereum.VBILL_PRICE_FEED, false); + test_asset( + AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, + AaveV3EthereumHorizonCustom.VBILL_PRICE_FEED, + false + ); } } @@ -318,38 +326,49 @@ contract OracleDynamicBoundsPostMigrationTest is OracleDynamicBoundsTest { } function test_ustb() public virtual override { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USTB_ADDRESS); - _printAssetPrice(AaveV3HorizonEthereum.USTB_ADDRESS, oracleSource); - test_aggregator_from_registry(AaveV3HorizonEthereum.USTB_ADDRESS, USTB_NEW_AGGREGATOR); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USTB_UNDERLYING); + _printAssetPrice(AaveV3EthereumHorizonCustom.USTB_UNDERLYING, oracleSource); + test_aggregator_from_registry(AaveV3EthereumHorizonCustom.USTB_UNDERLYING, USTB_NEW_AGGREGATOR); } function test_uscc() public virtual override { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USCC_ADDRESS); - _printAssetPrice(AaveV3HorizonEthereum.USCC_ADDRESS, oracleSource); - test_aggregator_from_registry(AaveV3HorizonEthereum.USCC_ADDRESS, USCC_NEW_AGGREGATOR); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USCC_UNDERLYING); + _printAssetPrice(AaveV3EthereumHorizonCustom.USCC_UNDERLYING, oracleSource); + test_aggregator_from_registry(AaveV3EthereumHorizonCustom.USCC_UNDERLYING, USCC_NEW_AGGREGATOR); } function test_usyc() public virtual override { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.USYC_ADDRESS); - _printAssetPrice(AaveV3HorizonEthereum.USYC_ADDRESS, oracleSource); - test_aggregator_from_registry(AaveV3HorizonEthereum.USYC_ADDRESS, USYC_NEW_AGGREGATOR); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.USYC_UNDERLYING); + _printAssetPrice(AaveV3EthereumHorizonCustom.USYC_UNDERLYING, oracleSource); + test_aggregator_from_registry(AaveV3EthereumHorizonCustom.USYC_UNDERLYING, USYC_NEW_AGGREGATOR); } function test_jtrsy() public virtual override { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.JTRSY_ADDRESS); - _printAssetPrice(AaveV3HorizonEthereum.JTRSY_ADDRESS, oracleSource); - test_aggregator_from_registry(AaveV3HorizonEthereum.JTRSY_ADDRESS, JTRSY_NEW_AGGREGATOR); + address oracleSource = aaveOracle.getSourceOfAsset( + AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING + ); + _printAssetPrice(AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING, oracleSource); + test_aggregator_from_registry( + AaveV3EthereumHorizonCustom.JTRSY_UNDERLYING, + JTRSY_NEW_AGGREGATOR + ); } function test_jaaa() public virtual override { - address oracleSource = aaveOracle.getSourceOfAsset(AaveV3HorizonEthereum.JAAA_ADDRESS); - _printAssetPrice(AaveV3HorizonEthereum.JAAA_ADDRESS, oracleSource); - test_aggregator_from_registry(AaveV3HorizonEthereum.JAAA_ADDRESS, JAAA_NEW_AGGREGATOR); + address oracleSource = aaveOracle.getSourceOfAsset(AaveV3EthereumHorizonCustom.JAAA_UNDERLYING); + _printAssetPrice(AaveV3EthereumHorizonCustom.JAAA_UNDERLYING, oracleSource); + test_aggregator_from_registry(AaveV3EthereumHorizonCustom.JAAA_UNDERLYING, JAAA_NEW_AGGREGATOR); } function test_vbill() public virtual override { - _printAssetPrice(AaveV3HorizonEthereum.VBILL_ADDRESS, AaveV3HorizonEthereum.VBILL_PRICE_FEED); - test_aggregator_from_registry(AaveV3HorizonEthereum.VBILL_ADDRESS, VBILL_NEW_AGGREGATOR); + _printAssetPrice( + AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, + AaveV3EthereumHorizonCustom.VBILL_PRICE_FEED + ); + test_aggregator_from_registry( + AaveV3EthereumHorizonCustom.VBILL_UNDERLYING, + VBILL_NEW_AGGREGATOR + ); } function _printAssetPrice(address asset, address oracleSource) internal { diff --git a/tests/horizon/dependencies/IParameterRegistry.sol b/tests/horizon/dependencies/IRwaOracleParameterRegistry.sol similarity index 95% rename from tests/horizon/dependencies/IParameterRegistry.sol rename to tests/horizon/dependencies/IRwaOracleParameterRegistry.sol index 30ec5d26..fdd98928 100644 --- a/tests/horizon/dependencies/IParameterRegistry.sol +++ b/tests/horizon/dependencies/IRwaOracleParameterRegistry.sol @@ -2,7 +2,7 @@ pragma solidity ^0.8.0; /// @dev minimal interface for the Llama Risk RWA Oracle parameter registry -interface IParameterRegistry { +interface IRwaOracleParameterRegistry { function assetExists(address asset) external view returns (bool); function getParametersForAsset( diff --git a/tests/horizon/utils/AaveV3HorizonEthereum.sol b/tests/horizon/utils/AaveV3EthereumHorizonCustom.sol similarity index 53% rename from tests/horizon/utils/AaveV3HorizonEthereum.sol rename to tests/horizon/utils/AaveV3EthereumHorizonCustom.sol index 3c75f700..e99c8412 100644 --- a/tests/horizon/utils/AaveV3HorizonEthereum.sol +++ b/tests/horizon/utils/AaveV3EthereumHorizonCustom.sol @@ -1,21 +1,21 @@ // SPDX-License-Identifier: MIT pragma solidity ^0.8.0; -library AaveV3HorizonEthereum { +library AaveV3EthereumHorizonCustom { address public constant HORIZON_OPS = 0xE6ec1f0Ae6Cd023bd0a9B4d0253BDC755103253c; address public constant HORIZON_EMERGENCY = 0x13B57382c36BAB566E75C72303622AF29E27e1d3; + address public constant HORIZON_EXECUTOR = 0x09e8E1408a68778CEDdC1938729Ea126710E7Dda; // horizon deployments - // address internal constant CONFIG_ENGINE = 0x366D1e3F41Ad5CC699bb8FC0B41323C68d895E2c; + address internal constant CONFIG_ENGINE = 0x30dA3a613c5b492BB4277Aa2a5D81f4759Ba83Af; address internal constant POOL_ADDRESSES_PROVIDER = 0x5D39E06b825C1F2B80bf2756a73e28eFAA128ba0; address internal constant POOL = 0xAe05Cd22df81871bc7cC2a04BeCfb516bFe332C8; address internal constant POOL_CONFIGURATOR = 0x83Cb1B4af26EEf6463aC20AFbAC9c0e2E017202F; address internal constant ACL_MANAGER = 0xEFD5df7b87d2dCe6DD454b4240b3e0A4db562321; address internal constant AAVE_PROTOCOL_DATA_PROVIDER = 0x53519c32f73fE1797d10210c4950fFeBa3b21504; - address internal constant ATOKEN_IMPLEMENTATION = 0xB2668573828029917ffbD1e76270373511818498; - address internal constant RWA_ATOKEN_IMPLEMENTATION = 0x8CA2a49c7Df42E67F9A532F0d383D648fB7Fe4C9; - address internal constant VARIABLE_DEBT_TOKEN_IMPLEMENTATION = - 0x15F03E5dE87c12cb2e2b8e5d6ECEf0a9E21ab269; + address internal constant ATOKEN_IMPL = 0xB2668573828029917ffbD1e76270373511818498; + address internal constant RWA_ATOKEN_IMPL = 0x8CA2a49c7Df42E67F9A532F0d383D648fB7Fe4C9; + address internal constant VARIABLE_DEBT_TOKEN_IMPL = 0x15F03E5dE87c12cb2e2b8e5d6ECEf0a9E21ab269; address internal constant DEFAULT_INTEREST_RATE_STRATEGY = 0x87593272C06f4FC49EC2942eBda0972d2F1Ab521; address internal constant REVENUE_SPLITTER = 0x70CC725B8f05e0f230B05C4e91ABc651E121354f; @@ -23,24 +23,33 @@ library AaveV3HorizonEthereum { address internal constant AAVE_ORACLE = 0x985BcfAB7e0f4EF2606CC5b64FC1A16311880442; // horizon assets - address public constant USTB_ADDRESS = 0x43415eB6ff9DB7E26A15b704e7A3eDCe97d31C4e; + address public constant USTB_UNDERLYING = 0x43415eB6ff9DB7E26A15b704e7A3eDCe97d31C4e; address public constant USTB_PRICE_FEED_ADAPTER = 0x5Ae4D93B9b9626Dc3289e1Afb14b821FD3C95F44; - address public constant USCC_ADDRESS = 0x14d60E7FDC0D71d8611742720E4C50E7a974020c; + address public constant USCC_UNDERLYING = 0x14d60E7FDC0D71d8611742720E4C50E7a974020c; address public constant USCC_PRICE_FEED_ADAPTER = 0x14CB2E810Eb93b79363f489D45a972b609E47230; - address public constant USYC_ADDRESS = 0x136471a34f6ef19fE571EFFC1CA711fdb8E49f2b; + address public constant USYC_UNDERLYING = 0x136471a34f6ef19fE571EFFC1CA711fdb8E49f2b; address public constant USYC_PRICE_FEED = 0xE8E65Fb9116875012F5990Ecaab290B3531DbeB9; - address public constant JTRSY_ADDRESS = 0x8c213ee79581Ff4984583C6a801e5263418C4b86; + address public constant JTRSY_UNDERLYING = 0x8c213ee79581Ff4984583C6a801e5263418C4b86; address public constant JTRSY_PRICE_FEED_ADAPTER = 0xfAB6790E399f0481e1303167c655b3c39ee6e7A0; - address public constant JAAA_ADDRESS = 0x5a0F93D040De44e78F251b03c43be9CF317Dcf64; + address public constant JAAA_UNDERLYING = 0x5a0F93D040De44e78F251b03c43be9CF317Dcf64; address public constant JAAA_PRICE_FEED_ADAPTER = 0xF77f2537dba4ffD60f77fACdfB2c1706364fA03d; - address public constant VBILL_ADDRESS = 0x2255718832bC9fD3bE1CaF75084F4803DA14FF01; + address public constant VBILL_UNDERLYING = 0x2255718832bC9fD3bE1CaF75084F4803DA14FF01; address public constant VBILL_PRICE_FEED = 0x5ed77a9D9b7cc80E9d0D7711024AF38C2643C1c4; + address public constant GHO_UNDERLYING = 0x40D16FC0246aD3160Ccc09B8D0D3A2cD28aE6C2f; + address public constant GHO_PRICE_FEED = 0xD110cac5d8682A3b045D5524a9903E031d70FCCd; + + address public constant USDC_UNDERLYING = 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48; + address public constant USDC_PRICE_FEED = 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6; + + address public constant RLUSD_UNDERLYING = 0x8292Bb45bf1Ee4d140127049757C2E0fF06317eD; + address public constant RLUSD_PRICE_FEED = 0x26C46B7aD0012cA71F2298ada567dC9Af14E7f2A; + // oracle param registry address public constant RWA_ORACLE_PARAMS_REGISTRY = 0x69D55D504BC9556E377b340D19818E736bbB318b; }