From 24b25470a19bf8b002cc01c48a3f858635ab3762 Mon Sep 17 00:00:00 2001 From: DhairyaSethi <55102840+DhairyaSethi@users.noreply.github.com> Date: Mon, 28 Oct 2024 19:31:46 +0530 Subject: [PATCH] test: improve off ramp tests --- .../ForkBase.t.sol | 102 +++++++++++++----- .../TokenPoolsUpgrade.t.sol | 98 +++++++++++++++-- 2 files changed, 167 insertions(+), 33 deletions(-) diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/ForkBase.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/ForkBase.t.sol index 94fd1d0e14..20dd00cbef 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/ForkBase.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/ForkBase.t.sol @@ -12,6 +12,8 @@ import {Client} from "../../../../../libraries/Client.sol"; import {Internal} from "../../../../../libraries/Internal.sol"; import {UpgradeableLockReleaseTokenPool_Sepolia} from "./LegacyTestnetTokenPools/UpgradeableLockReleaseTokenPool_Sepolia.sol"; import {UpgradeableBurnMintTokenPool_ArbSepolia} from "./LegacyTestnetTokenPools/UpgradeableBurnMintTokenPool_ArbSepolia.sol"; +import {EVM2EVMOffRamp} from "../../../../../offRamp/EVM2EVMOffRamp.sol"; +import {TransparentUpgradeableProxy} from "solidity-utils/contracts/transparent-proxy/TransparentUpgradeableProxy.sol"; interface IRouter is IRouterClient, IRouterBase { struct OffRamp { @@ -23,6 +25,18 @@ interface IRouter is IRouterClient, IRouterBase { function getOffRamps() external view returns (OffRamp[] memory); } +interface IEVM2EVMOffRamp_1_2 is IAny2EVMOffRamp, ITypeAndVersion { + function executeSingleMessage(Internal.EVM2EVMMessage memory message, bytes[] memory offchainTokenData) external; +} + +interface IEVM2EVMOffRamp_1_5 is IAny2EVMOffRamp, ITypeAndVersion { + function executeSingleMessage( + Internal.EVM2EVMMessage calldata message, + bytes[] calldata offchainTokenData, + uint32[] memory tokenGasOverrides + ) external; +} + struct SourceTokenData { bytes sourcePoolAddress; bytes destTokenAddress; @@ -32,7 +46,12 @@ struct SourceTokenData { contract ForkBase is Test { error CallerIsNotARampOnRouter(address caller); + event CCIPSendRequested(Internal.EVM2EVMMessage message); + event Locked(address indexed sender, uint256 amount); + event Burned(address indexed sender, uint256 amount); + event Released(address indexed sender, address indexed recipient, uint256 amount); + event Minted(address indexed sender, address indexed recipient, uint256 amount); struct L1 { UpgradeableLockReleaseTokenPool_Sepolia tokenPool; @@ -40,8 +59,8 @@ contract ForkBase is Test { IERC20 token; IEVM2AnyOnRamp EVM2EVMOnRamp1_2; IEVM2AnyOnRamp EVM2EVMOnRamp1_5; - IAny2EVMOffRamp EVM2EVMOffRamp1_2; - IAny2EVMOffRamp EVM2EVMOffRamp1_5; + IEVM2EVMOffRamp_1_2 EVM2EVMOffRamp1_2; + IEVM2EVMOffRamp_1_5 EVM2EVMOffRamp1_5; address proxyPool; uint64 chainSelector; bytes32 metadataHash; @@ -53,8 +72,8 @@ contract ForkBase is Test { IERC20 token; IEVM2AnyOnRamp EVM2EVMOnRamp1_2; IEVM2AnyOnRamp EVM2EVMOnRamp1_5; - IAny2EVMOffRamp EVM2EVMOffRamp1_2; - IAny2EVMOffRamp EVM2EVMOffRamp1_5; + IEVM2EVMOffRamp_1_2 EVM2EVMOffRamp1_2; + IEVM2EVMOffRamp_1_5 EVM2EVMOffRamp1_5; address proxyPool; uint64 chainSelector; bytes32 metadataHash; @@ -81,8 +100,8 @@ contract ForkBase is Test { l1.token = l1.tokenPool.getToken(); l1.EVM2EVMOnRamp1_2 = IEVM2AnyOnRamp(0xe4Dd3B16E09c016402585a8aDFdB4A18f772a07e); // legacy on ramp l1.EVM2EVMOnRamp1_5 = IEVM2AnyOnRamp(l1.router.getOnRamp(l2.chainSelector)); - l1.EVM2EVMOffRamp1_2 = IAny2EVMOffRamp(0xF18896AB20a09A29e64fdEbA99FDb8EC328f43b1); - l1.EVM2EVMOffRamp1_5 = IAny2EVMOffRamp(0xD2f5edfD4561d6E7599F6c6888Bd353cAFd0c55E); + l1.EVM2EVMOffRamp1_2 = IEVM2EVMOffRamp_1_2(0xF18896AB20a09A29e64fdEbA99FDb8EC328f43b1); + l1.EVM2EVMOffRamp1_5 = IEVM2EVMOffRamp_1_5(0xD2f5edfD4561d6E7599F6c6888Bd353cAFd0c55E); vm.prank(alice); l1.token.approve(address(l1.router), type(uint256).max); deal(address(l1.token), alice, 1000e18); @@ -96,15 +115,15 @@ contract ForkBase is Test { l2.token = l2.tokenPool.getToken(); l2.EVM2EVMOnRamp1_2 = IEVM2AnyOnRamp(0x4205E1Ca0202A248A5D42F5975A8FE56F3E302e9); // legacy on ramp l2.EVM2EVMOnRamp1_5 = IEVM2AnyOnRamp(l2.router.getOnRamp(l1.chainSelector)); - l2.EVM2EVMOffRamp1_2 = IAny2EVMOffRamp(0x1c71f141b4630EBE52d6aF4894812960abE207eB); - l2.EVM2EVMOffRamp1_5 = IAny2EVMOffRamp(0xBed6e9131916d724418C8a6FE810F727302a5c00); + l2.EVM2EVMOffRamp1_2 = IEVM2EVMOffRamp_1_2(0x1c71f141b4630EBE52d6aF4894812960abE207eB); + l2.EVM2EVMOffRamp1_5 = IEVM2EVMOffRamp_1_5(0xBed6e9131916d724418C8a6FE810F727302a5c00); vm.prank(alice); l2.token.approve(address(l2.router), type(uint256).max); deal(address(l2.token), alice, 1000e18); deal(alice, 1000e18); - l1.metadataHash = _generateMetadataHash(l1.chainSelector); - l2.metadataHash = _generateMetadataHash(l2.chainSelector); + l1.metadataHash = _generateMetadataHash(l1.chainSelector, l1.EVM2EVMOnRamp1_5); + l2.metadataHash = _generateMetadataHash(l2.chainSelector, l2.EVM2EVMOnRamp1_5); vm.selectFork(l1.forkId); assertEq(l1.chainSelector, 16015286601757825753); @@ -114,8 +133,8 @@ contract ForkBase is Test { assertEq(ITypeAndVersion(l1.proxyPool).typeAndVersion(), "LockReleaseTokenPoolAndProxy 1.5.0"); assertEq(ITypeAndVersion(address(l1.EVM2EVMOnRamp1_2)).typeAndVersion(), "EVM2EVMOnRamp 1.2.0"); assertEq(ITypeAndVersion(address(l1.EVM2EVMOnRamp1_5)).typeAndVersion(), "EVM2EVMOnRamp 1.5.0"); - assertEq(ITypeAndVersion(address(l1.EVM2EVMOffRamp1_2)).typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); - assertEq(ITypeAndVersion(address(l1.EVM2EVMOffRamp1_5)).typeAndVersion(), "EVM2EVMOffRamp 1.5.0"); + assertEq(l1.EVM2EVMOffRamp1_2.typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); + assertEq(l1.EVM2EVMOffRamp1_5.typeAndVersion(), "EVM2EVMOffRamp 1.5.0"); assertTrue(l1.router.isOffRamp(l2.chainSelector, address(l1.EVM2EVMOffRamp1_2))); assertTrue(l1.router.isOffRamp(l2.chainSelector, address(l1.EVM2EVMOffRamp1_5))); @@ -127,8 +146,8 @@ contract ForkBase is Test { assertEq(ITypeAndVersion(l2.proxyPool).typeAndVersion(), "BurnMintTokenPoolAndProxy 1.5.0"); assertEq(ITypeAndVersion(address(l2.EVM2EVMOnRamp1_2)).typeAndVersion(), "EVM2EVMOnRamp 1.2.0"); assertEq(ITypeAndVersion(address(l2.EVM2EVMOnRamp1_5)).typeAndVersion(), "EVM2EVMOnRamp 1.5.0"); - assertEq(ITypeAndVersion(address(l2.EVM2EVMOffRamp1_2)).typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); - assertEq(ITypeAndVersion(address(l2.EVM2EVMOffRamp1_5)).typeAndVersion(), "EVM2EVMOffRamp 1.5.0"); + assertEq(l2.EVM2EVMOffRamp1_2.typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); + assertEq(l2.EVM2EVMOffRamp1_5.typeAndVersion(), "EVM2EVMOffRamp 1.5.0"); assertTrue(l2.router.isOffRamp(l1.chainSelector, address(l2.EVM2EVMOffRamp1_2))); assertTrue(l2.router.isOffRamp(l1.chainSelector, address(l2.EVM2EVMOffRamp1_5))); @@ -194,10 +213,10 @@ contract ForkBase is Test { return messageEvent; } - function _generateMetadataHash(uint64 sourceChainSelector) internal view returns (bytes32) { + function _generateMetadataHash(uint64 sourceChainSelector, IEVM2AnyOnRamp onRamp) internal view returns (bytes32) { uint64 destChainSelector = sourceChainSelector == l1.chainSelector ? l2.chainSelector : l1.chainSelector; - address onRamp = address(sourceChainSelector == l1.chainSelector ? l1.EVM2EVMOnRamp1_5 : l2.EVM2EVMOnRamp1_5); - return keccak256(abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, sourceChainSelector, destChainSelector, onRamp)); + return + keccak256(abi.encode(Internal.EVM_2_EVM_MESSAGE_HASH, sourceChainSelector, destChainSelector, address(onRamp))); } function _label() internal { @@ -275,7 +294,7 @@ contract ForkPoolBeforeMigration is ForkBase { l2.chainSelector = l1.tokenPool.getSupportedChains()[0]; l1.token = l1.tokenPool.getToken(); l1.EVM2EVMOnRamp1_2 = IEVM2AnyOnRamp(l1.router.getOnRamp(l2.chainSelector)); - l1.EVM2EVMOffRamp1_2 = IAny2EVMOffRamp(0xdb92e73d1D630B5B7aC96840c4df0c591c7Ad23E); + l1.EVM2EVMOffRamp1_2 = IEVM2EVMOffRamp_1_2(0xdb92e73d1D630B5B7aC96840c4df0c591c7Ad23E); vm.prank(alice); l1.token.approve(address(l1.router), type(uint256).max); deal(address(l1.token), alice, 1000e18); @@ -287,7 +306,7 @@ contract ForkPoolBeforeMigration is ForkBase { l1.chainSelector = l2.tokenPool.getSupportedChains()[0]; l2.token = l2.tokenPool.getToken(); l2.EVM2EVMOnRamp1_2 = IEVM2AnyOnRamp(l2.router.getOnRamp(l1.chainSelector)); - l2.EVM2EVMOffRamp1_2 = IAny2EVMOffRamp(0xFf5e1c597c5DFfC896Ab8c7b9d876D513518c4b7); + l2.EVM2EVMOffRamp1_2 = IEVM2EVMOffRamp_1_2(0xFf5e1c597c5DFfC896Ab8c7b9d876D513518c4b7); vm.prank(alice); l2.token.approve(address(l2.router), type(uint256).max); deal(address(l2.token), alice, 1000e18); @@ -298,7 +317,7 @@ contract ForkPoolBeforeMigration is ForkBase { assertEq(address(l1.token), 0xc4bF5CbDaBE595361438F8c6a187bDc330539c60); assertEq(ITypeAndVersion(address(l1.router)).typeAndVersion(), "Router 1.2.0"); assertEq(ITypeAndVersion(address(l1.EVM2EVMOnRamp1_2)).typeAndVersion(), "EVM2EVMOnRamp 1.2.0"); - assertEq(ITypeAndVersion(address(l1.EVM2EVMOffRamp1_2)).typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); + assertEq(l1.EVM2EVMOffRamp1_2.typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); assertTrue(l1.router.isOffRamp(l2.chainSelector, address(l1.EVM2EVMOffRamp1_2))); // assert only one off ramp is set IRouter.OffRamp[] memory offRamps = l1.router.getOffRamps(); @@ -313,7 +332,7 @@ contract ForkPoolBeforeMigration is ForkBase { assertEq(address(l2.token), 0xb13Cfa6f8B2Eed2C37fB00fF0c1A59807C585810); assertEq(ITypeAndVersion(address(l2.router)).typeAndVersion(), "Router 1.2.0"); assertEq(ITypeAndVersion(address(l2.EVM2EVMOnRamp1_2)).typeAndVersion(), "EVM2EVMOnRamp 1.2.0"); - assertEq(ITypeAndVersion(address(l2.EVM2EVMOffRamp1_2)).typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); + assertEq(l2.EVM2EVMOffRamp1_2.typeAndVersion(), "EVM2EVMOffRamp 1.2.0"); assertTrue(l2.router.isOffRamp(l1.chainSelector, address(l2.EVM2EVMOffRamp1_2))); // assert only one off ramp is set offRamps = l2.router.getOffRamps(); @@ -374,25 +393,58 @@ contract ForkPoolBeforeMigration is ForkBase { function testReleaseOrMintVia1_2OffRamp() public { uint256 amount = 10e18; + Client.EVM2AnyMessage memory message = _generateMessage(alice, 1); + + // off ramp on L1 { + // build message + vm.selectFork(l2.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l2.token), amount: amount}); + uint256 feeTokenAmount = l2.router.getFee(l1.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l2.EVM2EVMOnRamp1_2, + feeTokenAmount, + alice, + false + ); + + // test off ramp vm.selectFork(l1.forkId); + uint256 balanceBefore = l1.token.balanceOf(alice); - vm.expectEmit(); + vm.expectEmit(address(l1.tokenPool)); emit Released(address(l1.EVM2EVMOffRamp1_2), alice, amount); vm.prank(address(l1.EVM2EVMOffRamp1_2)); - l1.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l2.chainSelector, ""); + l1.EVM2EVMOffRamp1_2.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length)); assertEq(l1.token.balanceOf(alice), balanceBefore + amount); } + + // off ramp on L2 { + // build message + vm.selectFork(l1.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l1.token), amount: amount}); + uint256 feeTokenAmount = l1.router.getFee(l2.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l1.EVM2EVMOnRamp1_2, + feeTokenAmount, + alice, + true + ); + + // test off ramp vm.selectFork(l2.forkId); + uint256 balanceBefore = l2.token.balanceOf(alice); - vm.expectEmit(); + vm.expectEmit(address(l2.tokenPool)); emit Minted(address(l2.EVM2EVMOffRamp1_2), alice, amount); vm.prank(address(l2.EVM2EVMOffRamp1_2)); - l2.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l1.chainSelector, ""); + l2.EVM2EVMOffRamp1_2.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length)); assertEq(l2.token.balanceOf(alice), balanceBefore + amount); } diff --git a/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/TokenPoolsUpgrade.t.sol b/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/TokenPoolsUpgrade.t.sol index 11e2f12403..1f302227ae 100644 --- a/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/TokenPoolsUpgrade.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/GHO/fork/GhoTokenPoolMigrate1_4To1_5/TokenPoolsUpgrade.t.sol @@ -81,40 +81,122 @@ contract ForkPoolUpgradeAfterMigration is ForkBase { function testReleaseOrMintVia1_2OffRamp() public { uint256 amount = 10e18; + Client.EVM2AnyMessage memory message = _generateMessage(alice, 1); + + // off ramp on L1 { + // build message + vm.selectFork(l2.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l2.token), amount: amount}); + uint256 feeTokenAmount = l2.router.getFee(l1.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l2.EVM2EVMOnRamp1_5, + feeTokenAmount, + alice, + false + ); + + // test off ramp vm.selectFork(l1.forkId); + uint256 balanceBefore = l1.token.balanceOf(alice); - // mock release on legacy offramp + + vm.expectEmit(address(l1.tokenPool)); + emit Released(address(l1.EVM2EVMOffRamp1_2), alice, amount); vm.prank(address(l1.EVM2EVMOffRamp1_2)); - l1.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l2.chainSelector, ""); + l1.EVM2EVMOffRamp1_2.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length)); + assertEq(l1.token.balanceOf(alice), balanceBefore + amount); } + + // off ramp on L2 { + // build message + vm.selectFork(l1.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l1.token), amount: amount}); + uint256 feeTokenAmount = l1.router.getFee(l2.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l1.EVM2EVMOnRamp1_5, + feeTokenAmount, + alice, + true + ); + + // test off ramp vm.selectFork(l2.forkId); + uint256 balanceBefore = l2.token.balanceOf(alice); - // mock release on legacy offramp + + vm.expectEmit(address(l2.tokenPool)); + emit Minted(address(l2.EVM2EVMOffRamp1_2), alice, amount); vm.prank(address(l2.EVM2EVMOffRamp1_2)); - l2.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l1.chainSelector, ""); + l2.EVM2EVMOffRamp1_2.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length)); + assertEq(l2.token.balanceOf(alice), balanceBefore + amount); } } function testReleaseOrMintVia1_5OffRamp() public { uint256 amount = 10e18; + Client.EVM2AnyMessage memory message = _generateMessage(alice, 1); + + // off ramp on L1 { + // build message + vm.selectFork(l2.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l2.token), amount: amount}); + uint256 feeTokenAmount = l2.router.getFee(l1.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l2.EVM2EVMOnRamp1_5, + feeTokenAmount, + alice, + false + ); + + // test off ramp vm.selectFork(l1.forkId); + uint256 balanceBefore = l1.token.balanceOf(alice); - // mock release on legacy offramp + + vm.expectEmit(address(l1.tokenPool)); + emit Released(address(l1.proxyPool), alice, amount); + vm.expectEmit(address(l1.proxyPool)); + emit Released(address(l1.EVM2EVMOffRamp1_5), alice, amount); vm.prank(address(l1.EVM2EVMOffRamp1_5)); - l1.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l2.chainSelector, ""); + l1.EVM2EVMOffRamp1_5.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length), new uint32[](0)); + assertEq(l1.token.balanceOf(alice), balanceBefore + amount); } + + // off ramp on L2 { + // build message + vm.selectFork(l1.forkId); + message.tokenAmounts[0] = Client.EVMTokenAmount({token: address(l1.token), amount: amount}); + uint256 feeTokenAmount = l1.router.getFee(l2.chainSelector, message); + Internal.EVM2EVMMessage memory eventArg = _messageToEvent( + message, + l1.EVM2EVMOnRamp1_5, + feeTokenAmount, + alice, + true + ); + + // test off ramp vm.selectFork(l2.forkId); + uint256 balanceBefore = l2.token.balanceOf(alice); - // mock release on legacy offramp + + vm.expectEmit(address(l2.tokenPool)); + emit Minted(address(l2.proxyPool), alice, amount); + vm.expectEmit(address(l2.proxyPool)); + emit Minted(address(l2.EVM2EVMOffRamp1_5), alice, amount); vm.prank(address(l2.EVM2EVMOffRamp1_5)); - l2.tokenPool.releaseOrMint(abi.encode(alice), alice, amount, l1.chainSelector, ""); + l2.EVM2EVMOffRamp1_5.executeSingleMessage(eventArg, new bytes[](message.tokenAmounts.length), new uint32[](0)); + assertEq(l2.token.balanceOf(alice), balanceBefore + amount); } }