Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
Latest 25 from a total of 275,711 transactions
| Transaction Hash |
Method
|
Block
|
From
|
To
|
Amount
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Commit | 35757846 | 18 secs ago | IN | 0 ETH | 0.000000093833 | ||||
| Commit | 35757833 | 44 secs ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35757801 | 1 min ago | IN | 0 ETH | 0.000000093797 | ||||
| Commit | 35757692 | 5 mins ago | IN | 0 ETH | 0.000000093833 | ||||
| Commit | 35757623 | 7 mins ago | IN | 0 ETH | 0.000000112705 | ||||
| Commit | 35757605 | 8 mins ago | IN | 0 ETH | 0.000000093821 | ||||
| Commit | 35757576 | 9 mins ago | IN | 0 ETH | 0.000000093809 | ||||
| Commit | 35757561 | 9 mins ago | IN | 0 ETH | 0.000000093833 | ||||
| Commit | 35757385 | 15 mins ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35757372 | 16 mins ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35757305 | 18 mins ago | IN | 0 ETH | 0.000000103227 | ||||
| Commit | 35757292 | 18 mins ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35757204 | 21 mins ago | IN | 0 ETH | 0.000000093797 | ||||
| Commit | 35757170 | 22 mins ago | IN | 0 ETH | 0.000000093821 | ||||
| Commit | 35757085 | 25 mins ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35757006 | 28 mins ago | IN | 0 ETH | 0.000000103263 | ||||
| Commit | 35756694 | 38 mins ago | IN | 0 ETH | 0.000000103227 | ||||
| Commit | 35756681 | 39 mins ago | IN | 0 ETH | 0.000000093833 | ||||
| Commit | 35756668 | 39 mins ago | IN | 0 ETH | 0.000000093821 | ||||
| Commit | 35756598 | 41 mins ago | IN | 0 ETH | 0.000000093833 | ||||
| Commit | 35756585 | 42 mins ago | IN | 0 ETH | 0.000000093845 | ||||
| Commit | 35756564 | 43 mins ago | IN | 0 ETH | 0.000000093785 | ||||
| Commit | 35756397 | 48 mins ago | IN | 0 ETH | 0.000000103275 | ||||
| Commit | 35756162 | 56 mins ago | IN | 0 ETH | 0.000000093821 | ||||
| Commit | 35756151 | 56 mins ago | IN | 0 ETH | 0.000000093833 |
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
OffRamp
Compiler Version
v0.8.26+commit.8a97fa7a
Optimization Enabled:
Yes with 800 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {IAny2EVMMessageReceiver} from "../interfaces/IAny2EVMMessageReceiver.sol";
import {IFeeQuoter} from "../interfaces/IFeeQuoter.sol";
import {IMessageInterceptor} from "../interfaces/IMessageInterceptor.sol";
import {INonceManager} from "../interfaces/INonceManager.sol";
import {IPoolV1} from "../interfaces/IPool.sol";
import {IRMNRemote} from "../interfaces/IRMNRemote.sol";
import {IRouter} from "../interfaces/IRouter.sol";
import {ITokenAdminRegistry} from "../interfaces/ITokenAdminRegistry.sol";
import {CallWithExactGas} from "../../shared/call/CallWithExactGas.sol";
import {Client} from "../libraries/Client.sol";
import {ERC165CheckerReverting} from "../libraries/ERC165CheckerReverting.sol";
import {Internal} from "../libraries/Internal.sol";
import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
import {Pool} from "../libraries/Pool.sol";
import {MultiOCR3Base} from "../ocr/MultiOCR3Base.sol";
import {IERC20} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/token/ERC20/IERC20.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/structs/EnumerableSet.sol";
/// @notice OffRamp enables OCR networks to execute multiple messages in an OffRamp in a single transaction.
/// @dev The OnRamp and OffRamp form a cross chain upgradeable unit. Any change to one of them results an
/// onchain upgrade of both contracts.
/// @dev MultiOCR3Base is used to store multiple OCR configs for the OffRamp. The execution plugin type has to be
/// configured without signature verification, and the commit plugin type with verification.
contract OffRamp is ITypeAndVersion, MultiOCR3Base {
using ERC165CheckerReverting for address;
using EnumerableSet for EnumerableSet.UintSet;
error ZeroChainSelectorNotAllowed();
error ExecutionError(bytes32 messageId, bytes err);
error SourceChainNotEnabled(uint64 sourceChainSelector);
error TokenDataMismatch(uint64 sourceChainSelector, uint64 sequenceNumber);
error UnexpectedTokenData();
error ManualExecutionNotYetEnabled(uint64 sourceChainSelector);
error ManualExecutionGasLimitMismatch();
error InvalidManualExecutionGasLimit(uint64 sourceChainSelector, bytes32 messageId, uint256 newLimit);
error InvalidManualExecutionTokenGasOverride(
bytes32 messageId, uint256 tokenIndex, uint256 oldLimit, uint256 tokenGasOverride
);
error ManualExecutionGasAmountCountMismatch(bytes32 messageId, uint64 sequenceNumber);
error RootNotCommitted(uint64 sourceChainSelector);
error RootAlreadyCommitted(uint64 sourceChainSelector, bytes32 merkleRoot);
error InvalidRoot();
error CanOnlySelfCall();
error ReceiverError(bytes err);
error TokenHandlingError(address target, bytes err);
error ReleaseOrMintBalanceMismatch(uint256 amountReleased, uint256 balancePre, uint256 balancePost);
error EmptyReport(uint64 sourceChainSelector);
error EmptyBatch();
error CursedByRMN(uint64 sourceChainSelector);
error NotACompatiblePool(address notPool);
error InvalidDataLength(uint256 expected, uint256 got);
error InvalidNewState(uint64 sourceChainSelector, uint64 sequenceNumber, Internal.MessageExecutionState newState);
error StaleCommitReport();
error InvalidInterval(uint64 sourceChainSelector, uint64 min, uint64 max);
error ZeroAddressNotAllowed();
error InvalidMessageDestChainSelector(uint64 messageDestChainSelector);
error SourceChainSelectorMismatch(uint64 reportSourceChainSelector, uint64 messageSourceChainSelector);
error SignatureVerificationRequiredInCommitPlugin();
error SignatureVerificationNotAllowedInExecutionPlugin();
error CommitOnRampMismatch(bytes reportOnRamp, bytes configOnRamp);
error InvalidOnRampUpdate(uint64 sourceChainSelector);
error RootBlessingMismatch(uint64 sourceChainSelector, bytes32 merkleRoot, bool isBlessed);
/// @dev Atlas depends on various events, if changing, please notify Atlas.
event StaticConfigSet(StaticConfig staticConfig);
event DynamicConfigSet(DynamicConfig dynamicConfig);
event ExecutionStateChanged(
uint64 indexed sourceChainSelector,
uint64 indexed sequenceNumber,
bytes32 indexed messageId,
bytes32 messageHash,
Internal.MessageExecutionState state,
bytes returnData,
uint256 gasUsed
);
event SourceChainSelectorAdded(uint64 sourceChainSelector);
event SourceChainConfigSet(uint64 indexed sourceChainSelector, SourceChainConfig sourceConfig);
event SkippedAlreadyExecutedMessage(uint64 sourceChainSelector, uint64 sequenceNumber);
event AlreadyAttempted(uint64 sourceChainSelector, uint64 sequenceNumber);
event CommitReportAccepted(
Internal.MerkleRoot[] blessedMerkleRoots,
Internal.MerkleRoot[] unblessedMerkleRoots,
Internal.PriceUpdates priceUpdates
);
event RootRemoved(bytes32 root);
event SkippedReportExecution(uint64 sourceChainSelector);
/// @dev Struct that contains the static configuration. The individual components are stored as immutable variables.
// solhint-disable-next-line gas-struct-packing
struct StaticConfig {
uint64 chainSelector; // ───────╮ Destination chainSelector
uint16 gasForCallExactCheck; // | Gas for call exact check
IRMNRemote rmnRemote; // ───────╯ RMN Verification Contract
address tokenAdminRegistry; // Token admin registry address
address nonceManager; // Nonce manager address
}
/// @dev Per-chain source config (defining a lane from a Source Chain -> Dest OffRamp).
struct SourceChainConfig {
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.
bool isRMNVerificationDisabled; // ─╯ Flag whether the RMN verification is disabled or not.
bytes onRamp; // OnRamp address on the source chain.
}
/// @dev Same as SourceChainConfig but with source chain selector so that an array of these
/// can be passed in the constructor and the applySourceChainConfigUpdates function.
struct SourceChainConfigArgs {
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.
bool isRMNVerificationDisabled; // ─╯ Flag whether the RMN verification is disabled or not.
bytes onRamp; // OnRamp address on the source chain.
}
/// @dev Dynamic offRamp config.
/// @dev Since DynamicConfig is part of DynamicConfigSet event, if changing it, we should update the ABI on Atlas.
struct DynamicConfig {
address feeQuoter; // ──────────────────────────────╮ FeeQuoter address on the local chain.
uint32 permissionLessExecutionThresholdSeconds; // ─╯ Waiting time before manual execution is enabled.
address messageInterceptor; // Optional, validates incoming messages (zero address = no interceptor).
}
/// @dev Report that is committed by the observing DON at the committing phase.
struct CommitReport {
Internal.PriceUpdates priceUpdates; // List of gas and price updates to commit.
Internal.MerkleRoot[] blessedMerkleRoots; // List of merkle roots from source chains for which RMN is enabled.
Internal.MerkleRoot[] unblessedMerkleRoots; // List of merkle roots from source chains for which RMN is disabled.
IRMNRemote.Signature[] rmnSignatures; // RMN signatures on the merkle roots.
}
/// @dev Both receiverExecutionGasLimit and tokenGasOverrides are optional. To indicate no override, set the value
/// to 0. The length of tokenGasOverrides must match the length of tokenAmounts, even if it only contains zeros.
struct GasLimitOverride {
uint256 receiverExecutionGasLimit; // Overrides EVM2EVMMessage.gasLimit.
uint32[] tokenGasOverrides; // Overrides EVM2EVMMessage.sourceTokenData.destGasAmount, length must be same as tokenAmounts.
}
// STATIC CONFIG
string public constant override typeAndVersion = "OffRamp 1.6.0";
/// @dev Hash of encoded address(0) used for empty address checks.
bytes32 internal constant EMPTY_ENCODED_ADDRESS_HASH = keccak256(abi.encode(address(0)));
/// @dev ChainSelector of this chain.
uint64 internal immutable i_chainSelector;
/// @dev The RMN verification contract.
IRMNRemote internal immutable i_rmnRemote;
/// @dev The address of the token admin registry.
address internal immutable i_tokenAdminRegistry;
/// @dev The address of the nonce manager.
address internal immutable i_nonceManager;
/// @dev The minimum amount of gas to perform the call with exact gas.
/// We include this in the offRamp so that we can redeploy to adjust it should a hardfork change the gas costs of
/// relevant opcodes in callWithExactGas.
uint16 internal immutable i_gasForCallExactCheck;
// DYNAMIC CONFIG
DynamicConfig internal s_dynamicConfig;
/// @notice Set of source chain selectors.
EnumerableSet.UintSet internal s_sourceChainSelectors;
/// @notice SourceChainConfig per source chain selector.
mapping(uint64 sourceChainSelector => SourceChainConfig sourceChainConfig) private s_sourceChainConfigs;
// STATE
/// @dev A mapping of sequence numbers (per source chain) to execution state using a bitmap with each execution
/// state only taking up 2 bits of the uint256, packing 128 states into a single slot.
/// Message state is tracked to ensure message can only be executed successfully once.
mapping(uint64 sourceChainSelector => mapping(uint64 seqNum => uint256 executionStateBitmap)) internal
s_executionStates;
/// @notice Commit timestamp of merkle roots per source chain.
mapping(uint64 sourceChainSelector => mapping(bytes32 merkleRoot => uint256 timestamp)) internal s_roots;
/// @dev The sequence number of the last price update.
uint64 private s_latestPriceSequenceNumber;
constructor(
StaticConfig memory staticConfig,
DynamicConfig memory dynamicConfig,
SourceChainConfigArgs[] memory sourceChainConfigs
) MultiOCR3Base() {
if (
address(staticConfig.rmnRemote) == address(0) || staticConfig.tokenAdminRegistry == address(0)
|| staticConfig.nonceManager == address(0)
) {
revert ZeroAddressNotAllowed();
}
if (staticConfig.chainSelector == 0) {
revert ZeroChainSelectorNotAllowed();
}
i_chainSelector = staticConfig.chainSelector;
i_rmnRemote = staticConfig.rmnRemote;
i_tokenAdminRegistry = staticConfig.tokenAdminRegistry;
i_nonceManager = staticConfig.nonceManager;
i_gasForCallExactCheck = staticConfig.gasForCallExactCheck;
emit StaticConfigSet(staticConfig);
_setDynamicConfig(dynamicConfig);
_applySourceChainConfigUpdates(sourceChainConfigs);
}
// ================================================================
// │ Execution │
// ================================================================
// The size of the execution state in bits.
uint256 private constant MESSAGE_EXECUTION_STATE_BIT_WIDTH = 2;
// The mask for the execution state bits.
uint256 private constant MESSAGE_EXECUTION_STATE_MASK = (1 << MESSAGE_EXECUTION_STATE_BIT_WIDTH) - 1;
/// @notice Returns the current execution state of a message based on its sequenceNumber.
/// @param sourceChainSelector The source chain to get the execution state for.
/// @param sequenceNumber The sequence number of the message to get the execution state for.
/// @return executionState The current execution state of the message.
/// @dev We use the literal number 128 because using a constant increased gas usage.
function getExecutionState(
uint64 sourceChainSelector,
uint64 sequenceNumber
) public view returns (Internal.MessageExecutionState) {
return Internal.MessageExecutionState(
(
_getSequenceNumberBitmap(sourceChainSelector, sequenceNumber)
>> ((sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH)
) & MESSAGE_EXECUTION_STATE_MASK
);
}
/// @notice Sets a new execution state for a given sequence number. It will overwrite any existing state.
/// @param sourceChainSelector The source chain to set the execution state for.
/// @param sequenceNumber The sequence number for which the state will be saved.
/// @param newState The new value the state will be in after this function is called.
/// @dev We use the literal number 128 because using a constant increased gas usage.
function _setExecutionState(
uint64 sourceChainSelector,
uint64 sequenceNumber,
Internal.MessageExecutionState newState
) internal {
uint256 offset = (sequenceNumber % 128) * MESSAGE_EXECUTION_STATE_BIT_WIDTH;
uint256 bitmap = _getSequenceNumberBitmap(sourceChainSelector, sequenceNumber);
// To unset any potential existing state we zero the bits of the section the state occupies,
// then we do an AND operation to blank out any existing state for the section.
bitmap &= ~(MESSAGE_EXECUTION_STATE_MASK << offset);
// Set the new state.
bitmap |= uint256(newState) << offset;
s_executionStates[sourceChainSelector][sequenceNumber / 128] = bitmap;
}
/// @param sourceChainSelector remote source chain selector to get sequence number bitmap for.
/// @param sequenceNumber sequence number to get bitmap for.
/// @return bitmap Bitmap of the given sequence number for the provided source chain selector. One bitmap represents
/// 128 sequence numbers.
function _getSequenceNumberBitmap(
uint64 sourceChainSelector,
uint64 sequenceNumber
) internal view returns (uint256 bitmap) {
return s_executionStates[sourceChainSelector][sequenceNumber / 128];
}
/// @notice Manually executes a set of reports.
/// @param reports Internal.ExecutionReportSingleChain[] - list of reports to execute.
/// @param gasLimitOverrides New gasLimit for each message per report. The outer array represents each report, the
// inner array represents each message in the report.
// i.e. gasLimitOverrides[report1][report1Message1] -> access message1 from report1
/// @dev We permit gas limit overrides so that users may manually execute messages which failed due to insufficient
/// gas provided. The reports do not have to contain all the messages (they can be omitted). Multiple reports can be
/// passed in simultaneously.
function manuallyExecute(
Internal.ExecutionReport[] memory reports,
GasLimitOverride[][] memory gasLimitOverrides
) external {
// We do this here because the other _execute path is already covered by MultiOCR3Base.
_whenChainNotForked();
uint256 numReports = reports.length;
if (numReports != gasLimitOverrides.length) revert ManualExecutionGasLimitMismatch();
for (uint256 reportIndex = 0; reportIndex < numReports; ++reportIndex) {
Internal.ExecutionReport memory report = reports[reportIndex];
uint256 numMsgs = report.messages.length;
GasLimitOverride[] memory msgGasLimitOverrides = gasLimitOverrides[reportIndex];
// Gas override values need to be provided, even when no override is desired. We expect an array of the correct
// size with all `0` values if no override is desired.
if (numMsgs != msgGasLimitOverrides.length) revert ManualExecutionGasLimitMismatch();
for (uint256 msgIndex = 0; msgIndex < numMsgs; ++msgIndex) {
uint256 newLimit = msgGasLimitOverrides[msgIndex].receiverExecutionGasLimit;
Internal.Any2EVMRampMessage memory message = report.messages[msgIndex];
if (newLimit != 0) {
// Checks to ensure messages will not be executed with less gas than specified.
if (newLimit < message.gasLimit) {
revert InvalidManualExecutionGasLimit(report.sourceChainSelector, message.header.messageId, newLimit);
}
}
if (message.tokenAmounts.length != msgGasLimitOverrides[msgIndex].tokenGasOverrides.length) {
revert ManualExecutionGasAmountCountMismatch(message.header.messageId, message.header.sequenceNumber);
}
// The gas limit can not be lowered as that could cause the message to fail. If manual execution is done
// from an UNTOUCHED state and we would allow lower gas limit, anyone could grief by executing the message with
// lower gas limit than the DON would have used. This results in the message being marked FAILURE and the DON
// would not attempt it with the correct gas limit.
for (uint256 tokenIndex = 0; tokenIndex < message.tokenAmounts.length; ++tokenIndex) {
uint256 tokenGasOverride = msgGasLimitOverrides[msgIndex].tokenGasOverrides[tokenIndex];
if (tokenGasOverride != 0) {
uint256 destGasAmount = message.tokenAmounts[tokenIndex].destGasAmount;
if (tokenGasOverride < destGasAmount) {
revert InvalidManualExecutionTokenGasOverride(
message.header.messageId, tokenIndex, destGasAmount, tokenGasOverride
);
}
}
}
}
}
_batchExecute(reports, gasLimitOverrides);
}
/// @notice Transmit function for execution reports. The function takes no signatures, and expects the exec plugin
/// type to be configured with no signatures.
/// @param report serialized execution report.
function execute(bytes32[2] calldata reportContext, bytes calldata report) external {
_batchExecute(abi.decode(report, (Internal.ExecutionReport[])), new GasLimitOverride[][](0));
bytes32[] memory emptySigs = new bytes32[](0);
_transmit(uint8(Internal.OCRPluginType.Execution), reportContext, report, emptySigs, emptySigs, bytes32(""));
}
/// @notice Batch executes a set of reports, each report matching one single source chain.
/// @param reports Set of execution reports (one per chain) containing the messages and proofs.
/// @param manualExecGasLimits An array of gas limits to use for manual execution The outer array represents each
// report, the inner array represents each message in the report.
// i.e. gasLimitOverrides[report1][report1Message1] -> access message1 from report1.
/// @dev The manualExecGasLimits array should either be empty, or match the length of the reports array.
/// @dev If called from manual execution, each inner array's length has to match the number of messages.
function _batchExecute(
Internal.ExecutionReport[] memory reports,
GasLimitOverride[][] memory manualExecGasOverrides
) internal {
if (reports.length == 0) revert EmptyBatch();
bool areManualGasLimitsEmpty = manualExecGasOverrides.length == 0;
// Cache array for gas savings in the loop's condition.
GasLimitOverride[] memory emptyGasLimits = new GasLimitOverride[](0);
for (uint256 i = 0; i < reports.length; ++i) {
_executeSingleReport(reports[i], areManualGasLimitsEmpty ? emptyGasLimits : manualExecGasOverrides[i]);
}
}
/// @notice Executes a report, executing each message in order.
/// @param report The execution report containing the messages and proofs.
/// @param manualExecGasExecOverrides An array of gas limits to use for manual execution.
/// @dev If called from the DON, this array is always empty.
/// @dev If called from manual execution, this array is always same length as messages.
/// @dev This function can fully revert in some cases, reverting potentially valid other reports with it. The reasons
/// for these reverts are so severe that we prefer to revert the entire batch instead of silently failing.
function _executeSingleReport(
Internal.ExecutionReport memory report,
GasLimitOverride[] memory manualExecGasExecOverrides
) internal {
uint64 sourceChainSelector = report.sourceChainSelector;
bool manualExecution = manualExecGasExecOverrides.length != 0;
if (i_rmnRemote.isCursed(bytes16(uint128(sourceChainSelector)))) {
if (manualExecution) {
// For manual execution we don't want to silently fail so we revert.
revert CursedByRMN(sourceChainSelector);
}
// For DON execution we do not revert as a single lane curse can revert the entire batch.
emit SkippedReportExecution(sourceChainSelector);
return;
}
uint256 numMsgs = report.messages.length;
if (numMsgs == 0) revert EmptyReport(report.sourceChainSelector);
if (numMsgs != report.offchainTokenData.length) revert UnexpectedTokenData();
bytes32[] memory hashedLeaves = new bytes32[](numMsgs);
{
// We do this hash here instead of in _verify to avoid two separate loops over the same data. Hashing all of the
// message fields ensures that the message being executed is correct and not tampered with. Including the known
// OnRamp ensures that the message originates from the correct on ramp version. We know the sourceChainSelector
// and i_destChainSelector are correct because we revert below when they are not.
bytes32 metaDataHash = keccak256(
abi.encode(
Internal.ANY_2_EVM_MESSAGE_HASH,
sourceChainSelector,
i_chainSelector,
keccak256(_getEnabledSourceChainConfig(sourceChainSelector).onRamp)
)
);
for (uint256 i = 0; i < numMsgs; ++i) {
Internal.Any2EVMRampMessage memory message = report.messages[i];
// Commits do not verify the destChainSelector in the message since only the root is committed, so we
// have to check it explicitly. This check is also important as we have assumed the metaDataHash above uses
// the i_chainSelector as the destChainSelector.
if (message.header.destChainSelector != i_chainSelector) {
revert InvalidMessageDestChainSelector(message.header.destChainSelector);
}
// If the message source chain selector does not match the report's source chain selector and the root has not
// been committed for the report source chain selector this will be caught by the root verification.
// This acts as an extra check to ensure the message source chain selector matches the report's source chain.
if (message.header.sourceChainSelector != sourceChainSelector) {
revert SourceChainSelectorMismatch(sourceChainSelector, message.header.sourceChainSelector);
}
hashedLeaves[i] = Internal._hash(message, metaDataHash);
}
}
// SECURITY CRITICAL CHECK.
uint256 timestampCommitted = _verify(sourceChainSelector, hashedLeaves, report.proofs, report.proofFlagBits);
if (timestampCommitted == 0) revert RootNotCommitted(sourceChainSelector);
// Execute messages.
for (uint256 i = 0; i < numMsgs; ++i) {
uint256 gasStart = gasleft();
Internal.Any2EVMRampMessage memory message = report.messages[i];
message = _beforeExecuteSingleMessage(message);
Internal.MessageExecutionState originalState =
getExecutionState(sourceChainSelector, message.header.sequenceNumber);
// Two valid cases here, we either have never touched this message before, or we tried to execute and failed. This
// check protects against reentry and re-execution because the other state is IN_PROGRESS which should not be
// allowed to execute.
if (
!(
originalState == Internal.MessageExecutionState.UNTOUCHED
|| originalState == Internal.MessageExecutionState.FAILURE
)
) {
// If the message has already been executed, we skip it. We want to not revert on race conditions between
// executing parties. This will allow us to open up manual exec while also attempting with the DON, without
// reverting an entire DON batch when a user manually executes while the tx is inflight.
emit SkippedAlreadyExecutedMessage(sourceChainSelector, message.header.sequenceNumber);
continue;
}
uint32[] memory tokenGasOverrides;
if (manualExecution) {
tokenGasOverrides = manualExecGasExecOverrides[i].tokenGasOverrides;
bool isOldCommitReport =
(block.timestamp - timestampCommitted) > s_dynamicConfig.permissionLessExecutionThresholdSeconds;
// Manually execution is fine if we previously failed or if the commit report is just too old.
// Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE, FAILURE->SUCCESS.
if (!(isOldCommitReport || originalState == Internal.MessageExecutionState.FAILURE)) {
revert ManualExecutionNotYetEnabled(sourceChainSelector);
}
// Manual execution gas limit can override gas limit specified in the message. Value of 0 indicates no override.
if (manualExecGasExecOverrides[i].receiverExecutionGasLimit != 0) {
message.gasLimit = manualExecGasExecOverrides[i].receiverExecutionGasLimit;
}
} else {
// DON can only execute a message once.
// Acceptable state transitions: UNTOUCHED->SUCCESS, UNTOUCHED->FAILURE.
if (originalState != Internal.MessageExecutionState.UNTOUCHED) {
emit AlreadyAttempted(sourceChainSelector, message.header.sequenceNumber);
continue;
}
}
// Nonce changes per state transition (these only apply for ordered messages):
// UNTOUCHED -> FAILURE nonce bump.
// UNTOUCHED -> SUCCESS nonce bump.
// FAILURE -> SUCCESS no nonce bump.
// UNTOUCHED messages MUST be executed in order always.
// If nonce == 0 then out of order execution is allowed.
if (message.header.nonce != 0) {
if (originalState == Internal.MessageExecutionState.UNTOUCHED) {
// If a nonce is not incremented, that means it was skipped, and we can ignore the message.
if (
!INonceManager(i_nonceManager).incrementInboundNonce(
sourceChainSelector, message.header.nonce, message.sender
)
) continue;
}
}
// We expect only valid messages will be committed but we check when executing as a defense in depth measure.
bytes[] memory offchainTokenData = report.offchainTokenData[i];
if (message.tokenAmounts.length != offchainTokenData.length) {
revert TokenDataMismatch(sourceChainSelector, message.header.sequenceNumber);
}
_setExecutionState(sourceChainSelector, message.header.sequenceNumber, Internal.MessageExecutionState.IN_PROGRESS);
(Internal.MessageExecutionState newState, bytes memory returnData) =
_trialExecute(message, offchainTokenData, tokenGasOverrides);
_setExecutionState(sourceChainSelector, message.header.sequenceNumber, newState);
// Since it's hard to estimate whether manual execution will succeed, we revert the entire transaction if it
// fails. This will show the user if their manual exec will fail before they submit it.
if (manualExecution) {
if (newState == Internal.MessageExecutionState.FAILURE) {
if (originalState != Internal.MessageExecutionState.UNTOUCHED) {
// If manual execution fails, we revert the entire transaction, unless the originalState is UNTOUCHED as we
// would still be making progress by changing the state from UNTOUCHED to FAILURE.
revert ExecutionError(message.header.messageId, returnData);
}
}
}
// The only valid prior states are UNTOUCHED and FAILURE (checked above).
// The only valid post states are FAILURE and SUCCESS (checked below).
if (newState != Internal.MessageExecutionState.SUCCESS) {
if (newState != Internal.MessageExecutionState.FAILURE) {
revert InvalidNewState(sourceChainSelector, message.header.sequenceNumber, newState);
}
}
emit ExecutionStateChanged(
sourceChainSelector,
message.header.sequenceNumber,
message.header.messageId,
hashedLeaves[i],
newState,
returnData,
// This emit covers not only the execution through the router, but also all of the overhead in executing the
// message. This gives the most accurate representation of the gas used in the execution.
gasStart - gasleft()
);
}
}
/// @notice Try executing a message.
/// @param message Internal.Any2EVMRampMessage memory message.
/// @param offchainTokenData Data provided by the DON for token transfers.
/// @return executionState The new state of the message, being either SUCCESS or FAILURE.
/// @return errData Revert data in bytes if CCIP receiver reverted during execution.
function _trialExecute(
Internal.Any2EVMRampMessage memory message,
bytes[] memory offchainTokenData,
uint32[] memory tokenGasOverrides
) internal returns (Internal.MessageExecutionState executionState, bytes memory) {
try this.executeSingleMessage(message, offchainTokenData, tokenGasOverrides) {}
catch (bytes memory err) {
if (msg.sender == Internal.GAS_ESTIMATION_SENDER) {
if (
CallWithExactGas.NOT_ENOUGH_GAS_FOR_CALL_SIG == bytes4(err)
|| CallWithExactGas.NO_GAS_FOR_CALL_EXACT_CHECK_SIG == bytes4(err)
|| ERC165CheckerReverting.InsufficientGasForStaticCall.selector == bytes4(err)
) {
revert InsufficientGasToCompleteTx(bytes4(err));
}
}
// return the message execution state as FAILURE and the revert data.
// Max length of revert data is Router.MAX_RET_BYTES, max length of err is 4 + Router.MAX_RET_BYTES.
return (Internal.MessageExecutionState.FAILURE, err);
}
// If message execution succeeded, no CCIP receiver return data is expected, return with empty bytes.
return (Internal.MessageExecutionState.SUCCESS, "");
}
/// @notice hook for applying custom logic to the input message before executeSingleMessage()
/// @param message initial message
/// @return transformedMessage modified message
function _beforeExecuteSingleMessage(
Internal.Any2EVMRampMessage memory message
) internal virtual returns (Internal.Any2EVMRampMessage memory transformedMessage) {
return message;
}
/// @notice Executes a single message.
/// @param message The message that will be executed.
/// @param offchainTokenData Token transfer data to be passed to TokenPool.
/// @dev We make this external and callable by the contract itself, in order to try/catch
/// 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[] calldata offchainTokenData,
uint32[] calldata tokenGasOverrides
) external {
if (msg.sender != address(this)) revert CanOnlySelfCall();
Client.EVMTokenAmount[] memory destTokenAmounts = new Client.EVMTokenAmount[](0);
if (message.tokenAmounts.length > 0) {
destTokenAmounts = _releaseOrMintTokens(
message.tokenAmounts,
message.sender,
message.receiver,
message.header.sourceChainSelector,
offchainTokenData,
tokenGasOverrides
);
}
Client.Any2EVMMessage memory any2EvmMessage = Client.Any2EVMMessage({
messageId: message.header.messageId,
sourceChainSelector: message.header.sourceChainSelector,
sender: message.sender,
data: message.data,
destTokenAmounts: destTokenAmounts
});
// The main message interceptor is the aggregate rate limiter, but we also allow for a custom interceptor. This is
// why we always have to call into the contract when it's enabled, even when there are no tokens in the message.
address messageInterceptor = s_dynamicConfig.messageInterceptor;
if (messageInterceptor != address(0)) {
try IMessageInterceptor(messageInterceptor).onInboundMessage(any2EvmMessage) {}
catch (bytes memory err) {
revert IMessageInterceptor.MessageValidationError(err);
}
}
// There are three cases in which we skip calling the receiver:
// 1. If the message data is empty AND the gas limit is 0.
// This indicates a message that only transfers tokens. It is valid to only send tokens to a contract
// that supports the IAny2EVMMessageReceiver interface, but without this first check we would call the
// receiver without any gas, which would revert the transaction.
// 2. If the receiver is not a contract.
// 3. If the receiver is a contract but it does not support the IAny2EVMMessageReceiver interface.
//
// The ordering of these checks is important, as the first check is the cheapest to execute.
//
// To prevent message delivery bypass issues, a modified version of the ERC165Checker is used
// which checks for sufficient gas before making the external call.
if (
(message.data.length == 0 && message.gasLimit == 0) || message.receiver.code.length == 0
|| !message.receiver._supportsInterfaceReverting(type(IAny2EVMMessageReceiver).interfaceId)
) return;
(bool success, bytes memory returnData,) = s_sourceChainConfigs[message.header.sourceChainSelector]
.router
.routeMessage(any2EvmMessage, i_gasForCallExactCheck, message.gasLimit, message.receiver);
// If CCIP receiver execution is not successful, revert the call including token transfers.
if (!success) revert ReceiverError(returnData);
}
// ================================================================
// │ Tokens and pools │
// ================================================================
/// @notice Uses a pool to release or mint a token to a receiver address, with balance checks before and after the
/// transfer. This is done to ensure the exact number of tokens the pool claims to release are actually transferred.
/// @dev The local token address is validated through the TokenAdminRegistry. If, due to some misconfiguration, the
/// token is unknown to the registry, the offRamp will revert. The tx, and the tokens, can be retrieved by registering
/// the token on this chain, and re-trying the msg.
/// @param sourceTokenAmount Amount and source data of the token to be released/minted.
/// @param originalSender The message sender on the source chain.
/// @param receiver The address that will receive the tokens.
/// @param sourceChainSelector The remote source chain selector
/// @param offchainTokenData Data fetched offchain by the DON.
/// @return destTokenAmount local token address with amount.
function _releaseOrMintSingleToken(
Internal.Any2EVMTokenTransfer memory sourceTokenAmount,
bytes memory originalSender,
address receiver,
uint64 sourceChainSelector,
bytes memory 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.
address localToken = sourceTokenAmount.destTokenAddress;
// We check with the token admin registry if the token has a pool on this chain.
address localPoolAddress = ITokenAdminRegistry(i_tokenAdminRegistry).getPool(localToken);
// This will call the supportsInterface through the ERC165Checker, and not directly on the pool address.
// This is done to prevent a pool from reverting the entire transaction if it doesn't support the interface.
// The call gets a max or 30k gas per instance, of which there are three. This means offchain gas estimations should
// account for 90k gas overhead due to the interface check.
if (localPoolAddress == address(0) || !localPoolAddress._supportsInterfaceReverting(Pool.CCIP_POOL_V1)) {
revert NotACompatiblePool(localPoolAddress);
}
// We retrieve the local token balance of the receiver before the pool call.
(uint256 balancePre, uint256 gasLeft) = _getBalanceOfReceiver(receiver, localToken, sourceTokenAmount.destGasAmount);
// We determined that the pool address is a valid EVM address, but that does not mean the code at this address is a
// (compatible) pool contract. _callWithExactGasSafeReturnData will check if the location contains a contract. If it
// doesn't it reverts with a known error. We call the pool with exact gas to increase resistance against malicious
// tokens or token pools. We protect against return data bombs by capping the return data size at MAX_RET_BYTES.
(bool success, bytes memory returnData, uint256 gasUsedReleaseOrMint) = CallWithExactGas
._callWithExactGasSafeReturnData(
abi.encodeCall(
IPoolV1.releaseOrMint,
Pool.ReleaseOrMintInV1({
originalSender: originalSender,
receiver: receiver,
amount: sourceTokenAmount.amount,
localToken: localToken,
remoteChainSelector: sourceChainSelector,
sourcePoolAddress: sourceTokenAmount.sourcePoolAddress,
sourcePoolData: sourceTokenAmount.extraData,
offchainTokenData: offchainTokenData
})
),
localPoolAddress,
gasLeft,
i_gasForCallExactCheck,
Internal.MAX_RET_BYTES
);
// Wrap and rethrow the error so we can catch it lower in the stack.
if (!success) revert TokenHandlingError(localPoolAddress, returnData);
// If the call was successful, the returnData should be the amount released or minted denominated in the local
// token's decimals.
if (returnData.length != Pool.CCIP_POOL_V1_RET_BYTES) {
revert InvalidDataLength(Pool.CCIP_POOL_V1_RET_BYTES, returnData.length);
}
uint256 localAmount = abi.decode(returnData, (uint256));
// We don't need to do balance checks if the pool is the receiver, as they would always fail in the case
// of a lockRelease pool.
if (receiver != localPoolAddress) {
(uint256 balancePost,) = _getBalanceOfReceiver(receiver, localToken, gasLeft - gasUsedReleaseOrMint);
// First we check if the subtraction would result in an underflow to ensure we revert with a clear error.
if (balancePost < balancePre || balancePost - balancePre != localAmount) {
revert ReleaseOrMintBalanceMismatch(localAmount, balancePre, balancePost);
}
}
return Client.EVMTokenAmount({token: localToken, amount: localAmount});
}
/// @notice Retrieves the balance of a receiver address for a given token.
/// @param receiver The address to check the balance of.
/// @param token The token address.
/// @param gasLimit The gas limit to use for the call.
/// @return balance The balance of the receiver.
/// @return gasLeft The gas left after the call.
function _getBalanceOfReceiver(
address receiver,
address token,
uint256 gasLimit
) internal returns (uint256 balance, uint256 gasLeft) {
(bool success, bytes memory returnData, uint256 gasUsed) = CallWithExactGas._callWithExactGasSafeReturnData(
abi.encodeCall(IERC20.balanceOf, (receiver)), token, gasLimit, i_gasForCallExactCheck, Internal.MAX_RET_BYTES
);
if (!success) revert TokenHandlingError(token, returnData);
// If the call was successful, the returnData should contain only the balance.
if (returnData.length != Internal.MAX_BALANCE_OF_RET_BYTES) {
revert InvalidDataLength(Internal.MAX_BALANCE_OF_RET_BYTES, returnData.length);
}
// Return the decoded balance, which cannot fail as we checked the length, and the gas that is left
// after this call.
return (abi.decode(returnData, (uint256)), gasLimit - gasUsed);
}
/// @notice Uses pools to release or mint a number of different tokens to a receiver address.
/// @param sourceTokenAmounts List of token amounts with source data of the tokens to be released/minted.
/// @param originalSender The message sender on the source chain.
/// @param receiver The address that will receive the tokens.
/// @param sourceChainSelector The remote source chain selector.
/// @param offchainTokenData Array of token data fetched offchain by the DON.
/// @param tokenGasOverrides Array of override gas limits to use for token transfers. If empty, the normal gas limit
/// as defined on the source chain is used.
/// @return destTokenAmounts local token addresses with amounts.
function _releaseOrMintTokens(
Internal.Any2EVMTokenTransfer[] memory sourceTokenAmounts,
bytes memory originalSender,
address receiver,
uint64 sourceChainSelector,
bytes[] calldata offchainTokenData,
uint32[] calldata tokenGasOverrides
) internal returns (Client.EVMTokenAmount[] memory destTokenAmounts) {
destTokenAmounts = new Client.EVMTokenAmount[](sourceTokenAmounts.length);
bool isTokenGasOverridesEmpty = tokenGasOverrides.length == 0;
for (uint256 i = 0; i < sourceTokenAmounts.length; ++i) {
if (!isTokenGasOverridesEmpty) {
if (tokenGasOverrides[i] != 0) {
sourceTokenAmounts[i].destGasAmount = tokenGasOverrides[i];
}
}
destTokenAmounts[i] = _releaseOrMintSingleToken(
sourceTokenAmounts[i], originalSender, receiver, sourceChainSelector, offchainTokenData[i]
);
}
return destTokenAmounts;
}
// ================================================================
// │ Commit │
// ================================================================
/// @notice Transmit function for commit reports. The function requires signatures,
/// and expects the commit plugin type to be configured with signatures.
/// @param report serialized commit report.
/// @dev A commitReport can have two distinct parts (batched together to amortize the cost of checking sigs):
/// 1. Price updates
/// 2. A batch of merkle root and sequence number intervals (per-source)
/// Both have their own, separate, staleness checks, with price updates using the epoch and round number of the latest
/// price update. The merkle root checks for staleness are based on the seqNums. They need to be separate because
/// a price report for round t+2 might be included before a report containing a merkle root for round t+1. This merkle
/// root report for round t+1 is still valid and should not be rejected. When a report with a stale root but valid
/// price updates is submitted, we are OK to revert to preserve the invariant that we always revert on invalid
/// sequence number ranges. If that happens, prices will be updated in later rounds.
function commit(
bytes32[2] calldata reportContext,
bytes calldata report,
bytes32[] calldata rs,
bytes32[] calldata ss,
bytes32 rawVs
) external {
CommitReport memory commitReport = abi.decode(report, (CommitReport));
DynamicConfig storage dynamicConfig = s_dynamicConfig;
// Verify RMN signatures
if (commitReport.blessedMerkleRoots.length > 0) {
i_rmnRemote.verify(address(this), commitReport.blessedMerkleRoots, commitReport.rmnSignatures);
}
// Check if the report contains price updates.
if (commitReport.priceUpdates.tokenPriceUpdates.length > 0 || commitReport.priceUpdates.gasPriceUpdates.length > 0)
{
uint64 ocrSequenceNumber = uint64(uint256(reportContext[1]));
// Check for price staleness based on the epoch and round.
if (s_latestPriceSequenceNumber < ocrSequenceNumber) {
// If prices are not stale, update the latest epoch and round.
s_latestPriceSequenceNumber = ocrSequenceNumber;
// And update the prices in the fee quoter.
IFeeQuoter(dynamicConfig.feeQuoter).updatePrices(commitReport.priceUpdates);
} else {
// If prices are stale and the report doesn't contain a root, this report does not have any valid information
// and we revert. If it does contain a merkle root, continue to the root checking section.
if (commitReport.blessedMerkleRoots.length + commitReport.unblessedMerkleRoots.length == 0) {
revert StaleCommitReport();
}
}
}
for (uint256 i = 0; i < commitReport.blessedMerkleRoots.length; ++i) {
_commitRoot(commitReport.blessedMerkleRoots[i], true);
}
for (uint256 i = 0; i < commitReport.unblessedMerkleRoots.length; ++i) {
_commitRoot(commitReport.unblessedMerkleRoots[i], false);
}
emit CommitReportAccepted(
commitReport.blessedMerkleRoots, commitReport.unblessedMerkleRoots, commitReport.priceUpdates
);
_transmit(uint8(Internal.OCRPluginType.Commit), reportContext, report, rs, ss, rawVs);
}
/// @notice Commits a single merkle root. The blessing status has to match the source chain config.
/// @dev An unblessed root means that RMN verification is disabled for the source chain. It does not mean there is
/// some future point where the root will be blessed.
/// @param root The merkle root to commit.
/// @param isBlessed The blessing status of the root.
function _commitRoot(Internal.MerkleRoot memory root, bool isBlessed) internal {
uint64 sourceChainSelector = root.sourceChainSelector;
if (i_rmnRemote.isCursed(bytes16(uint128(sourceChainSelector)))) {
revert CursedByRMN(sourceChainSelector);
}
SourceChainConfig storage sourceChainConfig = _getEnabledSourceChainConfig(sourceChainSelector);
// If the root is blessed but RMN blessing is disabled for the source chain, or if the root is not blessed but RMN
// blessing is enabled, we revert.
if (isBlessed == sourceChainConfig.isRMNVerificationDisabled) {
revert RootBlessingMismatch(sourceChainSelector, root.merkleRoot, isBlessed);
}
if (keccak256(root.onRampAddress) != keccak256(sourceChainConfig.onRamp)) {
revert CommitOnRampMismatch(root.onRampAddress, sourceChainConfig.onRamp);
}
if (sourceChainConfig.minSeqNr != root.minSeqNr || root.minSeqNr > root.maxSeqNr) {
revert InvalidInterval(sourceChainSelector, root.minSeqNr, root.maxSeqNr);
}
bytes32 merkleRoot = root.merkleRoot;
if (merkleRoot == bytes32(0)) revert InvalidRoot();
// If we reached this section, the report should contain a valid root.
// We disallow duplicate roots as that would reset the timestamp and delay potential manual execution.
if (s_roots[sourceChainSelector][merkleRoot] != 0) {
revert RootAlreadyCommitted(sourceChainSelector, merkleRoot);
}
sourceChainConfig.minSeqNr = root.maxSeqNr + 1;
s_roots[sourceChainSelector][merkleRoot] = block.timestamp;
}
/// @notice Returns the sequence number of the last price update.
/// @return sequenceNumber The latest price update sequence number.
function getLatestPriceSequenceNumber() external view returns (uint64) {
return s_latestPriceSequenceNumber;
}
/// @notice Returns the timestamp of a potentially previously committed merkle root.
/// If the root was never committed 0 will be returned.
/// @param sourceChainSelector The source chain selector.
/// @param root The merkle root to check the commit status for.
/// @return timestamp The timestamp of the committed root or zero in the case that it was never committed.
function getMerkleRoot(uint64 sourceChainSelector, bytes32 root) external view returns (uint256) {
return s_roots[sourceChainSelector][root];
}
/// @notice Returns timestamp of when root was accepted or 0 if verification fails.
/// @dev This method uses a merkle tree within a merkle tree, with the hashedLeaves,
/// proofs and proofFlagBits being used to get the root of the inner tree.
/// This root is then used as the singular leaf of the outer tree.
/// @return timestamp The commit timestamp of the root.
function _verify(
uint64 sourceChainSelector,
bytes32[] memory hashedLeaves,
bytes32[] memory proofs,
uint256 proofFlagBits
) internal view virtual returns (uint256 timestamp) {
bytes32 root = MerkleMultiProof._merkleRoot(hashedLeaves, proofs, proofFlagBits);
return s_roots[sourceChainSelector][root];
}
/// @inheritdoc MultiOCR3Base
function _afterOCR3ConfigSet(
uint8 ocrPluginType
) internal override {
bool isSignatureVerificationEnabled = s_ocrConfigs[ocrPluginType].configInfo.isSignatureVerificationEnabled;
if (ocrPluginType == uint8(Internal.OCRPluginType.Commit)) {
// Signature verification must be enabled for commit plugin.
if (!isSignatureVerificationEnabled) {
revert SignatureVerificationRequiredInCommitPlugin();
}
// When the OCR config changes, we reset the sequence number since it is scoped per config digest.
// Note that s_minSeqNr/roots do not need to be reset as the roots persist across reconfigurations
// and are de-duplicated separately.
s_latestPriceSequenceNumber = 0;
} else if (ocrPluginType == uint8(Internal.OCRPluginType.Execution)) {
// Signature verification must be disabled for execution plugin.
if (isSignatureVerificationEnabled) {
revert SignatureVerificationNotAllowedInExecutionPlugin();
}
}
}
// ================================================================
// │ Config │
// ================================================================
/// @notice Returns the static config.
/// @dev This function will always return the same struct as the contents is static and can never change.
/// @return staticConfig The static config.
function getStaticConfig() external view returns (StaticConfig memory) {
return StaticConfig({
chainSelector: i_chainSelector,
gasForCallExactCheck: i_gasForCallExactCheck,
rmnRemote: i_rmnRemote,
tokenAdminRegistry: i_tokenAdminRegistry,
nonceManager: i_nonceManager
});
}
/// @notice Returns the current dynamic config.
/// @return dynamicConfig The current dynamic config.
function getDynamicConfig() external view returns (DynamicConfig memory) {
return s_dynamicConfig;
}
/// @notice Returns the source chain config for the provided source chain selector.
/// @param sourceChainSelector chain to retrieve configuration for.
/// @return sourceChainConfig The config for the source chain.
function getSourceChainConfig(
uint64 sourceChainSelector
) external view returns (SourceChainConfig memory) {
return s_sourceChainConfigs[sourceChainSelector];
}
/// @notice Returns all source chain configs.
/// @return sourceChainConfigs The source chain configs corresponding to all the supported chain selectors.
function getAllSourceChainConfigs() external view returns (uint64[] memory, SourceChainConfig[] memory) {
SourceChainConfig[] memory sourceChainConfigs = new SourceChainConfig[](s_sourceChainSelectors.length());
uint64[] memory sourceChainSelectors = new uint64[](s_sourceChainSelectors.length());
for (uint256 i = 0; i < s_sourceChainSelectors.length(); ++i) {
sourceChainSelectors[i] = uint64(s_sourceChainSelectors.at(i));
sourceChainConfigs[i] = s_sourceChainConfigs[sourceChainSelectors[i]];
}
return (sourceChainSelectors, sourceChainConfigs);
}
/// @notice Updates source configs.
/// @param sourceChainConfigUpdates Source chain configs.
function applySourceChainConfigUpdates(
SourceChainConfigArgs[] memory sourceChainConfigUpdates
) external onlyOwner {
_applySourceChainConfigUpdates(sourceChainConfigUpdates);
}
/// @notice Updates source configs.
/// @param sourceChainConfigUpdates Source chain configs.
function _applySourceChainConfigUpdates(
SourceChainConfigArgs[] memory sourceChainConfigUpdates
) internal {
for (uint256 i = 0; i < sourceChainConfigUpdates.length; ++i) {
SourceChainConfigArgs memory sourceConfigUpdate = sourceChainConfigUpdates[i];
uint64 sourceChainSelector = sourceConfigUpdate.sourceChainSelector;
if (sourceChainSelector == 0) {
revert ZeroChainSelectorNotAllowed();
}
if (address(sourceConfigUpdate.router) == address(0)) {
revert ZeroAddressNotAllowed();
}
SourceChainConfig storage currentConfig = s_sourceChainConfigs[sourceChainSelector];
bytes memory newOnRamp = sourceConfigUpdate.onRamp;
if (currentConfig.onRamp.length == 0) {
currentConfig.minSeqNr = 1;
emit SourceChainSelectorAdded(sourceChainSelector);
} else {
if (currentConfig.minSeqNr != 1 && keccak256(currentConfig.onRamp) != keccak256(newOnRamp)) {
// OnRamp updates should only happens due to a misconfiguration.
// If an OnRamp is misconfigured, no reports should have been committed and no messages should have been
// executed. This is enforced by the onRamp address check in the commit function.
revert InvalidOnRampUpdate(sourceChainSelector);
}
}
// OnRamp can never be zero - if it is, then the source chain has been added for the first time.
if (newOnRamp.length == 0 || keccak256(newOnRamp) == EMPTY_ENCODED_ADDRESS_HASH) {
revert ZeroAddressNotAllowed();
}
currentConfig.onRamp = newOnRamp;
currentConfig.isEnabled = sourceConfigUpdate.isEnabled;
currentConfig.router = sourceConfigUpdate.router;
currentConfig.isRMNVerificationDisabled = sourceConfigUpdate.isRMNVerificationDisabled;
// We don't need to check the return value, as inserting the item twice has no effect.
s_sourceChainSelectors.add(sourceChainSelector);
emit SourceChainConfigSet(sourceChainSelector, currentConfig);
}
}
/// @notice Sets the dynamic config.
/// @param dynamicConfig The new dynamic config.
function setDynamicConfig(
DynamicConfig memory dynamicConfig
) external onlyOwner {
_setDynamicConfig(dynamicConfig);
}
/// @notice Sets the dynamic config.
/// @param dynamicConfig The dynamic config.
function _setDynamicConfig(
DynamicConfig memory dynamicConfig
) internal {
if (dynamicConfig.feeQuoter == address(0)) {
revert ZeroAddressNotAllowed();
}
s_dynamicConfig = dynamicConfig;
emit DynamicConfigSet(dynamicConfig);
}
/// @notice Returns a source chain config with a check that the config is enabled.
/// @param sourceChainSelector Source chain selector to check for cursing.
/// @return sourceChainConfig The source chain config storage pointer.
function _getEnabledSourceChainConfig(
uint64 sourceChainSelector
) internal view returns (SourceChainConfig storage) {
SourceChainConfig storage sourceChainConfig = s_sourceChainConfigs[sourceChainSelector];
if (!sourceChainConfig.isEnabled) {
revert SourceChainNotEnabled(sourceChainSelector);
}
return sourceChainConfig;
}
// ================================================================
// │ Access │
// ================================================================
/// @notice Reverts as this contract should not be able to receive CCIP messages.
function ccipReceive(
Client.Any2EVMMessage calldata
) external pure {
// solhint-disable-next-line
revert();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface ITypeAndVersion {
function typeAndVersion() external pure returns (string memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
/// @notice Application contracts that intend to receive messages from the router should implement this interface.
interface IAny2EVMMessageReceiver {
/// @notice Called by the Router to deliver a message. If this reverts, any token transfers also revert.
/// The message will move to a FAILED state and become available for manual execution.
/// @param message CCIP Message.
/// @dev Note ensure you check the msg.sender is the OffRampRouter.
function ccipReceive(
Client.Any2EVMMessage calldata message
) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Client} from "../libraries/Client.sol";
import {Internal} from "../libraries/Internal.sol";
import {IPriceRegistry} from "./IPriceRegistry.sol";
interface IFeeQuoter is IPriceRegistry {
/// @notice Validates the ccip message & returns the fee.
/// @param destChainSelector The destination chain selector.
/// @param message The message to get quote for.
/// @return feeTokenAmount The amount of fee token needed for the fee, in smallest denomination of the fee token.
function getValidatedFee(
uint64 destChainSelector,
Client.EVM2AnyMessage calldata message
) external view returns (uint256 feeTokenAmount);
/// @notice Converts the extraArgs to the latest version and returns the converted message fee in juels.
/// @notice Validates pool return data.
/// @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.
/// @param extraArgs Message extra args that were passed in by the client.
/// @param messageReceiver Message receiver address in bytes from EVM2AnyMessage.receiver
/// @return msgFeeJuels message fee in juels.
/// @return isOutOfOrderExecution true if the message should be executed out of order.
/// @return convertedExtraArgs extra args converted to the latest family-specific args version.
/// @return tokenReceiver token receiver address in bytes on destination chain
function processMessageArgs(
uint64 destChainSelector,
address feeToken,
uint256 feeTokenAmount,
bytes calldata extraArgs,
bytes calldata messageReceiver
)
external
view
returns (
uint256 msgFeeJuels,
bool isOutOfOrderExecution,
bytes memory convertedExtraArgs,
bytes memory tokenReceiver
);
/// @notice Validates pool return data.
/// @param destChainSelector Destination chain selector to which the token amounts are sent to.
/// @param onRampTokenTransfers Token amounts with populated pool return data.
/// @param sourceTokenAmounts Token amounts originally sent in a Client.EVM2AnyMessage message.
/// @return destExecDataPerToken Destination chain execution data.
function processPoolReturnData(
uint64 destChainSelector,
Internal.EVM2AnyTokenTransfer[] calldata onRampTokenTransfers,
Client.EVMTokenAmount[] calldata sourceTokenAmounts
) external view returns (bytes[] memory destExecDataPerToken);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
/// @notice Interface for plug-in message hook contracts that intercept OffRamp & OnRamp messages and perform
/// validations / state changes on top of the messages. The interceptor functions are expected to revert
/// on validation failures.
interface IMessageInterceptor {
/// @notice Common error that can be thrown on validation failures and used by consumers.
/// @param errorReason abi encoded revert reason.
error MessageValidationError(bytes errorReason);
/// @notice Intercepts & validates the given OffRamp message. Reverts on validation failure.
/// @param message to validate.
function onInboundMessage(
Client.Any2EVMMessage memory message
) external;
/// @notice Intercepts & validates the given OnRamp message. Reverts on validation failure.
/// @param destChainSelector remote destination chain selector where the message is being sent to.
/// @param message to validate.
function onOutboundMessage(uint64 destChainSelector, Client.EVM2AnyMessage memory message) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice Contract interface that allows managing sender nonces.
interface INonceManager {
/// @notice Increments the outbound nonce for a given sender on a given destination chain.
/// @param destChainSelector The destination chain selector.
/// @param sender The sender address.
/// @return incrementedOutboundNonce The new outbound nonce.
function getIncrementedOutboundNonce(uint64 destChainSelector, address sender) external returns (uint64);
/// @notice Increments the inbound nonce for a given sender on a given source chain.
/// @notice The increment is only applied if the resulting nonce matches the expectedNonce.
/// @param sourceChainSelector The destination chain selector.
/// @param expectedNonce The expected inbound nonce.
/// @param sender The encoded sender address.
/// @return incremented True if the nonce was incremented, false otherwise.
function incrementInboundNonce(
uint64 sourceChainSelector,
uint64 expectedNonce,
bytes calldata sender
) external returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Pool} from "../libraries/Pool.sol";
import {IERC165} from "../../vendor/openzeppelin-solidity/v5.0.2/contracts/utils/introspection/IERC165.sol";
/// @notice Shared public interface for multiple V1 pool types.
/// Each pool type handles a different child token model e.g. lock/unlock, mint/burn.
interface IPoolV1 is IERC165 {
/// @notice Lock tokens into the pool or burn the tokens.
/// @param lockOrBurnIn Encoded data fields for the processing of tokens on the source chain.
/// @return lockOrBurnOut Encoded data fields for the processing of tokens on the destination chain.
function lockOrBurn(
Pool.LockOrBurnInV1 calldata lockOrBurnIn
) external returns (Pool.LockOrBurnOutV1 memory lockOrBurnOut);
/// @notice Releases or mints tokens to the receiver address.
/// @param releaseOrMintIn All data required to release or mint tokens.
/// @return releaseOrMintOut The amount of tokens released or minted on the local chain, denominated
/// in the local token's decimals.
/// @dev The offramp asserts that the balanceOf of the receiver has been incremented by exactly the number
/// of tokens that is returned in ReleaseOrMintOutV1.destinationAmount. If the amounts do not match, the tx reverts.
function releaseOrMint(
Pool.ReleaseOrMintInV1 calldata releaseOrMintIn
) external returns (Pool.ReleaseOrMintOutV1 memory);
/// @notice Checks whether a remote chain is supported in the token pool.
/// @param remoteChainSelector The selector of the remote chain.
/// @return true if the given chain is a permissioned remote chain.
function isSupportedChain(
uint64 remoteChainSelector
) external view returns (bool);
/// @notice Returns if the token pool supports the given token.
/// @param token The address of the token.
/// @return true if the token is supported by the pool.
function isSupportedToken(
address token
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
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 IRMNRemote {
/// @notice signature components from RMN nodes.
struct Signature {
bytes32 r;
bytes32 s;
}
/// @notice Verifies signatures of RMN nodes, on dest lane updates as provided in the CommitReport.
/// @param offRampAddress is not inferred by msg.sender, in case the call is made through RMNProxy.
/// @param merkleRoots must be well formed, and is a representation of the CommitReport received from the oracles.
/// @param signatures rmnNodes ECDSA sigs, only r & s, must be sorted in ascending order by signer address.
/// @dev Will revert if verification fails.
function verify(
address offRampAddress,
Internal.MerkleRoot[] memory merkleRoots,
Signature[] memory signatures
) external view;
/// @notice gets the current set of cursed subjects.
/// @return subjects the list of cursed subjects.
function getCursedSubjects() external view returns (bytes16[] memory subjects);
/// @notice If there is an active global or legacy curse, this function returns true.
/// @return bool true if there is an active global curse.
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)).
/// @return bool true if the provided subject is cured *or* if there is an active global curse.
function isCursed(
bytes16 subject
) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {Client} from "../libraries/Client.sol";
interface IRouter {
error OnlyOffRamp();
/// @notice Route the message to its intended receiver contract.
/// @param message Client.Any2EVMMessage struct.
/// @param gasForCallExactCheck of params for exec.
/// @param gasLimit set of params for exec.
/// @param receiver set of params for exec.
/// @dev if the receiver is a contracts that signals support for CCIP execution through EIP-165.
/// the contract is called. If not, only tokens are transferred.
/// @return success A boolean value indicating whether the ccip message was received without errors.
/// @return retBytes A bytes array containing return data form CCIP receiver.
/// @return gasUsed the gas used by the external customer call. Does not include any overhead.
function routeMessage(
Client.Any2EVMMessage calldata message,
uint16 gasForCallExactCheck,
uint256 gasLimit,
address receiver
) external returns (bool success, bytes memory retBytes, uint256 gasUsed);
/// @notice Returns the configured onramp for a specific destination chain.
/// @param destChainSelector The destination chain Id to get the onRamp for.
/// @return onRampAddress The address of the onRamp.
function getOnRamp(
uint64 destChainSelector
) external view returns (address onRampAddress);
/// @notice Return true if the given offRamp is a configured offRamp for the given source chain.
/// @param sourceChainSelector The source chain selector to check.
/// @param offRamp The address of the offRamp to check.
function isOffRamp(uint64 sourceChainSelector, address offRamp) external view returns (bool isOffRamp);
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;
interface ITokenAdminRegistry {
/// @notice Returns the pool for the given token.
function getPool(
address token
) external view returns (address);
/// @notice Proposes an administrator for the given token as pending administrator.
/// @param localToken The token to register the administrator for.
/// @param administrator The administrator to register.
function proposeAdministrator(address localToken, address administrator) external;
/// @notice Accepts the administrator role for a token.
/// @param localToken The token to accept the administrator role for.
/// @dev This function can only be called by the pending administrator.
function acceptAdminRole(
address localToken
) external;
/// @notice Sets the pool for a token. Setting the pool to address(0) effectively delists the token
/// from CCIP. Setting the pool to any other address enables the token on CCIP.
/// @param localToken The token to set the pool for.
/// @param pool The pool to set for the token.
function setPool(address localToken, address pool) external;
/// @notice Transfers the administrator role for a token to a new address with a 2-step process.
/// @param localToken The token to transfer the administrator role for.
/// @param newAdmin The address to transfer the administrator role to. Can be address(0) to cancel
/// a pending transfer.
/// @dev The new admin must call `acceptAdminRole` to accept the role.
function transferAdminRole(address localToken, address newAdmin) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice This library contains various callWithExactGas functions. All of them are
/// safe from gas bomb attacks.
/// @dev There is code duplication in this library. This is done to not leave the assembly
/// the blocks.
library CallWithExactGas {
error NoContract();
error NoGasForCallExactCheck();
error NotEnoughGasForCall();
bytes4 internal constant NO_CONTRACT_SIG = 0x0c3b563c;
bytes4 internal constant NO_GAS_FOR_CALL_EXACT_CHECK_SIG = 0xafa32a2c;
bytes4 internal constant NOT_ENOUGH_GAS_FOR_CALL_SIG = 0x37c3be29;
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Accounts for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
function _callWithExactGas(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck
) internal returns (bool success) {
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
}
return success;
}
/// @notice calls target address with exactly gasAmount gas and payload as calldata.
/// Account for gasForCallExactCheck gas that will be used by this function. Will revert
/// if the target is not a contact. Will revert when there is not enough gas to call the
/// target with gasAmount gas.
/// @dev Caps the return data length, which makes it immune to gas bomb attacks.
/// @dev Return data cap logic borrowed from
/// https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
/// @return success whether the call succeeded
/// @return retData the return data from the call, capped at maxReturnBytes bytes
/// @return gasUsed the gas used by the external call. Does not include the overhead of this function.
function _callWithExactGasSafeReturnData(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck,
uint16 maxReturnBytes
) internal returns (bool success, bytes memory retData, uint256 gasUsed) {
// allocate retData memory ahead of time
retData = new bytes(maxReturnBytes);
assembly {
// solidity calls check that a contract actually exists at the destination, so we do the same
// Note we do this check prior to measuring gas so gasForCallExactCheck (our "cushion")
// doesn't need to account for it.
if iszero(extcodesize(target)) {
mstore(0x0, NO_CONTRACT_SIG)
revert(0x0, 0x4)
}
let g := gas()
// Compute g -= gasForCallExactCheck and check for underflow
// The gas actually passed to the callee is _min(gasAmount, 63//64*gas available).
// We want to ensure that we revert if gasAmount > 63//64*gas available
// as we do not want to provide them with less, however that check itself costs
// gas. gasForCallExactCheck ensures we have at least enough gas to be able
// to revert if gasAmount > 63//64*gas available.
if lt(g, gasForCallExactCheck) {
mstore(0x0, NO_GAS_FOR_CALL_EXACT_CHECK_SIG)
revert(0x0, 0x4)
}
g := sub(g, gasForCallExactCheck)
// if g - g//64 <= gasAmount, revert. We subtract g//64 because of EIP-150
if iszero(gt(sub(g, div(g, 64)), gasLimit)) {
mstore(0x0, NOT_ENOUGH_GAS_FOR_CALL_SIG)
revert(0x0, 0x4)
}
// We save the gas before the call so we can calculate how much gas the call used
let gasBeforeCall := gas()
// call and return whether we succeeded. ignore return data
// call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
gasUsed := sub(gasBeforeCall, gas())
// limit our copy to maxReturnBytes bytes
let toCopy := returndatasize()
if gt(toCopy, maxReturnBytes) {
toCopy := maxReturnBytes
}
// Store the length of the copied bytes
mstore(retData, toCopy)
// copy the bytes from retData[0:_toCopy]
returndatacopy(add(retData, 0x20), 0x0, toCopy)
}
return (success, retData, gasUsed);
}
/// @notice Calls target address with exactly gasAmount gas and payload as calldata
/// or reverts if at least gasLimit gas is not available.
/// @dev Does not check if target is a contract. If it is not a contract, the low-level
/// call will still be made and it will succeed.
/// @dev Ignores the return data, which makes it immune to gas bomb attacks.
/// @return success whether the call succeeded
/// @return sufficientGas Whether there was enough gas to make the call
function _callWithExactGasEvenIfTargetIsNoContract(
bytes memory payload,
address target,
uint256 gasLimit,
uint16 gasForCallExactCheck
) internal returns (bool success, bool sufficientGas) {
assembly {
let g := gas()
// Compute g -= CALL_WITH_EXACT_GAS_CUSHION and check for underflow. We
// need the cushion since the logic following the above call to gas also
// costs gas which we cannot account for exactly. So cushion is a
// conservative upper bound for the cost of this logic.
if iszero(lt(g, gasForCallExactCheck)) {
g := sub(g, gasForCallExactCheck)
// If g - g//64 <= gasAmount, we don't have enough gas. We subtract g//64 because of EIP-150.
if gt(sub(g, div(g, 64)), gasLimit) {
// Call and ignore success/return data. Note that we did not check
// whether a contract actually exists at the target address.
success := call(gasLimit, target, 0, add(payload, 0x20), mload(payload), 0x0, 0x0)
sufficientGas := true
}
}
}
return (success, sufficientGas);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
// End consumer library.
library Client {
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct EVMTokenAmount {
address token; // token address on the local chain.
uint256 amount; // Amount of tokens.
}
struct Any2EVMMessage {
bytes32 messageId; // MessageId corresponding to ccipSend on source.
uint64 sourceChainSelector; // Source chain selector.
bytes sender; // abi.decode(sender) if coming from an EVM chain.
bytes data; // payload sent in original message.
EVMTokenAmount[] destTokenAmounts; // Tokens and their amounts in their destination chain representation.
}
// If extraArgs is empty bytes, the default is 200k gas limit.
struct EVM2AnyMessage {
bytes receiver; // abi.encode(receiver address) for dest EVM chains.
bytes data; // Data payload.
EVMTokenAmount[] tokenAmounts; // Token transfers.
address feeToken; // Address of feeToken. address(0) means you will send msg.value.
bytes extraArgs; // Populate this with _argsToBytes(EVMExtraArgsV2).
}
// bytes4(keccak256("CCIP EVMExtraArgsV1"));
bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
struct EVMExtraArgsV1 {
uint256 gasLimit;
}
function _argsToBytes(
EVMExtraArgsV1 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V1_TAG, extraArgs);
}
// bytes4(keccak256("CCIP EVMExtraArgsV2"));
bytes4 public constant EVM_EXTRA_ARGS_V2_TAG = 0x181dcf10;
// bytes4(keccak256("CCIP SVMExtraArgsV1"));
bytes4 public constant SVM_EXTRA_ARGS_V1_TAG = 0x1f3b3aba;
/// @dev The maximum number of accounts that can be passed in SVMExtraArgs.
uint256 public constant SVM_EXTRA_ARGS_MAX_ACCOUNTS = 64;
/// @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
/// enforced, meaning if the expected value is not set, the message request will revert.
struct EVMExtraArgsV2 {
uint256 gasLimit;
bool allowOutOfOrderExecution;
}
struct SVMExtraArgsV1 {
uint32 computeUnits;
uint64 accountIsWritableBitmap;
bool allowOutOfOrderExecution;
bytes32 tokenReceiver;
bytes32[] accounts;
}
function _argsToBytes(
EVMExtraArgsV2 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(EVM_EXTRA_ARGS_V2_TAG, extraArgs);
}
function _svmArgsToBytes(
SVMExtraArgsV1 memory extraArgs
) internal pure returns (bytes memory bts) {
return abi.encodeWithSelector(SVM_EXTRA_ARGS_V1_TAG, extraArgs);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
import {IERC165} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/introspection/IERC165.sol";
/// @notice Library used to query support of an interface declared via {IERC165}.
/// @dev These functions return the actual result of the query: they do not `revert` if an interface is not supported.
library ERC165CheckerReverting {
error InsufficientGasForStaticCall();
// As per the EIP-165 spec, no interface should ever match 0xffffffff.
bytes4 private constant INTERFACE_ID_INVALID = 0xffffffff;
/// @dev 30k gas is required to make the staticcall. Under the 63/64 rule this means that 30,477 gas must be available
/// to ensure that at least 30k is forwarded. Checking for at least 31,000 ensures that after additional
/// operations are performed there is still >= 30,477 gas remaining.
/// 30,000 = ((30,477 * 63) / 64)
uint256 private constant MINIMUM_GAS_REQUIREMENT = 31_000;
/// @notice Returns true if `account` supports a defined interface.
/// @dev The function must support both the interfaceId and interfaces specified by ERC165 generally as per the standard.
/// @param account the contract to be queried for support.
/// @param interfaceId the interface being checked for support.
/// @return true if the contract at account indicates support of the interface with, false otherwise.
function _supportsInterfaceReverting(address account, bytes4 interfaceId) internal view returns (bool) {
// As a gas optimization, short circuit return false if interfaceId is not supported, as it is most likely interfaceId
// to be unsupported by the target.
return _supportsERC165InterfaceUncheckedReverting(account, interfaceId)
&& !_supportsERC165InterfaceUncheckedReverting(account, INTERFACE_ID_INVALID)
&& _supportsERC165InterfaceUncheckedReverting(account, type(IERC165).interfaceId);
}
/// @notice Query if a contract implements an interface, does not check ERC165 support
/// @param account The address of the contract to query for support of an interface
/// @param interfaceId The interface identifier, as specified in ERC-165
/// @return true if the contract at account indicates support of the interface with
/// identifier interfaceId, false otherwise
/// @dev Assumes that account contains a contract that supports ERC165, otherwise
/// the behavior of this method is undefined. This precondition can be checked.
/// @dev Function will only revert if the minimum gas requirement is not met before the staticcall is performed.
function _supportsERC165InterfaceUncheckedReverting(address account, bytes4 interfaceId) internal view returns (bool) {
bytes memory encodedParams = abi.encodeWithSelector(IERC165.supportsInterface.selector, interfaceId);
bool success;
uint256 returnSize;
uint256 returnValue;
bytes4 notEnoughGasSelector = InsufficientGasForStaticCall.selector;
assembly {
// The EVM does not return a specific error code if a revert is due to OOG. This check ensures that
// the message will not throw an OOG error by requiring that the amount of gas for the following
// staticcall exists before invoking it.
if lt(gas(), MINIMUM_GAS_REQUIREMENT) {
mstore(0x0, notEnoughGasSelector)
revert(0x0, 0x4)
}
success := staticcall(30000, account, add(encodedParams, 0x20), mload(encodedParams), 0x00, 0x20)
returnSize := returndatasize()
returnValue := mload(0x00)
}
return success && returnSize >= 0x20 && returnValue > 0;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {MerkleMultiProof} from "../libraries/MerkleMultiProof.sol";
/// @notice Library for CCIP internal definitions common to multiple contracts.
/// @dev The following is a non-exhaustive list of "known issues" for CCIP:
/// - We could implement yield claiming for Blast. This is not worth the custom code path on non-blast chains.
/// - uint32 is used for timestamps, which will overflow in 2106. This is not a concern for the current use case, as we
/// expect to have migrated to a new version by then.
library Internal {
error InvalidEVMAddress(bytes encodedAddress);
error InvalidSVMAddress(bytes SVMAddress);
/// @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.
uint16 internal constant MAX_RET_BYTES = 4 + 4 * 32;
/// @dev The expected number of bytes returned by the balanceOf function.
uint256 internal constant MAX_BALANCE_OF_RET_BYTES = 32;
/// @dev The address used to send calls for gas estimation.
/// You only need to use this address if the minimum gas limit specified by the user is not actually enough to execute the
/// given message and you're attempting to estimate the actual necessary gas limit
address public constant GAS_ESTIMATION_SENDER = address(0xC11C11C11C11C11C11C11C11C11C11C11C11C1);
/// @notice A collection of token price and gas price updates.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct PriceUpdates {
TokenPriceUpdate[] tokenPriceUpdates;
GasPriceUpdate[] gasPriceUpdates;
}
/// @notice Token price in USD.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct TokenPriceUpdate {
address sourceToken; // Source token.
uint224 usdPerToken; // 1e18 USD per 1e18 of the smallest token denomination.
}
/// @notice Gas price for a given chain in USD, its value may contain tightly packed fields.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct GasPriceUpdate {
uint64 destChainSelector; // Destination chain selector.
uint224 usdPerUnitGas; // 1e18 USD per smallest unit (e.g. wei) of destination chain gas.
}
/// @notice A timestamped uint224 value that can contain several tightly packed fields.
struct TimestampedPackedUint224 {
uint224 value; // ────╮ Value in uint224, packed.
uint32 timestamp; // ─╯ Timestamp of the most recent price update.
}
/// @dev Gas price is stored in 112-bit unsigned int. uint224 can pack 2 prices.
/// When packing L1 and L2 gas prices, L1 gas price is left-shifted to the higher-order bits.
/// Using uint8 type, which cannot be higher than other bit shift operands, to avoid shift operand type warning.
uint8 public constant GAS_PRICE_BITS = 112;
struct SourceTokenData {
// The source pool address, abi encoded. This value is trusted as it was obtained through the onRamp. It can be
// relied upon by the destination pool to validate the source pool.
bytes sourcePoolAddress;
// The address of the destination token, abi encoded in the case of EVM chains.
// This value is UNTRUSTED as any pool owner can return whatever value they want.
bytes destTokenAddress;
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint32 destGasAmount; // The amount of gas available for the releaseOrMint and balanceOf calls on the offRamp
}
/// @notice Report that is submitted by the execution DON at the execution phase, including chain selector data.
/// @dev RMN depends on this struct, if changing, please notify the RMN maintainers.
struct ExecutionReport {
uint64 sourceChainSelector; // Source chain selector for which the report is submitted.
Any2EVMRampMessage[] messages;
// Contains a bytes array for each message, each inner bytes array contains bytes per transferred token.
bytes[][] offchainTokenData;
bytes32[] proofs;
uint256 proofFlagBits;
}
/// @dev Any2EVMRampMessage struct has 10 fields, including 3 variable unnested arrays, sender, data and tokenAmounts.
/// Each variable array takes 1 more slot to store its length.
/// When abi encoded, excluding array contents, Any2EVMMessage takes up a fixed number of 13 slots, 32 bytes each.
/// Assume 1 slot for sender
/// For structs that contain arrays, 1 more slot is added to the front, reaching a total of 14.
/// The fixed bytes does not cover struct data (this is represented by MESSAGE_FIXED_BYTES_PER_TOKEN)
uint256 public constant MESSAGE_FIXED_BYTES = 32 * 15;
/// @dev Any2EVMTokensTransfer struct bytes length
/// 0x20
/// sourcePoolAddress_offset
/// destTokenAddress
/// destGasAmount
/// extraData_offset
/// amount
/// sourcePoolAddress_length
/// sourcePoolAddress_content // assume 1 slot
/// extraData_length // contents billed separately
uint256 public constant MESSAGE_FIXED_BYTES_PER_TOKEN = 32 * (4 + (3 + 2));
bytes32 internal constant ANY_2_EVM_MESSAGE_HASH = keccak256("Any2EVMMessageHashV1");
bytes32 internal constant EVM_2_ANY_MESSAGE_HASH = keccak256("EVM2AnyMessageHashV1");
/// @dev Used to hash messages for multi-lane family-agnostic OffRamps.
/// OnRamp hash(EVM2AnyMessage) != Any2EVMRampMessage.messageId.
/// OnRamp hash(EVM2AnyMessage) != OffRamp hash(Any2EVMRampMessage).
/// @param original OffRamp message to hash.
/// @param metadataHash Hash preimage to ensure global uniqueness.
/// @return hashedMessage hashed message as a keccak256.
function _hash(Any2EVMRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
return keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.header.messageId,
original.receiver,
original.header.sequenceNumber,
original.gasLimit,
original.header.nonce
)
),
keccak256(original.sender),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts))
)
);
}
function _hash(EVM2AnyRampMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
// Fixed-size message fields are included in nested hash to reduce stack pressure.
// This hashing scheme is also used by RMN. If changing it, please notify the RMN maintainers.
return keccak256(
abi.encode(
MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
metadataHash,
keccak256(
abi.encode(
original.sender,
original.header.sequenceNumber,
original.header.nonce,
original.feeToken,
original.feeTokenAmount
)
),
keccak256(original.receiver),
keccak256(original.data),
keccak256(abi.encode(original.tokenAmounts)),
keccak256(original.extraArgs)
)
);
}
/// @dev We disallow the first 1024 addresses to avoid calling into a range known for hosting precompiles. Calling
/// into precompiles probably won't cause any issues, but to be safe we can disallow this range. It is extremely
/// unlikely that anyone would ever be able to generate an address in this range. There is no official range of
/// precompiles, but EIP-7587 proposes to reserve the range 0x100 to 0x1ff. Our range is more conservative, even
/// though it might not be exhaustive for all chains, which is OK. We also disallow the zero address, which is a
/// common practice.
uint256 public constant PRECOMPILE_SPACE = 1024;
/// @notice This methods provides validation for parsing abi encoded addresses by ensuring the address is within the
/// EVM address space. If it isn't it will revert with an InvalidEVMAddress error, which we can catch and handle
/// more gracefully than a revert from abi.decode.
function _validateEVMAddress(
bytes memory encodedAddress
) internal pure {
if (encodedAddress.length != 32) revert InvalidEVMAddress(encodedAddress);
uint256 encodedAddressUint = abi.decode(encodedAddress, (uint256));
if (encodedAddressUint > type(uint160).max || encodedAddressUint < PRECOMPILE_SPACE) {
revert InvalidEVMAddress(encodedAddress);
}
}
function _validateSVMAddress(bytes memory encodedAddress, bool mustBeNonZero) internal pure {
if (encodedAddress.length != 32) revert InvalidSVMAddress(encodedAddress);
if (mustBeNonZero) {
if (abi.decode(encodedAddress, (bytes32)) == bytes32(0)) {
revert InvalidSVMAddress(encodedAddress);
}
}
}
/// @notice Enum listing the possible message execution states within the offRamp contract.
/// UNTOUCHED never executed.
/// IN_PROGRESS currently being executed, used a replay protection.
/// SUCCESS successfully executed. End state.
/// FAILURE unsuccessfully executed, manual execution is now enabled.
/// @dev RMN depends on this enum, if changing, please notify the RMN maintainers.
enum MessageExecutionState {
UNTOUCHED,
IN_PROGRESS,
SUCCESS,
FAILURE
}
/// @notice CCIP OCR plugin type, used to separate execution & commit transmissions and configs.
enum OCRPluginType {
Commit,
Execution
}
/// @notice Family-agnostic header for OnRamp & OffRamp messages.
/// The messageId is not expected to match hash(message), since it may originate from another ramp family.
struct RampMessageHeader {
bytes32 messageId; // Unique identifier for the message, generated with the source chain's encoding scheme (i.e. not necessarily abi.encoded).
uint64 sourceChainSelector; // ─╮ the chain selector of the source chain, note: not chainId.
uint64 destChainSelector; // │ the chain selector of the destination chain, note: not chainId.
uint64 sequenceNumber; // │ sequence number, not unique across lanes.
uint64 nonce; // ───────────────╯ nonce for this lane for this sender, not unique across senders/lanes.
}
struct EVM2AnyTokenTransfer {
// The source pool EVM address. This value is trusted as it was obtained through the onRamp. It can be relied
// upon by the destination pool to validate the source pool.
address sourcePoolAddress;
// The EVM address of the destination token.
// This value is UNTRUSTED as any pool owner can return whatever value they want.
bytes destTokenAddress;
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint256 amount; // Amount of tokens.
// Destination chain data used to execute the token transfer on the destination chain. For an EVM destination, it
// consists of the amount of gas available for the releaseOrMint and transfer calls made by the offRamp.
bytes destExecData;
}
struct Any2EVMTokenTransfer {
// The source pool EVM address encoded to bytes. This value is trusted as it is obtained through the onRamp. It can
// be relied upon by the destination pool to validate the source pool.
bytes sourcePoolAddress;
address destTokenAddress; // ─╮ Address of destination token
uint32 destGasAmount; // ─────╯ The amount of gas available for the releaseOrMint and transfer calls on the offRamp.
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes extraData;
uint256 amount; // Amount of tokens.
}
/// @notice Family-agnostic message routed to an OffRamp.
/// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage), hash(Any2EVMRampMessage) != messageId due to encoding
/// and parameter differences.
struct Any2EVMRampMessage {
RampMessageHeader header; // Message header.
bytes sender; // sender address on the source chain.
bytes data; // arbitrary data payload supplied by the message sender.
address receiver; // receiver address on the destination chain.
uint256 gasLimit; // user supplied maximum gas amount available for dest chain execution.
Any2EVMTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer.
}
/// @notice Family-agnostic message emitted from the OnRamp.
/// Note: hash(Any2EVMRampMessage) != hash(EVM2AnyRampMessage) due to encoding & parameter differences.
/// messageId = hash(EVM2AnyRampMessage) using the source EVM chain's encoding format.
struct EVM2AnyRampMessage {
RampMessageHeader header; // Message header.
address sender; // sender address on the source chain.
bytes data; // arbitrary data payload supplied by the message sender.
bytes receiver; // receiver address on the destination chain.
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 Juels.
EVM2AnyTokenTransfer[] tokenAmounts; // array of tokens and amounts to transfer.
}
// bytes4(keccak256("CCIP ChainFamilySelector EVM"));
bytes4 public constant CHAIN_FAMILY_SELECTOR_EVM = 0x2812d52c;
// bytes4(keccak256("CCIP ChainFamilySelector SVM"));
bytes4 public constant CHAIN_FAMILY_SELECTOR_SVM = 0x1e10bdc4;
/// @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.
// solhint-disable-next-line gas-struct-packing
struct MerkleRoot {
uint64 sourceChainSelector; // Remote source chain selector that the Merkle Root is scoped to
bytes onRampAddress; // Generic onRamp address, to support arbitrary sources; for EVM, use abi.encode
uint64 minSeqNr; // ─────────╮ Minimum sequence number, inclusive
uint64 maxSeqNr; // ─────────╯ Maximum sequence number, inclusive
bytes32 merkleRoot; // Merkle root covering the interval & source chain messages
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
library MerkleMultiProof {
/// @notice Leaf domain separator, should be used as the first 32 bytes of a leaf's preimage.
bytes32 internal constant LEAF_DOMAIN_SEPARATOR = 0x0000000000000000000000000000000000000000000000000000000000000000;
/// @notice Internal domain separator, should be used as the first 32 bytes of an internal node's preimage.
bytes32 internal constant INTERNAL_DOMAIN_SEPARATOR =
0x0000000000000000000000000000000000000000000000000000000000000001;
uint256 internal constant MAX_NUM_HASHES = 256;
error InvalidProof();
error LeavesCannotBeEmpty();
/// @notice Computes the root based on provided pre-hashed leaf nodes in leaves, internal nodes in proofs, and using
/// proofFlagBits' i-th bit to determine if an element of proofs or one of the previously computed leafs or internal
/// nodes will be used for the i-th hash.
/// @param leaves Should be pre-hashed and the first 32 bytes of a leaf's preimage should match LEAF_DOMAIN_SEPARATOR.
/// @param proofs Hashes to be used instead of a leaf hash when the proofFlagBits indicates a proof should be used.
/// @param proofFlagBits A single uint256 of which each bit indicates whether a leaf or a proof needs to be used in
/// a hash operation.
/// @dev the maximum number of hash operations it set to 256. Any input that would require more than 256 hashes to get
/// to a root will revert.
/// @dev For given input `leaves` = [a,b,c] `proofs` = [D] and `proofFlagBits` = 5
/// totalHashes = 3 + 1 - 1 = 3
/// ** round 1 **
/// proofFlagBits = (5 >> 0) & 1 = true
/// hashes[0] = hashPair(a, b)
/// (leafPos, hashPos, proofPos) = (2, 0, 0);
///
/// ** round 2 **
/// proofFlagBits = (5 >> 1) & 1 = false
/// hashes[1] = hashPair(D, c)
/// (leafPos, hashPos, proofPos) = (3, 0, 1);
///
/// ** round 3 **
/// proofFlagBits = (5 >> 2) & 1 = true
/// hashes[2] = hashPair(hashes[0], hashes[1])
/// (leafPos, hashPos, proofPos) = (3, 2, 1);
///
/// i = 3 and no longer < totalHashes. The algorithm is done
/// return hashes[totalHashes - 1] = hashes[2]; the last hash we computed.
// We mark this function as internal to force it to be inlined in contracts that use it, but semantically it is public.
function _merkleRoot(
bytes32[] memory leaves,
bytes32[] memory proofs,
uint256 proofFlagBits
) internal pure returns (bytes32) {
unchecked {
uint256 leavesLen = leaves.length;
uint256 proofsLen = proofs.length;
if (leavesLen == 0) revert LeavesCannotBeEmpty();
if (!(leavesLen <= MAX_NUM_HASHES + 1 && proofsLen <= MAX_NUM_HASHES + 1)) revert InvalidProof();
uint256 totalHashes = leavesLen + proofsLen - 1;
if (!(totalHashes <= MAX_NUM_HASHES)) revert InvalidProof();
if (totalHashes == 0) {
return leaves[0];
}
bytes32[] memory hashes = new bytes32[](totalHashes);
(uint256 leafPos, uint256 hashPos, uint256 proofPos) = (0, 0, 0);
for (uint256 i = 0; i < totalHashes; ++i) {
// Checks if the bit flag signals the use of a supplied proof or a leaf/previous hash.
bytes32 a;
if (proofFlagBits & (1 << i) == (1 << i)) {
// Use a leaf or a previously computed hash.
if (leafPos < leavesLen) {
a = leaves[leafPos++];
} else {
a = hashes[hashPos++];
}
} else {
// Use a supplied proof.
a = proofs[proofPos++];
}
// The second part of the hashed pair is never a proof as hashing two proofs would result in a
// hash that can already be computed offchain.
bytes32 b;
if (leafPos < leavesLen) {
b = leaves[leafPos++];
} else {
b = hashes[hashPos++];
}
if (!(hashPos <= i)) revert InvalidProof();
hashes[i] = _hashPair(a, b);
}
if (!(hashPos == totalHashes - 1 && leafPos == leavesLen && proofPos == proofsLen)) revert InvalidProof();
// Return the last hash.
return hashes[totalHashes - 1];
}
}
/// @notice Hashes two bytes32 objects in their given order, prepended by the INTERNAL_DOMAIN_SEPARATOR.
function _hashInternalNode(bytes32 left, bytes32 right) private pure returns (bytes32 hash) {
return keccak256(abi.encode(INTERNAL_DOMAIN_SEPARATOR, left, right));
}
/// @notice Hashes two bytes32 objects. The order is taken into account, using the lower value first.
function _hashPair(bytes32 a, bytes32 b) private pure returns (bytes32) {
return a < b ? _hashInternalNode(a, b) : _hashInternalNode(b, a);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
/// @notice This library contains various token pool functions to aid constructing the return data.
library Pool {
// The tag used to signal support for the pool v1 standard.
// bytes4(keccak256("CCIP_POOL_V1"))
bytes4 public constant CCIP_POOL_V1 = 0xaff2afbf;
// The number of bytes in the return data for a pool v1 releaseOrMint call.
// This should match the size of the ReleaseOrMintOutV1 struct.
uint16 public constant CCIP_POOL_V1_RET_BYTES = 32;
// The default max number of bytes in the return data for a pool v1 lockOrBurn call.
// This data can be used to send information to the destination chain token pool. Can be overwritten
// in the TokenTransferFeeConfig.destBytesOverhead if more data is required.
uint32 public constant CCIP_LOCK_OR_BURN_V1_RET_BYTES = 32;
struct LockOrBurnInV1 {
bytes receiver; // The recipient of the tokens on the destination chain, abi encoded.
uint64 remoteChainSelector; // ─╮ The chain ID of the destination chain.
address originalSender; // ─────╯ The original sender of the tx on the source chain.
uint256 amount; // The amount of tokens to lock or burn, denominated in the source token's decimals.
address localToken; // The address on this chain of the token to lock or burn.
}
struct LockOrBurnOutV1 {
// The address of the destination token, abi encoded in the case of EVM chains.
// This value is UNTRUSTED as any pool owner can return whatever value they want.
bytes destTokenAddress;
// Optional pool data to be transferred to the destination chain. Be default this is capped at
// CCIP_LOCK_OR_BURN_V1_RET_BYTES bytes. If more data is required, the TokenTransferFeeConfig.destBytesOverhead
// has to be set for the specific token.
bytes destPoolData;
}
struct ReleaseOrMintInV1 {
bytes originalSender; // The original sender of the tx on the source chain.
uint64 remoteChainSelector; // ─╮ The chain ID of the source chain.
address receiver; // ───────────╯ The recipient of the tokens on the destination chain.
uint256 amount; // The amount of tokens to release or mint, denominated in the source token's decimals.
address localToken; // The address on this chain of the token to release or mint.
/// @dev WARNING: sourcePoolAddress should be checked prior to any processing of funds. Make sure it matches the
/// expected pool address for the given remoteChainSelector.
bytes sourcePoolAddress; // The address of the source pool, abi encoded in the case of EVM chains.
bytes sourcePoolData; // The data received from the source pool to process the release or mint.
/// @dev WARNING: offchainTokenData is untrusted data.
bytes offchainTokenData; // The offchain data to process the release or mint.
}
struct ReleaseOrMintOutV1 {
// The number of tokens released or minted on the destination chain, denominated in the local token's decimals.
// This value is expected to be equal to the ReleaseOrMintInV1.amount in the case where the source and destination
// chain have the same number of decimals.
uint256 destinationAmount;
}
}// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.4;
import {Ownable2StepMsgSender} from "../../shared/access/Ownable2StepMsgSender.sol";
import {ITypeAndVersion} from "../../shared/interfaces/ITypeAndVersion.sol";
import {Internal} from "../libraries/Internal.sol";
/// @notice Onchain verification of reports from the offchain reporting protocol with multiple OCR plugin support.
abstract contract MultiOCR3Base is ITypeAndVersion, Ownable2StepMsgSender {
// Maximum number of oracles the offchain reporting protocol is designed for
uint256 internal constant MAX_NUM_ORACLES = 256;
/// @notice Triggers a new run of the offchain reporting protocol.
/// @param ocrPluginType OCR plugin type for which the config was set.
/// @param configDigest configDigest of this configuration.
/// @param signers ith element is address ith oracle uses to sign a report.
/// @param transmitters ith element is address ith oracle uses to transmit a report via the transmit method.
/// @param F maximum number of faulty/dishonest oracles the protocol can tolerate while still working correctly.
event ConfigSet(uint8 ocrPluginType, bytes32 configDigest, address[] signers, address[] transmitters, uint8 F);
/// @notice Optionally emitted to indicate the latest configDigest and sequence number
/// for which a report was successfully transmitted. Alternatively, the contract may
/// use latestConfigDigestAndEpoch with scanLogs set to false.
event Transmitted(uint8 indexed ocrPluginType, bytes32 configDigest, uint64 sequenceNumber);
enum InvalidConfigErrorType {
F_MUST_BE_POSITIVE,
TOO_MANY_TRANSMITTERS,
TOO_MANY_SIGNERS,
F_TOO_HIGH,
REPEATED_ORACLE_ADDRESS,
NO_TRANSMITTERS
}
error InvalidConfig(InvalidConfigErrorType errorType);
error WrongMessageLength(uint256 expected, uint256 actual);
error ConfigDigestMismatch(bytes32 expected, bytes32 actual);
error ForkedChain(uint256 expected, uint256 actual);
error WrongNumberOfSignatures();
error SignaturesOutOfRegistration();
error UnauthorizedTransmitter();
error UnauthorizedSigner();
error NonUniqueSignatures();
error OracleCannotBeZeroAddress();
error StaticConfigCannotBeChanged(uint8 ocrPluginType);
error InsufficientGasToCompleteTx(bytes4 err);
/// @dev Packing these fields used on the hot path in a ConfigInfo variable reduces the retrieval of all
/// of them to a minimum number of SLOADs.
struct ConfigInfo {
bytes32 configDigest;
uint8 F; // ─────────────────────────────╮ maximum number of faulty/dishonest oracles the system can tolerate.
uint8 n; // │ number of configured signers.
bool isSignatureVerificationEnabled; // ─╯ if true, requires signers and verifies signatures on transmission.
}
/// @notice Used for s_oracles[a].role, where a is an address, to track the purpose of the address, or to indicate
/// that the address is unset.
enum Role {
// No oracle role has been set for the address `a`
Unset,
// Signing address for the s_oracles[a].index'th oracle. I.e., report signatures from this oracle should ecrecover
// back to address `a`.
Signer,
// Transmission address for the s_oracles[a].index'th oracle. I.e., if `a` report is received by
// OCR2Aggregator.transmit in which msg.sender is a, it is attributed to the s_oracles[a].index'th oracle.
Transmitter
}
struct Oracle {
uint8 index; // ─╮ Index of oracle in s_signers/s_transmitters.
Role role; // ───╯ Role of the address which mapped to this struct.
}
/// @notice OCR configuration for a single OCR plugin within a DON.
struct OCRConfig {
ConfigInfo configInfo; // latest OCR config.
// NOTE: len(signers) can be different from len(transmitters). There is no index relationship between the two arrays.
address[] signers; // addresses oracles use to sign the reports.
address[] transmitters; // addresses oracles use to transmit the reports.
}
/// @notice Args to update an OCR Config.
struct OCRConfigArgs {
bytes32 configDigest; // The new config digest.
uint8 ocrPluginType; // ─────────────────╮ OCR plugin type to update config for.
uint8 F; // │ Maximum number of faulty/dishonest oracles.
bool isSignatureVerificationEnabled; // ─╯ If true, requires signers and verifies signatures on transmission.
address[] signers; // signing address of each oracle.
address[] transmitters; // the address the oracle sends transactions from.
}
/// @notice mapping of OCR plugin type -> DON config.
mapping(uint8 ocrPluginType => OCRConfig config) internal s_ocrConfigs;
/// @notice OCR plugin type => signer OR transmitter address mapping.
mapping(uint8 ocrPluginType => mapping(address signerOrTransmiter => Oracle oracle)) internal s_oracles;
// Constant-length components of the msg.data sent to transmit.
// See the "If we wanted to call sam" example on for example reasoning.
// https://solidity.readthedocs.io/en/v0.7.2/abi-spec.html
/// @notice Constant length component for transmit functions with no signatures.
/// The signatures are expected to match transmitPlugin(reportContext, report).
uint16 private constant TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT_NO_SIGNATURES = 4 // function selector.
+ 2 * 32 // 2 words containing reportContext.
+ 32 // word containing start location of abiencoded report value.
+ 32; // word containing length of report.
/// @notice Extra constant length component for transmit functions with signatures (relative to no signatures).
/// The signatures are expected to match transmitPlugin(reportContext, report, rs, ss, rawVs).
uint16 private constant TRANSMIT_MSGDATA_EXTRA_CONSTANT_LENGTH_COMPONENT_FOR_SIGNATURES = 32 // word containing location start of abiencoded rs value.
+ 32 // word containing start location of abiencoded ss value.
+ 32 // rawVs value.
+ 32 // word containing length rs.
+ 32; // word containing length of ss.
uint256 internal immutable i_chainID;
constructor() {
i_chainID = block.chainid;
}
/// @notice Sets offchain reporting protocol configuration incl. participating oracles.
/// NOTE: The OCR3 config must be sanity-checked against the home-chain registry configuration, to ensure home-chain
/// and remote-chain parity!
/// @param ocrConfigArgs OCR config update args.
/// @dev precondition number of transmitters should match the expected F/fChain relationship.
/// For transmitters, the function only validates that len(transmitters) > 0 && len(transmitters) <= MAX_NUM_ORACLES
/// && len(transmitters) <= len(signers) [if sig verification is enabled].
function setOCR3Configs(
OCRConfigArgs[] memory ocrConfigArgs
) external onlyOwner {
for (uint256 i; i < ocrConfigArgs.length; ++i) {
_setOCR3Config(ocrConfigArgs[i]);
}
}
/// @notice Sets offchain reporting protocol configuration incl. participating oracles for a single OCR plugin type.
/// @param ocrConfigArgs OCR config update args.
function _setOCR3Config(
OCRConfigArgs memory ocrConfigArgs
) internal {
if (ocrConfigArgs.F == 0) revert InvalidConfig(InvalidConfigErrorType.F_MUST_BE_POSITIVE);
uint8 ocrPluginType = ocrConfigArgs.ocrPluginType;
OCRConfig storage ocrConfig = s_ocrConfigs[ocrPluginType];
ConfigInfo storage configInfo = ocrConfig.configInfo;
// If F is 0, then the config is not yet set.
if (configInfo.F == 0) {
configInfo.isSignatureVerificationEnabled = ocrConfigArgs.isSignatureVerificationEnabled;
} else {
if (configInfo.isSignatureVerificationEnabled != ocrConfigArgs.isSignatureVerificationEnabled) {
revert StaticConfigCannotBeChanged(ocrPluginType);
}
}
address[] memory transmitters = ocrConfigArgs.transmitters;
if (transmitters.length > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_TRANSMITTERS);
if (transmitters.length == 0) revert InvalidConfig(InvalidConfigErrorType.NO_TRANSMITTERS);
_clearOracleRoles(ocrPluginType, ocrConfig.transmitters);
if (ocrConfigArgs.isSignatureVerificationEnabled) {
_clearOracleRoles(ocrPluginType, ocrConfig.signers);
address[] memory signers = ocrConfigArgs.signers;
if (signers.length > MAX_NUM_ORACLES) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_SIGNERS);
if (signers.length <= 3 * ocrConfigArgs.F) revert InvalidConfig(InvalidConfigErrorType.F_TOO_HIGH);
// NOTE: Transmitters cannot exceed signers. Transmitters do not have to be >= 3F + 1 because they can
// match >= 3fChain + 1, where fChain <= F. fChain is not represented in MultiOCR3Base - so we skip this check.
if (signers.length < transmitters.length) revert InvalidConfig(InvalidConfigErrorType.TOO_MANY_TRANSMITTERS);
configInfo.n = uint8(signers.length);
ocrConfig.signers = signers;
_assignOracleRoles(ocrPluginType, signers, Role.Signer);
}
_assignOracleRoles(ocrPluginType, transmitters, Role.Transmitter);
ocrConfig.transmitters = transmitters;
configInfo.F = ocrConfigArgs.F;
configInfo.configDigest = ocrConfigArgs.configDigest;
emit ConfigSet(
ocrPluginType, ocrConfigArgs.configDigest, ocrConfig.signers, ocrConfigArgs.transmitters, ocrConfigArgs.F
);
_afterOCR3ConfigSet(ocrPluginType);
}
/// @notice Hook that is called after a plugin's OCR3 config changes.
/// @param ocrPluginType Plugin type for which the config changed.
function _afterOCR3ConfigSet(
uint8 ocrPluginType
) internal virtual;
/// @notice Clears oracle roles for the provided oracle addresses.
/// @param ocrPluginType OCR plugin type to clear roles for.
/// @param oracleAddresses Oracle addresses to clear roles for.
function _clearOracleRoles(uint8 ocrPluginType, address[] memory oracleAddresses) internal {
for (uint256 i = 0; i < oracleAddresses.length; ++i) {
delete s_oracles[ocrPluginType][oracleAddresses[i]];
}
}
/// @notice Assigns oracles roles for the provided oracle addresses with uniqueness verification.
/// @param ocrPluginType OCR plugin type to assign roles for.
/// @param oracleAddresses Oracle addresses to assign roles to.
/// @param role Role to assign.
function _assignOracleRoles(uint8 ocrPluginType, address[] memory oracleAddresses, Role role) internal {
for (uint256 i = 0; i < oracleAddresses.length; ++i) {
address oracle = oracleAddresses[i];
if (s_oracles[ocrPluginType][oracle].role != Role.Unset) {
revert InvalidConfig(InvalidConfigErrorType.REPEATED_ORACLE_ADDRESS);
}
if (oracle == address(0)) revert OracleCannotBeZeroAddress();
s_oracles[ocrPluginType][oracle] = Oracle(uint8(i), role);
}
}
/// @notice _transmit is called to post a new report to the contract. The function should be called after the per-DON
/// reporting logic is completed.
/// @param ocrPluginType OCR plugin type to transmit report for
/// @param report serialized report, which the signatures are signing.
/// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries.
/// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries.
/// @param rawVs ith element is the the V component of the ith signature.
function _transmit(
uint8 ocrPluginType,
// NOTE: If these parameters are changed, expectedMsgDataLength and/or TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT
// need to be changed accordingly.
bytes32[2] calldata reportContext,
bytes calldata report,
bytes32[] memory rs,
bytes32[] memory ss,
bytes32 rawVs
) internal {
// reportContext consists of:
// reportContext[0]: ConfigDigest.
// reportContext[1]: 24 byte padding, 8 byte sequence number.
ConfigInfo memory configInfo = s_ocrConfigs[ocrPluginType].configInfo;
bytes32 configDigest = reportContext[0];
// Scoping this reduces stack pressure and gas usage.
{
// one byte per entry in _report
uint256 expectedDataLength = uint256(TRANSMIT_MSGDATA_CONSTANT_LENGTH_COMPONENT_NO_SIGNATURES) + report.length;
if (configInfo.isSignatureVerificationEnabled) {
// 32 bytes per entry in _rs, _ss
expectedDataLength +=
TRANSMIT_MSGDATA_EXTRA_CONSTANT_LENGTH_COMPONENT_FOR_SIGNATURES + rs.length * 32 + ss.length * 32;
}
if (msg.data.length != expectedDataLength) revert WrongMessageLength(expectedDataLength, msg.data.length);
}
if (configInfo.configDigest != configDigest) {
revert ConfigDigestMismatch(configInfo.configDigest, configDigest);
}
// If the cached chainID at time of deployment doesn't match the current chainID, we reject all signed reports.
// This avoids a (rare) scenario where chain A forks into chain A and A', A' still has configDigest calculated
// from chain A and so OCR reports will be valid on both forks.
_whenChainNotForked();
// Scoping this reduces stack pressure and gas usage.
{
Oracle memory transmitter = s_oracles[ocrPluginType][msg.sender];
// Check that sender is authorized to report.
if (
!(
transmitter.role == Role.Transmitter
&& msg.sender == s_ocrConfigs[ocrPluginType].transmitters[transmitter.index]
)
) {
if (msg.sender != Internal.GAS_ESTIMATION_SENDER) {
revert UnauthorizedTransmitter();
}
}
}
if (configInfo.isSignatureVerificationEnabled) {
// Scoping to reduce stack pressure.
{
if (rs.length != configInfo.F + 1) revert WrongNumberOfSignatures();
if (rs.length != ss.length) revert SignaturesOutOfRegistration();
}
bytes32 h = keccak256(abi.encodePacked(keccak256(report), reportContext));
_verifySignatures(ocrPluginType, h, rs, ss, rawVs);
}
emit Transmitted(ocrPluginType, configDigest, uint64(uint256(reportContext[1])));
}
/// @notice Verifies the signatures of a hashed report value for one OCR plugin type.
/// @param ocrPluginType OCR plugin type to transmit report for.
/// @param hashedReport hashed encoded packing of report + reportContext.
/// @param rs ith element is the R components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries.
/// @param ss ith element is the S components of the ith signature on report. Must have at most MAX_NUM_ORACLES entries.
/// @param rawVs ith element is the the V component of the ith signature.
function _verifySignatures(
uint8 ocrPluginType,
bytes32 hashedReport,
bytes32[] memory rs,
bytes32[] memory ss,
bytes32 rawVs
) internal view {
// Verify signatures attached to report. Using a uint256 means we can only verify up to 256 oracles.
uint256 signed = 0;
uint256 numberOfSignatures = rs.length;
for (uint256 i; i < numberOfSignatures; ++i) {
// Safe from ECDSA malleability here since we check for duplicate signers.
address signer = ecrecover(hashedReport, uint8(rawVs[i]) + 27, rs[i], ss[i]);
// Since we disallow address(0) as a valid signer address, it can never have a signer role.
Oracle memory oracle = s_oracles[ocrPluginType][signer];
if (oracle.role != Role.Signer) revert UnauthorizedSigner();
if (signed & (0x1 << oracle.index) != 0) revert NonUniqueSignatures();
signed |= 0x1 << oracle.index;
}
}
/// @notice Validates that the chain ID has not diverged after deployment. Reverts if the chain IDs do not match.
function _whenChainNotForked() internal view {
if (i_chainID != block.chainid) revert ForkedChain(i_chainID, block.chainid);
}
/// @notice Information about current offchain reporting protocol configuration.
/// @param ocrPluginType OCR plugin type to return config details for.
/// @return ocrConfig OCR config for the plugin type.
function latestConfigDetails(
uint8 ocrPluginType
) external view returns (OCRConfig memory ocrConfig) {
return s_ocrConfigs[ocrPluginType];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC20 standard as defined in the EIP.
*/
interface IERC20 {
/**
* @dev Emitted when `value` tokens are moved from one account (`from`) to
* another (`to`).
*
* Note that `value` may be zero.
*/
event Transfer(address indexed from, address indexed to, uint256 value);
/**
* @dev Emitted when the allowance of a `spender` for an `owner` is set by
* a call to {approve}. `value` is the new allowance.
*/
event Approval(address indexed owner, address indexed spender, uint256 value);
/**
* @dev Returns the value of tokens in existence.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns the value of tokens owned by `account`.
*/
function balanceOf(address account) external view returns (uint256);
/**
* @dev Moves a `value` amount of tokens from the caller's account to `to`.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transfer(address to, uint256 value) external returns (bool);
/**
* @dev Returns the remaining number of tokens that `spender` will be
* allowed to spend on behalf of `owner` through {transferFrom}. This is
* zero by default.
*
* This value changes when {approve} or {transferFrom} are called.
*/
function allowance(address owner, address spender) external view returns (uint256);
/**
* @dev Sets a `value` amount of tokens as the allowance of `spender` over the
* caller's tokens.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* IMPORTANT: Beware that changing an allowance with this method brings the risk
* that someone may use both the old and the new allowance by unfortunate
* transaction ordering. One possible solution to mitigate this race
* condition is to first reduce the spender's allowance to 0 and set the
* desired value afterwards:
* https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
*
* Emits an {Approval} event.
*/
function approve(address spender, uint256 value) external returns (bool);
/**
* @dev Moves a `value` amount of tokens from `from` to `to` using the
* allowance mechanism. `value` is then deducted from the caller's
* allowance.
*
* Returns a boolean value indicating whether the operation succeeded.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 value) external returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.
pragma solidity ^0.8.20;
/**
* @dev Library for managing
* https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
* types.
*
* Sets have the following properties:
*
* - Elements are added, removed, and checked for existence in constant time
* (O(1)).
* - Elements are enumerated in O(n). No guarantees are made on the ordering.
*
* ```solidity
* contract Example {
* // Add the library methods
* using EnumerableSet for EnumerableSet.AddressSet;
*
* // Declare a set state variable
* EnumerableSet.AddressSet private mySet;
* }
* ```
*
* As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
* and `uint256` (`UintSet`) are supported.
*
* [WARNING]
* ====
* Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
* unusable.
* See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
*
* In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
* array of EnumerableSet.
* ====
*/
library EnumerableSet {
// To implement this library for multiple types with as little code
// repetition as possible, we write it in terms of a generic Set type with
// bytes32 values.
// The Set implementation uses private functions, and user-facing
// implementations (such as AddressSet) are just wrappers around the
// underlying Set.
// This means that we can only create new EnumerableSets for types that fit
// in bytes32.
struct Set {
// Storage of set values
bytes32[] _values;
// Position is the index of the value in the `values` array plus 1.
// Position 0 is used to mean a value is not in the set.
mapping(bytes32 value => uint256) _positions;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function _add(Set storage set, bytes32 value) private returns (bool) {
if (!_contains(set, value)) {
set._values.push(value);
// The value is stored at length-1, but we add 1 to all indexes
// and use 0 as a sentinel value
set._positions[value] = set._values.length;
return true;
} else {
return false;
}
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function _remove(Set storage set, bytes32 value) private returns (bool) {
// We cache the value's position to prevent multiple reads from the same storage slot
uint256 position = set._positions[value];
if (position != 0) {
// Equivalent to contains(set, value)
// To delete an element from the _values array in O(1), we swap the element to delete with the last one in
// the array, and then remove the last element (sometimes called as 'swap and pop').
// This modifies the order of the array, as noted in {at}.
uint256 valueIndex = position - 1;
uint256 lastIndex = set._values.length - 1;
if (valueIndex != lastIndex) {
bytes32 lastValue = set._values[lastIndex];
// Move the lastValue to the index where the value to delete is
set._values[valueIndex] = lastValue;
// Update the tracked position of the lastValue (that was just moved)
set._positions[lastValue] = position;
}
// Delete the slot where the moved value was stored
set._values.pop();
// Delete the tracked position for the deleted slot
delete set._positions[value];
return true;
} else {
return false;
}
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function _contains(Set storage set, bytes32 value) private view returns (bool) {
return set._positions[value] != 0;
}
/**
* @dev Returns the number of values on the set. O(1).
*/
function _length(Set storage set) private view returns (uint256) {
return set._values.length;
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function _at(Set storage set, uint256 index) private view returns (bytes32) {
return set._values[index];
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function _values(Set storage set) private view returns (bytes32[] memory) {
return set._values;
}
// Bytes32Set
struct Bytes32Set {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _add(set._inner, value);
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
return _remove(set._inner, value);
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
return _contains(set._inner, value);
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(Bytes32Set storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
return _at(set._inner, index);
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
bytes32[] memory store = _values(set._inner);
bytes32[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// AddressSet
struct AddressSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(AddressSet storage set, address value) internal returns (bool) {
return _add(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(AddressSet storage set, address value) internal returns (bool) {
return _remove(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(AddressSet storage set, address value) internal view returns (bool) {
return _contains(set._inner, bytes32(uint256(uint160(value))));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(AddressSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(AddressSet storage set, uint256 index) internal view returns (address) {
return address(uint160(uint256(_at(set._inner, index))));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(AddressSet storage set) internal view returns (address[] memory) {
bytes32[] memory store = _values(set._inner);
address[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
// UintSet
struct UintSet {
Set _inner;
}
/**
* @dev Add a value to a set. O(1).
*
* Returns true if the value was added to the set, that is if it was not
* already present.
*/
function add(UintSet storage set, uint256 value) internal returns (bool) {
return _add(set._inner, bytes32(value));
}
/**
* @dev Removes a value from a set. O(1).
*
* Returns true if the value was removed from the set, that is if it was
* present.
*/
function remove(UintSet storage set, uint256 value) internal returns (bool) {
return _remove(set._inner, bytes32(value));
}
/**
* @dev Returns true if the value is in the set. O(1).
*/
function contains(UintSet storage set, uint256 value) internal view returns (bool) {
return _contains(set._inner, bytes32(value));
}
/**
* @dev Returns the number of values in the set. O(1).
*/
function length(UintSet storage set) internal view returns (uint256) {
return _length(set._inner);
}
/**
* @dev Returns the value stored at position `index` in the set. O(1).
*
* Note that there are no guarantees on the ordering of values inside the
* array, and it may change when more values are added or removed.
*
* Requirements:
*
* - `index` must be strictly less than {length}.
*/
function at(UintSet storage set, uint256 index) internal view returns (uint256) {
return uint256(_at(set._inner, index));
}
/**
* @dev Return the entire set in an array
*
* WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
* to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
* this function has an unbounded cost, and using it as part of a state-changing function may render the function
* uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
*/
function values(UintSet storage set) internal view returns (uint256[] memory) {
bytes32[] memory store = _values(set._inner);
uint256[] memory result;
/// @solidity memory-safe-assembly
assembly {
result := store
}
return result;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Internal} from "../libraries/Internal.sol";
interface IPriceRegistry {
/// @notice Update the price for given tokens and gas prices for given chains.
/// @param priceUpdates The price updates to apply.
function updatePrices(
Internal.PriceUpdates memory priceUpdates
) external;
/// @notice Get the `tokenPrice` for a given token.
/// @param token The token to get the price for.
/// @return tokenPrice The tokenPrice for the given token.
function getTokenPrice(
address token
) external view returns (Internal.TimestampedPackedUint224 memory);
/// @notice Get the `tokenPrice` for a given token, checks if the price is valid.
/// @param token The token to get the price for.
/// @return tokenPrice The tokenPrice for the given token if it exists and is valid.
function getValidatedTokenPrice(
address token
) external view returns (uint224);
/// @notice Get the `tokenPrice` for an array of tokens.
/// @param tokens The tokens to get prices for.
/// @return tokenPrices The tokenPrices for the given tokens.
function getTokenPrices(
address[] calldata tokens
) external view returns (Internal.TimestampedPackedUint224[] memory);
/// @notice Get an encoded `gasPrice` for a given destination chain ID.
/// The 224-bit result encodes necessary gas price components.
/// On L1 chains like Ethereum or Avax, the only component is the gas price.
/// On Optimistic Rollups, there are two components - the L2 gas price, and L1 base fee for data availability.
/// On future chains, there could be more or differing price components.
/// PriceRegistry does not contain chain-specific logic to parse destination chain price components.
/// @param destChainSelector The destination chain to get the price for.
/// @return gasPrice The encoded gasPrice for the given destination chain ID.
function getDestinationChainGasPrice(
uint64 destChainSelector
) external view returns (Internal.TimestampedPackedUint224 memory);
/// @notice Gets the fee token price and the gas price, both denominated in dollars.
/// @param token The source token to get the price for.
/// @param destChainSelector The destination chain to get the gas price for.
/// @return tokenPrice The price of the feeToken in 1e18 dollars per base unit.
/// @return gasPrice The price of gas in 1e18 dollars per base unit.
function getTokenAndGasPrices(
address token,
uint64 destChainSelector
) external view returns (uint224 tokenPrice, uint224 gasPrice);
/// @notice Convert a given token amount to target token amount.
/// @param fromToken The given token address.
/// @param fromTokenAmount The given token amount.
/// @param toToken The target token address.
/// @return toTokenAmount The target token amount.
function convertTokenAmount(
address fromToken,
uint256 fromTokenAmount,
address toToken
) external view returns (uint256 toTokenAmount);
/// @notice Get the list of fee tokens.
/// @return feeTokens The tokens set as fee tokens.
function getFeeTokens() external view returns (address[] memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Ownable2Step} from "./Ownable2Step.sol";
/// @notice Sets the msg.sender to be the owner of the contract and does not set a pending owner.
contract Ownable2StepMsgSender is Ownable2Step {
constructor() Ownable2Step(msg.sender, address(0)) {}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {IOwnable} from "../interfaces/IOwnable.sol";
/// @notice A minimal contract that implements 2-step ownership transfer and nothing more. It's made to be minimal
/// to reduce the impact of the bytecode size on any contract that inherits from it.
contract Ownable2Step is IOwnable {
/// @notice The pending owner is the address to which ownership may be transferred.
address private s_pendingOwner;
/// @notice The owner is the current owner of the contract.
/// @dev The owner is the second storage variable so any implementing contract could pack other state with it
/// instead of the much less used s_pendingOwner.
address private s_owner;
error OwnerCannotBeZero();
error MustBeProposedOwner();
error CannotTransferToSelf();
error OnlyCallableByOwner();
event OwnershipTransferRequested(address indexed from, address indexed to);
event OwnershipTransferred(address indexed from, address indexed to);
constructor(address newOwner, address pendingOwner) {
if (newOwner == address(0)) {
revert OwnerCannotBeZero();
}
s_owner = newOwner;
if (pendingOwner != address(0)) {
_transferOwnership(pendingOwner);
}
}
/// @notice Get the current owner
function owner() public view override returns (address) {
return s_owner;
}
/// @notice Allows an owner to begin transferring ownership to a new address. The new owner needs to call
/// `acceptOwnership` to accept the transfer before any permissions are changed.
/// @param to The address to which ownership will be transferred.
function transferOwnership(address to) public override onlyOwner {
_transferOwnership(to);
}
/// @notice validate, transfer ownership, and emit relevant events
/// @param to The address to which ownership will be transferred.
function _transferOwnership(address to) private {
if (to == msg.sender) {
revert CannotTransferToSelf();
}
s_pendingOwner = to;
emit OwnershipTransferRequested(s_owner, to);
}
/// @notice Allows an ownership transfer to be completed by the recipient.
function acceptOwnership() external override {
if (msg.sender != s_pendingOwner) {
revert MustBeProposedOwner();
}
address oldOwner = s_owner;
s_owner = msg.sender;
s_pendingOwner = address(0);
emit OwnershipTransferred(oldOwner, msg.sender);
}
/// @notice validate access
function _validateOwnership() internal view {
if (msg.sender != s_owner) {
revert OnlyCallableByOwner();
}
}
/// @notice Reverts if called by anyone other than the contract owner.
modifier onlyOwner() {
_validateOwnership();
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;
interface IOwnable {
function owner() external returns (address);
function transferOwnership(address recipient) external;
function acceptOwnership() external;
}{
"remappings": [
"forge-std/=src/v0.8/vendor/forge-std/src/",
"@openzeppelin/=node_modules/@openzeppelin/",
"@arbitrum/=node_modules/@arbitrum/",
"hardhat/=node_modules/hardhat/",
"@eth-optimism/=node_modules/@eth-optimism/",
"@scroll-tech/=node_modules/@scroll-tech/",
"@zksync/=node_modules/@zksync/"
],
"optimizer": {
"enabled": true,
"runs": 800
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "none",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris",
"viaIR": true,
"libraries": {}
}Contract ABI
API[{"inputs":[{"components":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint16","name":"gasForCallExactCheck","type":"uint16"},{"internalType":"contract IRMNRemote","name":"rmnRemote","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"},{"internalType":"address","name":"nonceManager","type":"address"}],"internalType":"struct OffRamp.StaticConfig","name":"staticConfig","type":"tuple"},{"components":[{"internalType":"address","name":"feeQuoter","type":"address"},{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"messageInterceptor","type":"address"}],"internalType":"struct OffRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"},{"components":[{"internalType":"contract IRouter","name":"router","type":"address"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isRMNVerificationDisabled","type":"bool"},{"internalType":"bytes","name":"onRamp","type":"bytes"}],"internalType":"struct OffRamp.SourceChainConfigArgs[]","name":"sourceChainConfigs","type":"tuple[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CanOnlySelfCall","type":"error"},{"inputs":[],"name":"CannotTransferToSelf","type":"error"},{"inputs":[{"internalType":"bytes","name":"reportOnRamp","type":"bytes"},{"internalType":"bytes","name":"configOnRamp","type":"bytes"}],"name":"CommitOnRampMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"expected","type":"bytes32"},{"internalType":"bytes32","name":"actual","type":"bytes32"}],"name":"ConfigDigestMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"CursedByRMN","type":"error"},{"inputs":[],"name":"EmptyBatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"EmptyReport","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"bytes","name":"err","type":"bytes"}],"name":"ExecutionError","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"ForkedChain","type":"error"},{"inputs":[{"internalType":"bytes4","name":"err","type":"bytes4"}],"name":"InsufficientGasToCompleteTx","type":"error"},{"inputs":[{"internalType":"enum MultiOCR3Base.InvalidConfigErrorType","name":"errorType","type":"uint8"}],"name":"InvalidConfig","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"got","type":"uint256"}],"name":"InvalidDataLength","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"min","type":"uint64"},{"internalType":"uint64","name":"max","type":"uint64"}],"name":"InvalidInterval","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint256","name":"newLimit","type":"uint256"}],"name":"InvalidManualExecutionGasLimit","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint256","name":"tokenIndex","type":"uint256"},{"internalType":"uint256","name":"oldLimit","type":"uint256"},{"internalType":"uint256","name":"tokenGasOverride","type":"uint256"}],"name":"InvalidManualExecutionTokenGasOverride","type":"error"},{"inputs":[{"internalType":"uint64","name":"messageDestChainSelector","type":"uint64"}],"name":"InvalidMessageDestChainSelector","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"enum Internal.MessageExecutionState","name":"newState","type":"uint8"}],"name":"InvalidNewState","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"InvalidOnRampUpdate","type":"error"},{"inputs":[],"name":"InvalidProof","type":"error"},{"inputs":[],"name":"InvalidRoot","type":"error"},{"inputs":[],"name":"LeavesCannotBeEmpty","type":"error"},{"inputs":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"ManualExecutionGasAmountCountMismatch","type":"error"},{"inputs":[],"name":"ManualExecutionGasLimitMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"ManualExecutionNotYetEnabled","type":"error"},{"inputs":[{"internalType":"bytes","name":"errorReason","type":"bytes"}],"name":"MessageValidationError","type":"error"},{"inputs":[],"name":"MustBeProposedOwner","type":"error"},{"inputs":[],"name":"NonUniqueSignatures","type":"error"},{"inputs":[{"internalType":"address","name":"notPool","type":"address"}],"name":"NotACompatiblePool","type":"error"},{"inputs":[],"name":"OnlyCallableByOwner","type":"error"},{"inputs":[],"name":"OracleCannotBeZeroAddress","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"inputs":[{"internalType":"bytes","name":"err","type":"bytes"}],"name":"ReceiverError","type":"error"},{"inputs":[{"internalType":"uint256","name":"amountReleased","type":"uint256"},{"internalType":"uint256","name":"balancePre","type":"uint256"},{"internalType":"uint256","name":"balancePost","type":"uint256"}],"name":"ReleaseOrMintBalanceMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"name":"RootAlreadyCommitted","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"},{"internalType":"bool","name":"isBlessed","type":"bool"}],"name":"RootBlessingMismatch","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"RootNotCommitted","type":"error"},{"inputs":[],"name":"SignatureVerificationNotAllowedInExecutionPlugin","type":"error"},{"inputs":[],"name":"SignatureVerificationRequiredInCommitPlugin","type":"error"},{"inputs":[],"name":"SignaturesOutOfRegistration","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"SourceChainNotEnabled","type":"error"},{"inputs":[{"internalType":"uint64","name":"reportSourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"messageSourceChainSelector","type":"uint64"}],"name":"SourceChainSelectorMismatch","type":"error"},{"inputs":[],"name":"StaleCommitReport","type":"error"},{"inputs":[{"internalType":"uint8","name":"ocrPluginType","type":"uint8"}],"name":"StaticConfigCannotBeChanged","type":"error"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"TokenDataMismatch","type":"error"},{"inputs":[{"internalType":"address","name":"target","type":"address"},{"internalType":"bytes","name":"err","type":"bytes"}],"name":"TokenHandlingError","type":"error"},{"inputs":[],"name":"UnauthorizedSigner","type":"error"},{"inputs":[],"name":"UnauthorizedTransmitter","type":"error"},{"inputs":[],"name":"UnexpectedTokenData","type":"error"},{"inputs":[{"internalType":"uint256","name":"expected","type":"uint256"},{"internalType":"uint256","name":"actual","type":"uint256"}],"name":"WrongMessageLength","type":"error"},{"inputs":[],"name":"WrongNumberOfSignatures","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"inputs":[],"name":"ZeroChainSelectorNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"AlreadyAttempted","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"onRampAddress","type":"bytes"},{"internalType":"uint64","name":"minSeqNr","type":"uint64"},{"internalType":"uint64","name":"maxSeqNr","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"indexed":false,"internalType":"struct Internal.MerkleRoot[]","name":"blessedMerkleRoots","type":"tuple[]"},{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"onRampAddress","type":"bytes"},{"internalType":"uint64","name":"minSeqNr","type":"uint64"},{"internalType":"uint64","name":"maxSeqNr","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"indexed":false,"internalType":"struct Internal.MerkleRoot[]","name":"unblessedMerkleRoots","type":"tuple[]"},{"components":[{"components":[{"internalType":"address","name":"sourceToken","type":"address"},{"internalType":"uint224","name":"usdPerToken","type":"uint224"}],"internalType":"struct Internal.TokenPriceUpdate[]","name":"tokenPriceUpdates","type":"tuple[]"},{"components":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint224","name":"usdPerUnitGas","type":"uint224"}],"internalType":"struct Internal.GasPriceUpdate[]","name":"gasPriceUpdates","type":"tuple[]"}],"indexed":false,"internalType":"struct Internal.PriceUpdates","name":"priceUpdates","type":"tuple"}],"name":"CommitReportAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"ocrPluginType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"address[]","name":"signers","type":"address[]"},{"indexed":false,"internalType":"address[]","name":"transmitters","type":"address[]"},{"indexed":false,"internalType":"uint8","name":"F","type":"uint8"}],"name":"ConfigSet","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"address","name":"feeQuoter","type":"address"},{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"messageInterceptor","type":"address"}],"indexed":false,"internalType":"struct OffRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"DynamicConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"indexed":true,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":false,"internalType":"enum Internal.MessageExecutionState","name":"state","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"gasUsed","type":"uint256"}],"name":"ExecutionStateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"RootRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"SkippedAlreadyExecutedMessage","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"SkippedReportExecution","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"components":[{"internalType":"contract IRouter","name":"router","type":"address"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint64","name":"minSeqNr","type":"uint64"},{"internalType":"bool","name":"isRMNVerificationDisabled","type":"bool"},{"internalType":"bytes","name":"onRamp","type":"bytes"}],"indexed":false,"internalType":"struct OffRamp.SourceChainConfig","name":"sourceConfig","type":"tuple"}],"name":"SourceChainConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"SourceChainSelectorAdded","type":"event"},{"anonymous":false,"inputs":[{"components":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint16","name":"gasForCallExactCheck","type":"uint16"},{"internalType":"contract IRMNRemote","name":"rmnRemote","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"},{"internalType":"address","name":"nonceManager","type":"address"}],"indexed":false,"internalType":"struct OffRamp.StaticConfig","name":"staticConfig","type":"tuple"}],"name":"StaticConfigSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint8","name":"ocrPluginType","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"Transmitted","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"contract IRouter","name":"router","type":"address"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"bool","name":"isRMNVerificationDisabled","type":"bool"},{"internalType":"bytes","name":"onRamp","type":"bytes"}],"internalType":"struct OffRamp.SourceChainConfigArgs[]","name":"sourceChainConfigUpdates","type":"tuple[]"}],"name":"applySourceChainConfigUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"components":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Client.EVMTokenAmount[]","name":"destTokenAmounts","type":"tuple[]"}],"internalType":"struct Client.Any2EVMMessage","name":"","type":"tuple"}],"name":"ccipReceive","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes32[2]","name":"reportContext","type":"bytes32[2]"},{"internalType":"bytes","name":"report","type":"bytes"},{"internalType":"bytes32[]","name":"rs","type":"bytes32[]"},{"internalType":"bytes32[]","name":"ss","type":"bytes32[]"},{"internalType":"bytes32","name":"rawVs","type":"bytes32"}],"name":"commit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32[2]","name":"reportContext","type":"bytes32[2]"},{"internalType":"bytes","name":"report","type":"bytes"}],"name":"execute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Internal.RampMessageHeader","name":"header","type":"tuple"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"bytes","name":"sourcePoolAddress","type":"bytes"},{"internalType":"address","name":"destTokenAddress","type":"address"},{"internalType":"uint32","name":"destGasAmount","type":"uint32"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Internal.Any2EVMTokenTransfer[]","name":"tokenAmounts","type":"tuple[]"}],"internalType":"struct Internal.Any2EVMRampMessage","name":"message","type":"tuple"},{"internalType":"bytes[]","name":"offchainTokenData","type":"bytes[]"},{"internalType":"uint32[]","name":"tokenGasOverrides","type":"uint32[]"}],"name":"executeSingleMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllSourceChainConfigs","outputs":[{"internalType":"uint64[]","name":"","type":"uint64[]"},{"components":[{"internalType":"contract IRouter","name":"router","type":"address"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint64","name":"minSeqNr","type":"uint64"},{"internalType":"bool","name":"isRMNVerificationDisabled","type":"bool"},{"internalType":"bytes","name":"onRamp","type":"bytes"}],"internalType":"struct OffRamp.SourceChainConfig[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDynamicConfig","outputs":[{"components":[{"internalType":"address","name":"feeQuoter","type":"address"},{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"messageInterceptor","type":"address"}],"internalType":"struct OffRamp.DynamicConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"}],"name":"getExecutionState","outputs":[{"internalType":"enum Internal.MessageExecutionState","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getLatestPriceSequenceNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes32","name":"root","type":"bytes32"}],"name":"getMerkleRoot","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"}],"name":"getSourceChainConfig","outputs":[{"components":[{"internalType":"contract IRouter","name":"router","type":"address"},{"internalType":"bool","name":"isEnabled","type":"bool"},{"internalType":"uint64","name":"minSeqNr","type":"uint64"},{"internalType":"bool","name":"isRMNVerificationDisabled","type":"bool"},{"internalType":"bytes","name":"onRamp","type":"bytes"}],"internalType":"struct OffRamp.SourceChainConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getStaticConfig","outputs":[{"components":[{"internalType":"uint64","name":"chainSelector","type":"uint64"},{"internalType":"uint16","name":"gasForCallExactCheck","type":"uint16"},{"internalType":"contract IRMNRemote","name":"rmnRemote","type":"address"},{"internalType":"address","name":"tokenAdminRegistry","type":"address"},{"internalType":"address","name":"nonceManager","type":"address"}],"internalType":"struct OffRamp.StaticConfig","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"ocrPluginType","type":"uint8"}],"name":"latestConfigDetails","outputs":[{"components":[{"components":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint8","name":"F","type":"uint8"},{"internalType":"uint8","name":"n","type":"uint8"},{"internalType":"bool","name":"isSignatureVerificationEnabled","type":"bool"}],"internalType":"struct MultiOCR3Base.ConfigInfo","name":"configInfo","type":"tuple"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"}],"internalType":"struct MultiOCR3Base.OCRConfig","name":"ocrConfig","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"components":[{"components":[{"internalType":"bytes32","name":"messageId","type":"bytes32"},{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"uint64","name":"sequenceNumber","type":"uint64"},{"internalType":"uint64","name":"nonce","type":"uint64"}],"internalType":"struct Internal.RampMessageHeader","name":"header","type":"tuple"},{"internalType":"bytes","name":"sender","type":"bytes"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"bytes","name":"sourcePoolAddress","type":"bytes"},{"internalType":"address","name":"destTokenAddress","type":"address"},{"internalType":"uint32","name":"destGasAmount","type":"uint32"},{"internalType":"bytes","name":"extraData","type":"bytes"},{"internalType":"uint256","name":"amount","type":"uint256"}],"internalType":"struct Internal.Any2EVMTokenTransfer[]","name":"tokenAmounts","type":"tuple[]"}],"internalType":"struct Internal.Any2EVMRampMessage[]","name":"messages","type":"tuple[]"},{"internalType":"bytes[][]","name":"offchainTokenData","type":"bytes[][]"},{"internalType":"bytes32[]","name":"proofs","type":"bytes32[]"},{"internalType":"uint256","name":"proofFlagBits","type":"uint256"}],"internalType":"struct Internal.ExecutionReport[]","name":"reports","type":"tuple[]"},{"components":[{"internalType":"uint256","name":"receiverExecutionGasLimit","type":"uint256"},{"internalType":"uint32[]","name":"tokenGasOverrides","type":"uint32[]"}],"internalType":"struct OffRamp.GasLimitOverride[][]","name":"gasLimitOverrides","type":"tuple[][]"}],"name":"manuallyExecute","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"feeQuoter","type":"address"},{"internalType":"uint32","name":"permissionLessExecutionThresholdSeconds","type":"uint32"},{"internalType":"address","name":"messageInterceptor","type":"address"}],"internalType":"struct OffRamp.DynamicConfig","name":"dynamicConfig","type":"tuple"}],"name":"setDynamicConfig","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"configDigest","type":"bytes32"},{"internalType":"uint8","name":"ocrPluginType","type":"uint8"},{"internalType":"uint8","name":"F","type":"uint8"},{"internalType":"bool","name":"isSignatureVerificationEnabled","type":"bool"},{"internalType":"address[]","name":"signers","type":"address[]"},{"internalType":"address[]","name":"transmitters","type":"address[]"}],"internalType":"struct MultiOCR3Base.OCRConfigArgs[]","name":"ocrConfigArgs","type":"tuple[]"}],"name":"setOCR3Configs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"typeAndVersion","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"}]Contract Creation Code
610140806040523461084b57616654803803809161001d8285610881565b8339810190808203610120811261084b5760a0811261084b5760405161004281610866565b61004b836108a4565b8152602083015161ffff8116810361084b57602082019081526040840151906001600160a01b038216820361084b576040830191825261008d606086016108b8565b926060810193845260606100a3608088016108b8565b6080830190815295609f19011261084b5760405194606086016001600160401b03811187821017610850576040526100dd60a088016108b8565b865260c08701519463ffffffff8616860361084b576020870195865261010560e089016108b8565b6040880190815261010089015190986001600160401b03821161084b570189601f8201121561084b578051996001600160401b038b11610850578a60051b916040519b6101568d6020860190610881565b8c526020808d01938201019082821161084b5760208101935b82851061073a575050505050331561072957600180546001600160a01b031916331790554660805284516001600160a01b0316158015610717575b8015610705575b6106e35782516001600160401b0316156106f45782516001600160401b0390811660a090815286516001600160a01b0390811660c0528351811660e0528451811661010052865161ffff90811661012052604080519751909416875296519096166020860152955185169084015251831660608301525190911660808201527fb0fa1fb01508c5097c502ad056fd77018870c9be9a86d9e56b6b471862d7c5b79190a181516001600160a01b0316156106e357905160048054835163ffffffff60a01b60a09190911b166001600160a01b039384166001600160c01b03199092168217179091558351600580549184166001600160a01b031990921691909117905560408051918252925163ffffffff166020820152925116908201527fa1c15688cb2c24508e158f6942b9276c6f3028a85e1af8cf3fff0c3ff3d5fc8d90606090a160005b8151811015610656576020600582901b8301810151908101516001600160401b031690600082156106475781516001600160a01b0316156105ae57828152600860205260408120916080810151600184019261035384546108d9565b6105e8578454600160a81b600160e81b031916600160a81b1785556040518681527ff4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb990602090a15b815180159081156105bd575b506105ae578151916001600160401b03831161059a576103c785546108d9565b601f8111610555575b50602091601f84116001146104d65760ff948460019a9998956104c2956000805160206166348339815191529995606095926104cb575b5050600019600383901b1c1916908b1b1783555b604081015115158554908760a01b9060a01b16908760a01b1916178555898060a01b038151168a8060a01b0319865416178555015115158354908560e81b9060e81b16908560e81b191617835561047186610996565b506040519384936020855254898060a01b0381166020860152818160a01c1615156040860152898060401b038160a81c16606086015260e81c161515608084015260a08084015260c0830190610913565b0390a2016102f7565b015190503880610407565b9190601f198416868452828420935b81811061053d5750946001856104c2956000805160206166348339815191529995606095849e9d9c9960ff9b10610524575b505050811b01835561041b565b015160001960f88460031b161c19169055388080610517565b929360206001819287860151815501950193016104e5565b85835260208320601f850160051c81019160208610610590575b601f0160051c01905b81811061058557506103d0565b838155600101610578565b909150819061056f565b634e487b7160e01b82526041600452602482fd5b6342bcdf7f60e11b8152600490fd5b905060208301206040516020810190838252602081526105de604082610881565b51902014386103a7565b845460a81c6001600160401b03166001141580610619575b1561039b57632105803760e11b81526004869052602490fd5b506040516106328161062b8188610913565b0382610881565b60208151910120825160208401201415610600565b63c656089560e01b8152600490fd5b604051615c0a9081610a2a82396080518161327e015260a05181818161019f0152614367015260c0518181816101f501528181612ebd0152818161379201528181613a660152614301015260e0518181816102240152614b63015261010051818181610253015261472c0152610120518181816101c6015281816121b101528181614c5601526158bb0152f35b6342bcdf7f60e11b60005260046000fd5b63c656089560e01b60005260046000fd5b5081516001600160a01b0316156101b1565b5080516001600160a01b0316156101aa565b639b15e16f60e01b60005260046000fd5b84516001600160401b03811161084b57820160a0818603601f19011261084b576040519061076782610866565b60208101516001600160a01b038116810361084b57825261078a604082016108a4565b602083015261079b606082016108cc565b60408301526107ac608082016108cc565b606083015260a08101516001600160401b03811161084b57602091010185601f8201121561084b5780516001600160401b03811161085057604051916107fc601f8301601f191660200184610881565b818352876020838301011161084b5760005b828110610836575050918160006020809694958196010152608082015281520194019361016f565b8060208092840101518282870101520161080e565b600080fd5b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b0382111761085057604052565b601f909101601f19168101906001600160401b0382119082101761085057604052565b51906001600160401b038216820361084b57565b51906001600160a01b038216820361084b57565b5190811515820361084b57565b90600182811c92168015610909575b60208310146108f357565b634e487b7160e01b600052602260045260246000fd5b91607f16916108e8565b60009291815491610923836108d9565b8083529260018116908115610979575060011461093f57505050565b60009081526020812093945091925b83831061095f575060209250010190565b60018160209294939454838587010152019101919061094e565b915050602093945060ff929192191683830152151560051b010190565b80600052600760205260406000205415600014610a235760065468010000000000000000811015610850576001810180600655811015610a0d577ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f0181905560065460009182526007602052604090912055600190565b634e487b7160e01b600052603260045260246000fd5b5060009056fe6080604052600436101561001257600080fd5b60003560e01c806306285c6914610157578063181f5a77146101525780633f4b04aa1461014d5780635215505b146101485780635e36480c146101435780635e7bb0081461013e57806360987c20146101395780636f9e320f146101345780637437ff9f1461012f57806379ba50971461012a57806385572ffb146101255780638da5cb5b14610120578063c673e5841461011b578063ccd37ba314610116578063cd19723714610111578063de5e0b9a1461010c578063e9d68a8e14610107578063f2fde38b14610102578063f58e03fc146100fd5763f716f99f146100f857600080fd5b6118ae565b611791565b611706565b611661565b6115c5565b611467565b611408565b611343565b61125b565b611225565b6111a5565b611105565b610f90565b610f15565b610d0e565b610729565b6105ba565b61049e565b61043f565b61016c565b600091031261016757565b600080fd5b34610167576000366003190112610167576101856119e9565b506102cd604051610195816102e7565b6001600160401b037f000000000000000000000000000000000000000000000000000000000000000016815261ffff7f00000000000000000000000000000000000000000000000000000000000000001660208201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660408201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660608201526001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001660808201526040519182918291909160806001600160a01b038160a08401956001600160401b03815116855261ffff6020820151166020860152826040820151166040860152826060820151166060860152015116910152565b0390f35b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b0382111761030257604052565b6102d1565b604081019081106001600160401b0382111761030257604052565b606081019081106001600160401b0382111761030257604052565b608081019081106001600160401b0382111761030257604052565b90601f801991011681019081106001600160401b0382111761030257604052565b6040519061038860c083610358565b565b6040519061038860a083610358565b60405190610388608083610358565b6040519061038861010083610358565b60405190610388604083610358565b6001600160401b03811161030257601f01601f191660200190565b604051906103f1602083610358565b60008252565b60005b83811061040a5750506000910152565b81810151838201526020016103fa565b90602091610433815180928185528580860191016103f7565b601f01601f1916010190565b34610167576000366003190112610167576102cd60408051906104628183610358565b600d82527f4f666652616d7020312e362e300000000000000000000000000000000000000060208301525191829160208352602083019061041a565b346101675760003660031901126101675760206001600160401b03600b5416604051908152f35b9060a06080610516936001600160a01b0381511684526020810151151560208501526001600160401b036040820151166040850152606081015115156060850152015191816080820152019061041a565b90565b6040810160408252825180915260206060830193019060005b81811061059b575050506020818303910152815180825260208201916020808360051b8301019401926000915b83831061056e57505050505090565b909192939460208061058c600193601f1986820301875289516104c5565b9701930193019193929061055f565b82516001600160401b0316855260209485019490920191600101610532565b34610167576000366003190112610167576006546105d781610771565b906105e56040519283610358565b808252601f196105f482610771565b0160005b8181106106b657505061060a81611a42565b9060005b8181106106265750506102cd60405192839283610519565b8061065c6106446106386001946141e8565b6001600160401b031690565b61064e8387611a9c565b906001600160401b03169052565b61069a61069561067c61066f8488611a9c565b516001600160401b031690565b6001600160401b03166000526008602052604060002090565b611b88565b6106a48287611a9c565b526106af8186611a9c565b500161060e565b6020906106c1611a14565b828287010152016105f8565b600435906001600160401b038216820361016757565b35906001600160401b038216820361016757565b634e487b7160e01b600052602160045260246000fd5b6004111561071757565b6106f7565b9060048210156107175752565b34610167576040366003190112610167576107426106cd565b602435906001600160401b03821682036101675760209161076291611c31565b61076f604051809261071c565bf35b6001600160401b0381116103025760051b60200190565b91908260a0910312610167576040516107a0816102e7565b60806107e5818395803585526107b8602082016106e3565b60208601526107c9604082016106e3565b60408601526107da606082016106e3565b6060860152016106e3565b910152565b9291926107f6826103c7565b916108046040519384610358565b829481845281830111610167578281602093846000960137010152565b9080601f8301121561016757816020610516933591016107ea565b6001600160a01b0381160361016757565b35906103888261083c565b63ffffffff81160361016757565b359061038882610858565b81601f820112156101675780359061088882610771565b926108966040519485610358565b82845260208085019360051b830101918183116101675760208101935b8385106108c257505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757604051916108ef836102e7565b60208201356001600160401b0381116101675785602061091192850101610821565b835260408201356109218161083c565b602084015261093260608301610866565b60408401526080820135926001600160401b0384116101675760a08361095f886020809881980101610821565b6060840152013560808201528152019401936108b3565b919091610140818403126101675761098c610379565b926109978183610788565b845260a08201356001600160401b03811161016757816109b8918401610821565b602085015260c08201356001600160401b03811161016757816109dc918401610821565b60408501526109ed60e0830161084d565b606085015261010082013560808501526101208201356001600160401b03811161016757610a1b9201610871565b60a0830152565b9080601f83011215610167578135610a3981610771565b92610a476040519485610358565b81845260208085019260051b820101918383116101675760208201905b838210610a7357505050505090565b81356001600160401b03811161016757602091610a9587848094880101610976565b815201910190610a64565b81601f8201121561016757803590610ab782610771565b92610ac56040519485610358565b82845260208085019360051b830101918183116101675760208101935b838510610af157505050505090565b84356001600160401b03811161016757820183603f82011215610167576020810135610b1c81610771565b91610b2a6040519384610358565b8183526020808085019360051b83010101918683116101675760408201905b838210610b63575050509082525060209485019401610ae2565b81356001600160401b03811161016757602091610b878a8480809589010101610821565b815201910190610b49565b929190610b9e81610771565b93610bac6040519586610358565b602085838152019160051b810192831161016757905b828210610bce57505050565b8135815260209182019101610bc2565b9080601f830112156101675781602061051693359101610b92565b81601f8201121561016757803590610c1082610771565b92610c1e6040519485610358565b82845260208085019360051b830101918183116101675760208101935b838510610c4a57505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757610c7261038a565b91610c7f602083016106e3565b835260408201356001600160401b03811161016757856020610ca392850101610a22565b602084015260608201356001600160401b03811161016757856020610cca92850101610aa0565b60408401526080820135926001600160401b0384116101675760a083610cf7886020809881980101610bde565b606084015201356080820152815201940193610c3b565b34610167576040366003190112610167576004356001600160401b03811161016757610d3e903690600401610bf9565b6024356001600160401b038111610167573660238201121561016757806004013591610d6983610771565b91610d776040519384610358565b8383526024602084019460051b820101903682116101675760248101945b828610610da857610da68585611c79565b005b85356001600160401b03811161016757820136604382011215610167576024810135610dd381610771565b91610de16040519384610358565b818352602060248185019360051b83010101903682116101675760448101925b828410610e1b575050509082525060209586019501610d95565b83356001600160401b038111610167576024908301016040601f1982360301126101675760405190610e4c82610307565b6020810135825260408101356001600160401b03811161016757602091010136601f8201121561016757803590610e8282610771565b91610e906040519384610358565b80835260208084019160051b8301019136831161016757602001905b828210610ecb5750505091816020938480940152815201930192610e01565b602080918335610eda81610858565b815201910190610eac565b9181601f84011215610167578235916001600160401b038311610167576020808501948460051b01011161016757565b34610167576060366003190112610167576004356001600160401b03811161016757610f45903690600401610976565b6024356001600160401b03811161016757610f64903690600401610ee5565b91604435926001600160401b03841161016757610f88610da6943690600401610ee5565b939092612089565b34610167576060366003190112610167576000604051610faf81610322565b600435610fbb8161083c565b8152602435610fc981610858565b6020820190815260443590610fdd8261083c565b60408301918252610fec613534565b6001600160a01b03835116156110f657916110b86001600160a01b036110f0937fa1c15688cb2c24508e158f6942b9276c6f3028a85e1af8cf3fff0c3ff3d5fc8d95611051838651166001600160a01b03166001600160a01b03196004541617600455565b517fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff77ffffffff00000000000000000000000000000000000000006004549260a01b1691161760045551166001600160a01b03166001600160a01b03196005541617600555565b6040519182918291909160406001600160a01b0381606084019582815116855263ffffffff6020820151166020860152015116910152565b0390a180f35b6342bcdf7f60e11b8452600484fd5b346101675760003660031901126101675760006040805161112581610322565b82815282602082015201526102cd60405161113f81610322565b63ffffffff6004546001600160a01b038116835260a01c1660208201526001600160a01b036005541660408201526040519182918291909160406001600160a01b0381606084019582815116855263ffffffff6020820151166020860152015116910152565b34610167576000366003190112610167576000546001600160a01b0381163303611214576001600160a01b0319600154913382841617600155166000556001600160a01b033391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b63015aa1e360e11b60005260046000fd5b34610167576020366003190112610167576004356001600160401b0381116101675760a090600319903603011261016757600080fd5b346101675760003660031901126101675760206001600160a01b0360015416604051908152f35b6004359060ff8216820361016757565b359060ff8216820361016757565b906020808351928381520192019060005b8181106112be5750505090565b82516001600160a01b03168452602093840193909201916001016112b1565b906105169160208152606082518051602084015260ff602082015116604084015260ff60408201511682840152015115156080820152604061132e602084015160c060a085015260e08401906112a0565b9201519060c0601f19828503019101526112a0565b346101675760203660031901126101675760ff61135e611282565b60606040805161136d81610322565b81516113788161033d565b6000815260006020820152600083820152600084820152815282602082015201521660005260026020526102cd604060002060036113f7604051926113bc84610322565b6113c581612366565b84526040516113e2816113db816002860161239f565b0382610358565b60208501526113db604051809481930161239f565b6040820152604051918291826112dd565b34610167576040366003190112610167576114216106cd565b6001600160401b036024359116600052600a6020526040600020906000526020526020604060002054604051908152f35b8015150361016757565b359061038882611452565b34610167576020366003190112610167576004356001600160401b0381116101675736602382011215610167578060040135906114a382610771565b906114b16040519283610358565b8282526024602083019360051b820101903682116101675760248101935b8285106114df57610da6846123f6565b84356001600160401b03811161016757820160a06023198236030112610167576040519161150c836102e7565b602482013561151a8161083c565b8352611528604483016106e3565b6020840152606482013561153b81611452565b6040840152608482013561154e81611452565b606084015260a4820135926001600160401b0384116101675761157b602094936024869536920101610821565b60808201528152019401936114cf565b9060049160441161016757565b9181601f84011215610167578235916001600160401b038311610167576020838186019501011161016757565b346101675760c0366003190112610167576115df3661158b565b6044356001600160401b038111610167576115fe903690600401611598565b6064929192356001600160401b03811161016757611620903690600401610ee5565b60843594916001600160401b03861161016757611644610da6963690600401610ee5565b94909360a43596612cb9565b9060206105169281815201906104c5565b34610167576020366003190112610167576001600160401b036116826106cd565b61168a611a14565b501660005260086020526102cd60406000206116f56001604051926116ae846102e7565b6116ef60ff82546001600160a01b0381168752818160a01c16151560208801526001600160401b038160a81c16604088015260e81c16606086019015159052565b01611b6d565b608082015260405191829182611650565b34610167576020366003190112610167576001600160a01b0360043561172b8161083c565b611733613534565b1633811461178057806001600160a01b031960005416176000556001600160a01b03600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278600080a3005b636d6c4ee560e11b60005260046000fd5b34610167576060366003190112610167576117ab3661158b565b6044356001600160401b038111610167576117ca903690600401611598565b91828201602083820312610167578235906001600160401b038211610167576117f4918401610bf9565b6040519060206118048184610358565b60008352601f19810160005b81811061183857505050610da69491611828916132bf565b611830612f33565b928392613bb0565b60608582018401528201611810565b9080601f8301121561016757813561185e81610771565b9261186c6040519485610358565b81845260208085019260051b82010192831161016757602001905b8282106118945750505090565b6020809183356118a38161083c565b815201910190611887565b34610167576020366003190112610167576004356001600160401b0381116101675736602382011215610167578060040135906118ea82610771565b906118f86040519283610358565b8282526024602083019360051b820101903682116101675760248101935b82851061192657610da684612f4f565b84356001600160401b03811161016757820160c060231982360301126101675761194e610379565b916024820135835261196260448301611292565b602084015261197360648301611292565b60408401526119846084830161145c565b606084015260a48201356001600160401b038111610167576119ac9060243691850101611847565b608084015260c4820135926001600160401b038411610167576119d9602094936024869536920101611847565b60a0820152815201940193611916565b604051906119f6826102e7565b60006080838281528260208201528260408201528260608201520152565b60405190611a21826102e7565b60606080836000815260006020820152600060408201526000838201520152565b90611a4c82610771565b611a596040519182610358565b8281528092611a6a601f1991610771565b0190602036910137565b634e487b7160e01b600052603260045260246000fd5b805115611a975760200190565b611a74565b8051821015611a975760209160051b010190565b90600182811c92168015611ae0575b6020831014611aca57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611abf565b60009291815491611afa83611ab0565b8083529260018116908115611b505750600114611b1657505050565b60009081526020812093945091925b838310611b36575060209250010190565b600181602092949394548385870101520191019190611b25565b915050602093945060ff929192191683830152151560051b010190565b90610388611b819260405193848092611aea565b0383610358565b9060016080604051611b99816102e7565b611bef819560ff81546001600160a01b0381168552818160a01c16151560208601526001600160401b038160a81c16604086015260e81c1615156060840152611be86040518096819301611aea565b0384610358565b0152565b634e487b7160e01b600052601160045260246000fd5b908160051b9180830460201490151715611c1f57565b611bf3565b91908203918211611c1f57565b611c3d82607f92613238565b9116906801fffffffffffffffe6001600160401b0383169260011b169180830460021490151715611c1f576003911c1660048110156107175790565b611c8161327c565b805182518103611e7c5760005b818110611ca157505090610388916132bf565b611cab8184611a9c565b516020810190815151611cbe8488611a9c565b519283518203611e7c5790916000925b808410611ce2575050505050600101611c8e565b91949398611cf4848b98939598611a9c565b515198611d02888851611a9c565b519980611e33575b5060a08a01988b6020611d208b8d515193611a9c565b5101515103611df25760005b8a5151811015611ddd57611d68611d5f611d558f6020611d4d8f8793611a9c565b510151611a9c565b5163ffffffff1690565b63ffffffff1690565b8b81611d79575b5050600101611d2c565b611d5f6040611d8c85611d989451611a9c565b51015163ffffffff1690565b90818110611da757508b611d6f565b8d51516040516348e617b360e01b81526004810191909152602481019390935260448301919091526064820152608490fd5b0390fd5b50985098509893949095600101929091611cce565b611e2f8b51611e0d606082519201516001600160401b031690565b6370a193fd60e01b6000526004919091526001600160401b0316602452604490565b6000fd5b60808b0151811015611d0a57611e2f908b611e5588516001600160401b031690565b905151633a98d46360e11b6000526001600160401b03909116600452602452604452606490565b6320f8fd5960e21b60005260046000fd5b60405190611e9a82610307565b60006020838281520152565b60405190611eb5602083610358565b600080835282815b828110611ec957505050565b602090611ed4611e8d565b82828501015201611ebd565b805182526001600160401b0360208201511660208301526080611f27611f15604084015160a0604087015260a086019061041a565b6060840151858203606087015261041a565b9101519160808183039101526020808351928381520192019060005b818110611f505750505090565b825180516001600160a01b031685526020908101518186015260409094019390920191600101611f43565b906020610516928181520190611ee0565b6040513d6000823e3d90fd5b3d15611fc3573d90611fa9826103c7565b91611fb76040519384610358565b82523d6000602084013e565b606090565b90602061051692818152019061041a565b9091606082840312610167578151611ff081611452565b9260208301516001600160401b0381116101675783019080601f830112156101675781519161201e836103c7565b9161202c6040519384610358565b838352602084830101116101675760409261204d91602080850191016103f7565b92015190565b9293606092959461ffff6120776001600160a01b0394608088526080880190611ee0565b97166020860152604085015216910152565b929093913033036123555761209c611ea6565b9460a0850151805161230e575b50505050508051916120c7602084519401516001600160401b031690565b9060208301519160408401926120f48451926120e161038a565b9788526001600160401b03166020880152565b6040860152606085015260808401526001600160a01b0361211d6005546001600160a01b031690565b1680612291575b5051511580612285575b801561226f575b8015612246575b612242576121da918161217f61217361216661067c602060009751016001600160401b0390511690565b546001600160a01b031690565b6001600160a01b031690565b908361219a606060808401519301516001600160a01b031690565b604051633cf9798360e01b815296879586948593917f00000000000000000000000000000000000000000000000000000000000000009060048601612053565b03925af190811561223d57600090600092612216575b50156121f95750565b6040516302a35ba360e21b8152908190611dd99060048301611fc8565b905061223591503d806000833e61222d8183610358565b810190611fd9565b5090386121f0565b611f8c565b5050565b5061226a61226661226160608401516001600160a01b031690565b6134e6565b1590565b61213c565b5060608101516001600160a01b03163b15612135565b5060808101511561212e565b803b1561016757600060405180926308d450a160e01b82528183816122b98a60048301611f7b565b03925af190816122f3575b506122ed57611dd96122d4611f98565b6040516309c2532560e01b815291829160048301611fc8565b38612124565b80612302600061230893610358565b8061015c565b386122c4565b859650602061234a96015161232d60608901516001600160a01b031690565b9061234460208a51016001600160401b0390511690565b926133cd565b9038808080806120a9565b6306e34e6560e31b60005260046000fd5b906040516123738161033d565b606060ff600183958054855201548181166020850152818160081c16604085015260101c161515910152565b906020825491828152019160005260206000209060005b8181106123c35750505090565b82546001600160a01b03168452602090930192600192830192016123b6565b90610388611b81926040519384809261239f565b6123fe613534565b60005b8151811015612242576124148183611a9c565b519061242a60208301516001600160401b031690565b6001600160401b0381169081156126c05761245261217361217386516001600160a01b031690565b1561262b57612474816001600160401b03166000526008602052604060002090565b60808501519060018101926124898454611ab0565b612652576124fc7ff4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb9916124e284750100000000000000000000000000000000000000000067ffffffffffffffff60a81b19825416179055565b6040516001600160401b0390911681529081906020820190565b0390a15b8151801590811561263c575b5061262b5761260c6125d7606060019861254a612622967fbd1ab25a0ff0a36a588597ba1af11e30f3f210de8b9e818cc9bbc457c94c8d8c986135d6565b6125a061255a6040830151151590565b86547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690151560a01b74ff000000000000000000000000000000000000000016178655565b6125d06125b482516001600160a01b031690565b86906001600160a01b03166001600160a01b0319825416179055565b0151151590565b82547fffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690151560e81b60ff60e81b16178255565b612615846159ce565b50604051918291826136a7565b0390a201612401565b6342bcdf7f60e11b60005260046000fd5b9050602083012061264b613559565b143861250c565b60016001600160401b0361267184546001600160401b039060a81c1690565b161415806126a1575b6126845750612500565b632105803760e11b6000526001600160401b031660045260246000fd5b506126ab84611b6d565b6020815191012083516020850120141561267a565b63c656089560e01b60005260046000fd5b35906001600160e01b038216820361016757565b81601f82011215610167578035906126fc82610771565b9261270a6040519485610358565b82845260208085019360061b8301019181831161016757602001925b828410612734575050505090565b604084830312610167576020604091825161274e81610307565b612757876106e3565b81526127648388016126d1565b83820152815201930192612726565b9190604083820312610167576040519061278c82610307565b819380356001600160401b03811161016757810182601f820112156101675780356127b681610771565b916127c46040519384610358565b81835260208084019260061b8201019085821161016757602001915b81831061280d5750505083526020810135916001600160401b038311610167576020926107e592016126e5565b604083870312610167576020604091825161282781610307565b85356128328161083c565b815261283f8387016126d1565b838201528152019201916127e0565b81601f820112156101675780359061286582610771565b926128736040519485610358565b82845260208085019360051b830101918183116101675760208101935b83851061289f57505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757604051916128cc836102e7565b6128d8602083016106e3565b83526040820135926001600160401b0384116101675760a083612902886020809881980101610821565b85840152612912606082016106e3565b6040840152612923608082016106e3565b606084015201356080820152815201940193612890565b81601f820112156101675780359061295182610771565b9261295f6040519485610358565b82845260208085019360061b8301019181831161016757602001925b828410612989575050505090565b60408483031261016757602060409182516129a381610307565b86358152828701358382015281520193019261297b565b602081830312610167578035906001600160401b0382116101675701608081830312610167576129e8610399565b9181356001600160401b0381116101675781612a05918401612773565b835260208201356001600160401b0381116101675781612a2691840161284e565b602084015260408201356001600160401b0381116101675781612a4a91840161284e565b604084015260608201356001600160401b03811161016757612a6c920161293a565b606082015290565b9080602083519182815201916020808360051b8301019401926000915b838310612aa057505050505090565b9091929394602080600192601f198582030186528851906001600160401b038251168152608080612ade8585015160a08786015260a085019061041a565b936001600160401b0360408201511660408501526001600160401b036060820151166060850152015191015297019301930191939290612a91565b916001600160a01b03612b3a92168352606060208401526060830190612a74565b9060408183039101526020808351928381520192019060005b818110612b605750505090565b8251805185526020908101518186015260409094019390920191600101612b53565b6084019081608411611c1f57565b60a001908160a011611c1f57565b91908201809211611c1f57565b906020808351928381520192019060005b818110612bc95750505090565b825180516001600160401b031685526020908101516001600160e01b03168186015260409094019390920191600101612bbc565b9190604081019083519160408252825180915260206060830193019060005b818110612c3d57505050602061051693940151906020818403910152612bab565b825180516001600160a01b031686526020908101516001600160e01b03168187015260409095019490920191600101612c1c565b906020610516928181520190612bfd565b91612cab90612c9d6105169593606086526060860190612a74565b908482036020860152612a74565b916040818403910152612bfd565b9197939796929695909495612cd0818701876129ba565b95602087019788518051612eb3575b5087518051511590811591612ea4575b50612dbf575b60005b89518051821015612d1f5790612d19612d1382600194611a9c565b51613757565b01612cf8565b50509193959799989092949698600099604081019a5b8b518051821015612d5c5790612d56612d5082600194611a9c565b51613a2b565b01612d35565b5050907fb967c9b9e1b7af9a61ca71ff00e9f5b89ec6f2e268de8dacf12f0de8e51f3e47612db193926103889c612da7612db998999a9b9c9d9f519151925160405193849384612c82565b0390a13691610b92565b943691610b92565b93613eaa565b612dd4602086015b356001600160401b031690565b600b546001600160401b0382811691161015612e7c57612e0a906001600160401b03166001600160401b0319600b541617600b55565b612e226121736121736004546001600160a01b031690565b885190803b1561016757604051633937306f60e01b8152916000918391829084908290612e529060048301612c71565b03925af1801561223d57612e67575b50612cf5565b806123026000612e7693610358565b38612e61565b50612e8f89515160408a01515190612b9e565b612cf557632261116760e01b60005260046000fd5b60209150015151151538612cef565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169060608a0151823b1561016757604051633854844f60e11b815292600092849283918291612f0f913060048501612b19565b03915afa801561223d5715612cdf57806123026000612f2d93610358565b38612cdf565b60405190612f42602083610358565b6000808352366020840137565b612f57613534565b60005b815181101561224257612f6d8183611a9c565b51906040820160ff612f80825160ff1690565b161561322257602083015160ff1692612fa68460ff166000526002602052604060002090565b9160018301918254612fc1612fbb8260ff1690565b60ff1690565b6131e75750612fee612fd66060830151151590565b845462ff0000191690151560101b62ff000016178455565b60a0810191825161010081511161318f578051156131d1576003860161301c613016826123e2565b8a61501a565b60608401516130ac575b947fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547946002946130886130786130a69a966130718760019f9c61306c61309e9a8f615188565b6140eb565b5160ff1690565b845460ff191660ff821617909455565b5190818555519060405195869501908886614171565b0390a161520a565b01612f5a565b979460028793959701966130c86130c2896123e2565b8861501a565b6080850151946101008651116131bb5785516130f0612fbb6130eb8a5160ff1690565b6140d7565b10156131a557855184511161318f576130886130787fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547986130718760019f61306c6130a69f9a8f61317760029f61317161309e9f8f9061306c8492613156845160ff1690565b908054909161ff001990911660089190911b61ff0016179055565b826150ae565b505050979c9f50975050969a50505094509450613026565b631b3fab5160e11b600052600160045260246000fd5b631b3fab5160e11b600052600360045260246000fd5b631b3fab5160e11b600052600260045260246000fd5b631b3fab5160e11b600052600560045260246000fd5b60101c60ff166132026131fd6060840151151590565b151590565b90151514612fee576321fd80df60e21b60005260ff861660045260246000fd5b631b3fab5160e11b600090815260045260246000fd5b906001600160401b03613278921660005260096020526701ffffffffffffff60406000209160071c166001600160401b0316600052602052604060002090565b5490565b7f00000000000000000000000000000000000000000000000000000000000000004681036132a75750565b630f01ce8560e01b6000526004524660245260446000fd5b9190918051156133615782511592602091604051926132de8185610358565b60008452601f19810160005b81811061333d5750505060005b8151811015613335578061331e61331060019385611a9c565b5188156133245786906142b0565b016132f7565b61332e8387611a9c565b51906142b0565b505050509050565b829060405161334b81610307565b60008152606083820152828289010152016132ea565b63c2e5347d60e01b60005260046000fd5b9190811015611a975760051b0190565b3561051681610858565b9190811015611a975760051b81013590601e19813603018212156101675701908135916001600160401b038311610167576020018236038113610167579190565b909294919397968151966133e088610771565b976133ee604051998a610358565b8089526133fd601f1991610771565b0160005b8181106134cf57505060005b83518110156134c257806134548c8a8a8a61344e613447878d613440828f8f9d8f9e60019f81613470575b505050611a9c565b519761338c565b36916107ea565b93614b14565b61345e828c611a9c565b52613469818b611a9c565b500161340d565b63ffffffff613488613483858585613372565b613382565b1615613438576134b89261349f9261348392613372565b60406134ab8585611a9c565b51019063ffffffff169052565b8f8f908391613438565b5096985050505050505050565b6020906134da611e8d565b82828d01015201613401565b6134f76385572ffb60e01b82614e77565b9081613511575b81613507575090565b6105169150614e49565b905061351c81614dce565b15906134fe565b6134f763aff2afbf60e01b82614e77565b6001600160a01b0360015416330361354857565b6315ae3a6f60e11b60005260046000fd5b60405160208101906000825260208152613574604082610358565b51902090565b818110613585575050565b6000815560010161357a565b9190601f81116135a057505050565b610388926000526020600020906020601f840160051c830193106135cc575b601f0160051c019061357a565b90915081906135bf565b91909182516001600160401b038111610302576135fd816135f78454611ab0565b84613591565b6020601f821160011461363e57819061362f939495600092613633575b50508160011b916000199060031b1c19161790565b9055565b01519050388061361a565b601f1982169061365384600052602060002090565b9160005b81811061368f57509583600195969710613676575b505050811b019055565b015160001960f88460031b161c1916905538808061366c565b9192602060018192868b015181550194019201613657565b90600160c0610516936020815260ff84546001600160a01b0381166020840152818160a01c16151560408401526001600160401b038160a81c16606084015260e81c161515608082015260a080820152019101611aea565b90816020910312610167575161051681611452565b909161372b6105169360408452604084019061041a565b916020818403910152611aea565b6001600160401b036001911601906001600160401b038211611c1f57565b8051604051632cbc26bb60e01b815267ffffffffffffffff60801b608083901b1660048201526001600160401b0390911691906020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561223d576000916139fc575b506139de576137d982614ea7565b805460ff60e882901c1615156001146139b3576020830180516020815191012090600184019161380883611b6d565b602081519101200361399657505060408301516001600160401b039081169160a81c16811480159061396e575b61392d5750608082015191821561391c5761387683613867866001600160401b0316600052600a602052604060002090565b90600052602052604060002090565b546138f9576138f6929161389f61389a60606138d89401516001600160401b031690565b613739565b67ffffffffffffffff60a81b197cffffffffffffffff00000000000000000000000000000000000000000083549260a81b169116179055565b61386742936001600160401b0316600052600a602052604060002090565b55565b6332cf0cbf60e01b6000526001600160401b038416600452602483905260446000fd5b63504570e360e01b60005260046000fd5b83611e2f9161394660608601516001600160401b031690565b636af0786b60e11b6000526001600160401b0392831660045290821660245216604452606490565b5061398661063860608501516001600160401b031690565b6001600160401b03821611613835565b51611dd960405192839263b80d8fa960e01b845260048401613714565b60808301516348e2b93360e11b6000526001600160401b038516600452602452600160445260646000fd5b637edeb53960e11b6000526001600160401b03821660045260246000fd5b613a1e915060203d602011613a24575b613a168183610358565b8101906136ff565b386137cb565b503d613a0c565b8051604051632cbc26bb60e01b815267ffffffffffffffff60801b608083901b1660048201526001600160401b0390911691906020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561223d57600091613b06575b506139de57613aad82614ea7565b805460ff60e882901c1615613ad8576020830180516020815191012090600184019161380883611b6d565b60808301516348e2b93360e11b60009081526001600160401b03861660045260249190915260445260646000fd5b613b1f915060203d602011613a2457613a168183610358565b38613a9f565b6003111561071757565b60038210156107175752565b90610388604051613b4b81610307565b602060ff829554818116845260081c169101613b2f565b8054821015611a975760005260206000200190600090565b60ff60019116019060ff8211611c1f57565b60ff601b9116019060ff8211611c1f57565b90606092604091835260208301370190565b6001600052600260205293613be47fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0612366565b93853594613bf185612b82565b6060820190613c008251151590565b613e7c575b803603613e6457508151878103613e4b5750613c1f61327c565b60016000526003602052613c6e613c697fa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c5b336001600160a01b0316600052602052604060002090565b613b3b565b60026020820151613c7e81613b25565b613c8781613b25565b149081613de3575b5015613db7575b51613cee575b50505050507f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef090613cd2612dc760019460200190565b604080519283526001600160401b0391909116602083015290a2565b613d0f612fbb613d0a602085969799989a955194015160ff1690565b613b7a565b03613da6578151835103613d9557613d8d6000613cd294612dc794613d597f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef09960019b36916107ea565b60208151910120604051613d8481613d7689602083019586613b9e565b03601f198101835282610358565b5190208a614ee4565b948394613c9c565b63a75d88af60e01b60005260046000fd5b6371253a2560e01b60005260046000fd5b72c11c11c11c11c11c11c11c11c11c11c11c11c1330315613c9657631b41e11d60e31b60005260046000fd5b60016000526002602052613e43915061217390613e3090613e2a60037fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e05b01915160ff1690565b90613b62565b90546001600160a01b039160031b1c1690565b331438613c8f565b6324f7d61360e21b600052600452602487905260446000fd5b638e1192e160e01b6000526004523660245260446000fd5b613ea590613e9f613e95613e908751611c09565b612b90565b613e9f8851611c09565b90612b9e565b613c05565b60008052600260205294909390929091613ee37fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b612366565b94863595613ef083612b82565b6060820190613eff8251151590565b6140b4575b803603613e645750815188810361409b5750613f1e61327c565b600080526003602052613f53613c697f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff613c51565b60026020820151613f6381613b25565b613f6c81613b25565b149081614052575b5015614026575b51613fb8575b5050505050507f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef090613cd2612dc760009460200190565b613fd4612fbb613d0a602087989a999b96975194015160ff1690565b03613da6578351865103613d95576000967f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef096613cd295613d5961401d94612dc79736916107ea565b94839438613f81565b72c11c11c11c11c11c11c11c11c11c11c11c11c1330315613f7b57631b41e11d60e31b60005260046000fd5b600080526002602052614093915061217390613e3090613e2a60037fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b613e21565b331438613f74565b6324f7d61360e21b600052600452602488905260446000fd5b6140d290613e9f6140c8613e908951611c09565b613e9f8a51611c09565b613f04565b60ff166003029060ff8216918203611c1f57565b8151916001600160401b03831161030257680100000000000000008311610302576020908254848455808510614154575b500190600052602060002060005b8381106141375750505050565b60019060206001600160a01b03855116940193818401550161412a565b61416b90846000528584600020918201910161357a565b3861411c565b95949392909160ff61419693168752602087015260a0604087015260a086019061239f565b84810360608601526020808351928381520192019060005b8181106141c9575050509060806103889294019060ff169052565b82516001600160a01b03168452602093840193909201916001016141ae565b600654811015611a975760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f015490565b6001600160401b03610516949381606094168352166020820152816040820152019061041a565b60409061051693928152816020820152019061041a565b9291906001600160401b0390816064951660045216602452600481101561071757604452565b94939261429a6060936142ab938852602088019061071c565b60806040870152608086019061041a565b930152565b906142c282516001600160401b031690565b8151604051632cbc26bb60e01b815267ffffffffffffffff60801b608084901b1660048201529015159391906001600160401b038216906020816024817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa90811561223d576000916149fd575b5061499e57602083019182515194851561496e5760408501805151870361495d5761436487611a42565b957f000000000000000000000000000000000000000000000000000000000000000061439460016116ef87614ea7565b602081519101206040516143f481613d766020820194868b876001600160401b036060929594938160808401977f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f85521660208401521660408201520152565b519020906001600160401b031660005b8a81106148c5575050508060806060614424930151910151908886615436565b9788156148a75760005b8881106144415750505050505050505050565b5a614456614450838a51611a9c565b51615468565b80516060015161446f906001600160401b031688611c31565b6144788161070d565b8015908d8283159384614894575b1561485157606088156147d457506144ad60206144a3898d611a9c565b5101519242611c24565b6004546144c29060a01c63ffffffff16611d5f565b1080156147c1575b156147a3576144d9878b611a9c565b515161478d575b8451608001516144f8906001600160401b0316610638565b6146d5575b50614509868951611a9c565b5160a085015151815103614699579361456e9695938c938f9661454e8e958c9261454861454260608951016001600160401b0390511690565b896154b2565b8661576a565b9a90809661456860608851016001600160401b0390511690565b90615537565b614647575b505061457e8261070d565b600282036145ff575b6001966145f57f05665fe9ad095383d018353f4cbcba77e84db27dd215081bbf7cdf9ae6fbe48b936001600160401b039351926145e66145dd8b6145d560608801516001600160401b031690565b96519b611a9c565b51985a90611c24565b91604051958695169885614281565b0390a45b0161442e565b9150919394925061460f8261070d565b60038203614623578b929493918a91614587565b51606001516349362d1f60e11b600052611e2f91906001600160401b03168961425b565b6146508461070d565b6003840361457357909294955061466891935061070d565b614678578b92918a913880614573565b5151604051632b11b8d960e01b8152908190611dd990879060048401614244565b611e2f8b6146b360608851016001600160401b0390511690565b631cfe6d8b60e01b6000526001600160401b0391821660045216602452604490565b6146de8361070d565b6146e9575b386144fd565b8351608001516001600160401b0316602080860151918c61471e60405194859384936370701e5760e11b85526004850161421d565b038160006001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165af190811561223d5760009161476f575b506146e35750505050506001906145f9565b614787915060203d8111613a2457613a168183610358565b3861475d565b614797878b611a9c565b515160808601526144e0565b6354e7e43160e11b6000526001600160401b038b1660045260246000fd5b506147cb8361070d565b600383146144ca565b9150836147e08461070d565b156144e057506001959450614849925061482791507f3ef2a99c550a751d4b0b261268f05a803dfb049ab43616a1ffb388f61fe651209351016001600160401b0390511690565b604080516001600160401b03808c168252909216602083015290918291820190565b0390a16145f9565b50505050600192915061484961482760607f3b575419319662b2a6f5e2467d84521517a3382b908eb3d557bb3fdb0c50e23c9351016001600160401b0390511690565b5061489e8361070d565b60038314614486565b633ee8bd3f60e11b6000526001600160401b03841660045260246000fd5b6148d0818a51611a9c565b518051604001516001600160401b031683810361494057508051602001516001600160401b031689810361491d57509061490c8460019361532e565b614916828d611a9c565b5201614404565b636c95f1eb60e01b6000526001600160401b03808a166004521660245260446000fd5b631c21951160e11b6000526001600160401b031660045260246000fd5b6357e0e08360e01b60005260046000fd5b611e2f61498286516001600160401b031690565b63676cf24b60e11b6000526001600160401b0316600452602490565b50929150506149e0576040516001600160401b039190911681527faab522ed53d887e56ed53dd37398a01aeef6a58e0fa77c2173beb9512d89493390602090a1565b637edeb53960e11b6000526001600160401b031660045260246000fd5b614a16915060203d602011613a2457613a168183610358565b3861433a565b9081602091031261016757516105168161083c565b90610516916020815260e0614acf614aba614a5a8551610100602087015261012086019061041a565b60208601516001600160401b0316604086015260408601516001600160a01b0316606086015260608601516080860152614aa4608087015160a08701906001600160a01b03169052565b60a0860151858203601f190160c087015261041a565b60c0850151848203601f19018486015261041a565b92015190610100601f198285030191015261041a565b6040906001600160a01b036105169493168152816020820152019061041a565b90816020910312610167575190565b91939293614b20611e8d565b5060208301516001600160a01b031660405163bbe4f6db60e01b81526001600160a01b038216600482015290959092602084806024810103816001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000165afa93841561223d57600094614d9d575b506001600160a01b0384169586158015614d8b575b614d6d57614c52614c7b92613d7692614bd6614bcf611d5f60408c015163ffffffff1690565b8c89615883565b9690996080810151614c046060835193015193614bf16103a8565b9687526001600160401b03166020870152565b6001600160a01b038a16604086015260608501526001600160a01b038d16608085015260a084015260c083015260e0820152604051633907753760e01b602082015292839160248301614a31565b82857f000000000000000000000000000000000000000000000000000000000000000092615911565b94909115614d515750805160208103614d38575090614ca4826020808a95518301019101614b05565b956001600160a01b03841603614cdc575b5050505050614cd4614cc56103b8565b6001600160a01b039093168352565b602082015290565b614cef93614ce991611c24565b91615883565b50908082108015614d25575b614d0757808481614cb5565b63a966e21f60e01b6000908152600493909352602452604452606490fd5b5082614d318284611c24565b1415614cfb565b631e3be00960e21b600052602060045260245260446000fd5b611dd9604051928392634ff17cad60e11b845260048401614ae5565b63ae9b4ce960e01b6000526001600160a01b03851660045260246000fd5b50614d9861226686613523565b614ba9565b614dc091945060203d602011614dc7575b614db88183610358565b810190614a1c565b9238614b94565b503d614dae565b60405160208101916301ffc9a760e01b835263ffffffff60e01b602483015260248252614dfc604483610358565b6179185a10614e38576020926000925191617530fa6000513d82614e2c575b5081614e25575090565b9050151590565b60201115915038614e1b565b63753fa58960e11b60005260046000fd5b60405160208101916301ffc9a760e01b83526301ffc9a760e01b602483015260248252614dfc604483610358565b6040519060208201926301ffc9a760e01b845263ffffffff60e01b16602483015260248252614dfc604483610358565b6001600160401b031680600052600860205260406000209060ff825460a01c1615614ed0575090565b63ed053c5960e01b60005260045260246000fd5b919390926000948051946000965b868810614f03575050505050505050565b6020881015611a975760206000614f1b878b1a613b8c565b614f258b87611a9c565b5190614f5c614f348d8a611a9c565b5160405193849389859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561223d57614fa2613c69600051614f8a8960ff166000526003602052604060002090565b906001600160a01b0316600052602052604060002090565b9060016020830151614fb381613b25565b614fbc81613b25565b0361500957614fd9614fcf835160ff1690565b60ff600191161b90565b8116614ff857614fef614fcf6001935160ff1690565b17970196614ef2565b633d9ef1f160e21b60005260046000fd5b636518c33d60e11b60005260046000fd5b91909160005b83518110156150735760019060ff83166000526003602052600061506c604082206001600160a01b03615053858a611a9c565b51166001600160a01b0316600052602052604060002090565b5501615020565b50509050565b8151815460ff191660ff919091161781559060200151600381101561071757815461ff00191660089190911b61ff0016179055565b919060005b8151811015615073576150d66150c98284611a9c565b516001600160a01b031690565b906150ff6150f583614f8a8860ff166000526003602052604060002090565b5460081c60ff1690565b61510881613b25565b615173576001600160a01b038216156151625761515c60019261515761512c6103b8565b60ff85168152916151408660208501613b2f565b614f8a8960ff166000526003602052604060002090565b615079565b016150b3565b63d6c62c9b60e01b60005260046000fd5b631b3fab5160e11b6000526004805260246000fd5b919060005b8151811015615073576151a36150c98284611a9c565b906151c26150f583614f8a8860ff166000526003602052604060002090565b6151cb81613b25565b615173576001600160a01b03821615615162576152046001926151576151ef6103b8565b60ff8516815291615140600260208501613b2f565b0161518d565b60ff1680600052600260205260ff60016040600020015460101c16908015600014615258575015615247576001600160401b0319600b5416600b55565b6317bd8dd160e11b60005260046000fd5b6001146152625750565b61526857565b6307b8c74d60e51b60005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b8383106152a557505050505090565b9091929394602080600192601f198582030186528851906080806153086152d5855160a0865260a086019061041a565b6001600160a01b0387870151168786015263ffffffff60408701511660408601526060860151858203606087015261041a565b93015191015297019301930191939290615296565b906020610516928181520190615279565b61357481518051906153c261534d60608601516001600160a01b031690565b613d7661536460608501516001600160401b031690565b9361537d6080808a01519201516001600160401b031690565b90604051958694602086019889936001600160401b036080946001600160a01b0382959998949960a089019a8952166020880152166040860152606085015216910152565b519020613d766020840151602081519101209360a06040820151602081519101209101516040516153fb81613d7660208201948561531d565b51902090604051958694602086019889919260a093969594919660c08401976000855260208501526040840152606083015260808201520152565b926001600160401b039261544992615a52565b9116600052600a60205260406000209060005260205260406000205490565b60405160c081018181106001600160401b038211176103025760609160a0916040526154926119e9565b815282602082015282604082015260008382015260006080820152015290565b607f8216906801fffffffffffffffe6001600160401b0383169260011b169180830460021490151715611c1f576138f6916001600160401b036154f58584613238565b921660005260096020526701ffffffffffffff60406000209460071c169160036001831b921b19161792906001600160401b0316600052602052604060002090565b9091607f83166801fffffffffffffffe6001600160401b0382169160011b169080820460021490151715611c1f5761556f8484613238565b6004831015610717576001600160401b036138f69416600052600960205260036701ffffffffffffff60406000209660071c1693831b921b19161792906001600160401b0316600052602052604060002090565b9080602083519182815201916020808360051b8301019401926000915b8383106155ef57505050505090565b909192939460208061560d600193601f19868203018752895161041a565b970193019301919392906155e0565b906020808351928381520192019060005b81811061563a5750505090565b825163ffffffff1684526020938401939092019160010161562d565b9161571f906157116105169593606086526001600160401b0360808251805160608a015282602082015116828a01528260408201511660a08a01528260608201511660c08a015201511660e087015260a06156dd6156c660208401516101406101008b01526101a08a019061041a565b6040840151898203605f19016101208b015261041a565b60608301516001600160a01b03166101408901529160808101516101608901520151868203605f1901610180880152615279565b9084820360208601526155c3565b91604081840391015261561c565b80516020909101516001600160e01b031981169291906004821061574f575050565b6001600160e01b031960049290920360031b82901b16169150565b90303b15610167576000916157936040519485938493630304c3e160e51b855260048501615656565b038183305af1908161586e575b50615863576157ad611f98565b9072c11c11c11c11c11c11c11c11c11c11c11c11c133146157cf575b60039190565b6157e86157db8361572d565b6001600160e01b03191690565b6337c3be2960e01b148015615848575b801561582d575b156157c957611e2f6158108361572d565b632882569d60e01b6000526001600160e01b031916600452602490565b5061583a6157db8361572d565b63753fa58960e11b146157ff565b506158556157db8361572d565b632be8ca8b60e21b146157f8565b6002906105166103e2565b80612302600061587d93610358565b386157a0565b6040516370a0823160e01b60208201526001600160a01b0390911660248201529192916158e0906158b78160448101613d76565b84837f000000000000000000000000000000000000000000000000000000000000000092615911565b92909115614d515750805160208103614d3857509061590b8260208061051695518301019101614b05565b93611c24565b93919361591e60846103c7565b9461592c6040519687610358565b6084865261593a60846103c7565b602087019590601f1901368737833b156159bd575a908082106159ac578291038060061c9003111561599b576000918291825a9560208451940192f1905a9003923d9060848211615992575b6000908287523e929190565b60849150615986565b6337c3be2960e01b60005260046000fd5b632be8ca8b60e21b60005260046000fd5b63030ed58f60e21b60005260046000fd5b80600052600760205260406000205415600014615a4c576006546801000000000000000081101561030257600181016006556000600654821015611a9757600690527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01819055600654906000526007602052604060002055600190565b50600090565b8051928251908415615bae5761010185111580615ba2575b15615ad157818501946000198601956101008711615ad1578615615b9257615a9187611a42565b9660009586978795885b848110615af6575050505050600119018095149384615aec575b505082615ae2575b505015615ad157615acd91611a9c565b5190565b6309bde33960e01b60005260046000fd5b1490503880615abd565b1492503880615ab5565b6001811b82811603615b8457868a1015615b6f57615b1860018b019a85611a9c565b51905b8c888c1015615b5b5750615b3360018c019b86611a9c565b515b818d11615ad157615b54828f92615b4e90600196615bbf565b92611a9c565b5201615a9b565b60018d019c615b6991611a9c565b51615b35565b615b7d60018c019b8d611a9c565b5190615b1b565b615b7d600189019884611a9c565b505050509050615acd9150611a8a565b50610101821115615a6a565b630469ac9960e21b60005260046000fd5b81811015615bd1579061051691615bd6565b610516915b9060405190602082019260018452604083015260608201526060815261357460808261035856fea164736f6c634300081a000abd1ab25a0ff0a36a588597ba1af11e30f3f210de8b9e818cc9bbc457c94c8d8c00000000000000000000000000000000000000000000000048810ec3e431431f00000000000000000000000000000000000000000000000000000000000013880000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e0000000000000000000000009a5181c93138fdf1463ad18945780067d177e9830000000000000000000000003491f985053d33aacdb4446bf3b1f0f9c719951c000000000000000000000000945d9845bc14a5e4ff64457bb6770aac028ced390000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806306285c6914610157578063181f5a77146101525780633f4b04aa1461014d5780635215505b146101485780635e36480c146101435780635e7bb0081461013e57806360987c20146101395780636f9e320f146101345780637437ff9f1461012f57806379ba50971461012a57806385572ffb146101255780638da5cb5b14610120578063c673e5841461011b578063ccd37ba314610116578063cd19723714610111578063de5e0b9a1461010c578063e9d68a8e14610107578063f2fde38b14610102578063f58e03fc146100fd5763f716f99f146100f857600080fd5b6118ae565b611791565b611706565b611661565b6115c5565b611467565b611408565b611343565b61125b565b611225565b6111a5565b611105565b610f90565b610f15565b610d0e565b610729565b6105ba565b61049e565b61043f565b61016c565b600091031261016757565b600080fd5b34610167576000366003190112610167576101856119e9565b506102cd604051610195816102e7565b6001600160401b037f00000000000000000000000000000000000000000000000048810ec3e431431f16815261ffff7f00000000000000000000000000000000000000000000000000000000000013881660208201526001600160a01b037f0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e1660408201526001600160a01b037f0000000000000000000000009a5181c93138fdf1463ad18945780067d177e9831660608201526001600160a01b037f0000000000000000000000003491f985053d33aacdb4446bf3b1f0f9c719951c1660808201526040519182918291909160806001600160a01b038160a08401956001600160401b03815116855261ffff6020820151166020860152826040820151166040860152826060820151166060860152015116910152565b0390f35b634e487b7160e01b600052604160045260246000fd5b60a081019081106001600160401b0382111761030257604052565b6102d1565b604081019081106001600160401b0382111761030257604052565b606081019081106001600160401b0382111761030257604052565b608081019081106001600160401b0382111761030257604052565b90601f801991011681019081106001600160401b0382111761030257604052565b6040519061038860c083610358565b565b6040519061038860a083610358565b60405190610388608083610358565b6040519061038861010083610358565b60405190610388604083610358565b6001600160401b03811161030257601f01601f191660200190565b604051906103f1602083610358565b60008252565b60005b83811061040a5750506000910152565b81810151838201526020016103fa565b90602091610433815180928185528580860191016103f7565b601f01601f1916010190565b34610167576000366003190112610167576102cd60408051906104628183610358565b600d82527f4f666652616d7020312e362e300000000000000000000000000000000000000060208301525191829160208352602083019061041a565b346101675760003660031901126101675760206001600160401b03600b5416604051908152f35b9060a06080610516936001600160a01b0381511684526020810151151560208501526001600160401b036040820151166040850152606081015115156060850152015191816080820152019061041a565b90565b6040810160408252825180915260206060830193019060005b81811061059b575050506020818303910152815180825260208201916020808360051b8301019401926000915b83831061056e57505050505090565b909192939460208061058c600193601f1986820301875289516104c5565b9701930193019193929061055f565b82516001600160401b0316855260209485019490920191600101610532565b34610167576000366003190112610167576006546105d781610771565b906105e56040519283610358565b808252601f196105f482610771565b0160005b8181106106b657505061060a81611a42565b9060005b8181106106265750506102cd60405192839283610519565b8061065c6106446106386001946141e8565b6001600160401b031690565b61064e8387611a9c565b906001600160401b03169052565b61069a61069561067c61066f8488611a9c565b516001600160401b031690565b6001600160401b03166000526008602052604060002090565b611b88565b6106a48287611a9c565b526106af8186611a9c565b500161060e565b6020906106c1611a14565b828287010152016105f8565b600435906001600160401b038216820361016757565b35906001600160401b038216820361016757565b634e487b7160e01b600052602160045260246000fd5b6004111561071757565b6106f7565b9060048210156107175752565b34610167576040366003190112610167576107426106cd565b602435906001600160401b03821682036101675760209161076291611c31565b61076f604051809261071c565bf35b6001600160401b0381116103025760051b60200190565b91908260a0910312610167576040516107a0816102e7565b60806107e5818395803585526107b8602082016106e3565b60208601526107c9604082016106e3565b60408601526107da606082016106e3565b6060860152016106e3565b910152565b9291926107f6826103c7565b916108046040519384610358565b829481845281830111610167578281602093846000960137010152565b9080601f8301121561016757816020610516933591016107ea565b6001600160a01b0381160361016757565b35906103888261083c565b63ffffffff81160361016757565b359061038882610858565b81601f820112156101675780359061088882610771565b926108966040519485610358565b82845260208085019360051b830101918183116101675760208101935b8385106108c257505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757604051916108ef836102e7565b60208201356001600160401b0381116101675785602061091192850101610821565b835260408201356109218161083c565b602084015261093260608301610866565b60408401526080820135926001600160401b0384116101675760a08361095f886020809881980101610821565b6060840152013560808201528152019401936108b3565b919091610140818403126101675761098c610379565b926109978183610788565b845260a08201356001600160401b03811161016757816109b8918401610821565b602085015260c08201356001600160401b03811161016757816109dc918401610821565b60408501526109ed60e0830161084d565b606085015261010082013560808501526101208201356001600160401b03811161016757610a1b9201610871565b60a0830152565b9080601f83011215610167578135610a3981610771565b92610a476040519485610358565b81845260208085019260051b820101918383116101675760208201905b838210610a7357505050505090565b81356001600160401b03811161016757602091610a9587848094880101610976565b815201910190610a64565b81601f8201121561016757803590610ab782610771565b92610ac56040519485610358565b82845260208085019360051b830101918183116101675760208101935b838510610af157505050505090565b84356001600160401b03811161016757820183603f82011215610167576020810135610b1c81610771565b91610b2a6040519384610358565b8183526020808085019360051b83010101918683116101675760408201905b838210610b63575050509082525060209485019401610ae2565b81356001600160401b03811161016757602091610b878a8480809589010101610821565b815201910190610b49565b929190610b9e81610771565b93610bac6040519586610358565b602085838152019160051b810192831161016757905b828210610bce57505050565b8135815260209182019101610bc2565b9080601f830112156101675781602061051693359101610b92565b81601f8201121561016757803590610c1082610771565b92610c1e6040519485610358565b82845260208085019360051b830101918183116101675760208101935b838510610c4a57505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757610c7261038a565b91610c7f602083016106e3565b835260408201356001600160401b03811161016757856020610ca392850101610a22565b602084015260608201356001600160401b03811161016757856020610cca92850101610aa0565b60408401526080820135926001600160401b0384116101675760a083610cf7886020809881980101610bde565b606084015201356080820152815201940193610c3b565b34610167576040366003190112610167576004356001600160401b03811161016757610d3e903690600401610bf9565b6024356001600160401b038111610167573660238201121561016757806004013591610d6983610771565b91610d776040519384610358565b8383526024602084019460051b820101903682116101675760248101945b828610610da857610da68585611c79565b005b85356001600160401b03811161016757820136604382011215610167576024810135610dd381610771565b91610de16040519384610358565b818352602060248185019360051b83010101903682116101675760448101925b828410610e1b575050509082525060209586019501610d95565b83356001600160401b038111610167576024908301016040601f1982360301126101675760405190610e4c82610307565b6020810135825260408101356001600160401b03811161016757602091010136601f8201121561016757803590610e8282610771565b91610e906040519384610358565b80835260208084019160051b8301019136831161016757602001905b828210610ecb5750505091816020938480940152815201930192610e01565b602080918335610eda81610858565b815201910190610eac565b9181601f84011215610167578235916001600160401b038311610167576020808501948460051b01011161016757565b34610167576060366003190112610167576004356001600160401b03811161016757610f45903690600401610976565b6024356001600160401b03811161016757610f64903690600401610ee5565b91604435926001600160401b03841161016757610f88610da6943690600401610ee5565b939092612089565b34610167576060366003190112610167576000604051610faf81610322565b600435610fbb8161083c565b8152602435610fc981610858565b6020820190815260443590610fdd8261083c565b60408301918252610fec613534565b6001600160a01b03835116156110f657916110b86001600160a01b036110f0937fa1c15688cb2c24508e158f6942b9276c6f3028a85e1af8cf3fff0c3ff3d5fc8d95611051838651166001600160a01b03166001600160a01b03196004541617600455565b517fffffffffffffffff00000000ffffffffffffffffffffffffffffffffffffffff77ffffffff00000000000000000000000000000000000000006004549260a01b1691161760045551166001600160a01b03166001600160a01b03196005541617600555565b6040519182918291909160406001600160a01b0381606084019582815116855263ffffffff6020820151166020860152015116910152565b0390a180f35b6342bcdf7f60e11b8452600484fd5b346101675760003660031901126101675760006040805161112581610322565b82815282602082015201526102cd60405161113f81610322565b63ffffffff6004546001600160a01b038116835260a01c1660208201526001600160a01b036005541660408201526040519182918291909160406001600160a01b0381606084019582815116855263ffffffff6020820151166020860152015116910152565b34610167576000366003190112610167576000546001600160a01b0381163303611214576001600160a01b0319600154913382841617600155166000556001600160a01b033391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b63015aa1e360e11b60005260046000fd5b34610167576020366003190112610167576004356001600160401b0381116101675760a090600319903603011261016757600080fd5b346101675760003660031901126101675760206001600160a01b0360015416604051908152f35b6004359060ff8216820361016757565b359060ff8216820361016757565b906020808351928381520192019060005b8181106112be5750505090565b82516001600160a01b03168452602093840193909201916001016112b1565b906105169160208152606082518051602084015260ff602082015116604084015260ff60408201511682840152015115156080820152604061132e602084015160c060a085015260e08401906112a0565b9201519060c0601f19828503019101526112a0565b346101675760203660031901126101675760ff61135e611282565b60606040805161136d81610322565b81516113788161033d565b6000815260006020820152600083820152600084820152815282602082015201521660005260026020526102cd604060002060036113f7604051926113bc84610322565b6113c581612366565b84526040516113e2816113db816002860161239f565b0382610358565b60208501526113db604051809481930161239f565b6040820152604051918291826112dd565b34610167576040366003190112610167576114216106cd565b6001600160401b036024359116600052600a6020526040600020906000526020526020604060002054604051908152f35b8015150361016757565b359061038882611452565b34610167576020366003190112610167576004356001600160401b0381116101675736602382011215610167578060040135906114a382610771565b906114b16040519283610358565b8282526024602083019360051b820101903682116101675760248101935b8285106114df57610da6846123f6565b84356001600160401b03811161016757820160a06023198236030112610167576040519161150c836102e7565b602482013561151a8161083c565b8352611528604483016106e3565b6020840152606482013561153b81611452565b6040840152608482013561154e81611452565b606084015260a4820135926001600160401b0384116101675761157b602094936024869536920101610821565b60808201528152019401936114cf565b9060049160441161016757565b9181601f84011215610167578235916001600160401b038311610167576020838186019501011161016757565b346101675760c0366003190112610167576115df3661158b565b6044356001600160401b038111610167576115fe903690600401611598565b6064929192356001600160401b03811161016757611620903690600401610ee5565b60843594916001600160401b03861161016757611644610da6963690600401610ee5565b94909360a43596612cb9565b9060206105169281815201906104c5565b34610167576020366003190112610167576001600160401b036116826106cd565b61168a611a14565b501660005260086020526102cd60406000206116f56001604051926116ae846102e7565b6116ef60ff82546001600160a01b0381168752818160a01c16151560208801526001600160401b038160a81c16604088015260e81c16606086019015159052565b01611b6d565b608082015260405191829182611650565b34610167576020366003190112610167576001600160a01b0360043561172b8161083c565b611733613534565b1633811461178057806001600160a01b031960005416176000556001600160a01b03600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278600080a3005b636d6c4ee560e11b60005260046000fd5b34610167576060366003190112610167576117ab3661158b565b6044356001600160401b038111610167576117ca903690600401611598565b91828201602083820312610167578235906001600160401b038211610167576117f4918401610bf9565b6040519060206118048184610358565b60008352601f19810160005b81811061183857505050610da69491611828916132bf565b611830612f33565b928392613bb0565b60608582018401528201611810565b9080601f8301121561016757813561185e81610771565b9261186c6040519485610358565b81845260208085019260051b82010192831161016757602001905b8282106118945750505090565b6020809183356118a38161083c565b815201910190611887565b34610167576020366003190112610167576004356001600160401b0381116101675736602382011215610167578060040135906118ea82610771565b906118f86040519283610358565b8282526024602083019360051b820101903682116101675760248101935b82851061192657610da684612f4f565b84356001600160401b03811161016757820160c060231982360301126101675761194e610379565b916024820135835261196260448301611292565b602084015261197360648301611292565b60408401526119846084830161145c565b606084015260a48201356001600160401b038111610167576119ac9060243691850101611847565b608084015260c4820135926001600160401b038411610167576119d9602094936024869536920101611847565b60a0820152815201940193611916565b604051906119f6826102e7565b60006080838281528260208201528260408201528260608201520152565b60405190611a21826102e7565b60606080836000815260006020820152600060408201526000838201520152565b90611a4c82610771565b611a596040519182610358565b8281528092611a6a601f1991610771565b0190602036910137565b634e487b7160e01b600052603260045260246000fd5b805115611a975760200190565b611a74565b8051821015611a975760209160051b010190565b90600182811c92168015611ae0575b6020831014611aca57565b634e487b7160e01b600052602260045260246000fd5b91607f1691611abf565b60009291815491611afa83611ab0565b8083529260018116908115611b505750600114611b1657505050565b60009081526020812093945091925b838310611b36575060209250010190565b600181602092949394548385870101520191019190611b25565b915050602093945060ff929192191683830152151560051b010190565b90610388611b819260405193848092611aea565b0383610358565b9060016080604051611b99816102e7565b611bef819560ff81546001600160a01b0381168552818160a01c16151560208601526001600160401b038160a81c16604086015260e81c1615156060840152611be86040518096819301611aea565b0384610358565b0152565b634e487b7160e01b600052601160045260246000fd5b908160051b9180830460201490151715611c1f57565b611bf3565b91908203918211611c1f57565b611c3d82607f92613238565b9116906801fffffffffffffffe6001600160401b0383169260011b169180830460021490151715611c1f576003911c1660048110156107175790565b611c8161327c565b805182518103611e7c5760005b818110611ca157505090610388916132bf565b611cab8184611a9c565b516020810190815151611cbe8488611a9c565b519283518203611e7c5790916000925b808410611ce2575050505050600101611c8e565b91949398611cf4848b98939598611a9c565b515198611d02888851611a9c565b519980611e33575b5060a08a01988b6020611d208b8d515193611a9c565b5101515103611df25760005b8a5151811015611ddd57611d68611d5f611d558f6020611d4d8f8793611a9c565b510151611a9c565b5163ffffffff1690565b63ffffffff1690565b8b81611d79575b5050600101611d2c565b611d5f6040611d8c85611d989451611a9c565b51015163ffffffff1690565b90818110611da757508b611d6f565b8d51516040516348e617b360e01b81526004810191909152602481019390935260448301919091526064820152608490fd5b0390fd5b50985098509893949095600101929091611cce565b611e2f8b51611e0d606082519201516001600160401b031690565b6370a193fd60e01b6000526004919091526001600160401b0316602452604490565b6000fd5b60808b0151811015611d0a57611e2f908b611e5588516001600160401b031690565b905151633a98d46360e11b6000526001600160401b03909116600452602452604452606490565b6320f8fd5960e21b60005260046000fd5b60405190611e9a82610307565b60006020838281520152565b60405190611eb5602083610358565b600080835282815b828110611ec957505050565b602090611ed4611e8d565b82828501015201611ebd565b805182526001600160401b0360208201511660208301526080611f27611f15604084015160a0604087015260a086019061041a565b6060840151858203606087015261041a565b9101519160808183039101526020808351928381520192019060005b818110611f505750505090565b825180516001600160a01b031685526020908101518186015260409094019390920191600101611f43565b906020610516928181520190611ee0565b6040513d6000823e3d90fd5b3d15611fc3573d90611fa9826103c7565b91611fb76040519384610358565b82523d6000602084013e565b606090565b90602061051692818152019061041a565b9091606082840312610167578151611ff081611452565b9260208301516001600160401b0381116101675783019080601f830112156101675781519161201e836103c7565b9161202c6040519384610358565b838352602084830101116101675760409261204d91602080850191016103f7565b92015190565b9293606092959461ffff6120776001600160a01b0394608088526080880190611ee0565b97166020860152604085015216910152565b929093913033036123555761209c611ea6565b9460a0850151805161230e575b50505050508051916120c7602084519401516001600160401b031690565b9060208301519160408401926120f48451926120e161038a565b9788526001600160401b03166020880152565b6040860152606085015260808401526001600160a01b0361211d6005546001600160a01b031690565b1680612291575b5051511580612285575b801561226f575b8015612246575b612242576121da918161217f61217361216661067c602060009751016001600160401b0390511690565b546001600160a01b031690565b6001600160a01b031690565b908361219a606060808401519301516001600160a01b031690565b604051633cf9798360e01b815296879586948593917f00000000000000000000000000000000000000000000000000000000000013889060048601612053565b03925af190811561223d57600090600092612216575b50156121f95750565b6040516302a35ba360e21b8152908190611dd99060048301611fc8565b905061223591503d806000833e61222d8183610358565b810190611fd9565b5090386121f0565b611f8c565b5050565b5061226a61226661226160608401516001600160a01b031690565b6134e6565b1590565b61213c565b5060608101516001600160a01b03163b15612135565b5060808101511561212e565b803b1561016757600060405180926308d450a160e01b82528183816122b98a60048301611f7b565b03925af190816122f3575b506122ed57611dd96122d4611f98565b6040516309c2532560e01b815291829160048301611fc8565b38612124565b80612302600061230893610358565b8061015c565b386122c4565b859650602061234a96015161232d60608901516001600160a01b031690565b9061234460208a51016001600160401b0390511690565b926133cd565b9038808080806120a9565b6306e34e6560e31b60005260046000fd5b906040516123738161033d565b606060ff600183958054855201548181166020850152818160081c16604085015260101c161515910152565b906020825491828152019160005260206000209060005b8181106123c35750505090565b82546001600160a01b03168452602090930192600192830192016123b6565b90610388611b81926040519384809261239f565b6123fe613534565b60005b8151811015612242576124148183611a9c565b519061242a60208301516001600160401b031690565b6001600160401b0381169081156126c05761245261217361217386516001600160a01b031690565b1561262b57612474816001600160401b03166000526008602052604060002090565b60808501519060018101926124898454611ab0565b612652576124fc7ff4c1390c70e5c0f491ae1ccbc06f9117cbbadf2767b247b3bc203280f24c0fb9916124e284750100000000000000000000000000000000000000000067ffffffffffffffff60a81b19825416179055565b6040516001600160401b0390911681529081906020820190565b0390a15b8151801590811561263c575b5061262b5761260c6125d7606060019861254a612622967fbd1ab25a0ff0a36a588597ba1af11e30f3f210de8b9e818cc9bbc457c94c8d8c986135d6565b6125a061255a6040830151151590565b86547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff1690151560a01b74ff000000000000000000000000000000000000000016178655565b6125d06125b482516001600160a01b031690565b86906001600160a01b03166001600160a01b0319825416179055565b0151151590565b82547fffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff1690151560e81b60ff60e81b16178255565b612615846159ce565b50604051918291826136a7565b0390a201612401565b6342bcdf7f60e11b60005260046000fd5b9050602083012061264b613559565b143861250c565b60016001600160401b0361267184546001600160401b039060a81c1690565b161415806126a1575b6126845750612500565b632105803760e11b6000526001600160401b031660045260246000fd5b506126ab84611b6d565b6020815191012083516020850120141561267a565b63c656089560e01b60005260046000fd5b35906001600160e01b038216820361016757565b81601f82011215610167578035906126fc82610771565b9261270a6040519485610358565b82845260208085019360061b8301019181831161016757602001925b828410612734575050505090565b604084830312610167576020604091825161274e81610307565b612757876106e3565b81526127648388016126d1565b83820152815201930192612726565b9190604083820312610167576040519061278c82610307565b819380356001600160401b03811161016757810182601f820112156101675780356127b681610771565b916127c46040519384610358565b81835260208084019260061b8201019085821161016757602001915b81831061280d5750505083526020810135916001600160401b038311610167576020926107e592016126e5565b604083870312610167576020604091825161282781610307565b85356128328161083c565b815261283f8387016126d1565b838201528152019201916127e0565b81601f820112156101675780359061286582610771565b926128736040519485610358565b82845260208085019360051b830101918183116101675760208101935b83851061289f57505050505090565b84356001600160401b03811161016757820160a0818503601f19011261016757604051916128cc836102e7565b6128d8602083016106e3565b83526040820135926001600160401b0384116101675760a083612902886020809881980101610821565b85840152612912606082016106e3565b6040840152612923608082016106e3565b606084015201356080820152815201940193612890565b81601f820112156101675780359061295182610771565b9261295f6040519485610358565b82845260208085019360061b8301019181831161016757602001925b828410612989575050505090565b60408483031261016757602060409182516129a381610307565b86358152828701358382015281520193019261297b565b602081830312610167578035906001600160401b0382116101675701608081830312610167576129e8610399565b9181356001600160401b0381116101675781612a05918401612773565b835260208201356001600160401b0381116101675781612a2691840161284e565b602084015260408201356001600160401b0381116101675781612a4a91840161284e565b604084015260608201356001600160401b03811161016757612a6c920161293a565b606082015290565b9080602083519182815201916020808360051b8301019401926000915b838310612aa057505050505090565b9091929394602080600192601f198582030186528851906001600160401b038251168152608080612ade8585015160a08786015260a085019061041a565b936001600160401b0360408201511660408501526001600160401b036060820151166060850152015191015297019301930191939290612a91565b916001600160a01b03612b3a92168352606060208401526060830190612a74565b9060408183039101526020808351928381520192019060005b818110612b605750505090565b8251805185526020908101518186015260409094019390920191600101612b53565b6084019081608411611c1f57565b60a001908160a011611c1f57565b91908201809211611c1f57565b906020808351928381520192019060005b818110612bc95750505090565b825180516001600160401b031685526020908101516001600160e01b03168186015260409094019390920191600101612bbc565b9190604081019083519160408252825180915260206060830193019060005b818110612c3d57505050602061051693940151906020818403910152612bab565b825180516001600160a01b031686526020908101516001600160e01b03168187015260409095019490920191600101612c1c565b906020610516928181520190612bfd565b91612cab90612c9d6105169593606086526060860190612a74565b908482036020860152612a74565b916040818403910152612bfd565b9197939796929695909495612cd0818701876129ba565b95602087019788518051612eb3575b5087518051511590811591612ea4575b50612dbf575b60005b89518051821015612d1f5790612d19612d1382600194611a9c565b51613757565b01612cf8565b50509193959799989092949698600099604081019a5b8b518051821015612d5c5790612d56612d5082600194611a9c565b51613a2b565b01612d35565b5050907fb967c9b9e1b7af9a61ca71ff00e9f5b89ec6f2e268de8dacf12f0de8e51f3e47612db193926103889c612da7612db998999a9b9c9d9f519151925160405193849384612c82565b0390a13691610b92565b943691610b92565b93613eaa565b612dd4602086015b356001600160401b031690565b600b546001600160401b0382811691161015612e7c57612e0a906001600160401b03166001600160401b0319600b541617600b55565b612e226121736121736004546001600160a01b031690565b885190803b1561016757604051633937306f60e01b8152916000918391829084908290612e529060048301612c71565b03925af1801561223d57612e67575b50612cf5565b806123026000612e7693610358565b38612e61565b50612e8f89515160408a01515190612b9e565b612cf557632261116760e01b60005260046000fd5b60209150015151151538612cef565b6001600160a01b037f0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e169060608a0151823b1561016757604051633854844f60e11b815292600092849283918291612f0f913060048501612b19565b03915afa801561223d5715612cdf57806123026000612f2d93610358565b38612cdf565b60405190612f42602083610358565b6000808352366020840137565b612f57613534565b60005b815181101561224257612f6d8183611a9c565b51906040820160ff612f80825160ff1690565b161561322257602083015160ff1692612fa68460ff166000526002602052604060002090565b9160018301918254612fc1612fbb8260ff1690565b60ff1690565b6131e75750612fee612fd66060830151151590565b845462ff0000191690151560101b62ff000016178455565b60a0810191825161010081511161318f578051156131d1576003860161301c613016826123e2565b8a61501a565b60608401516130ac575b947fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547946002946130886130786130a69a966130718760019f9c61306c61309e9a8f615188565b6140eb565b5160ff1690565b845460ff191660ff821617909455565b5190818555519060405195869501908886614171565b0390a161520a565b01612f5a565b979460028793959701966130c86130c2896123e2565b8861501a565b6080850151946101008651116131bb5785516130f0612fbb6130eb8a5160ff1690565b6140d7565b10156131a557855184511161318f576130886130787fab8b1b57514019638d7b5ce9c638fe71366fe8e2be1c40a7a80f1733d0e9f547986130718760019f61306c6130a69f9a8f61317760029f61317161309e9f8f9061306c8492613156845160ff1690565b908054909161ff001990911660089190911b61ff0016179055565b826150ae565b505050979c9f50975050969a50505094509450613026565b631b3fab5160e11b600052600160045260246000fd5b631b3fab5160e11b600052600360045260246000fd5b631b3fab5160e11b600052600260045260246000fd5b631b3fab5160e11b600052600560045260246000fd5b60101c60ff166132026131fd6060840151151590565b151590565b90151514612fee576321fd80df60e21b60005260ff861660045260246000fd5b631b3fab5160e11b600090815260045260246000fd5b906001600160401b03613278921660005260096020526701ffffffffffffff60406000209160071c166001600160401b0316600052602052604060002090565b5490565b7f0000000000000000000000000000000000000000000000000000000000aa37dc4681036132a75750565b630f01ce8560e01b6000526004524660245260446000fd5b9190918051156133615782511592602091604051926132de8185610358565b60008452601f19810160005b81811061333d5750505060005b8151811015613335578061331e61331060019385611a9c565b5188156133245786906142b0565b016132f7565b61332e8387611a9c565b51906142b0565b505050509050565b829060405161334b81610307565b60008152606083820152828289010152016132ea565b63c2e5347d60e01b60005260046000fd5b9190811015611a975760051b0190565b3561051681610858565b9190811015611a975760051b81013590601e19813603018212156101675701908135916001600160401b038311610167576020018236038113610167579190565b909294919397968151966133e088610771565b976133ee604051998a610358565b8089526133fd601f1991610771565b0160005b8181106134cf57505060005b83518110156134c257806134548c8a8a8a61344e613447878d613440828f8f9d8f9e60019f81613470575b505050611a9c565b519761338c565b36916107ea565b93614b14565b61345e828c611a9c565b52613469818b611a9c565b500161340d565b63ffffffff613488613483858585613372565b613382565b1615613438576134b89261349f9261348392613372565b60406134ab8585611a9c565b51019063ffffffff169052565b8f8f908391613438565b5096985050505050505050565b6020906134da611e8d565b82828d01015201613401565b6134f76385572ffb60e01b82614e77565b9081613511575b81613507575090565b6105169150614e49565b905061351c81614dce565b15906134fe565b6134f763aff2afbf60e01b82614e77565b6001600160a01b0360015416330361354857565b6315ae3a6f60e11b60005260046000fd5b60405160208101906000825260208152613574604082610358565b51902090565b818110613585575050565b6000815560010161357a565b9190601f81116135a057505050565b610388926000526020600020906020601f840160051c830193106135cc575b601f0160051c019061357a565b90915081906135bf565b91909182516001600160401b038111610302576135fd816135f78454611ab0565b84613591565b6020601f821160011461363e57819061362f939495600092613633575b50508160011b916000199060031b1c19161790565b9055565b01519050388061361a565b601f1982169061365384600052602060002090565b9160005b81811061368f57509583600195969710613676575b505050811b019055565b015160001960f88460031b161c1916905538808061366c565b9192602060018192868b015181550194019201613657565b90600160c0610516936020815260ff84546001600160a01b0381166020840152818160a01c16151560408401526001600160401b038160a81c16606084015260e81c161515608082015260a080820152019101611aea565b90816020910312610167575161051681611452565b909161372b6105169360408452604084019061041a565b916020818403910152611aea565b6001600160401b036001911601906001600160401b038211611c1f57565b8051604051632cbc26bb60e01b815267ffffffffffffffff60801b608083901b1660048201526001600160401b0390911691906020816024817f0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e6001600160a01b03165afa90811561223d576000916139fc575b506139de576137d982614ea7565b805460ff60e882901c1615156001146139b3576020830180516020815191012090600184019161380883611b6d565b602081519101200361399657505060408301516001600160401b039081169160a81c16811480159061396e575b61392d5750608082015191821561391c5761387683613867866001600160401b0316600052600a602052604060002090565b90600052602052604060002090565b546138f9576138f6929161389f61389a60606138d89401516001600160401b031690565b613739565b67ffffffffffffffff60a81b197cffffffffffffffff00000000000000000000000000000000000000000083549260a81b169116179055565b61386742936001600160401b0316600052600a602052604060002090565b55565b6332cf0cbf60e01b6000526001600160401b038416600452602483905260446000fd5b63504570e360e01b60005260046000fd5b83611e2f9161394660608601516001600160401b031690565b636af0786b60e11b6000526001600160401b0392831660045290821660245216604452606490565b5061398661063860608501516001600160401b031690565b6001600160401b03821611613835565b51611dd960405192839263b80d8fa960e01b845260048401613714565b60808301516348e2b93360e11b6000526001600160401b038516600452602452600160445260646000fd5b637edeb53960e11b6000526001600160401b03821660045260246000fd5b613a1e915060203d602011613a24575b613a168183610358565b8101906136ff565b386137cb565b503d613a0c565b8051604051632cbc26bb60e01b815267ffffffffffffffff60801b608083901b1660048201526001600160401b0390911691906020816024817f0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e6001600160a01b03165afa90811561223d57600091613b06575b506139de57613aad82614ea7565b805460ff60e882901c1615613ad8576020830180516020815191012090600184019161380883611b6d565b60808301516348e2b93360e11b60009081526001600160401b03861660045260249190915260445260646000fd5b613b1f915060203d602011613a2457613a168183610358565b38613a9f565b6003111561071757565b60038210156107175752565b90610388604051613b4b81610307565b602060ff829554818116845260081c169101613b2f565b8054821015611a975760005260206000200190600090565b60ff60019116019060ff8211611c1f57565b60ff601b9116019060ff8211611c1f57565b90606092604091835260208301370190565b6001600052600260205293613be47fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e0612366565b93853594613bf185612b82565b6060820190613c008251151590565b613e7c575b803603613e6457508151878103613e4b5750613c1f61327c565b60016000526003602052613c6e613c697fa15bc60c955c405d20d9149c709e2460f1c2d9a497496a7f46004d1772c3054c5b336001600160a01b0316600052602052604060002090565b613b3b565b60026020820151613c7e81613b25565b613c8781613b25565b149081613de3575b5015613db7575b51613cee575b50505050507f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef090613cd2612dc760019460200190565b604080519283526001600160401b0391909116602083015290a2565b613d0f612fbb613d0a602085969799989a955194015160ff1690565b613b7a565b03613da6578151835103613d9557613d8d6000613cd294612dc794613d597f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef09960019b36916107ea565b60208151910120604051613d8481613d7689602083019586613b9e565b03601f198101835282610358565b5190208a614ee4565b948394613c9c565b63a75d88af60e01b60005260046000fd5b6371253a2560e01b60005260046000fd5b72c11c11c11c11c11c11c11c11c11c11c11c11c1330315613c9657631b41e11d60e31b60005260046000fd5b60016000526002602052613e43915061217390613e3090613e2a60037fe90b7bceb6e7df5418fb78d8ee546e97c83a08bbccc01a0644d599ccd2a7c2e05b01915160ff1690565b90613b62565b90546001600160a01b039160031b1c1690565b331438613c8f565b6324f7d61360e21b600052600452602487905260446000fd5b638e1192e160e01b6000526004523660245260446000fd5b613ea590613e9f613e95613e908751611c09565b612b90565b613e9f8851611c09565b90612b9e565b613c05565b60008052600260205294909390929091613ee37fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b612366565b94863595613ef083612b82565b6060820190613eff8251151590565b6140b4575b803603613e645750815188810361409b5750613f1e61327c565b600080526003602052613f53613c697f3617319a054d772f909f7c479a2cebe5066e836a939412e32403c99029b92eff613c51565b60026020820151613f6381613b25565b613f6c81613b25565b149081614052575b5015614026575b51613fb8575b5050505050507f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef090613cd2612dc760009460200190565b613fd4612fbb613d0a602087989a999b96975194015160ff1690565b03613da6578351865103613d95576000967f198d6990ef96613a9026203077e422916918b03ff47f0be6bee7b02d8e139ef096613cd295613d5961401d94612dc79736916107ea565b94839438613f81565b72c11c11c11c11c11c11c11c11c11c11c11c11c1330315613f7b57631b41e11d60e31b60005260046000fd5b600080526002602052614093915061217390613e3090613e2a60037fac33ff75c19e70fe83507db0d683fd3465c996598dc972688b7ace676c89077b613e21565b331438613f74565b6324f7d61360e21b600052600452602488905260446000fd5b6140d290613e9f6140c8613e908951611c09565b613e9f8a51611c09565b613f04565b60ff166003029060ff8216918203611c1f57565b8151916001600160401b03831161030257680100000000000000008311610302576020908254848455808510614154575b500190600052602060002060005b8381106141375750505050565b60019060206001600160a01b03855116940193818401550161412a565b61416b90846000528584600020918201910161357a565b3861411c565b95949392909160ff61419693168752602087015260a0604087015260a086019061239f565b84810360608601526020808351928381520192019060005b8181106141c9575050509060806103889294019060ff169052565b82516001600160a01b03168452602093840193909201916001016141ae565b600654811015611a975760066000527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f015490565b6001600160401b03610516949381606094168352166020820152816040820152019061041a565b60409061051693928152816020820152019061041a565b9291906001600160401b0390816064951660045216602452600481101561071757604452565b94939261429a6060936142ab938852602088019061071c565b60806040870152608086019061041a565b930152565b906142c282516001600160401b031690565b8151604051632cbc26bb60e01b815267ffffffffffffffff60801b608084901b1660048201529015159391906001600160401b038216906020816024817f0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e6001600160a01b03165afa90811561223d576000916149fd575b5061499e57602083019182515194851561496e5760408501805151870361495d5761436487611a42565b957f00000000000000000000000000000000000000000000000048810ec3e431431f61439460016116ef87614ea7565b602081519101206040516143f481613d766020820194868b876001600160401b036060929594938160808401977f2425b0b9f9054c76ff151b0a175b18f37a4a4e82013a72e9f15c9caa095ed21f85521660208401521660408201520152565b519020906001600160401b031660005b8a81106148c5575050508060806060614424930151910151908886615436565b9788156148a75760005b8881106144415750505050505050505050565b5a614456614450838a51611a9c565b51615468565b80516060015161446f906001600160401b031688611c31565b6144788161070d565b8015908d8283159384614894575b1561485157606088156147d457506144ad60206144a3898d611a9c565b5101519242611c24565b6004546144c29060a01c63ffffffff16611d5f565b1080156147c1575b156147a3576144d9878b611a9c565b515161478d575b8451608001516144f8906001600160401b0316610638565b6146d5575b50614509868951611a9c565b5160a085015151815103614699579361456e9695938c938f9661454e8e958c9261454861454260608951016001600160401b0390511690565b896154b2565b8661576a565b9a90809661456860608851016001600160401b0390511690565b90615537565b614647575b505061457e8261070d565b600282036145ff575b6001966145f57f05665fe9ad095383d018353f4cbcba77e84db27dd215081bbf7cdf9ae6fbe48b936001600160401b039351926145e66145dd8b6145d560608801516001600160401b031690565b96519b611a9c565b51985a90611c24565b91604051958695169885614281565b0390a45b0161442e565b9150919394925061460f8261070d565b60038203614623578b929493918a91614587565b51606001516349362d1f60e11b600052611e2f91906001600160401b03168961425b565b6146508461070d565b6003840361457357909294955061466891935061070d565b614678578b92918a913880614573565b5151604051632b11b8d960e01b8152908190611dd990879060048401614244565b611e2f8b6146b360608851016001600160401b0390511690565b631cfe6d8b60e01b6000526001600160401b0391821660045216602452604490565b6146de8361070d565b6146e9575b386144fd565b8351608001516001600160401b0316602080860151918c61471e60405194859384936370701e5760e11b85526004850161421d565b038160006001600160a01b037f0000000000000000000000003491f985053d33aacdb4446bf3b1f0f9c719951c165af190811561223d5760009161476f575b506146e35750505050506001906145f9565b614787915060203d8111613a2457613a168183610358565b3861475d565b614797878b611a9c565b515160808601526144e0565b6354e7e43160e11b6000526001600160401b038b1660045260246000fd5b506147cb8361070d565b600383146144ca565b9150836147e08461070d565b156144e057506001959450614849925061482791507f3ef2a99c550a751d4b0b261268f05a803dfb049ab43616a1ffb388f61fe651209351016001600160401b0390511690565b604080516001600160401b03808c168252909216602083015290918291820190565b0390a16145f9565b50505050600192915061484961482760607f3b575419319662b2a6f5e2467d84521517a3382b908eb3d557bb3fdb0c50e23c9351016001600160401b0390511690565b5061489e8361070d565b60038314614486565b633ee8bd3f60e11b6000526001600160401b03841660045260246000fd5b6148d0818a51611a9c565b518051604001516001600160401b031683810361494057508051602001516001600160401b031689810361491d57509061490c8460019361532e565b614916828d611a9c565b5201614404565b636c95f1eb60e01b6000526001600160401b03808a166004521660245260446000fd5b631c21951160e11b6000526001600160401b031660045260246000fd5b6357e0e08360e01b60005260046000fd5b611e2f61498286516001600160401b031690565b63676cf24b60e11b6000526001600160401b0316600452602490565b50929150506149e0576040516001600160401b039190911681527faab522ed53d887e56ed53dd37398a01aeef6a58e0fa77c2173beb9512d89493390602090a1565b637edeb53960e11b6000526001600160401b031660045260246000fd5b614a16915060203d602011613a2457613a168183610358565b3861433a565b9081602091031261016757516105168161083c565b90610516916020815260e0614acf614aba614a5a8551610100602087015261012086019061041a565b60208601516001600160401b0316604086015260408601516001600160a01b0316606086015260608601516080860152614aa4608087015160a08701906001600160a01b03169052565b60a0860151858203601f190160c087015261041a565b60c0850151848203601f19018486015261041a565b92015190610100601f198285030191015261041a565b6040906001600160a01b036105169493168152816020820152019061041a565b90816020910312610167575190565b91939293614b20611e8d565b5060208301516001600160a01b031660405163bbe4f6db60e01b81526001600160a01b038216600482015290959092602084806024810103816001600160a01b037f0000000000000000000000009a5181c93138fdf1463ad18945780067d177e983165afa93841561223d57600094614d9d575b506001600160a01b0384169586158015614d8b575b614d6d57614c52614c7b92613d7692614bd6614bcf611d5f60408c015163ffffffff1690565b8c89615883565b9690996080810151614c046060835193015193614bf16103a8565b9687526001600160401b03166020870152565b6001600160a01b038a16604086015260608501526001600160a01b038d16608085015260a084015260c083015260e0820152604051633907753760e01b602082015292839160248301614a31565b82857f000000000000000000000000000000000000000000000000000000000000138892615911565b94909115614d515750805160208103614d38575090614ca4826020808a95518301019101614b05565b956001600160a01b03841603614cdc575b5050505050614cd4614cc56103b8565b6001600160a01b039093168352565b602082015290565b614cef93614ce991611c24565b91615883565b50908082108015614d25575b614d0757808481614cb5565b63a966e21f60e01b6000908152600493909352602452604452606490fd5b5082614d318284611c24565b1415614cfb565b631e3be00960e21b600052602060045260245260446000fd5b611dd9604051928392634ff17cad60e11b845260048401614ae5565b63ae9b4ce960e01b6000526001600160a01b03851660045260246000fd5b50614d9861226686613523565b614ba9565b614dc091945060203d602011614dc7575b614db88183610358565b810190614a1c565b9238614b94565b503d614dae565b60405160208101916301ffc9a760e01b835263ffffffff60e01b602483015260248252614dfc604483610358565b6179185a10614e38576020926000925191617530fa6000513d82614e2c575b5081614e25575090565b9050151590565b60201115915038614e1b565b63753fa58960e11b60005260046000fd5b60405160208101916301ffc9a760e01b83526301ffc9a760e01b602483015260248252614dfc604483610358565b6040519060208201926301ffc9a760e01b845263ffffffff60e01b16602483015260248252614dfc604483610358565b6001600160401b031680600052600860205260406000209060ff825460a01c1615614ed0575090565b63ed053c5960e01b60005260045260246000fd5b919390926000948051946000965b868810614f03575050505050505050565b6020881015611a975760206000614f1b878b1a613b8c565b614f258b87611a9c565b5190614f5c614f348d8a611a9c565b5160405193849389859094939260ff6060936080840197845216602083015260408201520152565b838052039060015afa1561223d57614fa2613c69600051614f8a8960ff166000526003602052604060002090565b906001600160a01b0316600052602052604060002090565b9060016020830151614fb381613b25565b614fbc81613b25565b0361500957614fd9614fcf835160ff1690565b60ff600191161b90565b8116614ff857614fef614fcf6001935160ff1690565b17970196614ef2565b633d9ef1f160e21b60005260046000fd5b636518c33d60e11b60005260046000fd5b91909160005b83518110156150735760019060ff83166000526003602052600061506c604082206001600160a01b03615053858a611a9c565b51166001600160a01b0316600052602052604060002090565b5501615020565b50509050565b8151815460ff191660ff919091161781559060200151600381101561071757815461ff00191660089190911b61ff0016179055565b919060005b8151811015615073576150d66150c98284611a9c565b516001600160a01b031690565b906150ff6150f583614f8a8860ff166000526003602052604060002090565b5460081c60ff1690565b61510881613b25565b615173576001600160a01b038216156151625761515c60019261515761512c6103b8565b60ff85168152916151408660208501613b2f565b614f8a8960ff166000526003602052604060002090565b615079565b016150b3565b63d6c62c9b60e01b60005260046000fd5b631b3fab5160e11b6000526004805260246000fd5b919060005b8151811015615073576151a36150c98284611a9c565b906151c26150f583614f8a8860ff166000526003602052604060002090565b6151cb81613b25565b615173576001600160a01b03821615615162576152046001926151576151ef6103b8565b60ff8516815291615140600260208501613b2f565b0161518d565b60ff1680600052600260205260ff60016040600020015460101c16908015600014615258575015615247576001600160401b0319600b5416600b55565b6317bd8dd160e11b60005260046000fd5b6001146152625750565b61526857565b6307b8c74d60e51b60005260046000fd5b9080602083519182815201916020808360051b8301019401926000915b8383106152a557505050505090565b9091929394602080600192601f198582030186528851906080806153086152d5855160a0865260a086019061041a565b6001600160a01b0387870151168786015263ffffffff60408701511660408601526060860151858203606087015261041a565b93015191015297019301930191939290615296565b906020610516928181520190615279565b61357481518051906153c261534d60608601516001600160a01b031690565b613d7661536460608501516001600160401b031690565b9361537d6080808a01519201516001600160401b031690565b90604051958694602086019889936001600160401b036080946001600160a01b0382959998949960a089019a8952166020880152166040860152606085015216910152565b519020613d766020840151602081519101209360a06040820151602081519101209101516040516153fb81613d7660208201948561531d565b51902090604051958694602086019889919260a093969594919660c08401976000855260208501526040840152606083015260808201520152565b926001600160401b039261544992615a52565b9116600052600a60205260406000209060005260205260406000205490565b60405160c081018181106001600160401b038211176103025760609160a0916040526154926119e9565b815282602082015282604082015260008382015260006080820152015290565b607f8216906801fffffffffffffffe6001600160401b0383169260011b169180830460021490151715611c1f576138f6916001600160401b036154f58584613238565b921660005260096020526701ffffffffffffff60406000209460071c169160036001831b921b19161792906001600160401b0316600052602052604060002090565b9091607f83166801fffffffffffffffe6001600160401b0382169160011b169080820460021490151715611c1f5761556f8484613238565b6004831015610717576001600160401b036138f69416600052600960205260036701ffffffffffffff60406000209660071c1693831b921b19161792906001600160401b0316600052602052604060002090565b9080602083519182815201916020808360051b8301019401926000915b8383106155ef57505050505090565b909192939460208061560d600193601f19868203018752895161041a565b970193019301919392906155e0565b906020808351928381520192019060005b81811061563a5750505090565b825163ffffffff1684526020938401939092019160010161562d565b9161571f906157116105169593606086526001600160401b0360808251805160608a015282602082015116828a01528260408201511660a08a01528260608201511660c08a015201511660e087015260a06156dd6156c660208401516101406101008b01526101a08a019061041a565b6040840151898203605f19016101208b015261041a565b60608301516001600160a01b03166101408901529160808101516101608901520151868203605f1901610180880152615279565b9084820360208601526155c3565b91604081840391015261561c565b80516020909101516001600160e01b031981169291906004821061574f575050565b6001600160e01b031960049290920360031b82901b16169150565b90303b15610167576000916157936040519485938493630304c3e160e51b855260048501615656565b038183305af1908161586e575b50615863576157ad611f98565b9072c11c11c11c11c11c11c11c11c11c11c11c11c133146157cf575b60039190565b6157e86157db8361572d565b6001600160e01b03191690565b6337c3be2960e01b148015615848575b801561582d575b156157c957611e2f6158108361572d565b632882569d60e01b6000526001600160e01b031916600452602490565b5061583a6157db8361572d565b63753fa58960e11b146157ff565b506158556157db8361572d565b632be8ca8b60e21b146157f8565b6002906105166103e2565b80612302600061587d93610358565b386157a0565b6040516370a0823160e01b60208201526001600160a01b0390911660248201529192916158e0906158b78160448101613d76565b84837f000000000000000000000000000000000000000000000000000000000000138892615911565b92909115614d515750805160208103614d3857509061590b8260208061051695518301019101614b05565b93611c24565b93919361591e60846103c7565b9461592c6040519687610358565b6084865261593a60846103c7565b602087019590601f1901368737833b156159bd575a908082106159ac578291038060061c9003111561599b576000918291825a9560208451940192f1905a9003923d9060848211615992575b6000908287523e929190565b60849150615986565b6337c3be2960e01b60005260046000fd5b632be8ca8b60e21b60005260046000fd5b63030ed58f60e21b60005260046000fd5b80600052600760205260406000205415600014615a4c576006546801000000000000000081101561030257600181016006556000600654821015611a9757600690527ff652222313e28459528d920b65115c16c04f3efc82aaedc97be59f3f377c0d3f01819055600654906000526007602052604060002055600190565b50600090565b8051928251908415615bae5761010185111580615ba2575b15615ad157818501946000198601956101008711615ad1578615615b9257615a9187611a42565b9660009586978795885b848110615af6575050505050600119018095149384615aec575b505082615ae2575b505015615ad157615acd91611a9c565b5190565b6309bde33960e01b60005260046000fd5b1490503880615abd565b1492503880615ab5565b6001811b82811603615b8457868a1015615b6f57615b1860018b019a85611a9c565b51905b8c888c1015615b5b5750615b3360018c019b86611a9c565b515b818d11615ad157615b54828f92615b4e90600196615bbf565b92611a9c565b5201615a9b565b60018d019c615b6991611a9c565b51615b35565b615b7d60018c019b8d611a9c565b5190615b1b565b615b7d600189019884611a9c565b505050509050615acd9150611a8a565b50610101821115615a6a565b630469ac9960e21b60005260046000fd5b81811015615bd1579061051691615bd6565b610516915b9060405190602082019260018452604083015260608201526060815261357460808261035856fea164736f6c634300081a000a
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000000000000000000000000000048810ec3e431431f00000000000000000000000000000000000000000000000000000000000013880000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e0000000000000000000000009a5181c93138fdf1463ad18945780067d177e9830000000000000000000000003491f985053d33aacdb4446bf3b1f0f9c719951c000000000000000000000000945d9845bc14a5e4ff64457bb6770aac028ced390000000000000000000000000000000000000000000000000000000000015180000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001200000000000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : staticConfig (tuple):
Arg [1] : chainSelector (uint64): 5224473277236331295
Arg [2] : gasForCallExactCheck (uint16): 5000
Arg [3] : rmnRemote (address): 0x2da3AA7dd4d7b88f557fF9EC318f19bd0FBcE98E
Arg [4] : tokenAdminRegistry (address): 0x9a5181c93138FDF1463aD18945780067d177E983
Arg [5] : nonceManager (address): 0x3491F985053D33AAcdb4446BF3b1F0F9c719951C
Arg [1] : dynamicConfig (tuple):
Arg [1] : feeQuoter (address): 0x945d9845BC14a5e4ff64457BB6770Aac028cEd39
Arg [2] : permissionLessExecutionThresholdSeconds (uint32): 86400
Arg [3] : messageInterceptor (address): 0x0000000000000000000000000000000000000000
Arg [2] : sourceChainConfigs (tuple[]):
-----Encoded View---------------
10 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000048810ec3e431431f
Arg [1] : 0000000000000000000000000000000000000000000000000000000000001388
Arg [2] : 0000000000000000000000002da3aa7dd4d7b88f557ff9ec318f19bd0fbce98e
Arg [3] : 0000000000000000000000009a5181c93138fdf1463ad18945780067d177e983
Arg [4] : 0000000000000000000000003491f985053d33aacdb4446bf3b1f0f9c719951c
Arg [5] : 000000000000000000000000945d9845bc14a5e4ff64457bb6770aac028ced39
Arg [6] : 0000000000000000000000000000000000000000000000000000000000015180
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000120
Arg [9] : 0000000000000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.