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-3360] contracts/src/v0.8/ccip: merge latest changes from the ccip repo #14345

Merged
merged 13 commits into from
Sep 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
5 changes: 5 additions & 0 deletions .changeset/plenty-glasses-rest.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"chainlink": patch
---

#internal merge ccip contracts
5 changes: 5 additions & 0 deletions contracts/.changeset/flat-turkeys-rule.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@chainlink/contracts': patch
---

#internal merge ccip contracts
3 changes: 1 addition & 2 deletions contracts/.solhintignore
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,4 @@
./node_modules/

# Ignore RMN contracts temporarily
./src/v0.8/ccip/RMNRemote.sol
./src/v0.8/ccip/RMNHome.sol
./src/v0.8/ccip/rmn
815 changes: 403 additions & 412 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion contracts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
"moment": "^2.30.1",
"prettier": "^3.3.3",
"prettier-plugin-solidity": "^1.3.1",
"solhint": "^5.0.3",
"solhint": "^5.0.1",
"solhint-plugin-chainlink-solidity": "git+https://github.com/smartcontractkit/chainlink-solhint-rules.git#v1.2.1",
"solhint-plugin-prettier": "^0.1.0",
"ts-node": "^10.9.2",
Expand Down
22 changes: 14 additions & 8 deletions contracts/pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 2 additions & 1 deletion contracts/scripts/native_solc_compile_all_ccip
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ SOLC_VERSION="0.8.24"
OPTIMIZE_RUNS=26000
OPTIMIZE_RUNS_OFFRAMP=18000
OPTIMIZE_RUNS_ONRAMP=4100
OPTIMIZE_RUNS_MULTI_OFFRAMP=2000
OPTIMIZE_RUNS_MULTI_OFFRAMP=1999


SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
Expand Down Expand Up @@ -59,6 +59,7 @@ compileContract () {
# Contracts should be ordered in reverse-import-complexity-order to minimize overwrite risks.
compileContract ccip/offRamp/EVM2EVMOffRamp.sol
compileContract ccip/offRamp/OffRamp.sol
compileContract ccip/rmn/RMNRemote.sol
compileContract ccip/applications/PingPongDemo.sol
compileContract ccip/applications/SelfFundedPingPong.sol
compileContract ccip/applications/EtherSenderReceiver.sol
Expand Down
6 changes: 2 additions & 4 deletions contracts/src/v0.8/ccip/FeeQuoter.sol
Original file line number Diff line number Diff line change
Expand Up @@ -467,8 +467,6 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
uint256 numberOfTokens = message.tokenAmounts.length;
_validateMessage(destChainConfig, message.data.length, numberOfTokens, message.receiver);

uint64 premiumMultiplierWeiPerEth = s_premiumMultiplierWeiPerEth[message.feeToken];

// The below call asserts that feeToken is a supported token
(uint224 feeTokenPrice, uint224 packedGasPrice) = getTokenAndGasPrices(message.feeToken, destChainSelector);

Expand Down Expand Up @@ -511,7 +509,6 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,

// NOTE: when supporting non-EVM chains, revisit how generic this fee logic can be
// NOTE: revisit parsing non-EVM args

uint256 executionCost = uint112(packedGasPrice)
* (
destChainConfig.destGasOverhead + (message.data.length * destChainConfig.destGasPerPayloadByte) + tokenTransferGas
Expand All @@ -521,7 +518,8 @@ contract FeeQuoter is AuthorizedCallers, IFeeQuoter, ITypeAndVersion, IReceiver,
// Calculate number of fee tokens to charge.
// Total USD fee is in 36 decimals, feeTokenPrice is in 18 decimals USD for 1e18 smallest token denominations.
// Result of the division is the number of smallest token denominations.
return ((premiumFee * premiumMultiplierWeiPerEth) + executionCost + dataAvailabilityCost) / feeTokenPrice;
return ((premiumFee * s_premiumMultiplierWeiPerEth[message.feeToken]) + executionCost + dataAvailabilityCost)
/ feeTokenPrice;
}

/// @notice Sets the fee configuration for a token.
Expand Down
74 changes: 29 additions & 45 deletions contracts/src/v0.8/ccip/capability/CCIPConfig.sol
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,6 @@ import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {ICapabilitiesRegistry} from "./interfaces/ICapabilitiesRegistry.sol";

import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";

import {SortedSetValidationUtil} from "../../shared/util/SortedSetValidationUtil.sol";
import {Internal} from "../libraries/Internal.sol";
import {CCIPConfigTypes} from "./libraries/CCIPConfigTypes.sol";

Expand All @@ -26,7 +24,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
/// @param chainSelector The chain selector.
/// @param chainConfig The chain configuration.
event ChainConfigSet(uint64 chainSelector, CCIPConfigTypes.ChainConfig chainConfig);

/// @notice Emitted when a chain's configuration is removed.
/// @param chainSelector The chain selector.
event ChainConfigRemoved(uint64 chainSelector);
Expand All @@ -37,8 +34,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
error ChainSelectorNotSet();
error TooManyOCR3Configs();
error TooManySigners();
error TooManyTransmitters();
error TooManyBootstrapP2PIds();
error P2PIdsLengthNotMatching(uint256 p2pIdsLength, uint256 signersLength, uint256 transmittersLength);
error NotEnoughTransmitters(uint256 got, uint256 minimum);
error FMustBePositive();
Expand All @@ -62,6 +57,15 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
/// @notice The canonical capabilities registry address.
address internal immutable i_capabilitiesRegistry;

uint8 internal constant MAX_OCR3_CONFIGS_PER_PLUGIN = 2;
uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
uint256 internal constant CONFIG_DIGEST_PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..0
/// @dev must be equal to libocr multi role: https://github.com/smartcontractkit/libocr/blob/ae747ca5b81236ffdbf1714318c652e923a5ff4d/offchainreporting2plus/types/config_digest.go#L28
uint256 internal constant CONFIG_DIGEST_PREFIX = 0x000a << (256 - 16); // 0x000a00..00
bytes32 internal constant EMPTY_ENCODED_ADDRESS_HASH = keccak256(abi.encode(address(0)));
/// @dev 256 is the hard limit due to the bit encoding of their indexes into a uint256.
uint256 internal constant MAX_NUM_ORACLES = 256;

/// @notice chain configuration for each chain that CCIP is deployed on.
mapping(uint64 chainSelector => CCIPConfigTypes.ChainConfig chainConfig) internal s_chainConfigurations;

Expand All @@ -75,13 +79,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
uint32 donId => mapping(Internal.OCRPluginType pluginType => CCIPConfigTypes.OCR3ConfigWithMeta[] ocr3Configs)
) internal s_ocr3Configs;

uint8 internal constant MAX_OCR3_CONFIGS_PER_PLUGIN = 2;
uint8 internal constant MAX_OCR3_CONFIGS_PER_DON = 4;
uint8 internal constant MAX_NUM_ORACLES = 31;
uint256 internal constant CONFIG_DIGEST_PREFIX_MASK = type(uint256).max << (256 - 16); // 0xFFFF00..0
/// @dev must be equal to libocr multi role: https://github.com/smartcontractkit/libocr/blob/ae747ca5b81236ffdbf1714318c652e923a5ff4d/offchainreporting2plus/types/config_digest.go#L28
uint256 internal constant CONFIG_DIGEST_PREFIX = 0x000a << (256 - 16); // 0x000a00..00

/// @param capabilitiesRegistry the canonical capabilities registry address.
constructor(address capabilitiesRegistry) {
if (capabilitiesRegistry == address(0)) {
Expand Down Expand Up @@ -172,9 +169,8 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
revert OnlyCapabilitiesRegistryCanCall();
}

CCIPConfigTypes.OCR3Config[] memory ocr3Configs = abi.decode(config, (CCIPConfigTypes.OCR3Config[]));
(CCIPConfigTypes.OCR3Config[] memory commitConfigs, CCIPConfigTypes.OCR3Config[] memory execConfigs) =
_groupByPluginType(ocr3Configs);
_groupByPluginType(abi.decode(config, (CCIPConfigTypes.OCR3Config[])));
if (commitConfigs.length > 0) {
_updatePluginConfig(donId, Internal.OCRPluginType.Commit, commitConfigs);
}
Expand Down Expand Up @@ -363,8 +359,8 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
// access in the for loop below.
commitConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
execConfigs = new CCIPConfigTypes.OCR3Config[](MAX_OCR3_CONFIGS_PER_PLUGIN);
uint256 commitCount;
uint256 execCount;
uint256 commitCount = 0;
uint256 execCount = 0;
for (uint256 i = 0; i < ocr3Configs.length; ++i) {
if (ocr3Configs[i].pluginType == Internal.OCRPluginType.Commit) {
commitConfigs[commitCount] = ocr3Configs[i];
Expand All @@ -391,36 +387,26 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
if (cfg.pluginType != Internal.OCRPluginType.Commit && cfg.pluginType != Internal.OCRPluginType.Execution) {
revert InvalidPluginType();
}
// TODO: can we do more sophisticated validation than this?
if (cfg.offrampAddress.length == 0) revert OfframpAddressCannotBeZero();
if (cfg.offrampAddress.length == 0 || keccak256(cfg.offrampAddress) == EMPTY_ENCODED_ADDRESS_HASH) {
revert OfframpAddressCannotBeZero();
}
if (!s_remoteChainSelectors.contains(cfg.chainSelector)) revert ChainSelectorNotFound(cfg.chainSelector);

// Some of these checks below are done in OCR2/3Base config validation, so we do them again here.
// Role DON OCR configs will have all the Role DON signers but only a subset of transmitters.
if (cfg.signers.length > MAX_NUM_ORACLES) revert TooManySigners();
if (cfg.transmitters.length > MAX_NUM_ORACLES) revert TooManyTransmitters();

// We check for chain config presence above, so fChain here must be non-zero.
uint256 minTransmittersLength = 3 * s_chainConfigurations[cfg.chainSelector].fChain + 1;
if (cfg.transmitters.length < minTransmittersLength) {
revert NotEnoughTransmitters(cfg.transmitters.length, minTransmittersLength);
}
if (cfg.F == 0) revert FMustBePositive();
if (cfg.signers.length <= 3 * cfg.F) revert FTooHigh();

if (cfg.p2pIds.length != cfg.signers.length || cfg.p2pIds.length != cfg.transmitters.length) {
uint256 numberOfSigners = cfg.signers.length;
if (numberOfSigners > MAX_NUM_ORACLES) revert TooManySigners();
if (numberOfSigners != cfg.p2pIds.length || numberOfSigners != cfg.transmitters.length) {
revert P2PIdsLengthNotMatching(cfg.p2pIds.length, cfg.signers.length, cfg.transmitters.length);
}
if (cfg.bootstrapP2PIds.length > cfg.p2pIds.length) revert TooManyBootstrapP2PIds();

// check for duplicate p2p ids and bootstrapP2PIds.
// check that p2p ids in cfg.bootstrapP2PIds are included in cfg.p2pIds.
SortedSetValidationUtil._checkIsValidUniqueSubset(cfg.bootstrapP2PIds, cfg.p2pIds);
if (cfg.F == 0) revert FMustBePositive();
if (numberOfSigners <= 3 * cfg.F) revert FTooHigh();

// Check that the readers are in the capabilities registry.
for (uint256 i = 0; i < cfg.signers.length; ++i) {
_ensureInRegistry(cfg.p2pIds[i]);
}
_ensureInRegistry(cfg.p2pIds);
}

/// @notice Computes the digest of the provided configuration.
Expand All @@ -445,7 +431,6 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
ocr3Config.pluginType,
ocr3Config.offrampAddress,
configCount,
ocr3Config.bootstrapP2PIds,
ocr3Config.p2pIds,
ocr3Config.signers,
ocr3Config.transmitters,
Expand Down Expand Up @@ -486,13 +471,10 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
// Process additions next.
for (uint256 i = 0; i < chainConfigAdds.length; ++i) {
CCIPConfigTypes.ChainConfig memory chainConfig = chainConfigAdds[i].chainConfig;
bytes32[] memory readers = chainConfig.readers;
uint64 chainSelector = chainConfigAdds[i].chainSelector;

// Verify that the provided readers are present in the capabilities registry.
for (uint256 j = 0; j < readers.length; j++) {
_ensureInRegistry(readers[j]);
}
_ensureInRegistry(chainConfig.readers);

// Verify that fChain is positive.
if (chainConfig.fChain == 0) {
Expand All @@ -507,11 +489,13 @@ contract CCIPConfig is ITypeAndVersion, ICapabilityConfiguration, OwnerIsCreator
}

/// @notice Helper function to ensure that a node is in the capabilities registry.
/// @param p2pId The P2P ID of the node to check.
function _ensureInRegistry(bytes32 p2pId) internal view {
ICapabilitiesRegistry.NodeInfo memory node = ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pId);
if (node.p2pId == bytes32("")) {
revert NodeNotInRegistry(p2pId);
/// @param p2pIds The P2P IDs of the node to check.
function _ensureInRegistry(bytes32[] memory p2pIds) internal view {
for (uint256 i = 0; i < p2pIds.length; ++i) {
// TODO add a method that does the validation in the ICapabilitiesRegistry contract
if (ICapabilitiesRegistry(i_capabilitiesRegistry).getNode(p2pIds[i]).p2pId == bytes32("")) {
revert NodeNotInRegistry(p2pIds[i]);
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -37,8 +37,6 @@ library CCIPConfigTypes {
uint8 F; // | The "big F" parameter for the role DON.
uint64 offchainConfigVersion; // ─────────────╯ The version of the offchain configuration.
bytes offrampAddress; // The remote chain offramp address.
// NOTE: bootstrapP2PIds and p2pIds should be sent as sorted sets
bytes32[] bootstrapP2PIds; // The bootstrap P2P IDs of the oracles that are part of the role DON.
// len(p2pIds) == len(signers) == len(transmitters) == 3 * F + 1
// NOTE: indexes matter here! The p2p ID at index i corresponds to the signer at index i and the transmitter at index i.
// This is crucial in order to build the oracle ID <-> peer ID mapping offchain.
Expand Down
22 changes: 22 additions & 0 deletions contracts/src/v0.8/ccip/interfaces/IRMNV2.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {Internal} from "../libraries/Internal.sol";

/// @notice This interface contains the only RMN-related functions that might be used on-chain by other CCIP contracts.
interface IRMNV2 {
/// @notice signature components from RMN nodes
struct Signature {
bytes32 r;
bytes32 s;
}

function verify(Internal.MerkleRoot[] memory merkleRoots, Signature[] memory signatures) external view;

/// @notice If there is an active global or legacy curse, this function returns true.
function isCursed() external view returns (bool);

/// @notice If there is an active global curse, or an active curse for `subject`, this function returns true.
/// @param subject To check whether a particular chain is cursed, set to bytes16(uint128(chainSelector)).
function isCursed(bytes16 subject) external view returns (bool);
}
10 changes: 10 additions & 0 deletions contracts/src/v0.8/ccip/libraries/Internal.sol
Original file line number Diff line number Diff line change
Expand Up @@ -338,4 +338,14 @@ library Internal {

// bytes4(keccak256("CCIP ChainFamilySelector EVM"))
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;

/// @dev Struct to hold a merkle root and an 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.
struct MerkleRoot {
uint64 sourceChainSelector; // ──╮ Remote source chain selector that the Merkle Root is scoped to
uint64 minSeqNr; // | Minimum sequence number, inclusive
uint64 maxSeqNr; // ─────────────╯ Maximum sequence number, inclusive
bytes32 merkleRoot; // Merkle root covering the interval & source chain messages
bytes onRampAddress; // Generic onramp address, to support arbitrary sources; for EVM, use abi.encode
}
}
Loading
Loading