diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index f5d2e7fc9be..7adc89fb4de 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -236,11 +236,11 @@ HybridLockReleaseUSDCTokenPool_lockOrBurn:test_onLockReleaseMechanism_thenSwitch HybridLockReleaseUSDCTokenPool_releaseOrMint:test_OnLockReleaseMechanism_Success() (gas: 213127) HybridLockReleaseUSDCTokenPool_releaseOrMint:test_WhileMigrationPause_Revert() (gas: 109646) HybridLockReleaseUSDCTokenPool_releaseOrMint:test_incomingMessageWithPrimaryMechanism() (gas: 265910) -LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 3053405) +LockReleaseTokenPool_canAcceptLiquidity:test_CanAcceptLiquidity_Success() (gas: 3123780) LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 29734) LockReleaseTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Success() (gas: 80647) LockReleaseTokenPool_lockOrBurn:test_PoolBurnRevertNotHealthy_Revert() (gas: 59227) -LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 3049734) +LockReleaseTokenPool_provideLiquidity:test_LiquidityNotAccepted_Revert() (gas: 3120109) LockReleaseTokenPool_provideLiquidity:test_Unauthorized_Revert() (gas: 11511) LockReleaseTokenPool_releaseOrMint:test_ChainNotAllowed_Revert() (gas: 74108) LockReleaseTokenPool_releaseOrMint:test_PoolMintNotHealthy_Revert() (gas: 54745) @@ -535,7 +535,7 @@ OnRamp_forwardFromRouter:test_ShouldIncrementNonceOnlyOnOrdered_Success() (gas: OnRamp_forwardFromRouter:test_ShouldIncrementSeqNumAndNonce_Success() (gas: 213012) OnRamp_forwardFromRouter:test_ShouldStoreLinkFees() (gas: 147026) OnRamp_forwardFromRouter:test_ShouldStoreNonLinkFees() (gas: 161215) -OnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3919758) +OnRamp_forwardFromRouter:test_SourceTokenDataTooLarge_Revert() (gas: 3987624) OnRamp_forwardFromRouter:test_UnAllowedOriginalSender_Revert() (gas: 24015) OnRamp_forwardFromRouter:test_UnsupportedToken_Revert() (gas: 75832) OnRamp_forwardFromRouter:test_forwardFromRouter_UnsupportedToken_Revert() (gas: 38588) @@ -681,14 +681,14 @@ TokenAdminRegistry_setPool:test_setPool_ZeroAddressRemovesPool_Success() (gas: 3 TokenAdminRegistry_transferAdminRole:test_transferAdminRole_OnlyAdministrator_Revert() (gas: 18202) TokenAdminRegistry_transferAdminRole:test_transferAdminRole_Success() (gas: 49592) TokenPoolFactory_constructor:test_constructor_Revert() (gas: 1121653) -TokenPoolFactory_createTokenPool:test_createTokenPoolLockRelease_ExistingToken_predict_Success() (gas: 12293466) -TokenPoolFactory_createTokenPool:test_createTokenPool_BurnFromMintTokenPool_Success() (gas: 6290905) -TokenPoolFactory_createTokenPool:test_createTokenPool_ExistingRemoteToken_AndPredictPool_Success() (gas: 13043750) -TokenPoolFactory_createTokenPool:test_createTokenPool_RemoteTokenHasDifferentDecimals_Success() (gas: 13051052) -TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingRemoteContracts_predict_Success() (gas: 13380456) -TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingTokenOnRemoteChain_Success() (gas: 6075765) -TokenPoolFactory_createTokenPool:test_createTokenPool_WithRemoteTokenAndRemotePool_Success() (gas: 6287377) -TokenPoolWithAllowList_applyAllowListUpdates:test_AllowListNotEnabled_Revert() (gas: 2670523) +TokenPoolFactory_createTokenPool:test_createTokenPoolLockRelease_ExistingToken_predict_Success() (gas: 12436024) +TokenPoolFactory_createTokenPool:test_createTokenPool_BurnFromMintTokenPool_Success() (gas: 6400000) +TokenPoolFactory_createTokenPool:test_createTokenPool_ExistingRemoteToken_AndPredictPool_Success() (gas: 13228940) +TokenPoolFactory_createTokenPool:test_createTokenPool_RemoteTokenHasDifferentDecimals_Success() (gas: 13236242) +TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingRemoteContracts_predict_Success() (gas: 13565664) +TokenPoolFactory_createTokenPool:test_createTokenPool_WithNoExistingTokenOnRemoteChain_Success() (gas: 6186359) +TokenPoolFactory_createTokenPool:test_createTokenPool_WithRemoteTokenAndRemotePool_Success() (gas: 6396544) +TokenPoolWithAllowList_applyAllowListUpdates:test_AllowListNotEnabled_Revert() (gas: 2740884) TokenPoolWithAllowList_applyAllowListUpdates:test_OnlyOwner_Revert() (gas: 12119) TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowListSkipsZero_Success() (gas: 23567) TokenPoolWithAllowList_applyAllowListUpdates:test_SetAllowList_Success() (gas: 178398) @@ -707,8 +707,8 @@ TokenPool_applyChainUpdates:test_applyChainUpdates_OnlyCallableByOwner_Revert() TokenPool_applyChainUpdates:test_applyChainUpdates_Success() (gas: 592089) TokenPool_applyChainUpdates:test_applyChainUpdates_UpdatesRemotePoolHashes() (gas: 1077776) TokenPool_applyChainUpdates:test_applyChainUpdates_ZeroAddressNotAllowed_Revert() (gas: 226472) -TokenPool_calculateLocalAmount:test_calculateLocalAmount() (gas: 84708) -TokenPool_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 71386) +TokenPool_calculateLocalAmount:test_calculateLocalAmount() (gas: 98017) +TokenPool_constructor:test_ZeroAddressNotAllowed_Revert() (gas: 71558) TokenPool_constructor:test_immutableFields_Success() (gas: 21902) TokenPool_getRemotePool:test_getRemotePools() (gas: 330500) TokenPool_onlyOffRamp:test_CallerIsNotARampOnRouter_Revert() (gas: 21504) @@ -726,20 +726,20 @@ TokenPool_setChainRateLimiterConfig:test_NonExistentChain_Revert() (gas: 17214) TokenPool_setChainRateLimiterConfig:test_OnlyOwnerOrRateLimitAdmin_Revert() (gas: 15307) TokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Revert() (gas: 11002) TokenPool_setRateLimitAdmin:test_SetRateLimitAdmin_Success() (gas: 37606) -USDCBridgeMigrator_BurnLockedUSDC:test_PrimaryMechanism_Success() (gas: 136004) -USDCBridgeMigrator_BurnLockedUSDC:test_WhileMigrationPause_Revert() (gas: 109849) +USDCBridgeMigrator_BurnLockedUSDC:test_PrimaryMechanism_Success() (gas: 135869) +USDCBridgeMigrator_BurnLockedUSDC:test_WhileMigrationPause_Revert() (gas: 109729) USDCBridgeMigrator_BurnLockedUSDC:test_invalidPermissions_Revert() (gas: 39493) -USDCBridgeMigrator_BurnLockedUSDC:test_lockOrBurn_then_BurnInCCTPMigration_Success() (gas: 310057) -USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism_Success() (gas: 147035) -USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism_thenSwitchToPrimary_Success() (gas: 209377) +USDCBridgeMigrator_BurnLockedUSDC:test_lockOrBurn_then_BurnInCCTPMigration_Success() (gas: 309798) +USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism_Success() (gas: 146939) +USDCBridgeMigrator_BurnLockedUSDC:test_onLockReleaseMechanism_thenSwitchToPrimary_Success() (gas: 209089) USDCBridgeMigrator_cancelMigrationProposal:test_cancelExistingCCTPMigrationProposal_Success() (gas: 56155) USDCBridgeMigrator_cancelMigrationProposal:test_cannotCancelANonExistentMigrationProposal_Revert() (gas: 12669) USDCBridgeMigrator_excludeTokensFromBurn:test_excludeTokensWhenNoMigrationProposalPending_Revert() (gas: 13579) USDCBridgeMigrator_proposeMigration:test_ChainNotUsingLockRelease_Revert() (gas: 15765) USDCBridgeMigrator_provideLiquidity:test_PrimaryMechanism_Success() (gas: 135986) USDCBridgeMigrator_provideLiquidity:test_WhileMigrationPause_Revert() (gas: 109871) -USDCBridgeMigrator_provideLiquidity:test_cannotModifyLiquidityWithoutPermissions_Revert() (gas: 13379) -USDCBridgeMigrator_provideLiquidity:test_cannotProvideLiquidityWhenMigrationProposalPending_Revert() (gas: 67417) +USDCBridgeMigrator_provideLiquidity:test_cannotModifyLiquidityWithoutPermissions_Revert() (gas: 13390) +USDCBridgeMigrator_provideLiquidity:test_cannotProvideLiquidityWhenMigrationProposalPending_Revert() (gas: 67428) USDCBridgeMigrator_provideLiquidity:test_cannotProvideLiquidity_AfterMigration_Revert() (gas: 313898) USDCBridgeMigrator_provideLiquidity:test_invalidPermissions_Revert() (gas: 39493) USDCBridgeMigrator_provideLiquidity:test_lockOrBurn_then_BurnInCCTPMigration_Success() (gas: 310057) @@ -758,13 +758,13 @@ USDCBridgeMigrator_updateChainSelectorMechanism:test_lockOrBurn_then_BurnInCCTPM USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism_Success() (gas: 147035) USDCBridgeMigrator_updateChainSelectorMechanism:test_onLockReleaseMechanism_thenSwitchToPrimary_Success() (gas: 209448) USDCTokenPool__validateMessage:test_ValidateInvalidMessage_Revert() (gas: 26049) -USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35369) -USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 29947) -USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 133581) -USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 433813) -USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 265825) +USDCTokenPool_lockOrBurn:test_CallerIsNotARampOnRouter_Revert() (gas: 35297) +USDCTokenPool_lockOrBurn:test_LockOrBurnWithAllowList_Revert() (gas: 29875) +USDCTokenPool_lockOrBurn:test_LockOrBurn_Success() (gas: 133408) +USDCTokenPool_lockOrBurn:test_UnknownDomain_Revert() (gas: 433408) +USDCTokenPool_releaseOrMint:test_ReleaseOrMintRealTx_Success() (gas: 265695) USDCTokenPool_releaseOrMint:test_TokenMaxCapacityExceeded_Revert() (gas: 47231) -USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 95315) +USDCTokenPool_releaseOrMint:test_UnlockingUSDCFailed_Revert() (gas: 95262) USDCTokenPool_setDomains:test_InvalidDomain_Revert() (gas: 66437) USDCTokenPool_setDomains:test_OnlyOwner_Revert() (gas: 11314) USDCTokenPool_supportsInterface:test_SupportsInterface_Success() (gas: 10107) \ No newline at end of file diff --git a/contracts/src/v0.8/ccip/pools/TokenPool.sol b/contracts/src/v0.8/ccip/pools/TokenPool.sol index be8cc1ee7a3..4a6e281a17f 100644 --- a/contracts/src/v0.8/ccip/pools/TokenPool.sol +++ b/contracts/src/v0.8/ccip/pools/TokenPool.sol @@ -10,6 +10,8 @@ import {Pool} from "../libraries/Pool.sol"; import {RateLimiter} from "../libraries/RateLimiter.sol"; import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol"; +import {IERC20Metadata} from + "../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/extensions/IERC20Metadata.sol"; import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol"; import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol"; @@ -49,6 +51,8 @@ abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender { error PoolAlreadyAdded(uint64 remoteChainSelector, bytes remotePoolAddress); error InvalidRemotePoolForChain(uint64 remoteChainSelector, bytes remotePoolAddress); error InvalidRemoteChainDecimals(bytes sourcePoolData); + error OverOrUnderflowDetected(uint8 sourceDecimals, uint8 localDecimals, uint256 localAmount); + error InvalidDecimalArgs(uint8 expected, uint8 actual); event Locked(address indexed sender, uint256 amount); event Burned(address indexed sender, uint256 amount); @@ -119,7 +123,17 @@ abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender { if (address(token) == address(0) || router == address(0) || rmnProxy == address(0)) revert ZeroAddressNotAllowed(); i_token = token; i_rmnProxy = rmnProxy; + + try IERC20Metadata(address(token)).decimals() returns (uint8 actualTokenDecimals) { + if (localTokenDecimals != actualTokenDecimals) { + revert InvalidDecimalArgs(localTokenDecimals, actualTokenDecimals); + } + } catch { + // The decimals function doesn't exist, which is possible since it's optional in the ERC20 spec. We skip the check and + // assume the supplied token decimals are correct. + } i_tokenDecimals = localTokenDecimals; + s_router = IRouter(router); // Pool can be set as permissioned or permissionless at deployment time only to save hot-path gas. @@ -256,17 +270,33 @@ abstract contract TokenPool is IPoolV1, Ownable2StepMsgSender { /// @param remoteAmount The amount on the remote chain. /// @param remoteDecimals The decimals of the token on the remote chain. /// @return The local amount. - /// @dev This function assumes the inputs don't overflow and does no checks to avoid this. For any normal inputs, this - /// should not be a problem. The only way to overflow is when the given arguments cannot be represented in the uint256 - /// type, which means the inputs are invalid. + /// @dev This function protects against overflows and underflows. If there is a transaction that hits the overflow + /// or underflow check, it is probably incorrect as that means the amount cannot be represented on this chain. If the + /// local decimals have been wrongly configured, the token issuer could redeploy the pool with the correct decimals + /// and manually re-execute the CCIP tx to fix the issue. function _calculateLocalAmount(uint256 remoteAmount, uint8 remoteDecimals) internal view virtual returns (uint256) { if (remoteDecimals == i_tokenDecimals) { return remoteAmount; } if (remoteDecimals > i_tokenDecimals) { + if (remoteDecimals - i_tokenDecimals > 77) { + // This is a safety check to prevent overflow in the next calculation. + revert OverOrUnderflowDetected(remoteDecimals, i_tokenDecimals, remoteAmount); + } // Solidity rounds down so there is no risk of minting more tokens than the remote chain sent. return remoteAmount / (10 ** (remoteDecimals - i_tokenDecimals)); } + + // This is a safety check to prevent overflow in the next calculation. + // More than 77 would never fit in a uint256 and would cause an overflow. We also check if the resulting amount + // would overflow. + if ( + i_tokenDecimals - remoteDecimals > 77 + || remoteAmount > type(uint256).max / (10 ** (i_tokenDecimals - remoteDecimals)) + ) { + revert OverOrUnderflowDetected(remoteDecimals, i_tokenDecimals, remoteAmount); + } + return remoteAmount * (10 ** (i_tokenDecimals - remoteDecimals)); } diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPoolSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPoolSetup.t.sol index 004c71ccd02..9b318b782ce 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPoolSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/HybridLockReleaseUSDCTokenPool/HybridLockReleaseUSDCTokenPoolSetup.t.sol @@ -1,61 +1,19 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; -import {IBurnMintERC20} from "../../../../../shared/token/ERC20/IBurnMintERC20.sol"; - import {BurnMintERC677} from "../../../../../shared/token/ERC677/BurnMintERC677.sol"; -import {Router} from "../../../../Router.sol"; -import {TokenPool} from "../../../../pools/TokenPool.sol"; + import {HybridLockReleaseUSDCTokenPool} from "../../../../pools/USDC/HybridLockReleaseUSDCTokenPool.sol"; import {USDCTokenPool} from "../../../../pools/USDC/USDCTokenPool.sol"; -import {BaseTest} from "../../../BaseTest.t.sol"; -import {MockE2EUSDCTransmitter} from "../../../mocks/MockE2EUSDCTransmitter.sol"; -import {MockUSDCTokenMessenger} from "../../../mocks/MockUSDCTokenMessenger.sol"; - -contract HybridLockReleaseUSDCTokenPoolSetup is BaseTest { - IBurnMintERC20 internal s_token; - MockUSDCTokenMessenger internal s_mockUSDC; - MockE2EUSDCTransmitter internal s_mockUSDCTransmitter; - uint32 internal constant USDC_DEST_TOKEN_GAS = 150_000; - - struct USDCMessage { - uint32 version; - uint32 sourceDomain; - uint32 destinationDomain; - uint64 nonce; - bytes32 sender; - bytes32 recipient; - bytes32 destinationCaller; - bytes messageBody; - } - - uint32 internal constant SOURCE_DOMAIN_IDENTIFIER = 0x02020202; - uint32 internal constant DEST_DOMAIN_IDENTIFIER = 0; - - bytes32 internal constant SOURCE_CHAIN_TOKEN_SENDER = bytes32(uint256(uint160(0x01111111221))); - address internal constant SOURCE_CHAIN_USDC_POOL = address(0x23789765456789); - address internal constant DEST_CHAIN_USDC_POOL = address(0x987384873458734); - address internal constant DEST_CHAIN_USDC_TOKEN = address(0x23598918358198766); - - address internal s_routerAllowedOnRamp = address(3456); - address internal s_routerAllowedOffRamp = address(234); - Router internal s_router; +import {USDCSetup} from "../USDCSetup.t.sol"; +contract HybridLockReleaseUSDCTokenPoolSetup is USDCSetup { HybridLockReleaseUSDCTokenPool internal s_usdcTokenPool; HybridLockReleaseUSDCTokenPool internal s_usdcTokenPoolTransferLiquidity; address[] internal s_allowedList; function setUp() public virtual override { - BaseTest.setUp(); - BurnMintERC677 usdcToken = new BurnMintERC677("LINK", "LNK", 18, 0); - s_token = usdcToken; - deal(address(s_token), OWNER, type(uint256).max); - _setUpRamps(); - - s_mockUSDCTransmitter = new MockE2EUSDCTransmitter(0, DEST_DOMAIN_IDENTIFIER, address(s_token)); - s_mockUSDC = new MockUSDCTokenMessenger(0, address(s_mockUSDCTransmitter)); - - usdcToken.grantMintAndBurnRoles(address(s_mockUSDCTransmitter)); + super.setUp(); s_usdcTokenPool = new HybridLockReleaseUSDCTokenPool(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router)); @@ -63,32 +21,9 @@ contract HybridLockReleaseUSDCTokenPoolSetup is BaseTest { s_usdcTokenPoolTransferLiquidity = new HybridLockReleaseUSDCTokenPool(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router)); - usdcToken.grantMintAndBurnRoles(address(s_mockUSDC)); - usdcToken.grantMintAndBurnRoles(address(s_usdcTokenPool)); - - bytes[] memory sourcePoolAddresses = new bytes[](1); - sourcePoolAddresses[0] = abi.encode(SOURCE_CHAIN_USDC_POOL); + BurnMintERC677(address(s_token)).grantMintAndBurnRoles(address(s_usdcTokenPool)); - bytes[] memory destPoolAddresses = new bytes[](1); - destPoolAddresses[0] = abi.encode(DEST_CHAIN_USDC_POOL); - - TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2); - chainUpdates[0] = TokenPool.ChainUpdate({ - remoteChainSelector: SOURCE_CHAIN_SELECTOR, - remotePoolAddresses: sourcePoolAddresses, - remoteTokenAddress: abi.encode(address(s_token)), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - chainUpdates[1] = TokenPool.ChainUpdate({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - remotePoolAddresses: destPoolAddresses, - remoteTokenAddress: abi.encode(DEST_CHAIN_USDC_TOKEN), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - - s_usdcTokenPool.applyChainUpdates(new uint64[](0), chainUpdates); + _poolApplyChainUpdates(address(s_usdcTokenPool)); USDCTokenPool.DomainUpdate[] memory domains = new USDCTokenPool.DomainUpdate[](1); domains[0] = USDCTokenPool.DomainUpdate({ @@ -100,38 +35,7 @@ contract HybridLockReleaseUSDCTokenPoolSetup is BaseTest { s_usdcTokenPool.setDomains(domains); - vm.expectEmit(); - emit HybridLockReleaseUSDCTokenPool.LiquidityProviderSet(address(0), OWNER, DEST_CHAIN_SELECTOR); - s_usdcTokenPool.setLiquidityProvider(DEST_CHAIN_SELECTOR, OWNER); s_usdcTokenPool.setLiquidityProvider(SOURCE_CHAIN_SELECTOR, OWNER); } - - function _setUpRamps() internal { - s_router = new Router(address(s_token), address(s_mockRMN)); - - Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1); - onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_routerAllowedOnRamp}); - Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1); - address[] memory offRamps = new address[](1); - offRamps[0] = s_routerAllowedOffRamp; - offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: offRamps[0]}); - - s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates); - } - - function _generateUSDCMessage( - USDCMessage memory usdcMessage - ) internal pure returns (bytes memory) { - return abi.encodePacked( - usdcMessage.version, - usdcMessage.sourceDomain, - usdcMessage.destinationDomain, - usdcMessage.nonce, - usdcMessage.sender, - usdcMessage.recipient, - usdcMessage.destinationCaller, - usdcMessage.messageBody - ); - } } diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCSetup.t.sol new file mode 100644 index 00000000000..9ec89b52582 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCSetup.t.sol @@ -0,0 +1,114 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {IBurnMintERC20} from "../../../../shared/token/ERC20/IBurnMintERC20.sol"; + +import {BurnMintERC677} from "../../../../shared/token/ERC677/BurnMintERC677.sol"; +import {Router} from "../../../Router.sol"; +import {TokenPool} from "../../../pools/TokenPool.sol"; + +import {BaseTest} from "../../BaseTest.t.sol"; +import {MockE2EUSDCTransmitter} from "../../mocks/MockE2EUSDCTransmitter.sol"; +import {MockUSDCTokenMessenger} from "../../mocks/MockUSDCTokenMessenger.sol"; + +contract USDCSetup is BaseTest { + struct USDCMessage { + uint32 version; + uint32 sourceDomain; + uint32 destinationDomain; + uint64 nonce; + bytes32 sender; + bytes32 recipient; + bytes32 destinationCaller; + bytes messageBody; + } + + uint32 internal constant USDC_DEST_TOKEN_GAS = 180_000; + uint32 internal constant SOURCE_DOMAIN_IDENTIFIER = 0x02020202; + uint32 internal constant DEST_DOMAIN_IDENTIFIER = 0; + + bytes32 internal constant SOURCE_CHAIN_TOKEN_SENDER = bytes32(uint256(uint160(0x01111111221))); + address internal constant SOURCE_CHAIN_USDC_POOL = address(0x23789765456789); + address internal constant DEST_CHAIN_USDC_POOL = address(0x987384873458734); + address internal constant DEST_CHAIN_USDC_TOKEN = address(0x23598918358198766); + + MockUSDCTokenMessenger internal s_mockUSDC; + MockE2EUSDCTransmitter internal s_mockUSDCTransmitter; + + address internal s_routerAllowedOnRamp = address(3456); + address internal s_routerAllowedOffRamp = address(234); + Router internal s_router; + + IBurnMintERC20 internal s_token; + + function setUp() public virtual override { + super.setUp(); + BurnMintERC677 usdcToken = new BurnMintERC677("USD Coin", "USDC", 6, 0); + s_token = usdcToken; + + deal(address(s_token), OWNER, type(uint256).max); + _setUpRamps(); + + s_mockUSDCTransmitter = new MockE2EUSDCTransmitter(0, DEST_DOMAIN_IDENTIFIER, address(s_token)); + s_mockUSDC = new MockUSDCTokenMessenger(0, address(s_mockUSDCTransmitter)); + + usdcToken.grantMintAndBurnRoles(address(s_mockUSDCTransmitter)); + usdcToken.grantMintAndBurnRoles(address(s_mockUSDC)); + } + + function _poolApplyChainUpdates( + address pool + ) internal { + bytes[] memory sourcePoolAddresses = new bytes[](1); + sourcePoolAddresses[0] = abi.encode(SOURCE_CHAIN_USDC_POOL); + + bytes[] memory destPoolAddresses = new bytes[](1); + destPoolAddresses[0] = abi.encode(DEST_CHAIN_USDC_POOL); + + TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2); + chainUpdates[0] = TokenPool.ChainUpdate({ + remoteChainSelector: SOURCE_CHAIN_SELECTOR, + remotePoolAddresses: sourcePoolAddresses, + remoteTokenAddress: abi.encode(address(s_token)), + outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), + inboundRateLimiterConfig: _getInboundRateLimiterConfig() + }); + chainUpdates[1] = TokenPool.ChainUpdate({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + remotePoolAddresses: destPoolAddresses, + remoteTokenAddress: abi.encode(DEST_CHAIN_USDC_TOKEN), + outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), + inboundRateLimiterConfig: _getInboundRateLimiterConfig() + }); + + TokenPool(pool).applyChainUpdates(new uint64[](0), chainUpdates); + } + + function _setUpRamps() internal { + s_router = new Router(address(s_token), address(s_mockRMN)); + + Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1); + onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_routerAllowedOnRamp}); + Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1); + address[] memory offRamps = new address[](1); + offRamps[0] = s_routerAllowedOffRamp; + offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: offRamps[0]}); + + s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates); + } + + function _generateUSDCMessage( + USDCMessage memory usdcMessage + ) internal pure returns (bytes memory) { + return abi.encodePacked( + usdcMessage.version, + usdcMessage.sourceDomain, + usdcMessage.destinationDomain, + usdcMessage.nonce, + usdcMessage.sender, + usdcMessage.recipient, + usdcMessage.destinationCaller, + usdcMessage.messageBody + ); + } +} diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPoolSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPoolSetup.t.sol index 26dd4a0a71b..bc6108926b3 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPoolSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPool/USDCTokenPoolSetup.t.sol @@ -1,94 +1,27 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; -import {IBurnMintERC20} from "../../../../../shared/token/ERC20/IBurnMintERC20.sol"; - -import {BurnMintERC20} from "../../../../../shared/token/ERC20/BurnMintERC20.sol"; -import {Router} from "../../../../Router.sol"; -import {TokenPool} from "../../../../pools/TokenPool.sol"; import {USDCTokenPool} from "../../../../pools/USDC/USDCTokenPool.sol"; -import {BaseTest} from "../../../BaseTest.t.sol"; import {USDCTokenPoolHelper} from "../../../helpers/USDCTokenPoolHelper.sol"; -import {MockE2EUSDCTransmitter} from "../../../mocks/MockE2EUSDCTransmitter.sol"; -import {MockUSDCTokenMessenger} from "../../../mocks/MockUSDCTokenMessenger.sol"; - -contract USDCTokenPoolSetup is BaseTest { - IBurnMintERC20 internal s_token; - MockUSDCTokenMessenger internal s_mockUSDC; - MockE2EUSDCTransmitter internal s_mockUSDCTransmitter; - uint32 internal constant USDC_DEST_TOKEN_GAS = 150_000; - - struct USDCMessage { - uint32 version; - uint32 sourceDomain; - uint32 destinationDomain; - uint64 nonce; - bytes32 sender; - bytes32 recipient; - bytes32 destinationCaller; - bytes messageBody; - } - - uint32 internal constant SOURCE_DOMAIN_IDENTIFIER = 0x02020202; - uint32 internal constant DEST_DOMAIN_IDENTIFIER = 0; - - bytes32 internal constant SOURCE_CHAIN_TOKEN_SENDER = bytes32(uint256(uint160(0x01111111221))); - address internal constant SOURCE_CHAIN_USDC_POOL = address(0x23789765456789); - address internal constant DEST_CHAIN_USDC_POOL = address(0x987384873458734); - address internal constant DEST_CHAIN_USDC_TOKEN = address(0x23598918358198766); - - address internal s_routerAllowedOnRamp = address(3456); - address internal s_routerAllowedOffRamp = address(234); - Router internal s_router; +import {USDCSetup} from "../USDCSetup.t.sol"; +contract USDCTokenPoolSetup is USDCSetup { USDCTokenPoolHelper internal s_usdcTokenPool; USDCTokenPoolHelper internal s_usdcTokenPoolWithAllowList; address[] internal s_allowedList; function setUp() public virtual override { - BaseTest.setUp(); - BurnMintERC20 usdcToken = new BurnMintERC20("LINK", "LNK", 18, 0, 0); - s_token = usdcToken; - deal(address(s_token), OWNER, type(uint256).max); - _setUpRamps(); - - s_mockUSDCTransmitter = new MockE2EUSDCTransmitter(0, DEST_DOMAIN_IDENTIFIER, address(s_token)); - s_mockUSDC = new MockUSDCTokenMessenger(0, address(s_mockUSDCTransmitter)); - - usdcToken.grantMintAndBurnRoles(address(s_mockUSDCTransmitter)); + super.setUp(); s_usdcTokenPool = new USDCTokenPoolHelper(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router)); - usdcToken.grantMintAndBurnRoles(address(s_mockUSDC)); s_allowedList.push(USER_1); s_usdcTokenPoolWithAllowList = new USDCTokenPoolHelper(s_mockUSDC, s_token, s_allowedList, address(s_mockRMN), address(s_router)); - bytes[] memory sourcePoolAddresses = new bytes[](1); - sourcePoolAddresses[0] = abi.encode(SOURCE_CHAIN_USDC_POOL); - - bytes[] memory destPoolAddresses = new bytes[](1); - destPoolAddresses[0] = abi.encode(DEST_CHAIN_USDC_POOL); - - TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2); - chainUpdates[0] = TokenPool.ChainUpdate({ - remoteChainSelector: SOURCE_CHAIN_SELECTOR, - remotePoolAddresses: sourcePoolAddresses, - remoteTokenAddress: abi.encode(address(s_token)), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - chainUpdates[1] = TokenPool.ChainUpdate({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - remotePoolAddresses: destPoolAddresses, - remoteTokenAddress: abi.encode(DEST_CHAIN_USDC_TOKEN), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - - s_usdcTokenPool.applyChainUpdates(new uint64[](0), chainUpdates); - s_usdcTokenPoolWithAllowList.applyChainUpdates(new uint64[](0), chainUpdates); + _poolApplyChainUpdates(address(s_usdcTokenPool)); + _poolApplyChainUpdates(address(s_usdcTokenPoolWithAllowList)); USDCTokenPool.DomainUpdate[] memory domains = new USDCTokenPool.DomainUpdate[](1); domains[0] = USDCTokenPool.DomainUpdate({ @@ -101,32 +34,4 @@ contract USDCTokenPoolSetup is BaseTest { s_usdcTokenPool.setDomains(domains); s_usdcTokenPoolWithAllowList.setDomains(domains); } - - function _setUpRamps() internal { - s_router = new Router(address(s_token), address(s_mockRMN)); - - Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1); - onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_routerAllowedOnRamp}); - Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1); - address[] memory offRamps = new address[](1); - offRamps[0] = s_routerAllowedOffRamp; - offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: offRamps[0]}); - - s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates); - } - - function _generateUSDCMessage( - USDCMessage memory usdcMessage - ) internal pure returns (bytes memory) { - return abi.encodePacked( - usdcMessage.version, - usdcMessage.sourceDomain, - usdcMessage.destinationDomain, - usdcMessage.nonce, - usdcMessage.sender, - usdcMessage.recipient, - usdcMessage.destinationCaller, - usdcMessage.messageBody - ); - } } diff --git a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPoolSetup.t.sol b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPoolSetup.t.sol index 69712f7c68f..b02ea11d6ba 100644 --- a/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPoolSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/pools/USDC/USDCTokenPoolSetup.t.sol @@ -1,137 +1,21 @@ // SPDX-License-Identifier: BUSL-1.1 pragma solidity 0.8.24; -import {IBurnMintERC20} from "../../../../shared/token/ERC20/IBurnMintERC20.sol"; - -import {BurnMintERC677} from "../../../../shared/token/ERC677/BurnMintERC677.sol"; -import {Router} from "../../../Router.sol"; -import {TokenPool} from "../../../pools/TokenPool.sol"; import {HybridLockReleaseUSDCTokenPool} from "../../../pools/USDC/HybridLockReleaseUSDCTokenPool.sol"; -import {USDCTokenPool} from "../../../pools/USDC/USDCTokenPool.sol"; -import {BaseTest} from "../../BaseTest.t.sol"; -import {MockE2EUSDCTransmitter} from "../../mocks/MockE2EUSDCTransmitter.sol"; -import {MockUSDCTokenMessenger} from "../../mocks/MockUSDCTokenMessenger.sol"; - -contract HybridLockReleaseUSDCTokenPoolSetup is BaseTest { - IBurnMintERC20 internal s_token; - MockUSDCTokenMessenger internal s_mockUSDC; - MockE2EUSDCTransmitter internal s_mockUSDCTransmitter; - uint32 internal constant USDC_DEST_TOKEN_GAS = 180_000; - - struct USDCMessage { - uint32 version; - uint32 sourceDomain; - uint32 destinationDomain; - uint64 nonce; - bytes32 sender; - bytes32 recipient; - bytes32 destinationCaller; - bytes messageBody; - } - - uint32 internal constant SOURCE_DOMAIN_IDENTIFIER = 0x02020202; - uint32 internal constant DEST_DOMAIN_IDENTIFIER = 0; - - bytes32 internal constant SOURCE_CHAIN_TOKEN_SENDER = bytes32(uint256(uint160(0x01111111221))); - address internal constant SOURCE_CHAIN_USDC_POOL = address(0x23789765456789); - address internal constant DEST_CHAIN_USDC_POOL = address(0x987384873458734); - address internal constant DEST_CHAIN_USDC_TOKEN = address(0x23598918358198766); - - address internal s_routerAllowedOnRamp = address(3456); - address internal s_routerAllowedOffRamp = address(234); - Router internal s_router; +import {USDCSetup} from "./USDCSetup.t.sol"; +contract HybridLockReleaseUSDCTokenPoolSetup is USDCSetup { HybridLockReleaseUSDCTokenPool internal s_usdcTokenPool; HybridLockReleaseUSDCTokenPool internal s_usdcTokenPoolTransferLiquidity; address[] internal s_allowedList; function setUp() public virtual override { - BaseTest.setUp(); - BurnMintERC677 usdcToken = new BurnMintERC677("LINK", "LNK", 18, 0); - s_token = usdcToken; - deal(address(s_token), OWNER, type(uint256).max); - _setUpRamps(); - - s_mockUSDCTransmitter = new MockE2EUSDCTransmitter(0, DEST_DOMAIN_IDENTIFIER, address(s_token)); - s_mockUSDC = new MockUSDCTokenMessenger(0, address(s_mockUSDCTransmitter)); - - usdcToken.grantMintAndBurnRoles(address(s_mockUSDCTransmitter)); + super.setUp(); s_usdcTokenPool = new HybridLockReleaseUSDCTokenPool(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router)); s_usdcTokenPoolTransferLiquidity = new HybridLockReleaseUSDCTokenPool(s_mockUSDC, s_token, new address[](0), address(s_mockRMN), address(s_router)); - - usdcToken.grantMintAndBurnRoles(address(s_mockUSDC)); - usdcToken.grantMintAndBurnRoles(address(s_usdcTokenPool)); - - bytes[] memory sourcePoolAddresses = new bytes[](1); - sourcePoolAddresses[0] = abi.encode(SOURCE_CHAIN_USDC_POOL); - - bytes[] memory destPoolAddresses = new bytes[](1); - destPoolAddresses[0] = abi.encode(DEST_CHAIN_USDC_POOL); - - TokenPool.ChainUpdate[] memory chainUpdates = new TokenPool.ChainUpdate[](2); - chainUpdates[0] = TokenPool.ChainUpdate({ - remoteChainSelector: SOURCE_CHAIN_SELECTOR, - remotePoolAddresses: sourcePoolAddresses, - remoteTokenAddress: abi.encode(address(s_token)), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - chainUpdates[1] = TokenPool.ChainUpdate({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - remotePoolAddresses: destPoolAddresses, - remoteTokenAddress: abi.encode(DEST_CHAIN_USDC_TOKEN), - outboundRateLimiterConfig: _getOutboundRateLimiterConfig(), - inboundRateLimiterConfig: _getInboundRateLimiterConfig() - }); - - s_usdcTokenPool.applyChainUpdates(new uint64[](0), chainUpdates); - - USDCTokenPool.DomainUpdate[] memory domains = new USDCTokenPool.DomainUpdate[](1); - domains[0] = USDCTokenPool.DomainUpdate({ - destChainSelector: DEST_CHAIN_SELECTOR, - domainIdentifier: 9999, - allowedCaller: keccak256("allowedCaller"), - enabled: true - }); - - s_usdcTokenPool.setDomains(domains); - - vm.expectEmit(); - emit HybridLockReleaseUSDCTokenPool.LiquidityProviderSet(address(0), OWNER, DEST_CHAIN_SELECTOR); - - s_usdcTokenPool.setLiquidityProvider(DEST_CHAIN_SELECTOR, OWNER); - s_usdcTokenPool.setLiquidityProvider(SOURCE_CHAIN_SELECTOR, OWNER); - } - - function _setUpRamps() internal { - s_router = new Router(address(s_token), address(s_mockRMN)); - - Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1); - onRampUpdates[0] = Router.OnRamp({destChainSelector: DEST_CHAIN_SELECTOR, onRamp: s_routerAllowedOnRamp}); - Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](1); - address[] memory offRamps = new address[](1); - offRamps[0] = s_routerAllowedOffRamp; - offRampUpdates[0] = Router.OffRamp({sourceChainSelector: SOURCE_CHAIN_SELECTOR, offRamp: offRamps[0]}); - - s_router.applyRampUpdates(onRampUpdates, new Router.OffRamp[](0), offRampUpdates); - } - - function _generateUSDCMessage( - USDCMessage memory usdcMessage - ) internal pure returns (bytes memory) { - return abi.encodePacked( - usdcMessage.version, - usdcMessage.sourceDomain, - usdcMessage.destinationDomain, - usdcMessage.nonce, - usdcMessage.sender, - usdcMessage.recipient, - usdcMessage.destinationCaller, - usdcMessage.messageBody - ); } }