ETH Price: $4,514.90 (-3.83%)

Contract

0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65

Overview

ETH Balance

0 ETH

ETH Value

$0.00

More Info

Private Name Tags

Multichain Info

N/A
Transaction Hash
Method
Block
From
To
Transfer Ownersh...54218382025-07-10 16:24:0989 days ago1752164649IN
0x1ba9bE96...b6336fd65
0 ETH0.000000050.00100275
Apply Authorized...45718652025-06-30 20:17:5699 days ago1751314676IN
0x1ba9bE96...b6336fd65
0 ETH0.000000140.00100025

View more zero value Internal Transactions in Advanced View mode

Advanced mode:

Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
NonceManager

Compiler Version
v0.8.26+commit.8a97fa7a

Optimization Enabled:
Yes with 80000 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.24;

import {IEVM2AnyOnRamp} from "./interfaces/IEVM2AnyOnRamp.sol";
import {INonceManager} from "./interfaces/INonceManager.sol";
import {ITypeAndVersion} from "@chainlink/shared/interfaces/ITypeAndVersion.sol";

import {AuthorizedCallers} from "@chainlink/shared/access/AuthorizedCallers.sol";

/// @title NonceManager
/// @notice NonceManager contract that manages sender nonces for the on/off ramps.
contract NonceManager is INonceManager, AuthorizedCallers, ITypeAndVersion {
  error PreviousRampAlreadySet();

  event PreviousRampsUpdated(uint64 indexed remoteChainSelector, PreviousRamps prevRamp);
  event SkippedIncorrectNonce(uint64 sourceChainSelector, uint64 nonce, bytes sender);

  /// @dev Struct that contains the previous on/off ramp addresses.
  struct PreviousRamps {
    address prevOnRamp; // Previous onRamp.
    address prevOffRamp; // Previous offRamp.
  }

  /// @dev Struct with the chain selector and the previous on/off ramps, same as PreviousRamps but with the chain
  /// selector so that an array of these can be passed to the applyPreviousRampsUpdates function.
  struct PreviousRampsArgs {
    uint64 remoteChainSelector; // ──╮ Chain selector.
    bool overrideExistingRamps; // ──╯ Whether to override existing ramps.
    PreviousRamps prevRamps; // Previous on/off ramps.
  }

  string public constant override typeAndVersion = "NonceManager 1.6.0";

  /// @dev The previous on/off ramps per chain selector.
  mapping(uint64 chainSelector => PreviousRamps previousRamps) private s_previousRamps;
  /// @dev The current outbound nonce per sender used on the onRamp.
  mapping(uint64 destChainSelector => mapping(address sender => uint64 outboundNonce)) private s_outboundNonces;
  /// @dev The current inbound nonce per sender used on the offRamp.
  /// Eventually in sync with the outbound nonce in the remote source chain NonceManager, used to enforce that messages
  /// are executed in the same order they are sent (assuming they are DON).
  mapping(uint64 sourceChainSelector => mapping(bytes sender => uint64 inboundNonce)) private s_inboundNonces;

  constructor(
    address[] memory authorizedCallers
  ) AuthorizedCallers(authorizedCallers) {}

  /// @inheritdoc INonceManager
  function getIncrementedOutboundNonce(
    uint64 destChainSelector,
    address sender
  ) external onlyAuthorizedCallers returns (uint64) {
    uint64 outboundNonce = _getOutboundNonce(destChainSelector, sender) + 1;
    s_outboundNonces[destChainSelector][sender] = outboundNonce;

    return outboundNonce;
  }

  /// @notice Returns the outbound nonce for a given sender on a given destination chain.
  /// @param destChainSelector The destination chain selector.
  /// @param sender The sender address.
  /// @return outboundNonce The outbound nonce.
  function getOutboundNonce(uint64 destChainSelector, address sender) external view returns (uint64) {
    return _getOutboundNonce(destChainSelector, sender);
  }

  function _getOutboundNonce(uint64 destChainSelector, address sender) private view returns (uint64) {
    uint64 outboundNonce = s_outboundNonces[destChainSelector][sender];

    // When introducing the NonceManager with existing lanes, we still want to have sequential nonces.
    // Referencing the old onRamp preserves sequencing between updates.
    if (outboundNonce == 0) {
      address prevOnRamp = s_previousRamps[destChainSelector].prevOnRamp;
      if (prevOnRamp != address(0)) {
        // This gets the current nonce for a sender, not the already incremented nonce like getIncrementedOutboundNonce
        // would return.
        return IEVM2AnyOnRamp(prevOnRamp).getSenderNonce(sender);
      }
    }

    return outboundNonce;
  }

  /// @inheritdoc INonceManager
  function incrementInboundNonce(
    uint64 sourceChainSelector,
    uint64 expectedNonce,
    bytes calldata sender
  ) external onlyAuthorizedCallers returns (bool) {
    uint64 inboundNonce = _getInboundNonce(sourceChainSelector, sender) + 1;

    if (inboundNonce != expectedNonce) {
      // If the nonce is not the expected one, this means that there are still messages in flight so we skip
      // the nonce increment.
      emit SkippedIncorrectNonce(sourceChainSelector, expectedNonce, sender);
      return false;
    }

    s_inboundNonces[sourceChainSelector][sender] = inboundNonce;

    return true;
  }

  /// @notice Returns the inbound nonce for a given sender on a given source chain.
  /// @param sourceChainSelector The source chain selector.
  /// @param sender The encoded sender address.
  /// @return inboundNonce The inbound nonce.
  function getInboundNonce(uint64 sourceChainSelector, bytes calldata sender) external view returns (uint64) {
    return _getInboundNonce(sourceChainSelector, sender);
  }

  function _getInboundNonce(uint64 sourceChainSelector, bytes calldata sender) private view returns (uint64) {
    uint64 inboundNonce = s_inboundNonces[sourceChainSelector][sender];

    // When introducing the NonceManager with existing lanes, we still want to have sequential nonces. Referencing the
    // old offRamp to check the expected nonce if none is set for a given sender allows us to skip the current message
    // in the current offRamp if it would not be the next according to the old offRamp. This preserves sequencing
    // between updates.
    if (inboundNonce == 0) {
      address prevOffRamp = s_previousRamps[sourceChainSelector].prevOffRamp;
      if (prevOffRamp != address(0)) {
        // We only expect EVM previous offRamps here so we can safely decode the sender.
        return IEVM2AnyOnRamp(prevOffRamp).getSenderNonce(abi.decode(sender, (address)));
      }
    }

    return inboundNonce;
  }

  /// @notice Updates the previous ramps addresses.
  /// @param previousRampsArgs The previous on/off ramps addresses.
  function applyPreviousRampsUpdates(
    PreviousRampsArgs[] calldata previousRampsArgs
  ) external onlyOwner {
    for (uint256 i = 0; i < previousRampsArgs.length; ++i) {
      PreviousRampsArgs calldata previousRampsArg = previousRampsArgs[i];

      PreviousRamps storage prevRamps = s_previousRamps[previousRampsArg.remoteChainSelector];

      // If the previous ramps are already set then they should not be updated.
      // In versions prior to the introduction of the NonceManager contract, nonces were tracked in the on/off ramps.
      // This config does a 1-time migration to move the nonce from on/off ramps into NonceManager.
      if (prevRamps.prevOnRamp != address(0) || prevRamps.prevOffRamp != address(0)) {
        // We do allow explicit overrides as an escape hatch in the case of a misconfiguration.
        if (!previousRampsArg.overrideExistingRamps) {
          revert PreviousRampAlreadySet();
        }
      }

      prevRamps.prevOnRamp = previousRampsArg.prevRamps.prevOnRamp;
      prevRamps.prevOffRamp = previousRampsArg.prevRamps.prevOffRamp;

      emit PreviousRampsUpdated(previousRampsArg.remoteChainSelector, previousRampsArg.prevRamps);
    }
  }

  /// @notice Gets the previous onRamp address for the given chain selector.
  /// @param chainSelector The chain selector.
  /// @return previousRamps The previous on/offRamp addresses.
  function getPreviousRamps(
    uint64 chainSelector
  ) external view returns (PreviousRamps memory) {
    return s_previousRamps[chainSelector];
  }
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IEVM2AnyOnRampClient} from "./IEVM2AnyOnRampClient.sol";

interface IEVM2AnyOnRamp is IEVM2AnyOnRampClient {
  /// @notice Gets the next sequence number to be used in the onRamp.
  /// @return the next sequence number to be used.
  function getExpectedNextSequenceNumber() external view returns (uint64);

  /// @notice Get the current nonce for a given sender.
  /// @param sender The sender to get the nonce for.
  /// @return nonce The current nonce for the sender.
  function getSenderNonce(
    address sender
  ) external view returns (uint64 nonce);
}

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IPoolV1} from "./IPool.sol";

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

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

interface IEVM2AnyOnRampClient {
  /// @notice Get the fee for a given ccip message.
  /// @param destChainSelector The destination chain selector.
  /// @param message The message to calculate the cost for.
  /// @return fee The calculated fee.
  function getFee(uint64 destChainSelector, Client.EVM2AnyMessage calldata message) external view returns (uint256 fee);

  /// @notice Get the pool for a specific token.
  /// @param destChainSelector The destination chain selector.
  /// @param sourceToken The source chain token to get the pool for.
  /// @return pool Token pool.
  function getPoolBySourceToken(uint64 destChainSelector, IERC20 sourceToken) external view returns (IPoolV1);

  /// @notice Gets a list of all supported source chain tokens.
  /// @param destChainSelector The destination chain selector.
  /// @return tokens The addresses of all tokens that this onRamp supports the given destination chain.
  function getSupportedTokens(
    uint64 destChainSelector
  ) external view returns (address[] memory tokens);

  /// @notice Send a message to the remote chain.
  /// @dev only callable by the Router.
  /// @dev approve() must have already been called on the token using the this ramp address as the spender.
  /// @dev if the contract is paused, this function will revert.
  /// @param destChainSelector The destination chain selector.
  /// @param message Message struct to send.
  /// @param feeTokenAmount Amount of fee tokens for payment.
  /// @param originalSender The original initiator of the CCIP request.
  /// @return messageId The message id.
  function forwardFromRouter(
    uint64 destChainSelector,
    Client.EVM2AnyMessage memory message,
    uint256 feeTokenAmount,
    address originalSender
  ) external returns (bytes32);
}

// 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 "@chainlink/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.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).
  }

  // Tag to indicate only a gas limit. Only usable for EVM as destination chain.
  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);
  }

  // Tag to indicate a gas limit (or dest chain equivalent processing units) and Out Of Order Execution. This tag is
  // available for multiple chain families. If there is no chain family specific tag, this is the default available
  // for a chain.
  // Note: not available for Solana VM based chains.
  bytes4 public constant GENERIC_EXTRA_ARGS_V2_TAG = 0x181dcf10;

  /// @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.
  /// @dev Fully compatible with the previously existing EVMExtraArgsV2.
  struct GenericExtraArgsV2 {
    uint256 gasLimit;
    bool allowOutOfOrderExecution;
  }

  // Extra args tag for chains that use the Solana VM.
  bytes4 public constant SVM_EXTRA_ARGS_V1_TAG = 0x1f3b3aba;

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

  /// @dev The maximum number of accounts that can be passed in SVMExtraArgs.
  uint256 public constant SVM_EXTRA_ARGS_MAX_ACCOUNTS = 64;

  function _argsToBytes(
    GenericExtraArgsV2 memory extraArgs
  ) internal pure returns (bytes memory bts) {
    return abi.encodeWithSelector(GENERIC_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);
  }
}

File 7 of 15 : Pool.sol
// 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 "./Ownable2StepMsgSender.sol";
import {EnumerableSet} from "../../vendor/openzeppelin-solidity/v4.8.3/contracts/utils/structs/EnumerableSet.sol";

/// @title The AuthorizedCallers contract
/// @notice A contract that manages multiple authorized callers. Enables restricting access to certain functions to a set of addresses.
contract AuthorizedCallers is Ownable2StepMsgSender {
  using EnumerableSet for EnumerableSet.AddressSet;

  event AuthorizedCallerAdded(address caller);
  event AuthorizedCallerRemoved(address caller);

  error UnauthorizedCaller(address caller);
  error ZeroAddressNotAllowed();

  /// @notice Update args for changing the authorized callers
  struct AuthorizedCallerArgs {
    address[] addedCallers;
    address[] removedCallers;
  }

  /// @dev Set of authorized callers
  EnumerableSet.AddressSet internal s_authorizedCallers;

  /// @param authorizedCallers the authorized callers to set
  constructor(address[] memory authorizedCallers) {
    _applyAuthorizedCallerUpdates(
      AuthorizedCallerArgs({addedCallers: authorizedCallers, removedCallers: new address[](0)})
    );
  }

  /// @return authorizedCallers Returns all authorized callers
  function getAllAuthorizedCallers() external view returns (address[] memory) {
    return s_authorizedCallers.values();
  }

  /// @notice Updates the list of authorized callers
  /// @param authorizedCallerArgs Callers to add and remove. Removals are performed first.
  function applyAuthorizedCallerUpdates(AuthorizedCallerArgs memory authorizedCallerArgs) external onlyOwner {
    _applyAuthorizedCallerUpdates(authorizedCallerArgs);
  }

  /// @notice Updates the list of authorized callers
  /// @param authorizedCallerArgs Callers to add and remove. Removals are performed first.
  function _applyAuthorizedCallerUpdates(AuthorizedCallerArgs memory authorizedCallerArgs) internal {
    address[] memory removedCallers = authorizedCallerArgs.removedCallers;
    for (uint256 i = 0; i < removedCallers.length; ++i) {
      address caller = removedCallers[i];

      if (s_authorizedCallers.remove(caller)) {
        emit AuthorizedCallerRemoved(caller);
      }
    }

    address[] memory addedCallers = authorizedCallerArgs.addedCallers;
    for (uint256 i = 0; i < addedCallers.length; ++i) {
      address caller = addedCallers[i];

      if (caller == address(0)) {
        revert ZeroAddressNotAllowed();
      }

      s_authorizedCallers.add(caller);
      emit AuthorizedCallerAdded(caller);
    }
  }

  /// @notice Checks the sender and reverts if it is anyone other than a listed authorized caller.
  function _validateCaller() internal view {
    if (!s_authorizedCallers.contains(msg.sender)) {
      revert UnauthorizedCaller(msg.sender);
    }
  }

  /// @notice Checks the sender and reverts if it is anyone other than a listed authorized caller.
  modifier onlyAuthorizedCallers() {
    _validateCaller();
    _;
  }
}

// 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();
    _;
  }
}

File 10 of 15 : Ownable2StepMsgSender.sol
// 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.0;

interface IOwnable {
  function owner() external returns (address);

  function transferOwnership(address recipient) external;

  function acceptOwnership() external;
}

File 12 of 15 : ITypeAndVersion.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

interface ITypeAndVersion {
  function typeAndVersion() external pure returns (string memory);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @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 amount of tokens in existence.
   */
  function totalSupply() external view returns (uint256);

  /**
   * @dev Returns the amount of tokens owned by `account`.
   */
  function balanceOf(address account) external view returns (uint256);

  /**
   * @dev Moves `amount` 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 amount) 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 `amount` 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 amount) external returns (bool);

  /**
   * @dev Moves `amount` tokens from `from` to `to` using the
   * allowance mechanism. `amount` 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 amount) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @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.
 *
 * ```
 * 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 of the value in the `values` array, plus 1 because index 0
    // means a value is not in the set.
    mapping(bytes32 => uint256) _indexes;
  }

  /**
   * @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._indexes[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 read and store the value's index to prevent multiple reads from the same storage slot
    uint256 valueIndex = set._indexes[value];

    if (valueIndex != 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 toDeleteIndex = valueIndex - 1;
      uint256 lastIndex = set._values.length - 1;

      if (lastIndex != toDeleteIndex) {
        bytes32 lastValue = set._values[lastIndex];

        // Move the last value to the index where the value to delete is
        set._values[toDeleteIndex] = lastValue;
        // Update the index for the moved value
        set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
      }

      // Delete the slot where the moved value was stored
      set._values.pop();

      // Delete the index for the deleted slot
      delete set._indexes[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._indexes[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
// 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);
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "appendCBOR": true,
    "bytecodeHash": "none",
    "useLiteralContent": false
  },
  "optimizer": {
    "enabled": true,
    "runs": 80000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "remappings": [
    "forge-std/=node_modules/@chainlink/contracts/src/v0.8/vendor/forge-std/src/",
    "@chainlink/=node_modules/@chainlink/contracts/src/v0.8/"
  ],
  "viaIR": true
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address[]","name":"authorizedCallers","type":"address[]"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotTransferToSelf","type":"error"},{"inputs":[],"name":"MustBeProposedOwner","type":"error"},{"inputs":[],"name":"OnlyCallableByOwner","type":"error"},{"inputs":[],"name":"OwnerCannotBeZero","type":"error"},{"inputs":[],"name":"PreviousRampAlreadySet","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"UnauthorizedCaller","type":"error"},{"inputs":[],"name":"ZeroAddressNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedCallerAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"caller","type":"address"}],"name":"AuthorizedCallerRemoved","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":true,"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"components":[{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"}],"indexed":false,"internalType":"struct NonceManager.PreviousRamps","name":"prevRamp","type":"tuple"}],"name":"PreviousRampsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"nonce","type":"uint64"},{"indexed":false,"internalType":"bytes","name":"sender","type":"bytes"}],"name":"SkippedIncorrectNonce","type":"event"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address[]","name":"addedCallers","type":"address[]"},{"internalType":"address[]","name":"removedCallers","type":"address[]"}],"internalType":"struct AuthorizedCallers.AuthorizedCallerArgs","name":"authorizedCallerArgs","type":"tuple"}],"name":"applyAuthorizedCallerUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"remoteChainSelector","type":"uint64"},{"internalType":"bool","name":"overrideExistingRamps","type":"bool"},{"components":[{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"}],"internalType":"struct NonceManager.PreviousRamps","name":"prevRamps","type":"tuple"}],"internalType":"struct NonceManager.PreviousRampsArgs[]","name":"previousRampsArgs","type":"tuple[]"}],"name":"applyPreviousRampsUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getAllAuthorizedCallers","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"}],"name":"getInboundNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"getIncrementedOutboundNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"getOutboundNonce","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"getPreviousRamps","outputs":[{"components":[{"internalType":"address","name":"prevOnRamp","type":"address"},{"internalType":"address","name":"prevOffRamp","type":"address"}],"internalType":"struct NonceManager.PreviousRamps","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"uint64","name":"expectedNonce","type":"uint64"},{"internalType":"bytes","name":"sender","type":"bytes"}],"name":"incrementInboundNonce","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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"}]

60806040523461020f576117738038038061001981610214565b92833981019060208183031261020f578051906001600160401b03821161020f570181601f8201121561020f578051916001600160401b0383116101c8578260051b9160208061006a818601610214565b80968152019382010191821161020f57602001915b8183106101ef578333156101de57600180546001600160a01b031916331790556020906100ab82610214565b60008152600036813760408051929083016001600160401b038111848210176101c8576040528252808383015260005b8151811015610142576001906001600160a01b036100f98285610239565b5116856101058261027b565b610112575b5050016100db565b7fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda7758091604051908152a1858561010a565b50505160005b81518110156101b9576001600160a01b036101638284610239565b51169081156101a8577feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef848361019a600195610379565b50604051908152a101610148565b6342bcdf7f60e11b60005260046000fd5b60405161139990816103da8239f35b634e487b7160e01b600052604160045260246000fd5b639b15e16f60e01b60005260046000fd5b82516001600160a01b038116810361020f5781526020928301920161007f565b600080fd5b6040519190601f01601f191682016001600160401b038111838210176101c857604052565b805182101561024d5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b805482101561024d5760005260206000200190600090565b600081815260036020526040902054801561037257600019810181811161035c5760025460001981019190821161035c5780820361030b575b50505060025480156102f557600019016102cf816002610263565b8154906000199060031b1b19169055600255600052600360205260006040812055600190565b634e487b7160e01b600052603160045260246000fd5b61034461031c61032d936002610263565b90549060031b1c9283926002610263565b819391549060031b91821b91600019901b19161790565b905560005260036020526040600020553880806102b4565b634e487b7160e01b600052601160045260246000fd5b5050600090565b806000526003602052604060002054156000146103d357600254680100000000000000008110156101c8576103ba61032d8260018594016002556002610263565b9055600254906000526003602052604060002055600190565b5060009056fe608080604052600436101561001357600080fd5b60003560e01c908163181f5a7714610a94575080632451a627146109a6578063294b5630146108ff57806379ba5097146108165780637a75a094146105f95780638da5cb5b146105a757806391a2749a146103bd578063bf18402a14610373578063c9223625146102fe578063e0e03cae14610272578063ea458c0c1461019b5763f2fde38b146100a357600080fd5b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043573ffffffffffffffffffffffffffffffffffffffff8116809103610196576100fb610e81565b33811461016c57807fffffffffffffffffffffffff0000000000000000000000000000000000000000600054161760005573ffffffffffffffffffffffffffffffffffffffff600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278600080a3005b7fdad89dca0000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760206101d4610bef565b6101dc610c06565b6101e461113a565b67ffffffffffffffff6101ff6101fa8385610f2f565b610d1e565b92166000526005835273ffffffffffffffffffffffffffffffffffffffff604060002091166000528252604060002067ffffffffffffffff82167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000082541617905567ffffffffffffffff60405191168152f35b346101965760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610196576102a9610bef565b60243567ffffffffffffffff81168103610196576044359067ffffffffffffffff8211610196576020926102e46102f4933690600401610cba565b9290916102ef61113a565b610d6d565b6040519015158152f35b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657610335610bef565b60243567ffffffffffffffff81116101965760209161035b610361923690600401610cba565b9161104a565b67ffffffffffffffff60405191168152f35b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760206103616103af610bef565b6103b7610c06565b90610f2f565b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043567ffffffffffffffff81116101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610196576040519061043782610b63565b806004013567ffffffffffffffff81116101965761045b9060043691840101610c4a565b825260248101359067ffffffffffffffff82116101965760046104819236920101610c4a565b60208201908152610490610e81565b519060005b8251811015610508578073ffffffffffffffffffffffffffffffffffffffff6104c060019386610ecc565b51166104cb81611196565b6104d7575b5001610495565b60207fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda7758091604051908152a1846104d0565b505160005b81518110156105a55773ffffffffffffffffffffffffffffffffffffffff6105358284610ecc565b511690811561057b577feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef60208361056d60019561132c565b50604051908152a10161050d565b7f8579befe0000000000000000000000000000000000000000000000000000000060005260046000fd5b005b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043567ffffffffffffffff8111610196573660238201121561019657806004013567ffffffffffffffff8111610196573660248260071b8401011161019657610670610e81565b60005b818110156105a55760008160071b84016024810167ffffffffffffffff61069982610ce8565b1683526004602052604083209273ffffffffffffffffffffffffffffffffffffffff845416158015906107f3575b6107b3575b5060408273ffffffffffffffffffffffffffffffffffffffff6107a667ffffffffffffffff6107907fa2e43edcbc4fd175ae4bebbe3fd6139871ed1f1783cd4a1ace59b90d302c3319966084606460019c9b9a01968661072b89610cfd565b167fffffffffffffffffffffffff00000000000000000000000000000000000000008c5416178b550198858c6107608c610cfd565b920191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055610ce8565b16958261079e865195610c29565b168452610c29565b166020820152a201610673565b60448301358015908115036107ef57156106cc57807fc6117ae20000000000000000000000000000000000000000000000000000000060049252fd5b5080fd5b5073ffffffffffffffffffffffffffffffffffffffff60018501541615156106c7565b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760005473ffffffffffffffffffffffffffffffffffffffff811633036108d5577fffffffffffffffffffffffff00000000000000000000000000000000000000006001549133828416176001551660005573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f02b543c60000000000000000000000000000000000000000000000000000000060005260046000fd5b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965767ffffffffffffffff61093f610bef565b6000602060405161094f81610b63565b828152015216600052600460205260408060002073ffffffffffffffffffffffffffffffffffffffff825161098381610b63565b602082600181865416958685520154169101908152835192835251166020820152f35b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610196576040518060206002549283815201809260026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9060005b818110610a7e5750505081610a25910382610bae565b6040519182916020830190602084525180915260408301919060005b818110610a4f575050500390f35b825173ffffffffffffffffffffffffffffffffffffffff16845285945060209384019390920191600101610a41565b8254845260209093019260019283019201610a0f565b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657610acc81610b63565b601281527f4e6f6e63654d616e6167657220312e362e300000000000000000000000000000602082015260405190602082528181519182602083015260005b838110610b4b5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604080968601015201168101030190f35b60208282018101516040878401015285935001610b0b565b6040810190811067ffffffffffffffff821117610b7f57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b7f57604052565b6004359067ffffffffffffffff8216820361019657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361019657565b359073ffffffffffffffffffffffffffffffffffffffff8216820361019657565b9080601f830112156101965781359167ffffffffffffffff8311610b7f578260051b9060405193610c7e6020840186610bae565b845260208085019282010192831161019657602001905b828210610ca25750505090565b60208091610caf84610c29565b815201910190610c95565b9181601f840112156101965782359167ffffffffffffffff8311610196576020838186019501011161019657565b3567ffffffffffffffff811681036101965790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101965790565b67ffffffffffffffff60019116019067ffffffffffffffff8211610d3e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291909267ffffffffffffffff610d886101fa85858561104a565b94168067ffffffffffffffff861603610df8575067ffffffffffffffff9291836020921660005260068252604060002083604051948593843782019081520301902091167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000825416179055600190565b7f606ff8179e5e3c059b82df931acc496b7b6053e8879042f8267f930e0595f69f9450601f8467ffffffffffffffff956080957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09460405198899716875260208701526060604087015281606087015286860137600085828601015201168101030190a1600090565b73ffffffffffffffffffffffffffffffffffffffff600154163303610ea257565b7f2b5c74de0000000000000000000000000000000000000000000000000000000060005260046000fd5b8051821015610ee05760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90816020910312610196575167ffffffffffffffff811681036101965790565b67ffffffffffffffff1690816000526005602052604060002073ffffffffffffffffffffffffffffffffffffffff821660005260205267ffffffffffffffff60406000205416918215610f8157505090565b600052600460205273ffffffffffffffffffffffffffffffffffffffff604060002054169081610fb057505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f856c82470000000000000000000000000000000000000000000000000000000084521660048301525afa90811561103e57600091611012575090565b611034915060203d602011611037575b61102c8183610bae565b810190610f0f565b90565b503d611022565b6040513d6000823e3d90fd5b67ffffffffffffffff90929192169182600052600660205267ffffffffffffffff60406000206020604051809286868337868201908152030190205416928315611095575b50505090565b600052600460205273ffffffffffffffffffffffffffffffffffffffff6001604060002001541691821561108f57819293509060209181010312610196573573ffffffffffffffffffffffffffffffffffffffff8116809103610196576020906024604051809481937f856c824700000000000000000000000000000000000000000000000000000000835260048301525afa90811561103e57600091611012575090565b3360005260036020526040600020541561115057565b7fd86ad9cf000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b8054821015610ee05760005260206000200190600090565b6000818152600360205260409020548015611325577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111610d3e57600254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610d3e578082036112b6575b5050506002548015611287577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161124481600261117e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600255600052600360205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61130d6112c76112d893600261117e565b90549060031b1c928392600261117e565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b9055600052600360205260406000205538808061120b565b5050600090565b806000526003602052604060002054156000146113865760025468010000000000000000811015610b7f5761136d6112d8826001859401600255600261117e565b9055600254906000526003602052604060002055600190565b5060009056fea164736f6c634300081a000a00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608080604052600436101561001357600080fd5b60003560e01c908163181f5a7714610a94575080632451a627146109a6578063294b5630146108ff57806379ba5097146108165780637a75a094146105f95780638da5cb5b146105a757806391a2749a146103bd578063bf18402a14610373578063c9223625146102fe578063e0e03cae14610272578063ea458c0c1461019b5763f2fde38b146100a357600080fd5b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043573ffffffffffffffffffffffffffffffffffffffff8116809103610196576100fb610e81565b33811461016c57807fffffffffffffffffffffffff0000000000000000000000000000000000000000600054161760005573ffffffffffffffffffffffffffffffffffffffff600154167fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae1278600080a3005b7fdad89dca0000000000000000000000000000000000000000000000000000000060005260046000fd5b600080fd5b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760206101d4610bef565b6101dc610c06565b6101e461113a565b67ffffffffffffffff6101ff6101fa8385610f2f565b610d1e565b92166000526005835273ffffffffffffffffffffffffffffffffffffffff604060002091166000528252604060002067ffffffffffffffff82167fffffffffffffffffffffffffffffffffffffffffffffffff000000000000000082541617905567ffffffffffffffff60405191168152f35b346101965760607ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610196576102a9610bef565b60243567ffffffffffffffff81168103610196576044359067ffffffffffffffff8211610196576020926102e46102f4933690600401610cba565b9290916102ef61113a565b610d6d565b6040519015158152f35b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657610335610bef565b60243567ffffffffffffffff81116101965760209161035b610361923690600401610cba565b9161104a565b67ffffffffffffffff60405191168152f35b346101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760206103616103af610bef565b6103b7610c06565b90610f2f565b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043567ffffffffffffffff81116101965760407ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc8236030112610196576040519061043782610b63565b806004013567ffffffffffffffff81116101965761045b9060043691840101610c4a565b825260248101359067ffffffffffffffff82116101965760046104819236920101610c4a565b60208201908152610490610e81565b519060005b8251811015610508578073ffffffffffffffffffffffffffffffffffffffff6104c060019386610ecc565b51166104cb81611196565b6104d7575b5001610495565b60207fc3803387881faad271c47728894e3e36fac830ffc8602ca6fc07733cbda7758091604051908152a1846104d0565b505160005b81518110156105a55773ffffffffffffffffffffffffffffffffffffffff6105358284610ecc565b511690811561057b577feb1b9b92e50b7f88f9ff25d56765095ac6e91540eee214906f4036a908ffbdef60208361056d60019561132c565b50604051908152a10161050d565b7f8579befe0000000000000000000000000000000000000000000000000000000060005260046000fd5b005b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657602073ffffffffffffffffffffffffffffffffffffffff60015416604051908152f35b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760043567ffffffffffffffff8111610196573660238201121561019657806004013567ffffffffffffffff8111610196573660248260071b8401011161019657610670610e81565b60005b818110156105a55760008160071b84016024810167ffffffffffffffff61069982610ce8565b1683526004602052604083209273ffffffffffffffffffffffffffffffffffffffff845416158015906107f3575b6107b3575b5060408273ffffffffffffffffffffffffffffffffffffffff6107a667ffffffffffffffff6107907fa2e43edcbc4fd175ae4bebbe3fd6139871ed1f1783cd4a1ace59b90d302c3319966084606460019c9b9a01968661072b89610cfd565b167fffffffffffffffffffffffff00000000000000000000000000000000000000008c5416178b550198858c6107608c610cfd565b920191167fffffffffffffffffffffffff0000000000000000000000000000000000000000825416179055610ce8565b16958261079e865195610c29565b168452610c29565b166020820152a201610673565b60448301358015908115036107ef57156106cc57807fc6117ae20000000000000000000000000000000000000000000000000000000060049252fd5b5080fd5b5073ffffffffffffffffffffffffffffffffffffffff60018501541615156106c7565b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965760005473ffffffffffffffffffffffffffffffffffffffff811633036108d5577fffffffffffffffffffffffff00000000000000000000000000000000000000006001549133828416176001551660005573ffffffffffffffffffffffffffffffffffffffff3391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3005b7f02b543c60000000000000000000000000000000000000000000000000000000060005260046000fd5b346101965760207ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc3601126101965767ffffffffffffffff61093f610bef565b6000602060405161094f81610b63565b828152015216600052600460205260408060002073ffffffffffffffffffffffffffffffffffffffff825161098381610b63565b602082600181865416958685520154169101908152835192835251166020820152f35b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc360112610196576040518060206002549283815201809260026000527f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace9060005b818110610a7e5750505081610a25910382610bae565b6040519182916020830190602084525180915260408301919060005b818110610a4f575050500390f35b825173ffffffffffffffffffffffffffffffffffffffff16845285945060209384019390920191600101610a41565b8254845260209093019260019283019201610a0f565b346101965760007ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffc36011261019657610acc81610b63565b601281527f4e6f6e63654d616e6167657220312e362e300000000000000000000000000000602082015260405190602082528181519182602083015260005b838110610b4b5750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f836000604080968601015201168101030190f35b60208282018101516040878401015285935001610b0b565b6040810190811067ffffffffffffffff821117610b7f57604052565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b90601f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0910116810190811067ffffffffffffffff821117610b7f57604052565b6004359067ffffffffffffffff8216820361019657565b6024359073ffffffffffffffffffffffffffffffffffffffff8216820361019657565b359073ffffffffffffffffffffffffffffffffffffffff8216820361019657565b9080601f830112156101965781359167ffffffffffffffff8311610b7f578260051b9060405193610c7e6020840186610bae565b845260208085019282010192831161019657602001905b828210610ca25750505090565b60208091610caf84610c29565b815201910190610c95565b9181601f840112156101965782359167ffffffffffffffff8311610196576020838186019501011161019657565b3567ffffffffffffffff811681036101965790565b3573ffffffffffffffffffffffffffffffffffffffff811681036101965790565b67ffffffffffffffff60019116019067ffffffffffffffff8211610d3e57565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b9291909267ffffffffffffffff610d886101fa85858561104a565b94168067ffffffffffffffff861603610df8575067ffffffffffffffff9291836020921660005260068252604060002083604051948593843782019081520301902091167fffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000825416179055600190565b7f606ff8179e5e3c059b82df931acc496b7b6053e8879042f8267f930e0595f69f9450601f8467ffffffffffffffff956080957fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09460405198899716875260208701526060604087015281606087015286860137600085828601015201168101030190a1600090565b73ffffffffffffffffffffffffffffffffffffffff600154163303610ea257565b7f2b5c74de0000000000000000000000000000000000000000000000000000000060005260046000fd5b8051821015610ee05760209160051b010190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b90816020910312610196575167ffffffffffffffff811681036101965790565b67ffffffffffffffff1690816000526005602052604060002073ffffffffffffffffffffffffffffffffffffffff821660005260205267ffffffffffffffff60406000205416918215610f8157505090565b600052600460205273ffffffffffffffffffffffffffffffffffffffff604060002054169081610fb057505090565b6020919250602473ffffffffffffffffffffffffffffffffffffffff9160405194859384927f856c82470000000000000000000000000000000000000000000000000000000084521660048301525afa90811561103e57600091611012575090565b611034915060203d602011611037575b61102c8183610bae565b810190610f0f565b90565b503d611022565b6040513d6000823e3d90fd5b67ffffffffffffffff90929192169182600052600660205267ffffffffffffffff60406000206020604051809286868337868201908152030190205416928315611095575b50505090565b600052600460205273ffffffffffffffffffffffffffffffffffffffff6001604060002001541691821561108f57819293509060209181010312610196573573ffffffffffffffffffffffffffffffffffffffff8116809103610196576020906024604051809481937f856c824700000000000000000000000000000000000000000000000000000000835260048301525afa90811561103e57600091611012575090565b3360005260036020526040600020541561115057565b7fd86ad9cf000000000000000000000000000000000000000000000000000000006000523360045260246000fd5b8054821015610ee05760005260206000200190600090565b6000818152600360205260409020548015611325577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8101818111610d3e57600254907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8201918211610d3e578082036112b6575b5050506002548015611287577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0161124481600261117e565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff82549160031b1b19169055600255600052600360205260006040812055600190565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fd5b61130d6112c76112d893600261117e565b90549060031b1c928392600261117e565b81939154907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff9060031b92831b921b19161790565b9055600052600360205260406000205538808061120b565b5050600090565b806000526003602052604060002054156000146113865760025468010000000000000000811015610b7f5761136d6112d8826001859401600255600261117e565b9055600254906000526003602052604060002055600190565b5060009056fea164736f6c634300081a000a

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

00000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : authorizedCallers (address[]):

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
0x1ba9bE96A5c21dcdB9D22bEC3f00abCb6336fd65
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.