diff --git a/contracts/gas-snapshots/ccip.gas-snapshot b/contracts/gas-snapshots/ccip.gas-snapshot index 4932473e38e..d655e886262 100644 --- a/contracts/gas-snapshots/ccip.gas-snapshot +++ b/contracts/gas-snapshots/ccip.gas-snapshot @@ -347,28 +347,24 @@ MultiOCR3Base_transmit:test_UnAuthorizedTransmitter_Revert() (gas: 24193) MultiOCR3Base_transmit:test_UnauthorizedSigner_Revert() (gas: 60994) MultiOCR3Base_transmit:test_UnconfiguredPlugin_Revert() (gas: 39824) MultiOCR3Base_transmit:test_ZeroSignatures_Revert() (gas: 32920) -NonceManager_NonceIncrementation:test_getIncrementedOutboundNonce_Success() (gas: 37956) -NonceManager_NonceIncrementation:test_incrementInboundNonce_Skip() (gas: 23706) -NonceManager_NonceIncrementation:test_incrementInboundNonce_Success() (gas: 38778) -NonceManager_NonceIncrementation:test_incrementNoncesInboundAndOutbound_Success() (gas: 71901) -NonceManager_OffRampUpgrade:test_NoPrevOffRampForChain_Success() (gas: 185810) -NonceManager_OffRampUpgrade:test_UpgradedNonceNewSenderStartsAtZero_Success() (gas: 189263) -NonceManager_OffRampUpgrade:test_UpgradedNonceStartsAtV1Nonce_Success() (gas: 252318) -NonceManager_OffRampUpgrade:test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() (gas: 220605) -NonceManager_OffRampUpgrade:test_UpgradedSenderNoncesReadsPreviousRamp_Success() (gas: 60497) -NonceManager_OffRampUpgrade:test_Upgraded_Success() (gas: 152975) -NonceManager_OnRampUpgrade:test_UpgradeNonceNewSenderStartsAtZero_Success() (gas: 166167) -NonceManager_OnRampUpgrade:test_UpgradeNonceStartsAtV1Nonce_Success() (gas: 195938) -NonceManager_OnRampUpgrade:test_UpgradeSenderNoncesReadsPreviousRamp_Success() (gas: 139164) -NonceManager_OnRampUpgrade:test_Upgrade_Success() (gas: 105212) -NonceManager_applyPreviousRampsUpdates:test_MultipleRampsUpdates_success() (gas: 123604) -NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOffRamp_Revert() (gas: 43403) -NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOnRampAndOffRamp_Revert() (gas: 64752) -NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySetOnRamp_Revert() (gas: 43245) -NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySet_overrideAllowed_success() (gas: 45941) +NonceManager_applyPreviousRampsUpdates:test_MultipleRampsUpdates() (gas: 123604) +NonceManager_applyPreviousRampsUpdates:test_PreviousRampAlreadySet_overrideAllowed() (gas: 45986) NonceManager_applyPreviousRampsUpdates:test_SingleRampUpdate_success() (gas: 66889) -NonceManager_applyPreviousRampsUpdates:test_ZeroInput_success() (gas: 12213) -NonceManager_typeAndVersion:test_typeAndVersion() (gas: 9705) +NonceManager_applyPreviousRampsUpdates:test_ZeroInput() (gas: 12169) +NonceManager_getInboundNonce:test_getInboundNonce_NoPrevOffRampForChain() (gas: 185821) +NonceManager_getInboundNonce:test_getInboundNonce_Upgraded() (gas: 152976) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceNewSenderStartsAtZero() (gas: 189296) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedNonceStartsAtV1Nonce() (gas: 252384) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedOffRampNonceSkipsIfMsgInFlight() (gas: 220672) +NonceManager_getInboundNonce:test_getInboundNonce_UpgradedSenderNoncesReadsPreviousRamp() (gas: 60520) +NonceManager_getIncrementedOutboundNonce:test_getIncrementedOutboundNonce() (gas: 37979) +NonceManager_getIncrementedOutboundNonce:test_incrementInboundNonce() (gas: 38756) +NonceManager_getIncrementedOutboundNonce:test_incrementInboundNonce_SkippedIncorrectNonce() (gas: 23759) +NonceManager_getIncrementedOutboundNonce:test_incrementNoncesInboundAndOutbound() (gas: 71901) +NonceManager_getOutboundNonce:test_getOutboundNonce_Upgrade() (gas: 105300) +NonceManager_getOutboundNonce:test_getOutboundNonce_UpgradeNonceNewSenderStartsAtZero() (gas: 166146) +NonceManager_getOutboundNonce:test_getOutboundNonce_UpgradeNonceStartsAtV1Nonce() (gas: 195937) +NonceManager_getOutboundNonce:test_getOutboundNonce_UpgradeSenderNoncesReadsPreviousRamp() (gas: 140158) OffRamp_afterOC3ConfigSet:test_afterOCR3ConfigSet_SignatureVerificationDisabled_Revert() (gas: 5903354) OffRamp_applySourceChainConfigUpdates:test_AddMultipleChains_Success() (gas: 626094) OffRamp_applySourceChainConfigUpdates:test_AddNewChain_Success() (gas: 166505) @@ -614,10 +610,8 @@ RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetC RegistryModuleOwnerCustom_registerAdminViaGetCCIPAdmin:test_registerAdminViaGetCCIPAdmin_Success() (gas: 130126) RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Revert() (gas: 19602) RegistryModuleOwnerCustom_registerAdminViaOwner:test_registerAdminViaOwner_Success() (gas: 129930) -Router_applyRampUpdates:test_OffRampMismatch_Revert() (gas: 89591) -Router_applyRampUpdates:test_OffRampUpdatesWithRouting() (gas: 10750087) -Router_applyRampUpdates:test_OnRampDisable() (gas: 56445) -Router_applyRampUpdates:test_OnlyOwner_Revert() (gas: 12414) +Router_applyRampUpdates:test_applyRampUpdates_OffRampUpdatesWithRouting() (gas: 10749731) +Router_applyRampUpdates:test_applyRampUpdates_OnRampDisable() (gas: 56422) Router_ccipSend:test_CCIPSendLinkFeeNoTokenSuccess_gas() (gas: 131447) Router_ccipSend:test_CCIPSendLinkFeeOneTokenSuccess_gas() (gas: 221710) Router_ccipSend:test_FeeTokenAmountTooLow_Revert() (gas: 71858) diff --git a/contracts/src/v0.8/ccip/FeeQuoter.sol b/contracts/src/v0.8/ccip/FeeQuoter.sol index 58261eff499..b312e732e61 100644 --- a/contracts/src/v0.8/ccip/FeeQuoter.sol +++ b/contracts/src/v0.8/ccip/FeeQuoter.sol @@ -103,12 +103,12 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, // The following three properties are defaults, they can be overridden by setting the TokenTransferFeeConfig for a token. uint16 defaultTokenFeeUSDCents; // │ Default token fee charged per token transfer. uint32 defaultTokenDestGasOverhead; // ──────╯ Default gas charged to execute a token transfer on the destination chain. - uint32 defaultTxGasLimit; //─────────────────╮ Default gas limit for a tx. - uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost. - uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD. - uint32 gasPriceStalenessThreshold; // │ The amount of time a gas price can be stale before it is considered invalid (0 means disabled). - bool enforceOutOfOrder; // │ Whether to enforce the allowOutOfOrderExecution extraArg value to be true. - bytes4 chainFamilySelector; // ──────────────╯ Selector that identifies the destination chain's family. Used to determine the correct validations to perform for the dest chain. + uint32 defaultTxGasLimit; //──────────╮ Default gas limit for a tx. + uint64 gasMultiplierWeiPerEth; // │ Multiplier for gas costs, 1e18 based so 11e17 = 10% extra cost. + uint32 networkFeeUSDCents; // │ Flat network fee to charge for messages, multiples of 0.01 USD. + uint32 gasPriceStalenessThreshold; // │ The amount of time a gas price can be stale before it is considered invalid (0 means disabled). + bool enforceOutOfOrder; // │ Whether to enforce the allowOutOfOrderExecution extraArg value to be true. + bytes4 chainFamilySelector; // ───────╯ Selector that identifies the destination chain's family. Used to determine the correct validations to perform for the dest chain. } /// @dev Struct to hold the configs and its destination chain selector. Same as DestChainConfig but with the @@ -121,13 +121,13 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, /// @dev Struct with transfer fee configuration for token transfers. struct TokenTransferFeeConfig { - uint32 minFeeUSDCents; // ────╮ Minimum fee to charge per token transfer, multiples of 0.01 USD. - uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD. - uint16 deciBps; // │ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5. - uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain. - // │ Extra data availability bytes that are returned from the source pool and sent to - uint32 destBytesOverhead; // │ the destination pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES. - bool isEnabled; // ───────────╯ Whether this token has custom transfer fees. + uint32 minFeeUSDCents; // ───╮ Minimum fee to charge per token transfer, multiples of 0.01 USD. + uint32 maxFeeUSDCents; // │ Maximum fee to charge per token transfer, multiples of 0.01 USD. + uint16 deciBps; // │ Basis points charged on token transfers, multiples of 0.1bps, or 1e-5. + uint32 destGasOverhead; // │ Gas charged to execute the token transfer on the destination chain. + // │ Data availability bytes that are returned from the source pool and sent to the dest + uint32 destBytesOverhead; // │ pool. Must be >= Pool.CCIP_LOCK_OR_BURN_V1_RET_BYTES. Set as multiple of 32 bytes. + bool isEnabled; // ──────────╯ Whether this token has custom transfer fees. } /// @dev Struct with token transfer fee configurations for a token, same as TokenTransferFeeConfig but with the token @@ -517,6 +517,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, for (uint256 i = 0; i < feeds.length; ++i) { TokenPriceFeedConfig memory feedConfig = s_usdPriceFeedsPerToken[feeds[i].token]; + // If the token is not enabled we revert the entire report as that indicates some type of misconfiguration. if (!feedConfig.isEnabled) { revert TokenNotSupported(feeds[i].token); } @@ -710,6 +711,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, continue; } + // In the case where bpsFeeUSDWei, minFeeUSDWei, and maxFeeUSDWei are all 0, we skip the fee. This is intended + // to allow for a fee of 0 to be set. tokenTransferFeeUSDWei += bpsFeeUSDWei; } @@ -863,7 +866,9 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, if (evmExtraArgs.gasLimit > uint256(destChainConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh(); - // If the chain enforces out of order execution, the extra args must allow it, otherwise revert. + // If the chain enforces out of order execution, the extra args must allow it, otherwise revert. We cannot assume + // the user intended to use OOO on any chain that requires it as it may lead to unexpected behavior. Therefore we + // revert instead of assuming the user intended to use OOO. if (destChainConfig.enforceOutOfOrder && !evmExtraArgs.allowOutOfOrderExecution) { revert ExtraArgOutOfOrderExecutionMustBeTrue(); } diff --git a/contracts/src/v0.8/ccip/NonceManager.sol b/contracts/src/v0.8/ccip/NonceManager.sol index f95380b23b2..382844c27d9 100644 --- a/contracts/src/v0.8/ccip/NonceManager.sol +++ b/contracts/src/v0.8/ccip/NonceManager.sol @@ -33,9 +33,9 @@ contract NonceManager is INonceManager, AuthorizedCallers, ITypeAndVersion { /// @dev The previous on/off ramps per chain selector. mapping(uint64 chainSelector => PreviousRamps previousRamps) private s_previousRamps; - /// @dev The current outbound nonce per sender used on the onramp. + /// @dev The current outbound nonce per sender used on the onRamp. mapping(uint64 destChainSelector => mapping(address sender => uint64 outboundNonce)) private s_outboundNonces; - /// @dev The current inbound nonce per sender used on the offramp. + /// @dev The current inbound nonce per sender used on the offRamp. /// Eventually in sync with the outbound nonce in the remote source chain NonceManager, used to enforce that messages /// are executed in the same order they are sent (assuming they are DON). mapping(uint64 sourceChainSelector => mapping(bytes sender => uint64 inboundNonce)) private s_inboundNonces; @@ -71,6 +71,8 @@ contract NonceManager is INonceManager, AuthorizedCallers, ITypeAndVersion { if (outboundNonce == 0) { address prevOnRamp = s_previousRamps[destChainSelector].prevOnRamp; if (prevOnRamp != address(0)) { + // This gets the current nonce for a sender, not the already incremented nonce like getIncrementedOutboundNonce + // would return. return IEVM2AnyOnRamp(prevOnRamp).getSenderNonce(sender); } } diff --git a/contracts/src/v0.8/ccip/capability/CCIPHome.sol b/contracts/src/v0.8/ccip/capability/CCIPHome.sol index 00ffe20ded4..829c54c5b62 100644 --- a/contracts/src/v0.8/ccip/capability/CCIPHome.sol +++ b/contracts/src/v0.8/ccip/capability/CCIPHome.sol @@ -2,7 +2,6 @@ pragma solidity 0.8.24; import {ICapabilityConfiguration} from "../../keystone/interfaces/ICapabilityConfiguration.sol"; - import {INodeInfoProvider} from "../../keystone/interfaces/INodeInfoProvider.sol"; import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol"; @@ -111,7 +110,7 @@ contract CCIPHome is Ownable2StepMsgSender, ITypeAndVersion, ICapabilityConfigur uint64 chainSelector; // │ The (remote) chain that the configuration is for. uint8 FRoleDON; // │ The "big F" parameter for the role DON. uint64 offchainConfigVersion; // ──────╯ The version of the exec offchain configuration. - bytes offrampAddress; // The remote chain offramp address. + bytes offrampAddress; // The remote chain offRamp address. bytes rmnHomeAddress; // The home chain RMN home address. OCR3Node[] nodes; // Keys & IDs of nodes part of the role DON. bytes offchainConfig; // The offchain configuration for the OCR3 plugin. Protobuf encoded. @@ -241,10 +240,9 @@ contract CCIPHome is Ownable2StepMsgSender, ITypeAndVersion, ICapabilityConfigur } /// @inheritdoc ICapabilityConfiguration - /// @dev The CCIP capability will fetch the configuration needed directly from this contract. - /// The offchain syncer will call this function, so its important that it doesn't revert. + /// @dev This function is not used in the CCIPHome contract but the interface requires it to be implemented. function getCapabilityConfiguration( - uint32 /* donId */ + uint32 ) external pure override returns (bytes memory configuration) { return bytes(""); } diff --git a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol index 2d27bd3a25c..e40b186dda4 100644 --- a/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol +++ b/contracts/src/v0.8/ccip/interfaces/IEVM2AnyOnRamp.sol @@ -8,9 +8,9 @@ interface IEVM2AnyOnRamp is IEVM2AnyOnRampClient { /// @return the next sequence number to be used. function getExpectedNextSequenceNumber() external view returns (uint64); - /// @notice Get the next nonce for a given sender. + /// @notice Get the current nonce for a given sender. /// @param sender The sender to get the nonce for. - /// @return nonce The next nonce for the sender. + /// @return nonce The current nonce for the sender. function getSenderNonce( address sender ) external view returns (uint64 nonce); diff --git a/contracts/src/v0.8/ccip/libraries/Internal.sol b/contracts/src/v0.8/ccip/libraries/Internal.sol index 6e0152c8cf5..25d923ee1ed 100644 --- a/contracts/src/v0.8/ccip/libraries/Internal.sol +++ b/contracts/src/v0.8/ccip/libraries/Internal.sol @@ -3,7 +3,11 @@ pragma solidity ^0.8.4; import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol"; -// Library for CCIP internal definitions common to multiple contracts. +/// @notice Library for CCIP internal definitions common to multiple contracts. +/// @dev The following is a non-exhaustive list of "known issues" for CCIP: +/// - We could implement yield claiming for Blast. This is not worth the custom code path on non-blast chains. +/// - uint32 is used for timestamps, which will overflow in 2106. This is not a concern for the current use case, as we +/// expect to have migrated to a new version by then. library Internal { error InvalidEVMAddress(bytes encodedAddress); @@ -36,8 +40,8 @@ library Internal { /// @notice A timestamped uint224 value that can contain several tightly packed fields. struct TimestampedPackedUint224 { - uint224 value; // ──────╮ Value in uint224, packed. - uint32 timestamp; // ───╯ Timestamp of the most recent price update. + uint224 value; // ────╮ Value in uint224, packed. + uint32 timestamp; // ─╯ Timestamp of the most recent price update. } /// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices. @@ -192,10 +196,10 @@ library Internal { /// The messageId is not expected to match hash(message), since it may originate from another ramp family. struct RampMessageHeader { bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded). - uint64 sourceChainSelector; // ──╮ the chain selector of the source chain, note: not chainId. - uint64 destChainSelector; // │ the chain selector of the destination chain, note: not chainId. - uint64 sequenceNumber; // │ sequence number, not unique across lanes. - uint64 nonce; // ────────────────╯ nonce for this lane for this sender, not unique across senders/lanes. + uint64 sourceChainSelector; // ─╮ the chain selector of the source chain, note: not chainId. + uint64 destChainSelector; // │ the chain selector of the destination chain, note: not chainId. + uint64 sequenceNumber; // │ sequence number, not unique across lanes. + uint64 nonce; // ───────────────╯ nonce for this lane for this sender, not unique across senders/lanes. } struct EVM2AnyTokenTransfer { @@ -264,7 +268,7 @@ library Internal { // solhint-disable-next-line gas-struct-packing struct MerkleRoot { uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to - bytes onRampAddress; // Generic onramp address, to support arbitrary sources; for EVM, use abi.encode + bytes onRampAddress; // Generic onRamp address, to support arbitrary sources; for EVM, use abi.encode uint64 minSeqNr; // ─────────╮ Minimum sequence number, inclusive uint64 maxSeqNr; // ─────────╯ Maximum sequence number, inclusive bytes32 merkleRoot; // Merkle root covering the interval & source chain messages diff --git a/contracts/src/v0.8/ccip/offRamp/OffRamp.sol b/contracts/src/v0.8/ccip/offRamp/OffRamp.sol index f3c171ce462..76424b4e2a7 100644 --- a/contracts/src/v0.8/ccip/offRamp/OffRamp.sol +++ b/contracts/src/v0.8/ccip/offRamp/OffRamp.sol @@ -362,6 +362,8 @@ contract OffRamp is ITypeAndVersion, MultiOCR3Base { /// @param manualExecGasExecOverrides An array of gas limits to use for manual execution. /// @dev If called from the DON, this array is always empty. /// @dev If called from manual execution, this array is always same length as messages. + /// @dev This function can fully revert in some cases, reverting potentially valid other reports with it. The reasons + /// for these reverts are so severe that we prefer to revert the entire batch instead of silently failing. function _executeSingleReport( Internal.ExecutionReport memory report, GasLimitOverride[] memory manualExecGasExecOverrides @@ -583,6 +585,8 @@ contract OffRamp is ITypeAndVersion, MultiOCR3Base { destTokenAmounts: destTokenAmounts }); + // The main message interceptor is the aggregate rate limiter, but we also allow for a custom interceptor. This is + // why we always have to call into the contract when it's enabled, even when there are no tokens in the message. address messageInterceptor = s_dynamicConfig.messageInterceptor; if (messageInterceptor != address(0)) { try IMessageInterceptor(messageInterceptor).onInboundMessage(any2EvmMessage) {} diff --git a/contracts/src/v0.8/ccip/test/NonceManager.t.sol b/contracts/src/v0.8/ccip/test/NonceManager.t.sol deleted file mode 100644 index b5c3ee6bd99..00000000000 --- a/contracts/src/v0.8/ccip/test/NonceManager.t.sol +++ /dev/null @@ -1,568 +0,0 @@ -// SPDX-License-Identifier: BUSL-1.1 -pragma solidity 0.8.24; - -import {IEVM2AnyOnRamp} from "../interfaces/IEVM2AnyOnRamp.sol"; - -import {NonceManager} from "../NonceManager.sol"; -import {Client} from "../libraries/Client.sol"; -import {Internal} from "../libraries/Internal.sol"; -import {OffRamp} from "../offRamp/OffRamp.sol"; -import {OnRamp} from "../onRamp/OnRamp.sol"; -import {BaseTest} from "./BaseTest.t.sol"; -import {EVM2EVMOffRampHelper} from "./helpers/EVM2EVMOffRampHelper.sol"; -import {OnRampHelper} from "./helpers/OnRampHelper.sol"; -import {OffRampSetup} from "./offRamp/OffRamp/OffRampSetup.t.sol"; -import {OnRampSetup} from "./onRamp/OnRamp/OnRampSetup.t.sol"; - -import {Test} from "forge-std/Test.sol"; - -contract NonceManager_typeAndVersion is Test { - NonceManager private s_nonceManager; - - function setUp() public { - s_nonceManager = new NonceManager(new address[](0)); - } - - function test_typeAndVersion() public view { - assertEq(s_nonceManager.typeAndVersion(), "NonceManager 1.6.0-dev"); - } -} - -contract NonceManager_NonceIncrementation is BaseTest { - NonceManager private s_nonceManager; - - function setUp() public override { - address[] memory authorizedCallers = new address[](1); - authorizedCallers[0] = address(this); - s_nonceManager = new NonceManager(authorizedCallers); - } - - function test_getIncrementedOutboundNonce_Success() public { - address sender = address(this); - - assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0); - - uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender); - assertEq(outboundNonce, 1); - } - - function test_incrementInboundNonce_Success() public { - address sender = address(this); - - s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, 1, abi.encode(sender)); - - assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 1); - } - - function test_incrementInboundNonce_Skip() public { - address sender = address(this); - uint64 expectedNonce = 2; - - vm.expectEmit(); - emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender)); - - s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender)); - - assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 0); - } - - function test_incrementNoncesInboundAndOutbound_Success() public { - address sender = address(this); - - assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0); - uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender); - assertEq(outboundNonce, 1); - - // Inbound nonce unchanged - assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 0); - - s_nonceManager.incrementInboundNonce(DEST_CHAIN_SELECTOR, 1, abi.encode(sender)); - assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 1); - - // Outbound nonce unchanged - assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 1); - } -} - -contract NonceManager_applyPreviousRampsUpdates is OnRampSetup { - function test_SingleRampUpdate_success() public { - address prevOnRamp = makeAddr("prevOnRamp"); - address prevOffRamp = makeAddr("prevOffRamp"); - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), - overrideExistingRamps: false - }); - - vm.expectEmit(); - emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps); - } - - function test_MultipleRampsUpdates_success() public { - address prevOnRamp1 = makeAddr("prevOnRamp1"); - address prevOnRamp2 = makeAddr("prevOnRamp2"); - address prevOffRamp1 = makeAddr("prevOffRamp1"); - address prevOffRamp2 = makeAddr("prevOffRamp2"); - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](2); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp1, prevOffRamp1), - overrideExistingRamps: false - }); - previousRamps[1] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR + 1, - prevRamps: NonceManager.PreviousRamps(prevOnRamp2, prevOffRamp2), - overrideExistingRamps: false - }); - - vm.expectEmit(); - emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps); - vm.expectEmit(); - emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR + 1, previousRamps[1].prevRamps); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps); - _assertPreviousRampsEqual( - s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR + 1), previousRamps[1].prevRamps - ); - } - - function test_PreviousRampAlreadySet_overrideAllowed_success() public { - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - address prevOffRamp = makeAddr("prevOffRamp"); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), - overrideExistingRamps: true - }); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), - overrideExistingRamps: true - }); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - } - - function test_ZeroInput_success() public { - vm.recordLogs(); - s_outboundNonceManager.applyPreviousRampsUpdates(new NonceManager.PreviousRampsArgs[](0)); - - assertEq(vm.getRecordedLogs().length, 0); - } - - function test_PreviousRampAlreadySetOnRamp_Revert() public { - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - address prevOnRamp = makeAddr("prevOnRamp"); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp, address(0)), - overrideExistingRamps: false - }); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp, address(0)), - overrideExistingRamps: false - }); - - vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - } - - function test_PreviousRampAlreadySetOffRamp_Revert() public { - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - address prevOffRamp = makeAddr("prevOffRamp"); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), - overrideExistingRamps: false - }); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), - overrideExistingRamps: false - }); - - vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - } - - function test_PreviousRampAlreadySetOnRampAndOffRamp_Revert() public { - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - address prevOnRamp = makeAddr("prevOnRamp"); - address prevOffRamp = makeAddr("prevOffRamp"); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), - overrideExistingRamps: false - }); - - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), - overrideExistingRamps: false - }); - - vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - } - - function _assertPreviousRampsEqual( - NonceManager.PreviousRamps memory a, - NonceManager.PreviousRamps memory b - ) internal pure { - assertEq(a.prevOnRamp, b.prevOnRamp); - assertEq(a.prevOffRamp, b.prevOffRamp); - } -} - -contract NonceManager_OnRampUpgrade is OnRampSetup { - uint256 internal constant FEE_AMOUNT = 1234567890; - OnRampHelper internal s_prevOnRamp; - - function setUp() public virtual override { - super.setUp(); - - (s_prevOnRamp,) = _deployOnRamp( - SOURCE_CHAIN_SELECTOR, s_sourceRouter, address(s_outboundNonceManager), address(s_tokenAdminRegistry) - ); - - // Since the previous onRamp is not a 1.5 ramp it doesn't have the getSenderNonce function. We mock it to return 0 - vm.mockCall(address(s_prevOnRamp), abi.encodeWithSelector(IEVM2AnyOnRamp.getSenderNonce.selector), abi.encode(0)); - - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: DEST_CHAIN_SELECTOR, - prevRamps: NonceManager.PreviousRamps(address(s_prevOnRamp), address(0)), - overrideExistingRamps: false - }); - s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - (s_onRamp, s_metadataHash) = _deployOnRamp( - SOURCE_CHAIN_SELECTOR, s_sourceRouter, address(s_outboundNonceManager), address(s_tokenAdminRegistry) - ); - - vm.startPrank(address(s_sourceRouter)); - } - - function test_Upgrade_Success() public { - Client.EVM2AnyMessage memory message = _generateEmptyMessage(); - - vm.expectEmit(); - emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, 1, FEE_AMOUNT, OWNER)); - - s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); - } - - function test_UpgradeSenderNoncesReadsPreviousRamp_Success() public { - Client.EVM2AnyMessage memory message = _generateEmptyMessage(); - uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER); - - for (uint64 i = 1; i < 4; ++i) { - s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER); - - assertEq(startNonce + i, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); - } - } - - function test_UpgradeNonceStartsAtV1Nonce_Success() public { - Client.EVM2AnyMessage memory message = _generateEmptyMessage(); - - uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER); - - // send 1 message from previous onramp - s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); - - assertEq(startNonce + 1, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); - - // new onramp nonce should start from 2, while sequence number start from 1 - vm.expectEmit(); - emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, startNonce + 2, FEE_AMOUNT, OWNER)); - s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); - - assertEq(startNonce + 2, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); - - // after another send, nonce should be 3, and sequence number be 2 - vm.expectEmit(); - emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 2, _messageToEvent(message, 2, startNonce + 3, FEE_AMOUNT, OWNER)); - s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); - - assertEq(startNonce + 3, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); - } - - function test_UpgradeNonceNewSenderStartsAtZero_Success() public { - Client.EVM2AnyMessage memory message = _generateEmptyMessage(); - - // send 1 message from previous onramp from OWNER - s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); - - address newSender = address(1234567); - // new onramp nonce should start from 1 for new sender - vm.expectEmit(); - emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, 1, FEE_AMOUNT, newSender)); - - s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, newSender); - } -} - -contract NonceManager_OffRampUpgrade is OffRampSetup { - EVM2EVMOffRampHelper internal s_prevOffRamp; - - address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_1 = abi.decode(ON_RAMP_ADDRESS_1, (address)); - address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_2 = abi.decode(ON_RAMP_ADDRESS_2, (address)); - address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_3 = abi.decode(ON_RAMP_ADDRESS_3, (address)); - - function setUp() public virtual override { - super.setUp(); - - s_prevOffRamp = new EVM2EVMOffRampHelper(); - - NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); - previousRamps[0] = NonceManager.PreviousRampsArgs({ - remoteChainSelector: SOURCE_CHAIN_SELECTOR_1, - prevRamps: NonceManager.PreviousRamps(address(0), address(s_prevOffRamp)), - overrideExistingRamps: false - }); - - s_inboundNonceManager.applyPreviousRampsUpdates(previousRamps); - - OffRamp.SourceChainConfigArgs[] memory sourceChainConfigs = new OffRamp.SourceChainConfigArgs[](3); - sourceChainConfigs[0] = OffRamp.SourceChainConfigArgs({ - router: s_destRouter, - sourceChainSelector: SOURCE_CHAIN_SELECTOR_1, - isEnabled: true, - onRamp: ON_RAMP_ADDRESS_1 - }); - sourceChainConfigs[1] = OffRamp.SourceChainConfigArgs({ - router: s_destRouter, - sourceChainSelector: SOURCE_CHAIN_SELECTOR_2, - isEnabled: true, - onRamp: ON_RAMP_ADDRESS_2 - }); - sourceChainConfigs[2] = OffRamp.SourceChainConfigArgs({ - router: s_destRouter, - sourceChainSelector: SOURCE_CHAIN_SELECTOR_3, - isEnabled: true, - onRamp: ON_RAMP_ADDRESS_3 - }); - - _setupMultipleOffRampsFromConfigs(sourceChainConfigs); - - s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1); - s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1); - } - - function test_Upgraded_Success() public { - Internal.Any2EVMRampMessage[] memory messages = - _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); - - vm.recordLogs(); - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) - ); - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_1, - messages[0].header.sequenceNumber, - messages[0].header.messageId, - _hashMessage(messages[0], ON_RAMP_ADDRESS_1), - Internal.MessageExecutionState.SUCCESS, - "" - ); - } - - function test_NoPrevOffRampForChain_Success() public { - address[] memory senders = new address[](1); - senders[0] = OWNER; - - uint64 startNonceChain3 = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(senders[0])); - s_prevOffRamp.execute(senders); - - // Nonce unchanged for chain 3 - assertEq(startNonceChain3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(senders[0]))); - - Internal.Any2EVMRampMessage[] memory messagesChain3 = - _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3); - - vm.recordLogs(); - - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messagesChain3), new OffRamp.GasLimitOverride[](0) - ); - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_3, - messagesChain3[0].header.sequenceNumber, - messagesChain3[0].header.messageId, - _hashMessage(messagesChain3[0], ON_RAMP_ADDRESS_3), - Internal.MessageExecutionState.SUCCESS, - "" - ); - - assertEq( - startNonceChain3 + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messagesChain3[0].sender) - ); - } - - function test_UpgradedSenderNoncesReadsPreviousRamp_Success() public { - address[] memory senders = new address[](1); - senders[0] = OWNER; - - uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0])); - - for (uint64 i = 1; i < 4; ++i) { - s_prevOffRamp.execute(senders); - - assertEq(startNonce + i, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); - } - } - - function test_UpgradedNonceStartsAtV1Nonce_Success() public { - address[] memory senders = new address[](1); - senders[0] = OWNER; - - uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0])); - s_prevOffRamp.execute(senders); - - assertEq(startNonce + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); - - Internal.Any2EVMRampMessage[] memory messagesMultiRamp = - _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); - - messagesMultiRamp[0].header.nonce++; - messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); - - vm.recordLogs(); - - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) - ); - - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_1, - messagesMultiRamp[0].header.sequenceNumber, - messagesMultiRamp[0].header.messageId, - _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), - Internal.MessageExecutionState.SUCCESS, - "" - ); - - assertEq( - startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender) - ); - - messagesMultiRamp[0].header.nonce++; - messagesMultiRamp[0].header.sequenceNumber++; - messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); - - vm.recordLogs(); - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) - ); - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_1, - messagesMultiRamp[0].header.sequenceNumber, - messagesMultiRamp[0].header.messageId, - _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), - Internal.MessageExecutionState.SUCCESS, - "" - ); - - assertEq( - startNonce + 3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender) - ); - } - - function test_UpgradedNonceNewSenderStartsAtZero_Success() public { - address[] memory senders = new address[](1); - senders[0] = OWNER; - - s_prevOffRamp.execute(senders); - - Internal.Any2EVMRampMessage[] memory messagesMultiRamp = - _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); - - bytes memory newSender = abi.encode(address(1234567)); - messagesMultiRamp[0].sender = newSender; - messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); - - // new sender nonce in new offramp should go from 0 -> 1 - assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 0); - vm.recordLogs(); - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) - ); - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_1, - messagesMultiRamp[0].header.sequenceNumber, - messagesMultiRamp[0].header.messageId, - _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), - Internal.MessageExecutionState.SUCCESS, - "" - ); - assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 1); - } - - function test_UpgradedOffRampNonceSkipsIfMsgInFlight_Success() public { - Internal.Any2EVMRampMessage[] memory messages = - _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); - - address newSender = address(1234567); - messages[0].sender = abi.encode(newSender); - messages[0].header.nonce = 2; - messages[0].header.messageId = _hashMessage(messages[0], ON_RAMP_ADDRESS_1); - - uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender); - - // new offramp sees msg nonce higher than senderNonce - // it waits for previous offramp to execute - vm.expectEmit(); - emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].header.nonce, messages[0].sender); - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) - ); - assertEq(startNonce, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)); - - address[] memory senders = new address[](1); - senders[0] = newSender; - - // previous offramp executes msg and increases nonce - s_prevOffRamp.execute(senders); - assertEq(startNonce + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); - - messages[0].header.nonce = 2; - messages[0].header.messageId = _hashMessage(messages[0], ON_RAMP_ADDRESS_1); - - // new offramp is able to execute - vm.recordLogs(); - s_offRamp.executeSingleReport( - _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) - ); - - _assertExecutionStateChangedEventLogs( - SOURCE_CHAIN_SELECTOR_1, - messages[0].header.sequenceNumber, - messages[0].header.messageId, - _hashMessage(messages[0], ON_RAMP_ADDRESS_1), - Internal.MessageExecutionState.SUCCESS, - "" - ); - - assertEq(startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)); - } -} diff --git a/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.applyPreviousRampsUpdates.t.sol b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.applyPreviousRampsUpdates.t.sol new file mode 100644 index 00000000000..fe4316423ec --- /dev/null +++ b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.applyPreviousRampsUpdates.t.sol @@ -0,0 +1,154 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {NonceManager} from "../../NonceManager.sol"; +import {OnRampSetup} from "../onRamp/OnRamp/OnRampSetup.t.sol"; + +contract NonceManager_applyPreviousRampsUpdates is OnRampSetup { + function test_SingleRampUpdate_success() public { + address prevOnRamp = makeAddr("prevOnRamp"); + address prevOffRamp = makeAddr("prevOffRamp"); + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), + overrideExistingRamps: false + }); + + vm.expectEmit(); + emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps); + } + + function test_MultipleRampsUpdates() public { + address prevOnRamp1 = makeAddr("prevOnRamp1"); + address prevOnRamp2 = makeAddr("prevOnRamp2"); + address prevOffRamp1 = makeAddr("prevOffRamp1"); + address prevOffRamp2 = makeAddr("prevOffRamp2"); + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](2); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp1, prevOffRamp1), + overrideExistingRamps: false + }); + previousRamps[1] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR + 1, + prevRamps: NonceManager.PreviousRamps(prevOnRamp2, prevOffRamp2), + overrideExistingRamps: false + }); + + vm.expectEmit(); + emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR, previousRamps[0].prevRamps); + vm.expectEmit(); + emit NonceManager.PreviousRampsUpdated(DEST_CHAIN_SELECTOR + 1, previousRamps[1].prevRamps); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + _assertPreviousRampsEqual(s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR), previousRamps[0].prevRamps); + _assertPreviousRampsEqual( + s_outboundNonceManager.getPreviousRamps(DEST_CHAIN_SELECTOR + 1), previousRamps[1].prevRamps + ); + } + + function test_PreviousRampAlreadySet_overrideAllowed() public { + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + address prevOffRamp = makeAddr("prevOffRamp"); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), + overrideExistingRamps: true + }); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), + overrideExistingRamps: true + }); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + } + + function test_ZeroInput() public { + vm.recordLogs(); + s_outboundNonceManager.applyPreviousRampsUpdates(new NonceManager.PreviousRampsArgs[](0)); + + assertEq(vm.getRecordedLogs().length, 0); + } + + function test_applyPreviousRampsUpdates_RevertWhen_PreviousRampAlreadySetOnRamp() public { + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + address prevOnRamp = makeAddr("prevOnRamp"); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp, address(0)), + overrideExistingRamps: false + }); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp, address(0)), + overrideExistingRamps: false + }); + + vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + } + + function test_applyPreviousRampsUpdates_RevertWhen_PreviousRampAlreadySetOffRamp() public { + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + address prevOffRamp = makeAddr("prevOffRamp"); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), + overrideExistingRamps: false + }); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(address(0), prevOffRamp), + overrideExistingRamps: false + }); + + vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + } + + function test_applyPreviousRampsUpdates_RevertWhen_PreviousRampAlreadySetOnRampAndOffRamp_Revert() public { + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + address prevOnRamp = makeAddr("prevOnRamp"); + address prevOffRamp = makeAddr("prevOffRamp"); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), + overrideExistingRamps: false + }); + + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(prevOnRamp, prevOffRamp), + overrideExistingRamps: false + }); + + vm.expectRevert(NonceManager.PreviousRampAlreadySet.selector); + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + } + + function _assertPreviousRampsEqual( + NonceManager.PreviousRamps memory a, + NonceManager.PreviousRamps memory b + ) internal pure { + assertEq(a.prevOnRamp, b.prevOnRamp); + assertEq(a.prevOffRamp, b.prevOffRamp); + } +} diff --git a/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getInboundNonce.t.sol b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getInboundNonce.t.sol new file mode 100644 index 00000000000..4078c3c0d01 --- /dev/null +++ b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getInboundNonce.t.sol @@ -0,0 +1,253 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {NonceManager} from "../../NonceManager.sol"; +import {Internal} from "../../libraries/Internal.sol"; +import {OffRamp} from "../../offRamp/OffRamp.sol"; +import {EVM2EVMOffRampHelper} from "../helpers/EVM2EVMOffRampHelper.sol"; +import {OffRampSetup} from "../offRamp/OffRamp/OffRampSetup.t.sol"; + +contract NonceManager_getInboundNonce is OffRampSetup { + EVM2EVMOffRampHelper internal s_prevOffRamp; + + address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_1 = abi.decode(ON_RAMP_ADDRESS_1, (address)); + address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_2 = abi.decode(ON_RAMP_ADDRESS_2, (address)); + address internal constant SINGLE_LANE_ON_RAMP_ADDRESS_3 = abi.decode(ON_RAMP_ADDRESS_3, (address)); + + function setUp() public virtual override { + super.setUp(); + + s_prevOffRamp = new EVM2EVMOffRampHelper(); + + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: SOURCE_CHAIN_SELECTOR_1, + prevRamps: NonceManager.PreviousRamps(address(0), address(s_prevOffRamp)), + overrideExistingRamps: false + }); + + s_inboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + OffRamp.SourceChainConfigArgs[] memory sourceChainConfigs = new OffRamp.SourceChainConfigArgs[](3); + sourceChainConfigs[0] = OffRamp.SourceChainConfigArgs({ + router: s_destRouter, + sourceChainSelector: SOURCE_CHAIN_SELECTOR_1, + isEnabled: true, + onRamp: ON_RAMP_ADDRESS_1 + }); + sourceChainConfigs[1] = OffRamp.SourceChainConfigArgs({ + router: s_destRouter, + sourceChainSelector: SOURCE_CHAIN_SELECTOR_2, + isEnabled: true, + onRamp: ON_RAMP_ADDRESS_2 + }); + sourceChainConfigs[2] = OffRamp.SourceChainConfigArgs({ + router: s_destRouter, + sourceChainSelector: SOURCE_CHAIN_SELECTOR_3, + isEnabled: true, + onRamp: ON_RAMP_ADDRESS_3 + }); + + _setupMultipleOffRampsFromConfigs(sourceChainConfigs); + + s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_1, 1); + s_offRamp.setVerifyOverrideResult(SOURCE_CHAIN_SELECTOR_3, 1); + } + + function test_getInboundNonce_Upgraded() public { + Internal.Any2EVMRampMessage[] memory messages = + _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); + + vm.recordLogs(); + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) + ); + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_1, + messages[0].header.sequenceNumber, + messages[0].header.messageId, + _hashMessage(messages[0], ON_RAMP_ADDRESS_1), + Internal.MessageExecutionState.SUCCESS, + "" + ); + } + + function test_getInboundNonce_NoPrevOffRampForChain() public { + address[] memory senders = new address[](1); + senders[0] = OWNER; + + uint64 startNonceChain3 = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(senders[0])); + s_prevOffRamp.execute(senders); + + // Nonce unchanged for chain 3 + assertEq(startNonceChain3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, abi.encode(senders[0]))); + + Internal.Any2EVMRampMessage[] memory messagesChain3 = + _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_3, ON_RAMP_ADDRESS_3); + + vm.recordLogs(); + + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messagesChain3), new OffRamp.GasLimitOverride[](0) + ); + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_3, + messagesChain3[0].header.sequenceNumber, + messagesChain3[0].header.messageId, + _hashMessage(messagesChain3[0], ON_RAMP_ADDRESS_3), + Internal.MessageExecutionState.SUCCESS, + "" + ); + + assertEq( + startNonceChain3 + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_3, messagesChain3[0].sender) + ); + } + + function test_getInboundNonce_UpgradedSenderNoncesReadsPreviousRamp() public { + address[] memory senders = new address[](1); + senders[0] = OWNER; + + uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0])); + + for (uint64 i = 1; i < 4; ++i) { + s_prevOffRamp.execute(senders); + + assertEq(startNonce + i, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); + } + } + + function test_getInboundNonce_UpgradedNonceStartsAtV1Nonce() public { + address[] memory senders = new address[](1); + senders[0] = OWNER; + + uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0])); + s_prevOffRamp.execute(senders); + + assertEq(startNonce + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); + + Internal.Any2EVMRampMessage[] memory messagesMultiRamp = + _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); + + messagesMultiRamp[0].header.nonce++; + messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); + + vm.recordLogs(); + + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) + ); + + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_1, + messagesMultiRamp[0].header.sequenceNumber, + messagesMultiRamp[0].header.messageId, + _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), + Internal.MessageExecutionState.SUCCESS, + "" + ); + + assertEq( + startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender) + ); + + messagesMultiRamp[0].header.nonce++; + messagesMultiRamp[0].header.sequenceNumber++; + messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); + + vm.recordLogs(); + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) + ); + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_1, + messagesMultiRamp[0].header.sequenceNumber, + messagesMultiRamp[0].header.messageId, + _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), + Internal.MessageExecutionState.SUCCESS, + "" + ); + + assertEq( + startNonce + 3, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp[0].sender) + ); + } + + function test_getInboundNonce_UpgradedNonceNewSenderStartsAtZero() public { + address[] memory senders = new address[](1); + senders[0] = OWNER; + + s_prevOffRamp.execute(senders); + + Internal.Any2EVMRampMessage[] memory messagesMultiRamp = + _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); + + bytes memory newSender = abi.encode(address(1234567)); + messagesMultiRamp[0].sender = newSender; + messagesMultiRamp[0].header.messageId = _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1); + + // new sender nonce in new offRamp should go from 0 -> 1 + assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 0); + vm.recordLogs(); + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0) + ); + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_1, + messagesMultiRamp[0].header.sequenceNumber, + messagesMultiRamp[0].header.messageId, + _hashMessage(messagesMultiRamp[0], ON_RAMP_ADDRESS_1), + Internal.MessageExecutionState.SUCCESS, + "" + ); + assertEq(s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, newSender), 1); + } + + function test_getInboundNonce_UpgradedOffRampNonceSkipsIfMsgInFlight() public { + Internal.Any2EVMRampMessage[] memory messages = + _generateSingleBasicMessage(SOURCE_CHAIN_SELECTOR_1, ON_RAMP_ADDRESS_1); + + address newSender = address(1234567); + messages[0].sender = abi.encode(newSender); + messages[0].header.nonce = 2; + messages[0].header.messageId = _hashMessage(messages[0], ON_RAMP_ADDRESS_1); + + uint64 startNonce = s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender); + + // new offRamp sees msg nonce higher than senderNonce + // it waits for previous offRamp to execute + vm.expectEmit(); + emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].header.nonce, messages[0].sender); + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) + ); + assertEq(startNonce, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)); + + address[] memory senders = new address[](1); + senders[0] = newSender; + + // previous offRamp executes msg and increases nonce + s_prevOffRamp.execute(senders); + assertEq(startNonce + 1, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, abi.encode(senders[0]))); + + messages[0].header.nonce = 2; + messages[0].header.messageId = _hashMessage(messages[0], ON_RAMP_ADDRESS_1); + + // new offRamp is able to execute + vm.recordLogs(); + s_offRamp.executeSingleReport( + _generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0) + ); + + _assertExecutionStateChangedEventLogs( + SOURCE_CHAIN_SELECTOR_1, + messages[0].header.sequenceNumber, + messages[0].header.messageId, + _hashMessage(messages[0], ON_RAMP_ADDRESS_1), + Internal.MessageExecutionState.SUCCESS, + "" + ); + + assertEq(startNonce + 2, s_inboundNonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR_1, messages[0].sender)); + } +} diff --git a/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getIncrementedOutboundNonce.t.sol b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getIncrementedOutboundNonce.t.sol new file mode 100644 index 00000000000..1ac25d6c31f --- /dev/null +++ b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getIncrementedOutboundNonce.t.sol @@ -0,0 +1,61 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {NonceManager} from "../../NonceManager.sol"; +import {BaseTest} from "../BaseTest.t.sol"; + +contract NonceManager_getIncrementedOutboundNonce is BaseTest { + NonceManager private s_nonceManager; + + function setUp() public override { + address[] memory authorizedCallers = new address[](1); + authorizedCallers[0] = address(this); + s_nonceManager = new NonceManager(authorizedCallers); + } + + function test_getIncrementedOutboundNonce() public { + address sender = address(this); + + assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0); + + uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender); + assertEq(outboundNonce, 1); + } + + function test_incrementInboundNonce() public { + address sender = address(this); + + s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, 1, abi.encode(sender)); + + assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 1); + } + + function test_incrementInboundNonce_SkippedIncorrectNonce() public { + address sender = address(this); + uint64 expectedNonce = 2; + + vm.expectEmit(); + emit NonceManager.SkippedIncorrectNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender)); + + s_nonceManager.incrementInboundNonce(SOURCE_CHAIN_SELECTOR, expectedNonce, abi.encode(sender)); + + assertEq(s_nonceManager.getInboundNonce(SOURCE_CHAIN_SELECTOR, abi.encode(sender)), 0); + } + + function test_incrementNoncesInboundAndOutbound() public { + address sender = address(this); + + assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 0); + uint64 outboundNonce = s_nonceManager.getIncrementedOutboundNonce(DEST_CHAIN_SELECTOR, sender); + assertEq(outboundNonce, 1); + + // Inbound nonce unchanged + assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 0); + + s_nonceManager.incrementInboundNonce(DEST_CHAIN_SELECTOR, 1, abi.encode(sender)); + assertEq(s_nonceManager.getInboundNonce(DEST_CHAIN_SELECTOR, abi.encode(sender)), 1); + + // Outbound nonce unchanged + assertEq(s_nonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, sender), 1); + } +} diff --git a/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getOutboundNonce.t.sol b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getOutboundNonce.t.sol new file mode 100644 index 00000000000..2fe02bfb59d --- /dev/null +++ b/contracts/src/v0.8/ccip/test/NonceManager/NonceManager.getOutboundNonce.t.sol @@ -0,0 +1,102 @@ +// SPDX-License-Identifier: BUSL-1.1 +pragma solidity 0.8.24; + +import {IEVM2AnyOnRamp} from "../../interfaces/IEVM2AnyOnRamp.sol"; + +import {NonceManager} from "../../NonceManager.sol"; +import {Client} from "../../libraries/Client.sol"; +import {OnRamp} from "../../onRamp/OnRamp.sol"; +import {OnRampHelper} from "../helpers/OnRampHelper.sol"; +import {OnRampSetup} from "../onRamp/OnRamp/OnRampSetup.t.sol"; + +contract NonceManager_getOutboundNonce is OnRampSetup { + uint256 internal constant FEE_AMOUNT = 1234567890; + OnRampHelper internal s_prevOnRamp; + + function setUp() public virtual override { + super.setUp(); + + (s_prevOnRamp,) = _deployOnRamp( + SOURCE_CHAIN_SELECTOR, s_sourceRouter, address(s_outboundNonceManager), address(s_tokenAdminRegistry) + ); + + // Since the previous onRamp is not a 1.5 ramp it doesn't have the getSenderNonce function. We mock it to return 0 + vm.mockCall(address(s_prevOnRamp), abi.encodeWithSelector(IEVM2AnyOnRamp.getSenderNonce.selector), abi.encode(0)); + + NonceManager.PreviousRampsArgs[] memory previousRamps = new NonceManager.PreviousRampsArgs[](1); + previousRamps[0] = NonceManager.PreviousRampsArgs({ + remoteChainSelector: DEST_CHAIN_SELECTOR, + prevRamps: NonceManager.PreviousRamps(address(s_prevOnRamp), address(0)), + overrideExistingRamps: false + }); + s_outboundNonceManager.applyPreviousRampsUpdates(previousRamps); + + (s_onRamp, s_metadataHash) = _deployOnRamp( + SOURCE_CHAIN_SELECTOR, s_sourceRouter, address(s_outboundNonceManager), address(s_tokenAdminRegistry) + ); + + vm.startPrank(address(s_sourceRouter)); + } + + function test_getOutboundNonce_Upgrade() public { + Client.EVM2AnyMessage memory message = _generateEmptyMessage(); + + vm.expectEmit(); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, 1, FEE_AMOUNT, OWNER)); + + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); + } + + function test_getOutboundNonce_UpgradeSenderNoncesReadsPreviousRamp() public { + Client.EVM2AnyMessage memory message = _generateEmptyMessage(); + uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER); + uint64 prevRampNextOutboundNonce = IEVM2AnyOnRamp(address(s_prevOnRamp)).getSenderNonce(OWNER); + + assertEq(startNonce, prevRampNextOutboundNonce); + + for (uint64 i = 1; i < 4; ++i) { + s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, 0, OWNER); + + assertEq(startNonce + i, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); + } + } + + function test_getOutboundNonce_UpgradeNonceStartsAtV1Nonce() public { + Client.EVM2AnyMessage memory message = _generateEmptyMessage(); + + uint64 startNonce = s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER); + + // send 1 message from previous onRamp + s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); + + assertEq(startNonce + 1, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); + + // new onRamp nonce should start from 2, while sequence number start from 1 + vm.expectEmit(); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, startNonce + 2, FEE_AMOUNT, OWNER)); + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); + + assertEq(startNonce + 2, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); + + // after another send, nonce should be 3, and sequence number be 2 + vm.expectEmit(); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 2, _messageToEvent(message, 2, startNonce + 3, FEE_AMOUNT, OWNER)); + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); + + assertEq(startNonce + 3, s_outboundNonceManager.getOutboundNonce(DEST_CHAIN_SELECTOR, OWNER)); + } + + function test_getOutboundNonce_UpgradeNonceNewSenderStartsAtZero() public { + Client.EVM2AnyMessage memory message = _generateEmptyMessage(); + + // send 1 message from previous onRamp from OWNER + s_prevOnRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, OWNER); + + address newSender = address(1234567); + // new onRamp nonce should start from 1 for new sender + vm.expectEmit(); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, 1, _messageToEvent(message, 1, 1, FEE_AMOUNT, newSender)); + + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, FEE_AMOUNT, newSender); + } +} diff --git a/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol b/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol index 9b46741f96d..be0999542ea 100644 --- a/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol +++ b/contracts/src/v0.8/ccip/test/router/Router/Router.applyRampUpdates.t.sol @@ -38,7 +38,7 @@ contract Router_applyRampUpdates is RouterSetup { ); } - function testFuzz_OffRampUpdates( + function testFuzz_applyRampUpdates_OffRampUpdates( address[20] memory offRampsInput ) public { Router.OffRamp[] memory offRamps = new Router.OffRamp[](20); @@ -72,7 +72,7 @@ contract Router_applyRampUpdates is RouterSetup { } } - function test_OffRampUpdatesWithRouting() public { + function test_applyRampUpdates_OffRampUpdatesWithRouting() public { // Explicitly construct chain selectors and ramp addresses so we have ramp uniqueness for the various test scenarios. uint256 numberOfSelectors = 10; uint64[] memory sourceChainSelectors = new uint64[](numberOfSelectors); @@ -219,7 +219,7 @@ contract Router_applyRampUpdates is RouterSetup { } } - function testFuzz_OnRampUpdates( + function testFuzz_applyRampUpdates_OnRampUpdates( Router.OnRamp[] memory onRamps ) public { // Test adding onRamps @@ -244,7 +244,7 @@ contract Router_applyRampUpdates is RouterSetup { } } - function test_OnRampDisable() public { + function test_applyRampUpdates_OnRampDisable() public { // Add onRamp Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](1); Router.OffRamp[] memory offRampUpdates = new Router.OffRamp[](0); @@ -267,7 +267,7 @@ contract Router_applyRampUpdates is RouterSetup { assertTrue(s_sourceRouter.isChainSupported(DEST_CHAIN_SELECTOR)); } - function test_OnlyOwner_Revert() public { + function test_applyRampUpdates_RevertWhen_OnlyOwner() public { vm.stopPrank(); vm.expectRevert("Only callable by owner"); Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0); @@ -275,7 +275,7 @@ contract Router_applyRampUpdates is RouterSetup { s_sourceRouter.applyRampUpdates(onRampUpdates, offRampUpdates, offRampUpdates); } - function test_OffRampMismatch_Revert() public { + function test_applyRampUpdates_RevertWhen_OffRampMismatch() public { address offRamp = address(uint160(2)); Router.OnRamp[] memory onRampUpdates = new Router.OnRamp[](0);