Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CCIP-4687 Support Solana in the FeeQuoter #15811

Merged
merged 51 commits into from
Jan 18, 2025
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
dd6d04e
Initial Scaffolding Tests still needed
jhweintraub Dec 24, 2024
6c3e296
Start writing tests for SolExtra args and rework a lot of stuff to ac…
jhweintraub Dec 26, 2024
06c66ae
[Bot] Update changeset file with jira issues
app-token-issuer-infra-releng[bot] Dec 27, 2024
f119246
Finish provisional tests
jhweintraub Dec 27, 2024
a44af09
Delete contracts/.changeset/tame-worms-sneeze.md
jhweintraub Dec 27, 2024
48d031b
Merge a44af0989dc7d0038d691ccc58b7fe917c28a61d into 498b0b8579ad52a8c…
jhweintraub Dec 27, 2024
3685fa3
Update gethwrappers
app-token-issuer-infra-releng[bot] Dec 27, 2024
dd8ca34
remove dead code
jhweintraub Dec 27, 2024
227b5c3
Merge dd8ca34e7ff8c475984f0672d2ea1b7f36bc7ef5 into 498b0b8579ad52a8c…
jhweintraub Dec 27, 2024
26e5812
Update gethwrappers
app-token-issuer-infra-releng[bot] Dec 27, 2024
484142b
Merge branch 'develop' into feat/feeQuoter_solSupport
jhweintraub Jan 6, 2025
ad747e7
remove superfluous extraArgs validation checks
jhweintraub Jan 6, 2025
6e9bbdb
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 7, 2025
4b619ce
update wrapper and snapshot
0xsuryansh Jan 7, 2025
475f671
optimise SolExtraArgsV1
0xsuryansh Jan 7, 2025
47e0621
fmt
0xsuryansh Jan 8, 2025
26047a1
rename solana args to SVM
0xsuryansh Jan 13, 2025
94d3850
add validation on token and logic receiver + add tokenReceiver to SVM…
0xsuryansh Jan 13, 2025
c5a9621
wrappers update
0xsuryansh Jan 13, 2025
e62279a
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 14, 2025
684c2ec
rm foundry lib
0xsuryansh Jan 14, 2025
2ecb33b
fix: svm tokenReceiver type bytes32
0xsuryansh Jan 14, 2025
d96d885
Sol/solana reference rename to SVM
0xsuryansh Jan 14, 2025
b0b8697
remove else, revert on invalid input and cleanup
0xsuryansh Jan 15, 2025
55c979d
Merge b0b869755fbfec0525d1fe874e663a69a7213558 into 547d2ed7ec6069111…
jhweintraub Jan 15, 2025
5e65708
Update gethwrappers
app-token-issuer-infra-releng[bot] Jan 15, 2025
9c6e409
add test for extra args tag const validation
0xsuryansh Jan 15, 2025
ff8fb02
Merge remote-tracking branch 'origin/feat/feeQuoter_solSupport' into …
0xsuryansh Jan 15, 2025
9032bd0
Merge ff8fb0210b04c9f0ec7c8e970323860af0740767 into 547d2ed7ec6069111…
jhweintraub Jan 15, 2025
de49e16
Update gethwrappers
app-token-issuer-infra-releng[bot] Jan 15, 2025
c48b361
remove else from _processChainFamilySelector
0xsuryansh Jan 15, 2025
f03544e
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 15, 2025
4094f39
update wrapper
0xsuryansh Jan 15, 2025
571bff6
compile FeeQuoter with 10_000 optimizer runs
0xsuryansh Jan 15, 2025
409575e
Merge 571bff63066fa4becb34d7517d64fb60607f1566 into 0b9bcaeb2bb5c9c95…
jhweintraub Jan 15, 2025
0e3527f
Update gethwrappers
app-token-issuer-infra-releng[bot] Jan 15, 2025
b450754
compile FeeQuoter with 10_000 optimizer runs
0xsuryansh Jan 15, 2025
62d677f
Merge remote-tracking branch 'origin/feat/feeQuoter_solSupport' into …
0xsuryansh Jan 15, 2025
723f4a4
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 15, 2025
abe3851
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 15, 2025
872ffd6
improved checks in extra args processing + tests
0xsuryansh Jan 16, 2025
2615206
fix test
0xsuryansh Jan 16, 2025
23ec006
move gas limit receiver check
0xsuryansh Jan 16, 2025
24e4248
make test run
RensR Jan 16, 2025
947d12b
golf
RensR Jan 16, 2025
a9357a4
clean up InvalidSVMAddress
RensR Jan 16, 2025
4a8abfb
Merge a9357a496275c77c3467347f7c22ac9820d65060 into 50c745396596a40e2…
jhweintraub Jan 16, 2025
539d4f1
Update gethwrappers
app-token-issuer-infra-releng[bot] Jan 16, 2025
5b7720e
fix test and add correct comments + SVM specific compute unit error
0xsuryansh Jan 17, 2025
d53361c
Merge branch 'develop' into feat/feeQuoter_solSupport
0xsuryansh Jan 17, 2025
4cb11db
remove unnecessary check
0xsuryansh Jan 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions contracts/.changeset/clean-horses-cheat.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
'@chainlink/contracts': minor
---

Update FeeQuoter to support Solana chain families #feature


PR issue: CCIP-4687

Solidity Review issue: CCIP-3966
199 changes: 102 additions & 97 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

120 changes: 107 additions & 13 deletions contracts/src/v0.8/ccip/FeeQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ import {EnumerableSet} from "../vendor/openzeppelin-solidity/v5.0.2/contracts/ut
/// The authorized callers in the contract represent the fee price updaters.
contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver, KeystoneFeedsPermissionHandler {
using EnumerableSet for EnumerableSet.AddressSet;
using EnumerableSet for EnumerableSet.Bytes32Set;
using USDPriceWith18Decimals for uint224;
using KeystoneFeedDefaultMetadataLib for bytes;

Expand All @@ -44,6 +45,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
error MessageTooLarge(uint256 maxSize, uint256 actualSize);
error UnsupportedNumberOfTokens(uint256 numberOfTokens, uint256 maxNumberOfTokensPerMsg);
error InvalidFeeRange(uint256 minFeeUSDCents, uint256 maxFeeUSDCents);
error FirstSolExtraArgsAddressCannotBeWritable();
error SolExtraArgsMustBeProvided();

event FeeTokenAdded(address indexed feeToken);
event FeeTokenRemoved(address indexed feeToken);
Expand All @@ -57,6 +60,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
event PremiumMultiplierWeiPerEthUpdated(address indexed token, uint64 premiumMultiplierWeiPerEth);
event DestChainConfigUpdated(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
event DestChainAdded(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
event ChainFamilySelectorModified(bytes4 chainFamilySelector, bool isAdded);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: we use updated instead of modified

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, fixed this


/// @dev Contains token price configuration used in both the keystone price updates and the price feed fallback logic.
struct TokenPriceFeedConfig {
Expand Down Expand Up @@ -602,7 +606,7 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
* (
destChainConfig.destGasOverhead
+ ((message.data.length + tokenTransferBytesOverhead) * destChainConfig.destGasPerPayloadByte) + tokenTransferGas
+ _parseEVMExtraArgsFromBytes(message.extraArgs, destChainConfig).gasLimit
+ _parseGasLimitFromExtraArgBytes(message.extraArgs, destChainConfig)
) * destChainConfig.gasMultiplierWeiPerEth;

// Calculate number of fee tokens to charge.
Expand Down Expand Up @@ -848,12 +852,73 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
/// @param chainFamilySelector Tag to identify the target family.
/// @param destAddress Dest address to validate.
/// @dev precondition - assumes the family tag is correct and validated.
/// @dev Since Solana addresses are parsed as bytes32, and no other form of validation occurs, no explicit
/// call is needed to a library function for address validation.
function _validateDestFamilyAddress(bytes4 chainFamilySelector, bytes memory destAddress) internal pure {
if (chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_EVM) {
Internal._validateEVMAddress(destAddress);
}
}

function _parseGasLimitFromExtraArgBytes(
bytes calldata extraArgs,
DestChainConfig memory destChainConfig
) internal pure returns (uint256 gasLimit) {
if (destChainConfig.chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_EVM) {
gasLimit = _parseEVMExtraArgsFromBytes(extraArgs, destChainConfig).gasLimit;
} else if (destChainConfig.chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_SOL) {
// If extra args are empty, generate default values.
gasLimit = _parseSolExtraArgsFromBytes(extraArgs, destChainConfig, 0).computeUnits;
} else {
gasLimit = destChainConfig.defaultTxGasLimit;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should revert in invalid input, not just let it pass

}

return gasLimit;
}

/// @notice Parse and validate the Solana specific Extra Args Bytes.
/// @param messageDataLengthBytes The length of the arbitrary message data. If this is non-zero, then an extraArgs
/// MUST be provided otherwise an error will be returned, due to requirements in how Solana accounts operate.
function _parseSolExtraArgsFromBytes(
bytes calldata extraArgs,
DestChainConfig memory destChainConfig,
uint256 messageDataLengthBytes
) internal pure returns (Client.SolExtraArgsV1 memory) {
Client.SolExtraArgsV1 memory SolExtraArgs =
_parseUnvalidatedSolExtraArgsFromBytes(extraArgs, destChainConfig.defaultTxGasLimit);

// If the message data length is non-zero, then accounts extra args must be provided.
if (messageDataLengthBytes != 0 && SolExtraArgs.accounts.length == 0) revert SolExtraArgsMustBeProvided();

// The Program name being invoked, which is the first account provided, cannot be writable on Solana.
if (SolExtraArgs.accounts.length != 0 && SolExtraArgs.accounts[0].isWritable) {
revert FirstSolExtraArgsAddressCannotBeWritable();
}

// Check that compute units is within the allowed range.
if (SolExtraArgs.computeUnits > uint256(destChainConfig.maxPerMsgGasLimit)) revert MessageGasLimitTooHigh();

return SolExtraArgs;
}

function _parseUnvalidatedSolExtraArgsFromBytes(
bytes calldata extraArgs,
uint64 defaultTxGasLimit
) internal pure returns (Client.SolExtraArgsV1 memory) {
if (extraArgs.length == 0) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is wrong I think, SVM always required extraArgs because it always needs OOO. It should revert here

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You mean we should include a field allowOutOfOrderExecution in

struct SVMExtraArgsV1 {
    uint32 computeUnits;
    uint64 accountIsWritableBitmap;
    bytes32 tokenReceiver;
    bytes32[] accounts;
  }

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes

return Client.SolExtraArgsV1({
computeUnits: uint32(defaultTxGasLimit), //TODO: Fix Potentially unsafe cast
accounts: new Client.SolanaAccountMeta[](0)
});
}

bytes memory argsData = extraArgs[4:];

Client.SolExtraArgsV1 memory solExtraArgs = abi.decode(argsData, (Client.SolExtraArgsV1));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

can return, don't need to assign

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we not need to check the validity of the computeUnits?


return solExtraArgs;
}

/// @dev Convert the extra args bytes into a struct with validations against the dest chain config.
/// @param extraArgs The extra args bytes.
/// @param destChainConfig Dest chain config to validate against.
Expand Down Expand Up @@ -928,7 +993,10 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,

/// @inheritdoc IFeeQuoter
/// @dev precondition - onRampTokenTransfers and sourceTokenAmounts lengths must be equal.
/// @param messageData The arbitrary bytes to be processed. Solana address requirements require that if an arbitrary message
/// exists, then extraArgs must also be checked for a valid recipient account.
function processMessageArgs(
bytes calldata messageData,
uint64 destChainSelector,
address feeToken,
uint256 feeTokenAmount,
Expand All @@ -945,6 +1013,12 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
bytes[] memory destExecDataPerToken
)
{
// Prevents a stack too deep error on messageData
{
bytes memory data = messageData;
(convertedExtraArgs, isOutOfOrderExecution) = _processChainFamilySelector(destChainSelector, data, extraArgs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only the length is ever used, it's a lot cheaper to pass in a single length property

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now that we don't have to check for message length though we can remove this anyways

}

// Convert feeToken to link if not already in link.
if (feeToken == i_linkToken) {
msgFeeJuels = feeTokenAmount;
Expand All @@ -954,16 +1028,38 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,

if (msgFeeJuels > i_maxFeeJuelsPerMsg) revert MessageFeeTooHigh(msgFeeJuels, i_maxFeeJuelsPerMsg);

uint64 defaultTxGasLimit = s_destChainConfigs[destChainSelector].defaultTxGasLimit;

// NOTE: Only EVM chains are supported for now, additional validation logic will be added when supporting other
// chain families to parse non-EVM args.
// Since the message is called after getFee, which will already validate the params, no validation is necessary.
Client.EVMExtraArgsV2 memory parsedExtraArgs = _parseUnvalidatedEVMExtraArgsFromBytes(extraArgs, defaultTxGasLimit);
isOutOfOrderExecution = parsedExtraArgs.allowOutOfOrderExecution;
destExecDataPerToken = _processPoolReturnData(destChainSelector, onRampTokenTransfers, sourceTokenAmounts);

return (msgFeeJuels, isOutOfOrderExecution, Client._argsToBytes(parsedExtraArgs), destExecDataPerToken);
return (msgFeeJuels, isOutOfOrderExecution, convertedExtraArgs, destExecDataPerToken);
}

/// @notice Parses the extra Args based on the chain family selector. Isolated into a separate function
/// as it was the only way to prevent a stack too deep error, and makes future chain family additions easier.
function _processChainFamilySelector(
uint64 destChainSelector,
bytes memory message,
bytes calldata extraArgs
) internal view returns (bytes memory convertedExtraArgs, bool isOutOfOrderExecution) {
DestChainConfig memory destChainConfig = s_destChainConfigs[destChainSelector];
if (destChainConfig.chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_EVM) {
// Since the message is called after getFee, which will already validate the params, no validation is necessary.
Client.EVMExtraArgsV2 memory parsedExtraArgs =
_parseUnvalidatedEVMExtraArgsFromBytes(extraArgs, destChainConfig.defaultTxGasLimit);

convertedExtraArgs = Client._argsToBytes(parsedExtraArgs);

isOutOfOrderExecution = parsedExtraArgs.allowOutOfOrderExecution;
} else if (destChainConfig.chainFamilySelector == Internal.CHAIN_FAMILY_SELECTOR_SOL) {
Client.SolExtraArgsV1 memory parsedExtraArgs =
_parseSolExtraArgsFromBytes(extraArgs, destChainConfig, message.length);

convertedExtraArgs = Client._solArgsToBytes(parsedExtraArgs);

// On Solana OOO execution is enabled for all messages.
isOutOfOrderExecution = true;
}

return (convertedExtraArgs, isOutOfOrderExecution);
}

/// @notice Validates pool return data.
Expand Down Expand Up @@ -1038,12 +1134,10 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
uint64 destChainSelector = destChainConfigArgs[i].destChainSelector;
DestChainConfig memory destChainConfig = destChainConfigArg.destChainConfig;

// destChainSelector must be non-zero, defaultTxGasLimit must be set, and must be less than maxPerMsgGasLimit.
// Only EVM chains are supported for now, additional validation logic will be added when supporting other chain
// families
// destChainSelector must be non-zero, defaultTxGasLimit must be set, must be less than maxPerMsgGasLimit
// TODO: With the addition of Solana and other Non-evm Chains, family selector is not validated.
if (
destChainSelector == 0 || destChainConfig.defaultTxGasLimit == 0
|| destChainConfig.chainFamilySelector != Internal.CHAIN_FAMILY_SELECTOR_EVM
|| destChainConfig.defaultTxGasLimit > destChainConfig.maxPerMsgGasLimit
) {
revert InvalidDestChainConfig(destChainSelector);
Expand Down
2 changes: 2 additions & 0 deletions contracts/src/v0.8/ccip/interfaces/IFeeQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ interface IFeeQuoter is IPriceRegistry {

/// @notice Converts the extraArgs to the latest version and returns the converted message fee in juels.
/// @notice Validates pool return data.
/// @param message The message to process, necessary when sending messages to Solana to check against extraArgs validity.
/// @param destChainSelector destination chain selector to process, must be a configured valid chain.
/// @param feeToken token address used to pay for message fees, must be a configured valid fee token.
/// @param feeTokenAmount Fee token amount.
Expand All @@ -28,6 +29,7 @@ interface IFeeQuoter is IPriceRegistry {
/// @return convertedExtraArgs extra args converted to the latest family-specific args version.
/// @return destExecDataPerToken Destination chain execution data.
function processMessageArgs(
bytes calldata message,
uint64 destChainSelector,
address feeToken,
uint256 feeTokenAmount,
Expand Down
19 changes: 19 additions & 0 deletions contracts/src/v0.8/ccip/libraries/Client.sol
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,9 @@ library Client {
// bytes4(keccak256("CCIP EVMExtraArgsV2"));
bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;

// bytes4(keccak256("CCIP SolExtraArgsV1"));
bytes4 public constant SOL_EXTRA_EXTRA_ARGS_V1_TAG = 0x3f2538fa;

/// @param gasLimit: gas limit for the callback on the destination chain.
/// @param allowOutOfOrderExecution: if true, it indicates that the message can be executed in any order relative to
/// other messages from the same sender. This value's default varies by chain. On some chains, a particular value is
Expand All @@ -51,9 +54,25 @@ library Client {
bool allowOutOfOrderExecution;
}

struct SolExtraArgsV1 {
uint32 computeUnits;
SolanaAccountMeta[] accounts;
}

struct SolanaAccountMeta {
bytes32 pubKey;
bool isWritable;
}

function _argsToBytes(
EVMExtraArgsV2 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);
}

function _solArgsToBytes(
SolExtraArgsV1 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(SOL_EXTRA_EXTRA_ARGS_V1_TAG, extraArgs);
}
}
11 changes: 11 additions & 0 deletions contracts/src/v0.8/ccip/libraries/Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
/// expect to have migrated to a new version by then.
library Internal {
error InvalidEVMAddress(bytes encodedAddress);
error InvalidSolAddress(bytes SolAddress);

/// @dev We limit return data to a selector plus 4 words. This is to avoid malicious contracts from returning
/// large amounts of data and causing repeated out-of-gas scenarios.
Expand Down Expand Up @@ -173,6 +174,13 @@ library Internal {
return address(uint160(encodedAddressUint));
}

// TODO: Comments for why this single check is done here so that it is future thinking
function _validateSolAddress(
bytes memory solAddress
) internal pure {
if (solAddress.length != 32) revert InvalidSolAddress(solAddress);
}

/// @notice Enum listing the possible message execution states within the offRamp contract.
/// UNTOUCHED never executed.
/// IN_PROGRESS currently being executed, used a replay protection.
Expand Down Expand Up @@ -262,6 +270,9 @@ library Internal {
// bytes4(keccak256("CCIP ChainFamilySelector EVM"));
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;

// bytes4(keccak256("CCIP ChainFamilySelector SOL"));
bytes4 public constant CHAIN_FAMILY_SELECTOR_SOL = 0x2d4dfc1c;

/// @dev Holds a merkle root and interval for a source chain so that an array of these can be passed in the CommitReport.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
/// @dev inefficient struct packing intentionally chosen to maintain order of specificity. Not a storage struct so impact is minimal.
Expand Down
9 changes: 8 additions & 1 deletion contracts/src/v0.8/ccip/onRamp/OnRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -221,13 +221,20 @@ contract OnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, Ownable2StepMsgSender

// Convert message fee to juels and retrieve converted args.
// Validate pool return data after it is populated (view function - no state changes).
// Using newMessage.data prevents a stack too deep error.
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
newMessage.data,
destChainSelector,
message.feeToken,
feeTokenAmount,
message.extraArgs,
newMessage.tokenAmounts,
tokenAmounts
);

newMessage.header.nonce = isOutOfOrderExecution
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -109,16 +109,4 @@ contract FeeQuoter_applyDestChainConfigUpdates is FeeQuoterSetup {
);
s_feeQuoter.applyDestChainConfigUpdates(destChainConfigArgs);
}

function test_RevertWhen_InvalidChainFamilySelector() 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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,22 @@ contract FeeQuoter_getValidatedFee is FeeQuoterFeeSetup {
s_feeQuoter.getValidatedFee(DEST_CHAIN_SELECTOR, message);
}

function test_SolChainFamilySelector() public {
// Update config to enforce allowOutOfOrderExecution = true.
vm.stopPrank();
vm.startPrank(OWNER);

FeeQuoter.DestChainConfigArgs[] memory destChainConfigArgs = _generateFeeQuoterDestChainConfigArgs();
destChainConfigArgs[0].destChainConfig.chainFamilySelector = Internal.CHAIN_FAMILY_SELECTOR_SOL;

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

Client.EVM2AnyMessage memory message = _generateEmptyMessage2Sol();

s_feeQuoter.getValidatedFee(DEST_CHAIN_SELECTOR, message);
}

// Reverts

function test_RevertWhen_DestinationChainNotEnabled() public {
Expand Down
Loading
Loading