diff --git a/contracts/src/v0.8/ccip/libraries/Internal.sol b/contracts/src/v0.8/ccip/libraries/Internal.sol index d09717f63a..e99acad110 100644 --- a/contracts/src/v0.8/ccip/libraries/Internal.sol +++ b/contracts/src/v0.8/ccip/libraries/Internal.sol @@ -342,6 +342,7 @@ library Internal { bytes extraArgs; // destination-chain specific extra args, such as the gasLimit for EVM chains address feeToken; // fee token uint256 feeTokenAmount; // fee token amount + uint256 feeValueJuels; // fee amount in Jules EVM2AnyTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer } diff --git a/contracts/src/v0.8/ccip/onRamp/OnRamp.sol b/contracts/src/v0.8/ccip/onRamp/OnRamp.sol index 76e966311d..959d831a39 100644 --- a/contracts/src/v0.8/ccip/onRamp/OnRamp.sol +++ b/contracts/src/v0.8/ccip/onRamp/OnRamp.sol @@ -46,7 +46,6 @@ contract OnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCreator { event DestChainConfigSet( uint64 indexed destChainSelector, uint64 sequenceNumber, IRouter router, bool allowListEnabled ); - event FeePaid(address indexed feeToken, uint256 feeValueJuels); event FeeTokenWithdrawn(address indexed feeAggregator, address indexed feeToken, uint256 amount); /// RMN depends on this event, if changing, please notify the RMN maintainers. event CCIPMessageSent(uint64 indexed destChainSelector, Internal.EVM2AnyRampMessage message); @@ -211,6 +210,7 @@ contract OnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCreator { receiver: message.receiver, feeToken: message.feeToken, feeTokenAmount: feeTokenAmount, + feeValueJuels: 0, // calculated later // Should be populated via lock / burn pool calls tokenAmounts: new Internal.EVM2AnyTokenTransfer[](message.tokenAmounts.length) }); @@ -224,17 +224,15 @@ contract OnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCreator { // Convert message fee to juels and retrieve converted args // Validate pool return data after it is populated (view function - no state changes) - ( - uint256 msgFeeJuels, - bool isOutOfOrderExecution, - bytes memory convertedExtraArgs, - bytes[] memory destExecDataPerToken - ) = IFeeQuoter(s_dynamicConfig.feeQuoter).processMessageArgs( + bool isOutOfOrderExecution; + bytes memory convertedExtraArgs; + bytes[] memory destExecDataPerToken; + (newMessage.feeValueJuels, isOutOfOrderExecution, convertedExtraArgs, destExecDataPerToken) = IFeeQuoter( + s_dynamicConfig.feeQuoter + ).processMessageArgs( destChainSelector, message.feeToken, feeTokenAmount, message.extraArgs, newMessage.tokenAmounts, tokenAmounts ); - emit FeePaid(message.feeToken, msgFeeJuels); - newMessage.header.nonce = isOutOfOrderExecution ? 0 : INonceManager(i_nonceManager).getIncrementedOutboundNonce(destChainSelector, originalSender); diff --git a/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.t.sol b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.t.sol index 5f06a37e13..59f727c251 100644 --- a/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.t.sol +++ b/contracts/src/v0.8/ccip/test/e2e/MultiRampsEnd2End.t.sol @@ -251,6 +251,8 @@ contract MultiRampsE2E is OnRampSetup, OffRampSetup { IERC20(s_sourceTokens[0]).approve(address(router), i_tokenAmount0 + router.getFee(DEST_CHAIN_SELECTOR, message)); IERC20(s_sourceTokens[1]).approve(address(router), i_tokenAmount1); + uint256 feeAmount = router.getFee(DEST_CHAIN_SELECTOR, message); + message.receiver = abi.encode(address(s_receiver)); Internal.EVM2AnyRampMessage memory msgEvent = _messageToEvent( message, @@ -258,7 +260,8 @@ contract MultiRampsE2E is OnRampSetup, OffRampSetup { DEST_CHAIN_SELECTOR, expectedSeqNum, nonce, - router.getFee(DEST_CHAIN_SELECTOR, message), + feeAmount, + feeAmount, OWNER, metadataHash, tokenAdminRegistry diff --git a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoterSetup.t.sol b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoterSetup.t.sol index 340fe3662d..d630c55c0d 100644 --- a/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoterSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/feeQuoter/FeeQuoterSetup.t.sol @@ -367,6 +367,7 @@ contract FeeQuoterFeeSetup is FeeQuoterSetup { uint64 seqNum, uint64 nonce, uint256 feeTokenAmount, + uint256 feeValueJuels, address originalSender, bytes32 metadataHash, TokenAdminRegistry tokenAdminRegistry @@ -388,6 +389,7 @@ contract FeeQuoterFeeSetup is FeeQuoterSetup { extraArgs: Client._argsToBytes(extraArgs), feeToken: message.feeToken, feeTokenAmount: feeTokenAmount, + feeValueJuels: feeValueJuels, tokenAmounts: new Internal.EVM2AnyTokenTransfer[](message.tokenAmounts.length) }); diff --git a/contracts/src/v0.8/ccip/test/onRamp/OnRamp.t.sol b/contracts/src/v0.8/ccip/test/onRamp/OnRamp.t.sol index 72be798738..2a7fac892c 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/OnRamp.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/OnRamp.t.sol @@ -287,7 +287,8 @@ contract OnRamp_forwardFromRouter is OnRampSetup { IERC20(s_sourceFeeToken).transferFrom(OWNER, address(s_onRamp), feeAmount); vm.expectEmit(); - emit OnRamp.FeePaid(s_sourceFeeToken, feeAmount); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, OWNER)); + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER); assertEq(IERC20(s_sourceFeeToken).balanceOf(address(s_onRamp)), feeAmount); @@ -307,7 +308,8 @@ contract OnRamp_forwardFromRouter is OnRampSetup { uint256 expectedJuels = (feeAmount * conversionRate) / 1e18; vm.expectEmit(); - emit OnRamp.FeePaid(s_sourceTokens[1], expectedJuels); + emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, _messageToEvent(message, 1, 1, feeAmount, expectedJuels, OWNER)); + s_onRamp.forwardFromRouter(DEST_CHAIN_SELECTOR, message, feeAmount, OWNER); assertEq(IERC20(s_sourceTokens[1]).balanceOf(address(s_onRamp)), feeAmount); @@ -352,8 +354,6 @@ contract OnRamp_forwardFromRouter is OnRampSetup { Internal.EVM2AnyRampMessage memory expectedEvent = _messageToEvent(message, 1, 1, feeTokenAmount, originalSender); vm.expectEmit(); - emit OnRamp.FeePaid(s_sourceFeeToken, feeTokenAmount); - vm.expectEmit(false, false, false, true); emit OnRamp.CCIPMessageSent(DEST_CHAIN_SELECTOR, expectedEvent); // Assert the message Id is correct diff --git a/contracts/src/v0.8/ccip/test/onRamp/OnRampSetup.t.sol b/contracts/src/v0.8/ccip/test/onRamp/OnRampSetup.t.sol index ddcbbd5620..6ecd3a5807 100644 --- a/contracts/src/v0.8/ccip/test/onRamp/OnRampSetup.t.sol +++ b/contracts/src/v0.8/ccip/test/onRamp/OnRampSetup.t.sol @@ -64,13 +64,33 @@ contract OnRampSetup is FeeQuoterFeeSetup { }); } + /// @dev a helper function to compose EVM2AnyRampMessage messages + /// @dev it is assummed that LINK is the payment token because feeTokenAmount == feeValueJuels function _messageToEvent( Client.EVM2AnyMessage memory message, uint64 seqNum, uint64 nonce, uint256 feeTokenAmount, address originalSender - ) public view returns (Internal.EVM2AnyRampMessage memory) { + ) internal view returns (Internal.EVM2AnyRampMessage memory) { + return _messageToEvent( + message, + seqNum, + nonce, + feeTokenAmount, // fee paid + feeTokenAmount, // converstion to jules is the same + originalSender + ); + } + + function _messageToEvent( + Client.EVM2AnyMessage memory message, + uint64 seqNum, + uint64 nonce, + uint256 feeTokenAmount, + uint256 feeValueJuels, + address originalSender + ) internal view returns (Internal.EVM2AnyRampMessage memory) { return _messageToEvent( message, SOURCE_CHAIN_SELECTOR, @@ -78,6 +98,7 @@ contract OnRampSetup is FeeQuoterFeeSetup { seqNum, nonce, feeTokenAmount, + feeValueJuels, originalSender, s_metadataHash, s_tokenAdminRegistry