Skip to content

Commit

Permalink
Merge branch 'ccip-develop' of github.com:smartcontractkit/ccip into …
Browse files Browse the repository at this point in the history
…ccip-2824
  • Loading branch information
b-gopalswami committed Aug 8, 2024
2 parents c9eb8d0 + e4df584 commit ca12409
Show file tree
Hide file tree
Showing 64 changed files with 1,158 additions and 570 deletions.
423 changes: 213 additions & 210 deletions contracts/gas-snapshots/ccip.gas-snapshot

Large diffs are not rendered by default.

8 changes: 4 additions & 4 deletions contracts/gas-snapshots/liquiditymanager.gas-snapshot
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,9 @@ LiquidityManager_addLiquidity:test_addLiquiditySuccess() (gas: 279154)
LiquidityManager_rebalanceLiquidity:test_InsufficientLiquidityReverts() (gas: 206745)
LiquidityManager_rebalanceLiquidity:test_InvalidRemoteChainReverts() (gas: 192319)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess() (gas: 9141768)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() (gas: 8957594)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_MultiStageFinalization() (gas: 8952800)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_NativeRewrap() (gas: 8880598)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPoolsSuccess_AlreadyFinalized() (gas: 8981838)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_MultiStageFinalization() (gas: 8977044)
LiquidityManager_rebalanceLiquidity:test_rebalanceBetweenPools_NativeRewrap() (gas: 8904842)
LiquidityManager_rebalanceLiquidity:test_rebalanceLiquiditySuccess() (gas: 382897)
LiquidityManager_receive:test_receive_success() (gas: 21182)
LiquidityManager_removeLiquidity:test_InsufficientLiquidityReverts() (gas: 184869)
Expand All @@ -19,7 +19,7 @@ LiquidityManager_setFinanceRole:test_OnlyOwnerReverts() (gas: 10987)
LiquidityManager_setFinanceRole:test_setFinanceRoleSuccess() (gas: 21836)
LiquidityManager_setLocalLiquidityContainer:test_OnlyOwnerReverts() (gas: 11052)
LiquidityManager_setLocalLiquidityContainer:test_ReverstWhen_CalledWithTheZeroAddress() (gas: 10643)
LiquidityManager_setLocalLiquidityContainer:test_setLocalLiquidityContainerSuccess() (gas: 3495598)
LiquidityManager_setLocalLiquidityContainer:test_setLocalLiquidityContainerSuccess() (gas: 3519863)
LiquidityManager_setMinimumLiquidity:test_OnlyOwnerReverts() (gas: 10925)
LiquidityManager_setMinimumLiquidity:test_setMinimumLiquiditySuccess() (gas: 36389)
LiquidityManager_withdrawERC20:test_withdrawERC20Reverts() (gas: 180359)
Expand Down
2 changes: 1 addition & 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=2500
OPTIMIZE_RUNS_MULTI_OFFRAMP=2000


SCRIPTPATH="$( cd "$(dirname "$0")" >/dev/null 2>&1 ; pwd -P )"
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/v0.8/ccip/RMN.sol
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ contract RMN is IRMN, OwnerIsCreator, ITypeAndVersion {
using EnumerableSet for EnumerableSet.AddressSet;

// STATIC CONFIG
string public constant override typeAndVersion = "RMN 1.5.0-dev";
string public constant override typeAndVersion = "RMN 1.5.0";

uint256 private constant MAX_NUM_VOTERS = 16;

Expand Down
42 changes: 25 additions & 17 deletions contracts/src/v0.8/ccip/offRamp/EVM2EVMMultiOffRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -89,27 +89,28 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {

/// @notice Per-chain source config (defining a lane from a Source Chain -> Dest OffRamp)
struct SourceChainConfig {
bool isEnabled; // ──────────╮ Flag whether the source chain is enabled or not
IRouter router; // ──────────╮ Local router to use for messages coming from this source chain
bool isEnabled; // | Flag whether the source chain is enabled or not
uint64 minSeqNr; // ─────────╯ The min sequence number expected for future messages
bytes onRamp; // OnRamp address on the source chain
}

/// @notice SourceChainConfig update args scoped to one source chain
struct SourceChainConfigArgs {
uint64 sourceChainSelector; // ───╮ Source chain selector of the config to update
IRouter router; // ────────────────╮ Local router to use for messages coming from this source chain
uint64 sourceChainSelector; // | Source chain selector of the config to update
bool isEnabled; // ────────────────╯ Flag whether the source chain is enabled or not
bytes onRamp; // OnRamp address on the source chain
}

/// @notice Dynamic offRamp config
/// @dev since OffRampConfig is part of OffRampConfigChanged event, if changing it, we should update the ABI on Atlas
struct DynamicConfig {
address router; // ─────────────────────────────────╮ Router address
address priceRegistry; // ──────────────────────────╮ Price registry address on the local chain
uint32 permissionLessExecutionThresholdSeconds; // │ Waiting time before manual execution is enabled
uint32 maxTokenTransferGas; // │ Maximum amount of gas passed on to token `transfer` call
uint32 maxPoolReleaseOrMintGas; // ─────────────────╯ Maximum amount of gas passed on to token pool when calling releaseOrMint
address messageValidator; // Optional message validator to validate incoming messages (zero address = no validator)
address priceRegistry; // Price registry address on the local chain
}

/// @notice a sequenceNumber interval
Expand Down Expand Up @@ -495,7 +496,10 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
/// its execution and enforce atomicity among successful message processing and token transfer.
/// @dev We use ERC-165 to check for the ccipReceive interface to permit sending tokens to contracts
/// (for example smart contract wallets) without an associated message.
function executeSingleMessage(Internal.Any2EVMRampMessage memory message, bytes[] memory offchainTokenData) external {
function executeSingleMessage(
Internal.Any2EVMRampMessage calldata message,
bytes[] calldata offchainTokenData
) external {
if (msg.sender != address(this)) revert CanOnlySelfCall();
Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](0);
if (message.tokenAmounts.length > 0) {
Expand Down Expand Up @@ -534,9 +538,9 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
|| !message.receiver.supportsInterface(type(IAny2EVMMessageReceiver).interfaceId)
) return;

(bool success, bytes memory returnData,) = IRouter(s_dynamicConfig.router).routeMessage(
any2EvmMessage, Internal.GAS_FOR_CALL_EXACT_CHECK, message.gasLimit, message.receiver
);
(bool success, bytes memory returnData,) = s_sourceChainConfigs[message.header.sourceChainSelector]
.router
.routeMessage(any2EvmMessage, Internal.GAS_FOR_CALL_EXACT_CHECK, message.gasLimit, message.receiver);
// If CCIP receiver execution is not successful, revert the call including token transfers
if (!success) revert ReceiverError(returnData);
}
Expand Down Expand Up @@ -729,6 +733,10 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
revert ZeroChainSelectorNotAllowed();
}

if (address(sourceConfigUpdate.router) == address(0)) {
revert ZeroAddressNotAllowed();
}

SourceChainConfig storage currentConfig = s_sourceChainConfigs[sourceChainSelector];
bytes memory currentOnRamp = currentConfig.onRamp;
bytes memory newOnRamp = sourceConfigUpdate.onRamp;
Expand All @@ -746,8 +754,8 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
revert InvalidStaticConfig(sourceChainSelector);
}

// The only dynamic config is the isEnabled flag
currentConfig.isEnabled = sourceConfigUpdate.isEnabled;
currentConfig.router = sourceConfigUpdate.router;
emit SourceChainConfigSet(sourceChainSelector, currentConfig);
}
}
Expand All @@ -761,7 +769,7 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
/// @notice Sets the dynamic config.
/// @param dynamicConfig The dynamic config.
function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
if (dynamicConfig.priceRegistry == address(0) || dynamicConfig.router == address(0)) {
if (dynamicConfig.priceRegistry == address(0)) {
revert ZeroAddressNotAllowed();
}

Expand Down Expand Up @@ -799,11 +807,11 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
/// @param offchainTokenData Data fetched offchain by the DON.
/// @return destTokenAmount local token address with amount
function _releaseOrMintSingleToken(
Internal.RampTokenAmount memory sourceTokenAmount,
bytes memory originalSender,
Internal.RampTokenAmount calldata sourceTokenAmount,
bytes calldata originalSender,
address receiver,
uint64 sourceChainSelector,
bytes memory offchainTokenData
bytes calldata offchainTokenData
) internal returns (Client.EVMTokenAmount memory destTokenAmount) {
// We need to safely decode the token address from the sourceTokenData, as it could be wrong,
// in which case it doesn't have to be a valid EVM address.
Expand Down Expand Up @@ -855,7 +863,7 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
// transfer them to the final receiver. We use the _callWithExactGasSafeReturnData function because
// the token contracts are not considered trusted.
(success, returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
abi.encodeCall(IERC20.transfer, (receiver, localAmount)),
abi.encodeCall(IERC20.transferFrom, (localPoolAddress, receiver, localAmount)),
localToken,
s_dynamicConfig.maxTokenTransferGas,
Internal.GAS_FOR_CALL_EXACT_CHECK,
Expand All @@ -878,11 +886,11 @@ contract EVM2EVMMultiOffRamp is ITypeAndVersion, MultiOCR3Base {
/// any non-rate limiting errors that may occur. If we encounter a rate limiting related error
/// we bubble it up. If we encounter a non-rate limiting error we wrap it in a TokenHandlingError.
function _releaseOrMintTokens(
Internal.RampTokenAmount[] memory sourceTokenAmounts,
bytes memory originalSender,
Internal.RampTokenAmount[] calldata sourceTokenAmounts,
bytes calldata originalSender,
address receiver,
uint64 sourceChainSelector,
bytes[] memory offchainTokenData
bytes[] calldata offchainTokenData
) internal returns (Client.EVMTokenAmount[] memory destTokenAmounts) {
destTokenAmounts = new Client.EVMTokenAmount[](sourceTokenAmounts.length);
for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) {
Expand Down
2 changes: 1 addition & 1 deletion contracts/src/v0.8/ccip/offRamp/EVM2EVMOffRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -649,7 +649,7 @@ contract EVM2EVMOffRamp is IAny2EVMOffRamp, AggregateRateLimiter, ITypeAndVersio
// transfer them to the final receiver. We use the _callWithExactGasSafeReturnData function because
// the token contracts are not considered trusted.
(success, returnData,) = CallWithExactGas._callWithExactGasSafeReturnData(
abi.encodeCall(IERC20.transfer, (receiver, localAmount)),
abi.encodeCall(IERC20.transferFrom, (localPoolAddress, receiver, localAmount)),
localToken,
sourceTokenData.destGasAmount - gasUsedReleaseOrMint,
Internal.GAS_FOR_CALL_EXACT_CHECK,
Expand Down
86 changes: 73 additions & 13 deletions contracts/src/v0.8/ccip/onRamp/EVM2EVMMultiOnRamp.sol
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {INonceManager} from "../interfaces/INonceManager.sol";
import {IPoolV1} from "../interfaces/IPool.sol";
import {IPriceRegistry} from "../interfaces/IPriceRegistry.sol";
import {IRMN} from "../interfaces/IRMN.sol";
import {IRouter} from "../interfaces/IRouter.sol";
import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";

import {OwnerIsCreator} from "../../shared/access/OwnerIsCreator.sol";
Expand All @@ -33,8 +34,10 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
error InvalidConfig();
error CursedByRMN(uint64 sourceChainSelector);
error GetSupportedTokensFunctionalityRemovedCheckAdminRegistry();
error InvalidDestChainConfig(uint64 sourceChainSelector);

event ConfigSet(StaticConfig staticConfig, DynamicConfig dynamicConfig);
event DestChainConfigSet(uint64 indexed destChainSelector, DestChainConfig destChainConfig);
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.
Expand All @@ -53,12 +56,29 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
/// @dev Struct to contains the dynamic configuration
// solhint-disable-next-line gas-struct-packing
struct DynamicConfig {
address router; // Router address
address priceRegistry; // Price registry address
address messageValidator; // Optional message validator to validate outbound messages (zero address = no validator)
address feeAggregator; // Fee aggregator address
}

/// @dev Struct to hold the configs for a destination chain
struct DestChainConfig {
// The last used sequence number. This is zero in the case where no messages has been sent yet.
// 0 is not a valid sequence number for any real transaction.
uint64 sequenceNumber;
// This is the local router address that is allowed to send messages to the destination chain.
// This is NOT the receiving router address on the destination chain.
IRouter router;
}

/// @dev Same as DestChainConfig but with the destChainSelector so that an array of these
/// can be passed in the constructor and the applyDestChainConfigUpdates function
//solhint-disable gas-struct-packing
struct DestChainConfigArgs {
uint64 destChainSelector; // Destination chain selector
IRouter router; // Source router address
}

// STATIC CONFIG
string public constant override typeAndVersion = "EVM2EVMMultiOnRamp 1.6.0-dev";
/// @dev The chain ID of the source chain that this contract is deployed to
Expand All @@ -75,12 +95,14 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
/// @dev The config for the onRamp
DynamicConfig internal s_dynamicConfig;

/// @dev Last used sequence number per destination chain.
/// This is zero in the case where no messages have been sent yet.
/// 0 is not a valid sequence number for any real transaction.
mapping(uint64 destChainSelector => uint64 sequenceNumber) internal s_destChainSequenceNumbers;
/// @dev The destination chain specific configs
mapping(uint64 destChainSelector => DestChainConfig destChainConfig) internal s_destChainConfigs;

constructor(StaticConfig memory staticConfig, DynamicConfig memory dynamicConfig) {
constructor(
StaticConfig memory staticConfig,
DynamicConfig memory dynamicConfig,
DestChainConfigArgs[] memory destChainConfigArgs
) {
if (
staticConfig.chainSelector == 0 || staticConfig.rmnProxy == address(0) || staticConfig.nonceManager == address(0)
|| staticConfig.tokenAdminRegistry == address(0)
Expand All @@ -94,6 +116,7 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;

_setDynamicConfig(dynamicConfig);
_applyDestChainConfigUpdates(destChainConfigArgs);
}

// ================================================================
Expand All @@ -104,7 +127,7 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
/// @param destChainSelector The destination chain selector
/// @return the next sequence number to be used
function getExpectedNextSequenceNumber(uint64 destChainSelector) external view returns (uint64) {
return s_destChainSequenceNumbers[destChainSelector] + 1;
return s_destChainConfigs[destChainSelector].sequenceNumber + 1;
}

/// @inheritdoc IEVM2AnyOnRampClient
Expand All @@ -114,15 +137,20 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
uint256 feeTokenAmount,
address originalSender
) external returns (bytes32) {
DestChainConfig storage destChainConfig = s_destChainConfigs[destChainSelector];

// NOTE: assumes the message has already been validated through the getFee call
// Validate message sender is set and allowed. Not validated in `getFee` since it is not user-driven.
if (originalSender == address(0)) revert RouterMustSetOriginalSender();
// Router address may be zero intentionally to pause.
if (msg.sender != s_dynamicConfig.router) revert MustBeCalledByRouter();
if (msg.sender != address(destChainConfig.router)) revert MustBeCalledByRouter();

address messageValidator = s_dynamicConfig.messageValidator;
if (messageValidator != address(0)) {
IMessageInterceptor(messageValidator).onOutboundMessage(destChainSelector, message);
{
// scoped to reduce stack usage
address messageValidator = s_dynamicConfig.messageValidator;
if (messageValidator != address(0)) {
IMessageInterceptor(messageValidator).onOutboundMessage(destChainSelector, message);
}
}

// Convert message fee to juels and retrieve converted args
Expand All @@ -139,7 +167,7 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
sourceChainSelector: i_chainSelector,
destChainSelector: destChainSelector,
// We need the next available sequence number so we increment before we use the value
sequenceNumber: ++s_destChainSequenceNumbers[destChainSelector],
sequenceNumber: ++destChainConfig.sequenceNumber,
// Only bump nonce for messages that specify allowOutOfOrderExecution == false. Otherwise, we
// may block ordered message nonces, which is not what we want.
nonce: isOutOfOrderExecution
Expand Down Expand Up @@ -256,9 +284,15 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
_setDynamicConfig(dynamicConfig);
}

/// @notice Gets the source router for a destination chain
/// @param destChainSelector The destination chain selector
/// @return router the router for the provided destination chain
function getRouter(uint64 destChainSelector) external view returns (IRouter) {
return s_destChainConfigs[destChainSelector].router;
}

/// @notice Internal version of setDynamicConfig to allow for reuse in the constructor.
function _setDynamicConfig(DynamicConfig memory dynamicConfig) internal {
// We permit router to be set to zero as a way to pause the contract.
if (dynamicConfig.priceRegistry == address(0) || dynamicConfig.feeAggregator == address(0)) revert InvalidConfig();

s_dynamicConfig = dynamicConfig;
Expand All @@ -274,6 +308,32 @@ contract EVM2EVMMultiOnRamp is IEVM2AnyOnRampClient, ITypeAndVersion, OwnerIsCre
);
}

/// @notice Updates the destination chain specific config.
/// @param destChainConfigArgs Array of source chain specific configs.
function applyDestChainConfigUpdates(DestChainConfigArgs[] memory destChainConfigArgs) external onlyOwner {
_applyDestChainConfigUpdates(destChainConfigArgs);
}

/// @notice Internal version of applyDestChainConfigUpdates.
function _applyDestChainConfigUpdates(DestChainConfigArgs[] memory destChainConfigArgs) internal {
for (uint256 i = 0; i < destChainConfigArgs.length; ++i) {
DestChainConfigArgs memory destChainConfigArg = destChainConfigArgs[i];
uint64 destChainSelector = destChainConfigArgs[i].destChainSelector;

if (destChainSelector == 0) {
revert InvalidDestChainConfig(destChainSelector);
}

DestChainConfig memory newDestChainConfig = DestChainConfig({
sequenceNumber: s_destChainConfigs[destChainSelector].sequenceNumber,
router: destChainConfigArg.router
});
s_destChainConfigs[destChainSelector] = newDestChainConfig;

emit DestChainConfigSet(destChainSelector, newDestChainConfig);
}
}

// ================================================================
// │ Tokens and pools │
// ================================================================
Expand Down
3 changes: 2 additions & 1 deletion contracts/src/v0.8/ccip/pools/BurnMintTokenPoolAbstract.sol
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,8 @@ abstract contract BurnMintTokenPoolAbstract is TokenPool {
_validateReleaseOrMint(releaseOrMintIn);

// Mint to the offRamp, which forwards it to the recipient
IBurnMintERC20(address(i_token)).mint(msg.sender, releaseOrMintIn.amount);
IBurnMintERC20(address(i_token)).mint(address(this), releaseOrMintIn.amount);
IBurnMintERC20(address(i_token)).approve(msg.sender, releaseOrMintIn.amount);

emit Minted(msg.sender, releaseOrMintIn.receiver, releaseOrMintIn.amount);

Expand Down
Loading

0 comments on commit ca12409

Please sign in to comment.