Skip to content

Commit

Permalink
CCIP-4115 split tests for onRamp and FeeQuoter (#15116)
Browse files Browse the repository at this point in the history
* Clean up offRamp tests

* split onRamp

* cleanup onRamp

* split feeQuoter

* cleanup feeQuoter

* cleanup misc

* lint
  • Loading branch information
RensR authored Nov 6, 2024
1 parent 5528a21 commit 58995a5
Show file tree
Hide file tree
Showing 53 changed files with 4,051 additions and 3,960 deletions.
5 changes: 5 additions & 0 deletions contracts/.changeset/poor-ears-hear.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/contracts': patch
---

#internal split onRamp and feeQuoter tests
324 changes: 162 additions & 162 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

27 changes: 0 additions & 27 deletions contracts/src/v0.8/ccip/test/BaseTest.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,8 @@ contract BaseTest is Test {
// Addresses
address internal constant OWNER = 0x00007e64E1fB0C487F25dd6D3601ff6aF8d32e4e;
address internal constant STRANGER = address(999999);
address internal constant DUMMY_CONTRACT_ADDRESS = 0x1111111111111111111111111111111111111112;
address internal constant ON_RAMP_ADDRESS = 0x11118e64e1FB0c487f25dD6D3601FF6aF8d32E4e;
address internal constant ZERO_ADDRESS = address(0);
address internal constant FEE_AGGREGATOR = 0xa33CDB32eAEce34F6affEfF4899cef45744EDea3;

address internal constant USER_1 = address(1);
address internal constant USER_2 = address(2);
address internal constant USER_3 = address(3);
address internal constant USER_4 = address(4);

// Message info
uint64 internal constant SOURCE_CHAIN_SELECTOR = 1;
Expand All @@ -34,7 +27,6 @@ contract BaseTest is Test {
uint32 internal constant TWELVE_HOURS = 60 * 60 * 12;

// Onramp
uint96 internal constant MAX_NOP_FEES_JUELS = 1e27;
uint96 internal constant MAX_MSG_FEES_JUELS = 1_000e18;
uint32 internal constant DEST_GAS_OVERHEAD = 300_000;
uint16 internal constant DEST_GAS_PER_PAYLOAD_BYTE = 16;
Expand All @@ -45,31 +37,12 @@ contract BaseTest is Test {

bool private s_baseTestInitialized;

// Use 16 gas per data availability byte in our tests.
// This is an overestimation in OP stack, it ignores 4 gas per 0 byte rule.
// Arbitrum on the other hand, does always use 16 gas per data availability byte.
// This value may be substantially decreased after EIP 4844.
uint16 internal constant DEST_GAS_PER_DATA_AVAILABILITY_BYTE = 16;

// Total L1 data availability overhead estimate is 33_596 gas.
// This value includes complete CommitStore and OffRamp call data.
uint32 internal constant DEST_DATA_AVAILABILITY_OVERHEAD_GAS = 188 // Fixed data availability overhead in OP stack.
+ (32 * 31 + 4) * DEST_GAS_PER_DATA_AVAILABILITY_BYTE // CommitStore single-root transmission takes up about 31 slots, plus selector.
+ (32 * 34 + 4) * DEST_GAS_PER_DATA_AVAILABILITY_BYTE; // OffRamp transmission excluding EVM2EVMMessage takes up about 34 slots, plus selector.

// Multiples of bps, or 0.0001, use 6840 to be same as OP mainnet compression factor of 0.684.
uint16 internal constant DEST_GAS_DATA_AVAILABILITY_MULTIPLIER_BPS = 6840;

// OffRamp
uint32 internal constant MAX_DATA_SIZE = 30_000;
uint16 internal constant MAX_TOKENS_LENGTH = 5;
uint16 internal constant GAS_FOR_CALL_EXACT_CHECK = 5000;
uint32 internal constant PERMISSION_LESS_EXECUTION_THRESHOLD_SECONDS = 500;
uint32 internal constant MAX_GAS_LIMIT = 4_000_000;

// Rate limiter
address internal constant ADMIN = 0x11118e64e1FB0c487f25dD6D3601FF6aF8d32E4e;

MockRMN internal s_mockRMN;
IRMNRemote internal s_mockRMNRemote;

Expand Down
14 changes: 7 additions & 7 deletions contracts/src/v0.8/ccip/test/NonceManager.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ 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/OnRampSetup.t.sol";
import {OnRampSetup} from "./onRamp/onRamp/OnRampSetup.t.sol";

import {Test} from "forge-std/Test.sol";

Expand Down Expand Up @@ -377,7 +377,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
s_offRamp.executeSingleReport(
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0)
);
assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_1,
messages[0].header.sequenceNumber,
messages[0].header.messageId,
Expand Down Expand Up @@ -405,7 +405,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
s_offRamp.executeSingleReport(
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_3, messagesChain3), new OffRamp.GasLimitOverride[](0)
);
assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_3,
messagesChain3[0].header.sequenceNumber,
messagesChain3[0].header.messageId,
Expand Down Expand Up @@ -453,7 +453,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0)
);

assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_1,
messagesMultiRamp[0].header.sequenceNumber,
messagesMultiRamp[0].header.messageId,
Expand All @@ -474,7 +474,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
s_offRamp.executeSingleReport(
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0)
);
assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_1,
messagesMultiRamp[0].header.sequenceNumber,
messagesMultiRamp[0].header.messageId,
Expand Down Expand Up @@ -507,7 +507,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
s_offRamp.executeSingleReport(
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messagesMultiRamp), new OffRamp.GasLimitOverride[](0)
);
assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_1,
messagesMultiRamp[0].header.sequenceNumber,
messagesMultiRamp[0].header.messageId,
Expand Down Expand Up @@ -554,7 +554,7 @@ contract NonceManager_OffRampUpgrade is OffRampSetup {
_generateReportFromMessages(SOURCE_CHAIN_SELECTOR_1, messages), new OffRamp.GasLimitOverride[](0)
);

assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR_1,
messages[0].header.sequenceNumber,
messages[0].header.messageId,
Expand Down
13 changes: 0 additions & 13 deletions contracts/src/v0.8/ccip/test/TokenSetup.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@
pragma solidity 0.8.24;

import {BurnMintERC677} from "../../shared/token/ERC677/BurnMintERC677.sol";
import {Client} from "../libraries/Client.sol";
import {BurnMintTokenPool} from "../pools/BurnMintTokenPool.sol";
import {LockReleaseTokenPool} from "../pools/LockReleaseTokenPool.sol";
import {TokenPool} from "../pools/TokenPool.sol";
Expand Down Expand Up @@ -136,18 +135,6 @@ contract TokenSetup is RouterSetup {
}
}

function _getCastedSourceEVMTokenAmountsWithZeroAmounts()
internal
view
returns (Client.EVMTokenAmount[] memory tokenAmounts)
{
tokenAmounts = new Client.EVMTokenAmount[](s_sourceTokens.length);
for (uint256 i = 0; i < tokenAmounts.length; ++i) {
tokenAmounts[i].token = s_sourceTokens[i];
}
return tokenAmounts;
}

function _setPool(
TokenAdminRegistry tokenAdminRegistry,
address token,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ pragma solidity ^0.8.0;

import {DefensiveExample} from "../../applications/DefensiveExample.sol";
import {Client} from "../../libraries/Client.sol";
import {OnRampSetup} from "../onRamp/OnRampSetup.t.sol";
import {OnRampSetup} from "../onRamp/onRamp/OnRampSetup.t.sol";

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import {IAny2EVMMessageReceiver} from "../../interfaces/IAny2EVMMessageReceiver.

import {CCIPClientExample} from "../../applications/CCIPClientExample.sol";
import {Client} from "../../libraries/Client.sol";
import {OnRampSetup} from "../onRamp/OnRampSetup.t.sol";
import {OnRampSetup} from "../onRamp/onRamp/OnRampSetup.t.sol";

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";
import {ERC165Checker} from
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import {PingPongDemo} from "../../applications/PingPongDemo.sol";
import {Client} from "../../libraries/Client.sol";
import {Internal} from "../../libraries/Internal.sol";
import {OnRamp} from "../../onRamp/OnRamp.sol";
import {OnRampSetup} from "../onRamp/OnRampSetup.t.sol";
import {OnRampSetup} from "../onRamp/onRamp/OnRampSetup.t.sol";

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ pragma solidity 0.8.24;
import {Client} from "../../../libraries/Client.sol";
import {OnRamp} from "../../../onRamp/OnRamp.sol";
import {TokenPool} from "../../../pools/TokenPool.sol";
import {OnRampSetup} from "../../onRamp/OnRampSetup.t.sol";
import {OnRampSetup} from "../../onRamp/onRamp/OnRampSetup.t.sol";
import {FacadeClient} from "./FacadeClient.sol";
import {ReentrantMaliciousTokenPool} from "./ReentrantMaliciousTokenPool.sol";

Expand Down
32 changes: 24 additions & 8 deletions contracts/src/v0.8/ccip/test/e2e/End2End.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import {TokenAdminRegistry} from "../../tokenAdminRegistry/TokenAdminRegistry.so
import {MerkleHelper} from "../helpers/MerkleHelper.sol";
import {OnRampHelper} from "../helpers/OnRampHelper.sol";
import {OffRampSetup} from "../offRamp/offRamp/OffRampSetup.t.sol";
import {OnRampSetup} from "../onRamp/OnRampSetup.t.sol";
import {OnRampSetup} from "../onRamp/onRamp/OnRampSetup.t.sol";

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/token/ERC20/IERC20.sol";

Expand All @@ -28,6 +28,9 @@ import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.3/contracts/tok
contract E2E is OnRampSetup, OffRampSetup {
using Internal for Internal.Any2EVMRampMessage;

uint256 internal constant TOKEN_AMOUNT_1 = 9;
uint256 internal constant TOKEN_AMOUNT_2 = 7;

Router internal s_sourceRouter2;
OnRampHelper internal s_onRamp2;
TokenAdminRegistry internal s_tokenAdminRegistry2;
Expand Down Expand Up @@ -137,9 +140,9 @@ contract E2E is OnRampSetup, OffRampSetup {
uint256 expectedFee = s_sourceRouter.getFee(DEST_CHAIN_SELECTOR, _generateTokenMessage());
// Asserts that the tokens have been sent and the fee has been paid.
assertEq(
balance0Pre - (messages1.length + messages2.length) * (i_tokenAmount0 + expectedFee), token0.balanceOf(OWNER)
balance0Pre - (messages1.length + messages2.length) * (TOKEN_AMOUNT_1 + expectedFee), token0.balanceOf(OWNER)
);
assertEq(balance1Pre - (messages1.length + messages2.length) * i_tokenAmount1, token1.balanceOf(OWNER));
assertEq(balance1Pre - (messages1.length + messages2.length) * TOKEN_AMOUNT_2, token1.balanceOf(OWNER));
}

// Commit
Expand Down Expand Up @@ -215,7 +218,7 @@ contract E2E is OnRampSetup, OffRampSetup {
vm.recordLogs();
_execute(reports);

assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR,
messages1[0].header.sequenceNumber,
messages1[0].header.messageId,
Expand All @@ -224,7 +227,7 @@ contract E2E is OnRampSetup, OffRampSetup {
""
);

assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR,
messages1[1].header.sequenceNumber,
messages1[1].header.messageId,
Expand All @@ -233,7 +236,7 @@ contract E2E is OnRampSetup, OffRampSetup {
""
);

assertExecutionStateChangedEventLogs(
_assertExecutionStateChangedEventLogs(
SOURCE_CHAIN_SELECTOR + 1,
messages2[0].header.sequenceNumber,
messages2[0].header.messageId,
Expand All @@ -252,8 +255,8 @@ contract E2E is OnRampSetup, OffRampSetup {
TokenAdminRegistry tokenAdminRegistry
) public returns (Internal.Any2EVMRampMessage memory) {
Client.EVM2AnyMessage memory message = _generateTokenMessage();
IERC20(s_sourceTokens[0]).approve(address(router), i_tokenAmount0 + router.getFee(DEST_CHAIN_SELECTOR, message));
IERC20(s_sourceTokens[1]).approve(address(router), i_tokenAmount1);
IERC20(s_sourceTokens[0]).approve(address(router), TOKEN_AMOUNT_1 + router.getFee(DEST_CHAIN_SELECTOR, message));
IERC20(s_sourceTokens[1]).approve(address(router), TOKEN_AMOUNT_2);

uint256 feeAmount = router.getFee(DEST_CHAIN_SELECTOR, message);

Expand Down Expand Up @@ -306,4 +309,17 @@ contract E2E is OnRampSetup, OffRampSetup {
tokenAmounts: any2EVMTokenTransfer
});
}

function _generateTokenMessage() public view returns (Client.EVM2AnyMessage memory) {
Client.EVMTokenAmount[] memory tokenAmounts = _getCastedSourceEVMTokenAmountsWithZeroAmounts();
tokenAmounts[0].amount = TOKEN_AMOUNT_1;
tokenAmounts[1].amount = TOKEN_AMOUNT_2;
return Client.EVM2AnyMessage({
receiver: abi.encode(OWNER),
data: "",
tokenAmounts: tokenAmounts,
feeToken: s_sourceFeeToken,
extraArgs: Client._argsToBytes(Client.EVMExtraArgsV1({gasLimit: GAS_LIMIT}))
});
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.24;

import {FeeQuoter} from "../../FeeQuoter.sol";
import {Internal} from "../../libraries/Internal.sol";
import {FeeQuoterSetup} from "./FeeQuoterSetup.t.sol";

contract FeeQuoter_applyDestChainConfigUpdates is FeeQuoterSetup {
function test_Fuzz_applyDestChainConfigUpdates_Success(
FeeQuoter.DestChainConfigArgs memory destChainConfigArgs
) public {
vm.assume(destChainConfigArgs.destChainSelector != 0);
vm.assume(destChainConfigArgs.destChainConfig.maxPerMsgGasLimit != 0);
destChainConfigArgs.destChainConfig.defaultTxGasLimit = uint32(
bound(
destChainConfigArgs.destChainConfig.defaultTxGasLimit, 1, destChainConfigArgs.destChainConfig.maxPerMsgGasLimit
)
);
destChainConfigArgs.destChainConfig.chainFamilySelector = Internal.CHAIN_FAMILY_SELECTOR_EVM;

bool isNewChain = destChainConfigArgs.destChainSelector != DEST_CHAIN_SELECTOR;

FeeQuoter.DestChainConfigArgs[] memory newDestChainConfigArgs = new FeeQuoter.DestChainConfigArgs[](1);
newDestChainConfigArgs[0] = destChainConfigArgs;

if (isNewChain) {
vm.expectEmit();
emit FeeQuoter.DestChainAdded(destChainConfigArgs.destChainSelector, destChainConfigArgs.destChainConfig);
} else {
vm.expectEmit();
emit FeeQuoter.DestChainConfigUpdated(destChainConfigArgs.destChainSelector, destChainConfigArgs.destChainConfig);
}

s_feeQuoter.applyDestChainConfigUpdates(newDestChainConfigArgs);

_assertFeeQuoterDestChainConfigsEqual(
destChainConfigArgs.destChainConfig, s_feeQuoter.getDestChainConfig(destChainConfigArgs.destChainSelector)
);
}

function test_applyDestChainConfigUpdates_Success() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = new FeeQuoter.DestChainConfigArgs[](2);
destChainConfigArgs[0] = _generateFeeQuoterDestChainConfigArgs()[0];
destChainConfigArgs[0].destChainConfig.isEnabled = false;
destChainConfigArgs[1] = _generateFeeQuoterDestChainConfigArgs()[0];
destChainConfigArgs[1].destChainSelector = DEST_CHAIN_SELECTOR + 1;

vm.expectEmit();
emit FeeQuoter.DestChainConfigUpdated(DEST_CHAIN_SELECTOR, destChainConfigArgs[0].destChainConfig);
vm.expectEmit();
emit FeeQuoter.DestChainAdded(DEST_CHAIN_SELECTOR + 1, destChainConfigArgs[1].destChainConfig);

vm.recordLogs();
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);

FeeQuoter.DestChainConfig memory gotDestChainConfig0 = s_feeQuoter.getDestChainConfig(DEST_CHAIN_SELECTOR);
FeeQuoter.DestChainConfig memory gotDestChainConfig1 = s_feeQuoter.getDestChainConfig(DEST_CHAIN_SELECTOR + 1);

assertEq(vm.getRecordedLogs().length, 2);
_assertFeeQuoterDestChainConfigsEqual(destChainConfigArgs[0].destChainConfig, gotDestChainConfig0);
_assertFeeQuoterDestChainConfigsEqual(destChainConfigArgs[1].destChainConfig, gotDestChainConfig1);
}

function test_applyDestChainConfigUpdatesZeroInput_Success() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = new FeeQuoter.DestChainConfigArgs[](0);

vm.recordLogs();
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);

assertEq(vm.getRecordedLogs().length, 0);
}

// Reverts

function test_applyDestChainConfigUpdatesDefaultTxGasLimitEqZero_Revert() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = _generateFeeQuoterDestChainConfigArgs();
FeeQuoter.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];

destChainConfigArg.destChainConfig.defaultTxGasLimit = 0;
vm.expectRevert(
abi.encodeWithSelector(FeeQuoter.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
);
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);
}

function test_applyDestChainConfigUpdatesDefaultTxGasLimitGtMaxPerMessageGasLimit_Revert() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = _generateFeeQuoterDestChainConfigArgs();
FeeQuoter.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];

// Allow setting to the max value
destChainConfigArg.destChainConfig.defaultTxGasLimit = destChainConfigArg.destChainConfig.maxPerMsgGasLimit;
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);

// Revert when exceeding max value
destChainConfigArg.destChainConfig.defaultTxGasLimit = destChainConfigArg.destChainConfig.maxPerMsgGasLimit + 1;
vm.expectRevert(
abi.encodeWithSelector(FeeQuoter.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
);
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);
}

function test_InvalidDestChainConfigDestChainSelectorEqZero_Revert() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = _generateFeeQuoterDestChainConfigArgs();
FeeQuoter.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];

destChainConfigArg.destChainSelector = 0;
vm.expectRevert(
abi.encodeWithSelector(FeeQuoter.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
);
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);
}

function test_InvalidChainFamilySelector_Revert() public {
FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = _generateFeeQuoterDestChainConfigArgs();
FeeQuoter.DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[0];

destChainConfigArg.destChainConfig.chainFamilySelector = bytes4(uint32(1));

vm.expectRevert(
abi.encodeWithSelector(FeeQuoter.InvalidDestChainConfig.selector, destChainConfigArg.destChainSelector)
);
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);
}
}
Loading

0 comments on commit 58995a5

Please sign in to comment.