From fa6e6595bd1c0079de3a7df1fbb73fffc2aec876 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Pawe=C5=82=20K=C4=99dzia?= <67273035+KedziaPawel@users.noreply.github.com> Date: Mon, 9 Dec 2024 13:25:36 +0100 Subject: [PATCH] chore: add base chain tests --- .env.example | 1 + foundry.toml | 1 + tests/bases/IntegrationTest.sol | 104 +++++++++++- .../tests/protocols/aave/AaveV3Adapter.t.sol | 20 ++- .../tests/protocols/aave/AaveV3Constants.sol | 6 + .../protocols/aave/AaveV3DebtPosition.t.sol | 158 +++++++++++++++++- .../morpho-blue/MorphoBluePosition.t.sol | 26 +++ .../protocols/one-inch/OneInchV5Adapter.t.sol | 138 ++++++++++++++- tests/utils/Constants.sol | 17 ++ tests/utils/common/AssetBalanceUtils.sol | 5 +- .../core/deployment/PersistentContracts.sol | 11 ++ .../core/deployment/V4ReleaseContracts.sol | 19 +++ .../core/deployment/V5ReleaseContracts.sol | 5 + 13 files changed, 500 insertions(+), 11 deletions(-) diff --git a/.env.example b/.env.example index 98099ba61..03066184a 100644 --- a/.env.example +++ b/.env.example @@ -1,6 +1,7 @@ ETHEREUM_NODE_MAINNET= ETHEREUM_NODE_POLYGON= ETHEREUM_NODE_ARBITRUM= +ETHEREUM_NODE_BASE= ETHERSCAN_API_KEY_MAINNET= ETHERSCAN_API_KEY_POLYGON= diff --git a/foundry.toml b/foundry.toml index e8580ac9c..dfa91c057 100644 --- a/foundry.toml +++ b/foundry.toml @@ -27,6 +27,7 @@ optimizer=false mainnet = "${ETHEREUM_NODE_MAINNET}" polygon = "${ETHEREUM_NODE_POLYGON}" arbitrum = "${ETHEREUM_NODE_ARBITRUM}" +base = "${ETHEREUM_NODE_BASE}" [etherscan] mainnet = { key = "${ETHERSCAN_API_KEY_MAINNET}", chain = "mainnet" } diff --git a/tests/bases/IntegrationTest.sol b/tests/bases/IntegrationTest.sol index 5c647c6a5..460bd8b36 100644 --- a/tests/bases/IntegrationTest.sol +++ b/tests/bases/IntegrationTest.sol @@ -11,20 +11,23 @@ import { Contracts as PersistentContracts, getMainnetDeployment as getMainnetPersistentContracts, getPolygonDeployment as getPolygonPersistentContracts, - getArbitrumDeployment as getArbitrumPersistentContracts + getArbitrumDeployment as getArbitrumPersistentContracts, + getBaseChainDeployment as getBaseChainPersistentContracts } from "tests/utils/core/deployment/PersistentContracts.sol"; import {ReleaseConfig} from "tests/utils/core/deployment/DeploymentUtils.sol"; import { Contracts as V4ReleaseContracts, getMainnetDeployment as getV4MainnetReleaseContracts, getPolygonDeployment as getV4PolygonReleaseContracts, - getArbitrumDeployment as getV4ArbitrumReleaseContracts + getArbitrumDeployment as getV4ArbitrumReleaseContracts, + getBaseChainDeployment as getV4BaseChainReleaseContracts } from "tests/utils/core/deployment/V4ReleaseContracts.sol"; import { Contracts as ReleaseContracts, getMainnetDeployment as getMainnetReleaseContracts, getPolygonDeployment as getPolygonReleaseContracts, - getArbitrumDeployment as getArbitrumReleaseContracts + getArbitrumDeployment as getArbitrumReleaseContracts, + getBaseChainDeployment as getBaseReleaseContracts } from "tests/utils/core/deployment/V5ReleaseContracts.sol"; import {IERC20} from "tests/interfaces/external/IERC20.sol"; @@ -96,7 +99,7 @@ abstract contract IntegrationTest is CoreUtils { } function setUpLiveArbitrumEnvironment(uint256 _forkBlock) internal { - vm.createSelectFork("polygon", _forkBlock); + vm.createSelectFork("arbitrum", _forkBlock); core.persistent = getArbitrumPersistentContracts(); v4ReleaseContracts = getV4ArbitrumReleaseContracts(); @@ -105,6 +108,16 @@ abstract contract IntegrationTest is CoreUtils { // core.release = getArbitrumReleaseContracts(); } + function setUpLiveBaseChainEnvironment(uint256 _forkBlock) internal { + vm.createSelectFork("base", _forkBlock); + + core.persistent = getBaseChainPersistentContracts(); + v4ReleaseContracts = getV4BaseChainReleaseContracts(); + + // No v5 release live + // core.release = getBaseReleaseContracts(); + } + // Partially-live deployments (persistent layer only) function setUpLiveMainnetEnvironmentWithNewRelease(uint256 _forkBlock) internal { @@ -131,6 +144,14 @@ abstract contract IntegrationTest is CoreUtils { __setUpEnvironment({_config: getDefaultArbitrumConfig(), _persistentContractsAlreadySet: true}); } + function setUpLiveBaseChainEnvironmentWithNewRelease(uint256 _forkBlock) internal { + vm.createSelectFork("base", _forkBlock); + + core.persistent = getBaseChainPersistentContracts(); + + __setUpEnvironment({_config: getDefaultBaseChainConfig(), _persistentContractsAlreadySet: true}); + } + // New deployments function setUpNetworkEnvironment(uint256 _chainId) internal { if (_chainId == ETHEREUM_CHAIN_ID) { @@ -139,6 +160,8 @@ abstract contract IntegrationTest is CoreUtils { setUpPolygonEnvironment(); } else if (_chainId == ARBITRUM_CHAIN_ID) { setUpArbitrumEnvironment(); + } else if (_chainId == BASE_CHAIN_ID) { + setUpBaseChainEnvironment(); } else { revert("setUpNetworkEnvironment: Unsupported network"); } @@ -151,6 +174,8 @@ abstract contract IntegrationTest is CoreUtils { setUpPolygonEnvironment(_forkBlock); } else if (_chainId == ARBITRUM_CHAIN_ID) { setUpArbitrumEnvironment(_forkBlock); + } else if (_chainId == BASE_CHAIN_ID) { + setUpBaseChainEnvironment(_forkBlock); } else { revert("setUpNetworkEnvironment: Unsupported network"); } @@ -168,6 +193,10 @@ abstract contract IntegrationTest is CoreUtils { setUpArbitrumEnvironment(ARBITRUM_BLOCK_LATEST); } + function setUpBaseChainEnvironment() internal { + setUpBaseChainEnvironment(BASE_BLOCK_LATEST); + } + function setUpMainnetEnvironment(uint256 _forkBlock) internal { vm.createSelectFork({urlOrAlias: "mainnet", blockNumber: _forkBlock}); @@ -361,6 +390,49 @@ abstract contract IntegrationTest is CoreUtils { __addCorePrimitives(corePrimitives); } + function setUpBaseChainEnvironment(uint256 _forkBlock) internal { + vm.createSelectFork("base", _forkBlock); + + v4ReleaseContracts = getV4BaseChainReleaseContracts(); + + ReleaseConfig memory config = getDefaultBaseChainConfig(); + + __setUpEnvironment({_config: config, _persistentContractsAlreadySet: false}); + + // Deploy minimal asset universe + + // Treat WETH specially and directly add to coreTokens storage (does not require an aggregator) + symbolToCoreToken["WETH"] = IERC20(wethToken); + tokenToIsCore[IERC20(wethToken)] = true; + + address simulatedUsdAddress = address(deployUsdEthSimulatedAggregator(config.chainlinkEthUsdAggregatorAddress)); + + CorePrimitiveInput[] memory corePrimitives = new CorePrimitiveInput[](2); + // TODO: ucomment this when the real MLN aggregator address is available + // System primitives + // corePrimitives[0] = CorePrimitiveInput({ + // symbol: "MLN", + // assetAddress: BASE_MLN, + // aggregatorAddress: BASE_MLN_ETH_AGGREGATOR, + // rateAsset: IChainlinkPriceFeedMixinProd.RateAsset.ETH + // }); + // Extra primitives + corePrimitives[0] = CorePrimitiveInput({ + symbol: "USD", + assetAddress: simulatedUsdAddress, + aggregatorAddress: simulatedUsdAddress, + rateAsset: IChainlinkPriceFeedMixinProd.RateAsset.ETH + }); + corePrimitives[1] = CorePrimitiveInput({ + symbol: "USDC", + assetAddress: BASE_USDC, + aggregatorAddress: BASE_USDC_USD_AGGREGATOR, + rateAsset: IChainlinkPriceFeedMixinProd.RateAsset.USD + }); + + __addCorePrimitives(corePrimitives); + } + function setUpStandaloneEnvironment() internal { // Warp beyond Chainlink aggregator staleness threshold uint256 chainlinkStaleRateThreshold = 3650 days; @@ -546,6 +618,30 @@ abstract contract IntegrationTest is CoreUtils { }); } + function getDefaultBaseChainConfig() internal returns (ReleaseConfig memory) { + address mlnBurner = makeAddr("MlnBurner"); + + return ReleaseConfig({ + // Chainlink + chainlinkEthUsdAggregatorAddress: BASE_ETH_USD_AGGREGATOR, + chainlinkStaleRateThreshold: 3650 days, + // Tokens + mlnTokenAddress: BASE_MLN, + wethTokenAddress: BASE_WETH, + wrappedNativeTokenAddress: BASE_WETH, + // Gas relayer + gasRelayDepositCooldown: 1 days, + gasRelayDepositMaxTotal: 1 ether, + gasRelayFeeMaxPercent: 10, + gasRelayHubAddress: address(0), // TODO: lookup real value + gasRelayRelayFeeMaxBase: 0, + gasRelayTrustedForwarderAddress: address(0), // TODO: lookup real value + // Vault settings + vaultMlnBurner: mlnBurner, + vaultPositionsLimit: 20 + }); + } + // ASSET UNIVERSE /// @dev Keep private to avoid accidental use diff --git a/tests/tests/protocols/aave/AaveV3Adapter.t.sol b/tests/tests/protocols/aave/AaveV3Adapter.t.sol index f2bb6dfa8..8ac72cb51 100644 --- a/tests/tests/protocols/aave/AaveV3Adapter.t.sol +++ b/tests/tests/protocols/aave/AaveV3Adapter.t.sol @@ -16,7 +16,9 @@ import { POLYGON_POOL_ADDRESS, POLYGON_POOL_ADDRESS_PROVIDER, ARBITRUM_POOL_ADDRESS, - ARBITRUM_POOL_ADDRESS_PROVIDER + ARBITRUM_POOL_ADDRESS_PROVIDER, + BASE_POOL_ADDRESS, + BASE_POOL_ADDRESS_PROVIDER } from "./AaveV3Constants.sol"; abstract contract AaveV3AdapterTest is AaveAdapterTest, AaveV3Utils { @@ -132,3 +134,19 @@ contract AaveV3AdapterTestArbitrum is AaveV3AdapterTest { super.setUp(); } } + +contract AaveV3AdapterTestBaseChain is AaveV3AdapterTest { + function setUp() public override { + lendingPool = BASE_POOL_ADDRESS; + lendingPoolAddressProvider = BASE_POOL_ADDRESS_PROVIDER; + + setUpBaseChainEnvironment(); + + regular18DecimalUnderlying = IERC20(BASE_WETH); + non18DecimalUnderlying = IERC20(BASE_USDC); + + __registerTokensAndATokensForThem(toArray(address(regular18DecimalUnderlying), address(non18DecimalUnderlying))); + + super.setUp(); + } +} diff --git a/tests/tests/protocols/aave/AaveV3Constants.sol b/tests/tests/protocols/aave/AaveV3Constants.sol index 7bfa33cf0..462b73c1a 100644 --- a/tests/tests/protocols/aave/AaveV3Constants.sol +++ b/tests/tests/protocols/aave/AaveV3Constants.sol @@ -18,3 +18,9 @@ address constant ARBITRUM_POOL_ADDRESS = 0x794a61358D6845594F94dc1DB02A252b5b481 address constant ARBITRUM_POOL_ADDRESS_PROVIDER = 0xa97684ead0e402dC232d5A977953DF7ECBaB3CDb; address constant ARBITRUM_PROTOCOL_DATA_PROVIDER = 0x69FA688f1Dc47d4B5d8029D5a35FB7a548310654; address constant ARBITRUM_REWARDS_CONTROLLER = 0x0C501fB73808e1BD73cBDdd0c99237bbc481Bb58; + +// Base +address constant BASE_POOL_ADDRESS = 0xA238Dd80C259a72e81d7e4664a9801593F98d1c5; +address constant BASE_POOL_ADDRESS_PROVIDER = 0xe20fCBdBfFC4Dd138cE8b2E6FBb6CB49777ad64D; +address constant BASE_PROTOCOL_DATA_PROVIDER = 0xd82a47fdebB5bf5329b09441C3DaB4b5df2153Ad; +address constant BASE_REWARDS_CONTROLLER = 0xf9cc4F0D883F1a1eb2c253bdb46c254Ca51E1F44; diff --git a/tests/tests/protocols/aave/AaveV3DebtPosition.t.sol b/tests/tests/protocols/aave/AaveV3DebtPosition.t.sol index 879f7b55d..47c500c7e 100644 --- a/tests/tests/protocols/aave/AaveV3DebtPosition.t.sol +++ b/tests/tests/protocols/aave/AaveV3DebtPosition.t.sol @@ -32,7 +32,10 @@ import { POLYGON_REWARDS_CONTROLLER, ARBITRUM_POOL_ADDRESS_PROVIDER, ARBITRUM_PROTOCOL_DATA_PROVIDER, - ARBITRUM_REWARDS_CONTROLLER + ARBITRUM_REWARDS_CONTROLLER, + BASE_POOL_ADDRESS_PROVIDER, + BASE_PROTOCOL_DATA_PROVIDER, + BASE_REWARDS_CONTROLLER } from "./AaveV3Constants.sol"; import {AaveV3Utils} from "./AaveV3Utils.sol"; @@ -1144,6 +1147,151 @@ contract AaveV3DebtPositionTestArbitrum is AaveV3DebtPositionTest { } } +contract AaveV3DebtPositionTestBaseChain is AaveV3DebtPositionTest { + function setUp() public virtual override { + setUpBaseChainEnvironment(); + + poolAddressProvider = IAaveV3PoolAddressProvider(BASE_POOL_ADDRESS_PROVIDER); + protocolDataProvider = IAaveV3ProtocolDataProvider(BASE_PROTOCOL_DATA_PROVIDER); + rewardsController = IAaveV3RewardsController(BASE_REWARDS_CONTROLLER); + + super.setUp(); + + // set up all underlyings used in test cases + __registerUnderlyingsAndATokensForThem(toArray(BASE_WETH, BASE_WSTETH, BASE_CBETH, BASE_USDC)); + } + + function test_addCollateral_success() public { + address[] memory underlyings = toArray(BASE_WSTETH, BASE_CBETH, BASE_CBETH); + + uint256[] memory amounts = new uint256[](underlyings.length); + for (uint256 i = 0; i < underlyings.length; i++) { + amounts[i] = (i + 1) * assetUnit(IERC20(underlyings[i])); + } + + __test_addCollateral_success({ + _aTokens: __getATokensAddresses(underlyings), + _amounts: amounts, + _fromUnderlying: false + }); + } + + function test_addCollateralFromUnderlying_success() public { + address[] memory underlyings = toArray(BASE_WSTETH, BASE_CBETH, BASE_CBETH); + + uint256[] memory amounts = new uint256[](underlyings.length); + for (uint256 i = 0; i < underlyings.length; i++) { + amounts[i] = (i + 1) * assetUnit(IERC20(underlyings[i])); + } + + __test_addCollateral_success({ + _aTokens: __getATokensAddresses(underlyings), + _amounts: amounts, + _fromUnderlying: true + }); + } + + function test_removeCollateralToATokens_success() public { + __test_removeCollateral_success({_toUnderlying: true}); + } + + function test_removeCollateralToUnderlyings_success() public { + __test_removeCollateral_success({_toUnderlying: false}); + } + + function test_borrow_success() public { + address[] memory aTokensCollateral = toArray(__getATokenAddress(BASE_WETH)); + + uint256[] memory aTokensCollateralAmounts = toArray(100 * assetUnit(IERC20(aTokensCollateral[0]))); + + address[] memory underlyingsToBorrow = new address[](3); + underlyingsToBorrow[0] = BASE_USDC; + underlyingsToBorrow[1] = BASE_WSTETH; + underlyingsToBorrow[2] = BASE_WSTETH; + + uint256[] memory underlyingsToBorrowAmounts = new uint256[](3); + underlyingsToBorrowAmounts[0] = 10_000 * assetUnit(IERC20(underlyingsToBorrow[0])); + underlyingsToBorrowAmounts[1] = 1 * assetUnit(IERC20(underlyingsToBorrow[1])); + underlyingsToBorrowAmounts[2] = 2 * assetUnit(IERC20(underlyingsToBorrow[2])); + + __test_borrow_success({ + _aTokensCollateral: aTokensCollateral, + _aTokensCollateralAmounts: aTokensCollateralAmounts, + _underlyingsToBorrow: underlyingsToBorrow, + _underlyingsToBorrowAmounts: underlyingsToBorrowAmounts + }); + } + + function test_repayBorrow_success() public { + address[] memory aTokensCollateral = toArray(__getATokenAddress(BASE_WETH)); + + uint256[] memory aTokensCollateralAmounts = toArray(40 * assetUnit(IERC20(aTokensCollateral[0]))); + + address[] memory underlyingsToBorrowAndRepay = new address[](3); + underlyingsToBorrowAndRepay[0] = BASE_USDC; + underlyingsToBorrowAndRepay[1] = BASE_WSTETH; + underlyingsToBorrowAndRepay[2] = BASE_WETH; + + uint256[] memory underlyingsToBorrowAmounts = new uint256[](3); + underlyingsToBorrowAmounts[0] = 10_000 * assetUnit(IERC20(underlyingsToBorrowAndRepay[0])); + underlyingsToBorrowAmounts[1] = 2 * assetUnit(IERC20(underlyingsToBorrowAndRepay[1])); + underlyingsToBorrowAmounts[2] = 1 * assetUnit(IERC20(underlyingsToBorrowAndRepay[2])); + + uint256[] memory underlyingsVaultAmounts = new uint256[](3); + underlyingsVaultAmounts[0] = 5_000 * assetUnit(IERC20(underlyingsToBorrowAndRepay[0])); + underlyingsVaultAmounts[1] = 3 * assetUnit(IERC20(underlyingsToBorrowAndRepay[1])); + underlyingsVaultAmounts[2] = 1 * assetUnit(IERC20(underlyingsToBorrowAndRepay[2])); + + uint256[] memory underlyingsToRepayAmounts = new uint256[](3); + underlyingsToRepayAmounts[0] = 5_000 * assetUnit(IERC20(underlyingsToBorrowAndRepay[0])); + underlyingsToRepayAmounts[1] = type(uint256).max; + underlyingsToRepayAmounts[2] = 1 * assetUnit(IERC20(underlyingsToBorrowAndRepay[2])); + + __test_repayBorrow_success({ + _aTokensCollateral: aTokensCollateral, + _aTokensCollateralAmounts: aTokensCollateralAmounts, + _underlyingsToBorrowAndRepay: underlyingsToBorrowAndRepay, + _underlyingsToBorrowAmounts: underlyingsToBorrowAmounts, + _underlyingsVaultAmounts: underlyingsVaultAmounts, + _underlyingsToRepayAmounts: underlyingsToRepayAmounts + }); + } + + function test_setUseReserveAsCollateral_success() public { + __test_setUseReserveAsCollateral_success({_underlying: BASE_USDC}); + } + + function __test_removeCollateral_success(bool _toUnderlying) internal { + address[] memory aTokens = new address[](5); + aTokens[0] = __getATokenAddress(BASE_WETH); + aTokens[1] = __getATokenAddress(BASE_WSTETH); + aTokens[2] = __getATokenAddress(BASE_WSTETH); + aTokens[3] = __getATokenAddress(BASE_CBETH); + aTokens[4] = __getATokenAddress(BASE_USDC); + + uint256[] memory amountsToAdd = new uint256[](5); + amountsToAdd[0] = 3 * assetUnit(IERC20(aTokens[0])); + amountsToAdd[1] = 3 * assetUnit(IERC20(aTokens[1])); + amountsToAdd[2] = 3 * assetUnit(IERC20(aTokens[2])); + amountsToAdd[3] = 100 * assetUnit(IERC20(aTokens[3])); + amountsToAdd[4] = 15_000 * assetUnit(IERC20(aTokens[4])); + + uint256[] memory amountsToRemove = new uint256[](5); + amountsToRemove[0] = 3 * assetUnit(IERC20(aTokens[0])); + amountsToRemove[1] = 3 * assetUnit(IERC20(aTokens[1])); + amountsToRemove[2] = 3 * assetUnit(IERC20(aTokens[2])); + amountsToRemove[3] = type(uint256).max; + amountsToRemove[4] = 10_000 * assetUnit(IERC20(aTokens[4])); + + __test_removeCollateral_success({ + _aTokens: aTokens, + _amountsToAdd: amountsToAdd, + _amountsToRemove: amountsToRemove, + _toUnderlying: _toUnderlying + }); + } +} + contract AaveV3DebtPositionTestEthereumV4 is AaveV3DebtPositionTestEthereum { function setUp() public override { version = EnzymeVersion.V4; @@ -1167,3 +1315,11 @@ contract AaveV3DebtPositionTestArbitrumV4 is AaveV3DebtPositionTestArbitrum { super.setUp(); } } + +contract AaveV3DebtPositionTestBaseChainV4 is AaveV3DebtPositionTestBaseChain { + function setUp() public override { + version = EnzymeVersion.V4; + + super.setUp(); + } +} diff --git a/tests/tests/protocols/morpho-blue/MorphoBluePosition.t.sol b/tests/tests/protocols/morpho-blue/MorphoBluePosition.t.sol index f70058774..f10e2ec04 100644 --- a/tests/tests/protocols/morpho-blue/MorphoBluePosition.t.sol +++ b/tests/tests/protocols/morpho-blue/MorphoBluePosition.t.sol @@ -23,6 +23,10 @@ import {IMorphoBluePositionParser} from "tests/interfaces/internal/IMorphoBluePo address constant ETHEREUM_MORPHO_BLUE = 0xBBBBBbbBBb9cC5e90e3b3Af64bdAF62C37EEFFCb; bytes32 constant ETHEREUM_MORPHO_USDC_WETH_MARKET = 0x7dde86a1e94561d9690ec678db673c1a6396365f7d1d65e129c5fff0990ff758; +// BASE MAINNET CONSTANTS +address constant BASE_MORPHO_BLUE = ETHEREUM_MORPHO_BLUE; +bytes32 constant BASE_MORPHO_USDC_WETH_MARKET = 0x8793cf302b8ffd655ab97bd1c695dbd967807e8367a65cb2f4edaf1380ba1bda; + abstract contract MorphoBlueTestBase is IntegrationTest { event MarketIdAdded(bytes32 indexed marketId); @@ -628,3 +632,25 @@ contract MorphoBlueUsdcWethTestEthereumV4 is MorphoBlueTestBase { }); } } + +contract MorphoBlueUsdcWethTestBaseChain is MorphoBlueTestBase { + function setUp() public override { + __initialize({ + _version: EnzymeVersion.Current, + _morphoBlueAddress: BASE_MORPHO_BLUE, + _morphoBlueMarketId: BASE_MORPHO_USDC_WETH_MARKET, + _chainId: BASE_CHAIN_ID + }); + } +} + +contract MorphoBlueUsdcWethTestBaseChainV4 is MorphoBlueTestBase { + function setUp() public override { + __initialize({ + _version: EnzymeVersion.V4, + _morphoBlueAddress: BASE_MORPHO_BLUE, + _morphoBlueMarketId: BASE_MORPHO_USDC_WETH_MARKET, + _chainId: BASE_CHAIN_ID + }); + } +} diff --git a/tests/tests/protocols/one-inch/OneInchV5Adapter.t.sol b/tests/tests/protocols/one-inch/OneInchV5Adapter.t.sol index 7e9ffa757..efc3e71ee 100644 --- a/tests/tests/protocols/one-inch/OneInchV5Adapter.t.sol +++ b/tests/tests/protocols/one-inch/OneInchV5Adapter.t.sol @@ -19,8 +19,8 @@ address constant POLYGON_ONE_INCH_EXECUTOR = ETHEREUM_ONE_INCH_EXECUTOR; address constant ARBITRUM_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS = ETHEREUM_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS; address constant ARBITRUM_ONE_INCH_EXECUTOR = ETHEREUM_ONE_INCH_EXECUTOR; -// A specific block is required because we have retrieved data from a particular block -uint256 constant ETHEREUM_BLOCK_ONE_INCH_V5_TIME_SENSITIVE = 19_518_890; // March 26th, 2024 +address constant BASE_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS = ETHEREUM_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS; +address constant BASE_ONE_INCH_EXECUTOR = ETHEREUM_ONE_INCH_EXECUTOR; // "data" in the TakeOrders is taken from the One Inch api https://api.1inch.dev/swap/v5.2 abstract contract TestBase is IntegrationTest { @@ -594,7 +594,7 @@ abstract contract TestBasePolygon is TestBase { _chainId: POLYGON_CHAIN_ID, _version: _version, _oneInchV5ExchangeAddress: POLYGON_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS, - _forkBlock: 55_136_740 + _forkBlock: POLYGON_BLOCK_TIME_SENSITIVE_ONE_INCH_V5 }); } @@ -739,7 +739,7 @@ abstract contract TestBaseArbitrum is TestBase { _chainId: ARBITRUM_CHAIN_ID, _version: _version, _oneInchV5ExchangeAddress: ARBITRUM_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS, - _forkBlock: 55_136_740 // TODO: REPLACE THIS + _forkBlock: 55_136_740 // TODO: REPLACE THIS, and assign this value into the ARBITRUM_BLOCK_TIME_SENSITIVE_ONE_INCH_V5 in Constants.sol }); } @@ -877,6 +877,123 @@ abstract contract TestBaseArbitrum is TestBase { } } +abstract contract TestBaseBaseChain is TestBase { + function __initialize(EnzymeVersion _version) internal { + __initialize({ + _chainId: BASE_CHAIN_ID, + _version: _version, + _oneInchV5ExchangeAddress: BASE_ONE_INCH_V5_AGGREGATION_ROUTER_ADDRESS, + _forkBlock: BASE_CHAIN_BLOCK_TIME_SENSITIVE_ONE_INCH_V5 + }); + } + + function test_takeMultipleOrders_notAllowedFailure_success() public { + TakeOrder[] memory takeOrders = new TakeOrder[](2); + + takeOrders[0] = TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_USDC, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 1 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 3601930662, // 3601.930662 USDC + flags: 4 + }), + data: hex"00000000000000000000000000000000000000000000000000022e00001a0020d6bdbf78420000000000000000000000000000000000000600a0c9e75c48000000000000000007030000000000000000000000000000000000000000000000000001e600018300a007e5c0d200000000000000000000000000000000000000000000000000015f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501f6c0a374a483101e04ef5f7ac9bd15d9142bac9542000000000000000000000000000000000000064922616535324976f8dbcef19df0705b95ace86ebb48d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca00243eece7db0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001ee63c1e58172ab388e2e2f6facef59e3c3fa2c4e29011c2d3842000000000000000000000000000000000000061111111254eeb25477b68fb85ed929f73a960582" + }); + takeOrders[1] = TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_DAI, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 2 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 7204961908149106211640, // 7204.961908149106211640 DAI + flags: 4 + }), + data: hex"0000000000000000000000000000000000000002350002070001bd00001a0020d6bdbf78420000000000000000000000000000000000000600a007e5c0d200000000000000000000000000000000000000000000000000017f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501b2cc224c1c9fee385f8ad6a55b4d94e92359dc594200000000000000000000000000000000000006512001538aa697ce8cc8252c70c41452dae86ce22a3e833589fcd6edb6e08f4c7c32d4f71b54bda0291300a4a5dcbcdf000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000050c5725949a6f0c72e6c4a641f24049a917db0cb0000000000000000000000001b55d94b553475e7561fab889bf88fe4f491d29c000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0f2fa6b6650c5725949a6f0c72e6c4a641f24049a917db0cb00000000000000000000000000000000000000000000018694eeb9eff8177b38000000000000000045683028d2c53e8680a06c4eca2750c5725949a6f0c72e6c4a641f24049a917db0cb1111111254eeb25477b68fb85ed929f73a960582" + }); + + __test_takeMultipleOrders_notAllowedFailure_success(takeOrders); + } + + function test_takeMultipleOrders_allowedFailure_success() public { + TakeOrder[] memory takeOrdersSucceed = new TakeOrder[](2); + + takeOrdersSucceed[0] = TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_USDC, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 1 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 3601930662, // 3601.930662 USDC + flags: 4 + }), + data: hex"00000000000000000000000000000000000000000000000000022e00001a0020d6bdbf78420000000000000000000000000000000000000600a0c9e75c48000000000000000007030000000000000000000000000000000000000000000000000001e600018300a007e5c0d200000000000000000000000000000000000000000000000000015f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501f6c0a374a483101e04ef5f7ac9bd15d9142bac9542000000000000000000000000000000000000064922616535324976f8dbcef19df0705b95ace86ebb48d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca00243eece7db0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001ee63c1e58172ab388e2e2f6facef59e3c3fa2c4e29011c2d3842000000000000000000000000000000000000061111111254eeb25477b68fb85ed929f73a960582" + }); + takeOrdersSucceed[1] = TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_DAI, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 2 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 7204961908149106211640, // 7204.961908149106211640 DAI + flags: 4 + }), + data: hex"0000000000000000000000000000000000000002350002070001bd00001a0020d6bdbf78420000000000000000000000000000000000000600a007e5c0d200000000000000000000000000000000000000000000000000017f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501b2cc224c1c9fee385f8ad6a55b4d94e92359dc594200000000000000000000000000000000000006512001538aa697ce8cc8252c70c41452dae86ce22a3e833589fcd6edb6e08f4c7c32d4f71b54bda0291300a4a5dcbcdf000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000050c5725949a6f0c72e6c4a641f24049a917db0cb0000000000000000000000001b55d94b553475e7561fab889bf88fe4f491d29c000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0f2fa6b6650c5725949a6f0c72e6c4a641f24049a917db0cb00000000000000000000000000000000000000000000018694eeb9eff8177b38000000000000000045683028d2c53e8680a06c4eca2750c5725949a6f0c72e6c4a641f24049a917db0cb1111111254eeb25477b68fb85ed929f73a960582" + }); + + TakeOrder[] memory takeOrdersFailed = new TakeOrder[](1); + takeOrdersFailed[0] = TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_DAI, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 2 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 8204961908149106211640, // 8204.9619081491062116400 DAI + flags: 4 + }), + data: hex"0000000000000000000000000000000000000002350002070001bd00001a0020d6bdbf78420000000000000000000000000000000000000600a007e5c0d200000000000000000000000000000000000000000000000000017f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501b2cc224c1c9fee385f8ad6a55b4d94e92359dc594200000000000000000000000000000000000006512001538aa697ce8cc8252c70c41452dae86ce22a3e833589fcd6edb6e08f4c7c32d4f71b54bda0291300a4a5dcbcdf000000000000000000000000833589fcd6edb6e08f4c7c32d4f71b54bda0291300000000000000000000000050c5725949a6f0c72e6c4a641f24049a917db0cb0000000000000000000000001b55d94b553475e7561fab889bf88fe4f491d29c000000000000000000000000e37e799d5077682fa0a244d46e5649f71457bd09ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a0f2fa6b6650c5725949a6f0c72e6c4a641f24049a917db0cb00000000000000000000000000000000000000000000018694eeb9eff8177b38000000000000000045683028d2c53e8680a06c4eca2750c5725949a6f0c72e6c4a641f24049a917db0cb1111111254eeb25477b68fb85ed929f73a960582" + }); + + bytes[] memory takeOrdersFailedReasons = new bytes[](1); + takeOrdersFailedReasons[0] = abi.encodePacked(ReturnAmountIsNotEnough.selector); + + __test_takeMultipleOrders_allowedFailure_success({ + _takeOrdersSucceed: takeOrdersSucceed, + _takeOrdersFailed: takeOrdersFailed, + _takeOrdersFailedReasons: takeOrdersFailedReasons + }); + } + + function test_takeOrder_success() public { + __test_takeOrder_success( + TakeOrder({ + executor: BASE_ONE_INCH_EXECUTOR, + swapDescription: IOneInchV5AggregationRouter.SwapDescription({ + srcToken: BASE_WETH, + dstToken: BASE_USDC, + srcReceiver: payable(BASE_ONE_INCH_EXECUTOR), + dstReceiver: payable(vaultProxyAddress), + amount: 1 * assetUnit(IERC20(BASE_WETH)), + minReturnAmount: 3601930662, // 3601.930662 USDC + flags: 4 + }), + data: hex"00000000000000000000000000000000000000000000000000022e00001a0020d6bdbf78420000000000000000000000000000000000000600a0c9e75c48000000000000000007030000000000000000000000000000000000000000000000000001e600018300a007e5c0d200000000000000000000000000000000000000000000000000015f00004f02a00000000000000000000000000000000000000000000000000000000000000001ee63c1e501f6c0a374a483101e04ef5f7ac9bd15d9142bac9542000000000000000000000000000000000000064922616535324976f8dbcef19df0705b95ace86ebb48d9aaec86b65d86f6a7b5b1b0c42ffa531710b6ca00243eece7db0000000000000000000000001111111254eeb25477b68fb85ed929f73a960582000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9b00000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000002a00000000000000000000000000000000000000000000000000000000000000001ee63c1e58172ab388e2e2f6facef59e3c3fa2c4e29011c2d3842000000000000000000000000000000000000061111111254eeb25477b68fb85ed929f73a960582" + }) + ); + } +} + contract OneInchV5AdapterEthereumTest is TestBaseEthereum { function setUp() public override { __initialize(EnzymeVersion.Current); @@ -912,3 +1029,16 @@ contract OneInchV5AdapterPolygonTestV4 is TestBasePolygon { // __initialize(EnzymeVersion.V4); // } // } + +contract OneInchV5AdapterBaseTest is TestBaseBaseChain { + function setUp() public override { + __initialize(EnzymeVersion.Current); + } +} + +// TODO: uncomment when the Base asset universe will be registered, and bump the test block number +// contract OneInchV5AdapterBaseTestV4 is TestBaseBaseChain { +// function setUp() public override { +// __initialize(EnzymeVersion.V4); +// } +// } diff --git a/tests/utils/Constants.sol b/tests/utils/Constants.sol index 5d8919142..a83a2ced2 100644 --- a/tests/utils/Constants.sol +++ b/tests/utils/Constants.sol @@ -19,6 +19,7 @@ abstract contract Constants { uint256 internal constant ETHEREUM_CHAIN_ID = 1; uint256 internal constant POLYGON_CHAIN_ID = 137; uint256 internal constant ARBITRUM_CHAIN_ID = 42161; + uint256 internal constant BASE_CHAIN_ID = 8453; // Miscellaneous uint8 internal constant CHAINLINK_AGGREGATOR_DECIMALS_ETH = 18; @@ -40,10 +41,14 @@ abstract contract Constants { uint256 internal constant POLYGON_BLOCK_LATEST = 61606585; // Sep 9th, 2024 uint256 internal constant POLYGON_BLOCK_TIME_SENSITIVE = 54900000; // March 21st, 2024 + uint256 internal constant POLYGON_BLOCK_TIME_SENSITIVE_ONE_INCH_V5 = 55136740; // March 27th, 2024 uint256 internal constant ARBITRUM_BLOCK_LATEST = 278101140; // Nov 25th, 2024 uint256 internal constant ARBITRUM_BLOCK_TIME_SENSITIVE = 231099000; // July 11th, 2024 + uint256 internal constant BASE_BLOCK_LATEST = 23180290; // Dec 2nd, 2024 + uint256 internal constant BASE_CHAIN_BLOCK_TIME_SENSITIVE_ONE_INCH_V5 = 23218719; // Dec 3rd, 2024 + // Network assets address internal constant NATIVE_ASSET_ADDRESS = 0xEeeeeEeeeEeEeeEeEeEeeEEEeeeeEeeeeeeeEEeE; @@ -98,6 +103,13 @@ abstract contract Constants { address internal constant ARBITRUM_WBTC = 0x2f2a2543B76A4166549F7aaB2e75Bef0aefC5B0f; address internal constant ARBITRUM_WETH = 0x82aF49447D8a07e3bd95BD0d56f35241523fBab1; + address internal constant BASE_CBETH = 0x2Ae3F1Ec7F1F5012CFEab0185bfc7aa3cf0DEc22; + address internal constant BASE_DAI = 0x50c5725949A6F0c72E6C4a641F24049A917DB0Cb; + address internal constant BASE_MLN = 0x7C298664BD6582f6f264c2Cb5a4B9cC09b6E3889; + address internal constant BASE_USDC = 0x833589fCD6eDb6E08f4c7C32D4f71b54bdA02913; + address internal constant BASE_WETH = 0x4200000000000000000000000000000000000006; + address internal constant BASE_WSTETH = 0xc1CBa3fCea344f92D9239c08C0568f6F2F0ee452; + // Network Chainlink aggregators address internal constant ETHEREUM_BAL_ETH_AGGREGATOR = 0xC1438AA3823A6Ba0C159CfA8D98dF5A994bA120b; address internal constant ETHEREUM_DAI_ETH_AGGREGATOR = 0x773616E4d11A78F511299002da57A0a94577F1f4; @@ -124,4 +136,9 @@ abstract contract Constants { address internal constant ARBITRUM_MLN_ETH_AGGREGATOR = 0xb7c8Fb1dB45007F98A68Da0588e1AA524C317f27; address internal constant ARBITRUM_USDC_USD_AGGREGATOR = 0x50834F3163758fcC1Df9973b6e91f0F0F0434aD3; address internal constant ARBITRUM_USDT_USD_AGGREGATOR = 0x3f3f5dF88dC9F13eac63DF89EC16ef6e7E25DdE7; + + address internal constant BASE_ETH_USD_AGGREGATOR = 0x71041dddad3595F9CEd3DcCFBe3D1F4b0a16Bb70; + address internal constant BASE_MLN_ETH_AGGREGATOR = 0x0000000000000000000000000000000000000000; // TODO: add this + address internal constant BASE_USDC_USD_AGGREGATOR = 0x7e860098F58bBFC8648a4311b374B1D669a2bc6B; + address internal constant BASE_WSTETH_ETH_AGGREGATOR = 0x43a5C292A453A3bF3606fa856197f09D7B74251a; } diff --git a/tests/utils/common/AssetBalanceUtils.sol b/tests/utils/common/AssetBalanceUtils.sol index ba671c5fe..bf3e6b567 100644 --- a/tests/utils/common/AssetBalanceUtils.sol +++ b/tests/utils/common/AssetBalanceUtils.sol @@ -11,7 +11,8 @@ import { import { ETHEREUM_POOL_ADDRESS as ETHEREUM_AAVE_V3_POOL_ADDRESS, POLYGON_POOL_ADDRESS as POLYGON_AAVE_V3_POOL_ADDRESS, - ARBITRUM_POOL_ADDRESS as ARBITRUM_AAVE_V3_POOL_ADDRESS + ARBITRUM_POOL_ADDRESS as ARBITRUM_AAVE_V3_POOL_ADDRESS, + BASE_POOL_ADDRESS as BASE_AAVE_V3_POOL_ADDRESS } from "tests/tests/protocols/aave/AaveV3Constants.sol"; import { @@ -125,6 +126,8 @@ abstract contract AssetBalanceUtils is CommonUtilsBase { return POLYGON_AAVE_V3_POOL_ADDRESS; } else if (block.chainid == ARBITRUM_CHAIN_ID) { return ARBITRUM_AAVE_V3_POOL_ADDRESS; + } else if (block.chainid == BASE_CHAIN_ID) { + return BASE_AAVE_V3_POOL_ADDRESS; } } diff --git a/tests/utils/core/deployment/PersistentContracts.sol b/tests/utils/core/deployment/PersistentContracts.sol index 72c688253..97f0d2a5e 100644 --- a/tests/utils/core/deployment/PersistentContracts.sol +++ b/tests/utils/core/deployment/PersistentContracts.sol @@ -49,3 +49,14 @@ function getArbitrumDeployment() pure returns (Contracts memory contracts_) { uintListRegistry: IUintListRegistry(0xC438E48F5D2F99eb4a2b9865F8cccfC9915f227A) }); } + +function getBaseChainDeployment() pure returns (Contracts memory contracts_) { + return Contracts({ + addressListRegistry: IAddressListRegistry(0x42232ff4F38639ED942e0C76723e76e1A0588899), + dispatcher: IDispatcher(0xD79FCD6eb56115f9757EC4C90fc2C5D143f83C16), + externalPositionFactory: IExternalPositionFactory(0x097C44Da5E720641a60c2C438C0C921D28968a00), + globalConfigProxy: IGlobalConfigLib(0x65b8f1f82CE8a6b72Db0937c522A52Af5693D4d3), + protocolFeeReserveProxy: IProtocolFeeReserveLib(0x410F5bC40668b729675DACB48A3467861Bb36C50), + uintListRegistry: IUintListRegistry(0x305357dBb4f4A65601751eb25D275Ad071466CD2) + }); +} diff --git a/tests/utils/core/deployment/V4ReleaseContracts.sol b/tests/utils/core/deployment/V4ReleaseContracts.sol index db516a6d5..b330b8cf6 100644 --- a/tests/utils/core/deployment/V4ReleaseContracts.sol +++ b/tests/utils/core/deployment/V4ReleaseContracts.sol @@ -84,3 +84,22 @@ function getArbitrumDeployment() pure returns (Contracts memory contracts_) { usdEthSimulatedAggregator: IUsdEthSimulatedAggregator(address(0)) // Not deployed on Arbitrum }); } + +function getBaseChainDeployment() pure returns (Contracts memory contracts_) { + return Contracts({ + // Core + comptrollerLibAddress: 0x67132b2D9B31fFcab67C9216f3FA937B259673B8, + fundDeployer: IFundDeployer(0xbB274DF654F71827cca120e0B916AEC1f2cEaaEb), + vaultLibAddress: 0x944d01bF533Ed041d9947826429F086bf56C5856, + // Extensions + externalPositionManager: IExternalPositionManager(0xE7E6db86B10E2CF1F409eb635998dE81C841330f), + feeManager: IFeeManager(0xa9928195a36ef1C238B1B8B5912B9fBCe7554F73), + integrationManager: IIntegrationManager(0x5D8703b4a08Fd3F698bAFD5389fa25463fb383dD), + policyManager: IPolicyManager(0x7d1a8314c6a56A8312053Bfd5A3b9e4C768E8D24), + // Infrastructure + gasRelayPaymasterFactory: IGasRelayPaymasterFactory(0xc6780E244Fd22f21F019fEC4b802019D17BD558D), + protocolFeeTracker: IProtocolFeeTracker(0x44ddf1831fb1f9CD62Bd07b4C351C826751594A6), + valueInterpreter: IValueInterpreter(0xA76BC052a4D200d851C27312B32c35502824E8e1), + usdEthSimulatedAggregator: IUsdEthSimulatedAggregator(address(0)) // Not deployed on Base + }); +} diff --git a/tests/utils/core/deployment/V5ReleaseContracts.sol b/tests/utils/core/deployment/V5ReleaseContracts.sol index e545b5fdf..6943113aa 100644 --- a/tests/utils/core/deployment/V5ReleaseContracts.sol +++ b/tests/utils/core/deployment/V5ReleaseContracts.sol @@ -41,3 +41,8 @@ function getArbitrumDeployment() pure returns (Contracts memory contracts_) { // placeholder return contracts_; } + +function getBaseChainDeployment() pure returns (Contracts memory contracts_) { + // placeholder + return contracts_; +}