Contract 0xeb52e9ae4a9fb37172978642d4c141ef53876f26

  Note: Our ETH balance display is temporarily unavailable. Please check back later.
Txn Hash Method
Block
From
To
Value
0xb5cc1c691901ef21da921ba32cf3e76b6448de39765082ebcec3c895adec5abdApply Ramp Updat...213337372024-02-16 14:59:0260 days 22 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000040935640.001000252
0x32e24d1d2fe55a66bbcf7ead7cde7d4a5963a859498de2adfd17508285d0b962Drip183658222023-12-09 22:08:32129 days 15 hrs ago0x39d1fe94a377d8eb87d7e39337e6a1ad501e02f4 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000324330051.500000252
0x5f3bf68bc038dad620e50b61b28bad2619f62e03ddfb7bcdd87e5ffbe664eda9Ccip Send163937192023-10-25 6:31:46175 days 6 hrs ago0x8ed27ab67aea9bc50628fba25ab52d23ae8d0eae IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000132188060.10000005
0x83927c8964db430a26bd3812847855761c1e505e36b2a5cd9210974ca701d711Ccip Send162977622023-10-23 1:13:12177 days 11 hrs ago0x282954b339ce27289f4c8461746a98e9ab948afa IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260.000330277777777 ETH0.0006007020473.00000005
0xb913ba7d43a746f40e02f56c919bb7740c98c25e7afafbd84ccc0e185cfaf378Ccip Send161814972023-10-20 8:37:42180 days 4 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000107773050.10000005
0x085c11c462b23fe906f8aee0d80c2707bfc7b972d239c4b6fbb91b5977063604Ccip Send161204232023-10-18 22:41:54181 days 14 hrs ago0x8ed27ab67aea9bc50628fba25ab52d23ae8d0eae IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000115059050.10000005
0x60ed05ea99aa88b3e88fbe9497afe98d746084c901956a52a311c00033bcf6c3Ccip Send161201072023-10-18 22:31:22181 days 14 hrs ago0x8ed27ab67aea9bc50628fba25ab52d23ae8d0eae IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000115059050.10000005
0xc9331e1a75f2568ff7755d7aaf540f6b91268913039565f0bc3f39e890d67a62Ccip Send161196892023-10-18 22:17:26181 days 14 hrs ago0x8ed27ab67aea9bc50628fba25ab52d23ae8d0eae IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000115059050.10000005
0xd4a5cf0079f8d98bc11eb5b51b440bd7780c0e7f41ece85d74f8f49b99811074Ccip Send160812512023-10-18 0:56:10182 days 12 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000091877040.10000005
0x92bccd9c436280e5f50aac7c4831e176614b6b8a17f8cee67feee96d372e45efCcip Send160811982023-10-18 0:54:24182 days 12 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000091877040.10000005
0x52f447a61effedaa9c37354dd96950d0940df7f0244ae9b4a49f2a72a03c7e34Ccip Send160811772023-10-18 0:53:42182 days 12 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000091877040.10000005
0xb58640819685a15f4b43c0d47a26c625d1437d9b28634c26120cedd4ba320c0eCcip Send155094852023-10-04 19:17:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x8da25702ec87b167287bd6bec2f3c61366e9d29784ca0e59bad7ed8f70b90cf8Ccip Send155094552023-10-04 19:16:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x570d298d76316d164adb93d1e26a1a334c3004e9e800f14ae2207c14ae0e1d0eCcip Send155094252023-10-04 19:15:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0xcfac426fbc2a96800672318f9c1463d163319f7b46025ba7689c4e24835857f5Ccip Send155093952023-10-04 19:14:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x175d632e2f4191ed9f126fadc8dd2eed8160f233315d4637fe3339f21d8f244eCcip Send155093652023-10-04 19:13:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x178bff00fe9ff2a8f96ee8b3aed2b9c5c40b7a54c2d7050060fb8e1413805644Ccip Send155093352023-10-04 19:12:18195 days 17 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x1c191d68e3028fbc2f96ebdb70a4e7b4803338b5899b3cd1a09437a6bfa4490bCcip Send155093052023-10-04 19:11:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x19a1c04830f62103bfc0ae65264ab6b93d14a532db2fba512e6a7ac9b3fee132Ccip Send155092752023-10-04 19:10:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x2ed141486ca59616bfb9b015414614404e51e12936c44fb925490fb6254243cfCcip Send155092452023-10-04 19:09:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x5112d4efc187fb3c9cbea481c4d746774f29966a321a8075bdb33d808d360fa2Ccip Send155092152023-10-04 19:08:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0xc0827321badf40c0609ed670c1fbf20dc8d895284334bd01764191a7ae8bc9dbCcip Send155091852023-10-04 19:07:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x819f89a3089741031507f19ffd7215fde536b16b870e1082951dc862d1c53fe6Ccip Send155091552023-10-04 19:06:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x04e63cb3278f5cbdbe9cf62b8956ec7a406551584df489cbd7501eb1e2236ad1Ccip Send155091252023-10-04 19:05:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
0x592217e507f3a69c4f1342849434d3c19cca18201927d947a3fcf5fbff7c1b09Ccip Send155090952023-10-04 19:04:18195 days 18 hrs ago0xda9e8e71bb750a996af33ebb8abb18cd9eb9dc75 IN  0xeb52e9ae4a9fb37172978642d4c141ef53876f260 ETH0.0000116010050.10000005
[ Download CSV Export 
Latest 25 internal transaction
Parent Txn Hash Block From To Value
0x5403c3d3d0f37736b1a7f248bdf0e875fbb6029176f317918899d123b91fec95184165582023-12-11 2:19:44128 days 10 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x5403c3d3d0f37736b1a7f248bdf0e875fbb6029176f317918899d123b91fec95184165582023-12-11 2:19:44128 days 10 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x5403c3d3d0f37736b1a7f248bdf0e875fbb6029176f317918899d123b91fec95184165582023-12-11 2:19:44128 days 10 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x5403c3d3d0f37736b1a7f248bdf0e875fbb6029176f317918899d123b91fec95184165582023-12-11 2:19:44128 days 10 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0xa8f1a6d98b45e98c2fc6a8b514165de82be55647ff912d9f3bd0a0a0491ea5f4184163782023-12-11 2:13:44128 days 10 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0xa8f1a6d98b45e98c2fc6a8b514165de82be55647ff912d9f3bd0a0a0491ea5f4184163782023-12-11 2:13:44128 days 10 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0xa8f1a6d98b45e98c2fc6a8b514165de82be55647ff912d9f3bd0a0a0491ea5f4184163782023-12-11 2:13:44128 days 10 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0xa8f1a6d98b45e98c2fc6a8b514165de82be55647ff912d9f3bd0a0a0491ea5f4184163782023-12-11 2:13:44128 days 10 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x929571d1ccc32e39b95eb2f927be644a9f8b1b0b297e3837a68cf0b6d24ba417184161982023-12-11 2:07:44128 days 11 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x929571d1ccc32e39b95eb2f927be644a9f8b1b0b297e3837a68cf0b6d24ba417184161982023-12-11 2:07:44128 days 11 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x929571d1ccc32e39b95eb2f927be644a9f8b1b0b297e3837a68cf0b6d24ba417184161982023-12-11 2:07:44128 days 11 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x929571d1ccc32e39b95eb2f927be644a9f8b1b0b297e3837a68cf0b6d24ba417184161982023-12-11 2:07:44128 days 11 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x4fc05baa7543777920189431f76b7c82aa8fb11dc09f9e70a08cc4b3f0100d60184142392023-12-11 1:02:26128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x4fc05baa7543777920189431f76b7c82aa8fb11dc09f9e70a08cc4b3f0100d60184142392023-12-11 1:02:26128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x4fc05baa7543777920189431f76b7c82aa8fb11dc09f9e70a08cc4b3f0100d60184142392023-12-11 1:02:26128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x4fc05baa7543777920189431f76b7c82aa8fb11dc09f9e70a08cc4b3f0100d60184142392023-12-11 1:02:26128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0xea04052967772bfa18068bfceb4576a9f4f1085fad617193ea9a2ccfd9779fd5184136782023-12-11 0:43:44128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0xea04052967772bfa18068bfceb4576a9f4f1085fad617193ea9a2ccfd9779fd5184136782023-12-11 0:43:44128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0xea04052967772bfa18068bfceb4576a9f4f1085fad617193ea9a2ccfd9779fd5184136782023-12-11 0:43:44128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0xea04052967772bfa18068bfceb4576a9f4f1085fad617193ea9a2ccfd9779fd5184136782023-12-11 0:43:44128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x2409043fdfaf160e5493ae25fae82aa5c1e40bda8f3b75ba9af3e225c3bd0ea1184127382023-12-11 0:12:24128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x2409043fdfaf160e5493ae25fae82aa5c1e40bda8f3b75ba9af3e225c3bd0ea1184127382023-12-11 0:12:24128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x2409043fdfaf160e5493ae25fae82aa5c1e40bda8f3b75ba9af3e225c3bd0ea1184127382023-12-11 0:12:24128 days 12 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
0x2409043fdfaf160e5493ae25fae82aa5c1e40bda8f3b75ba9af3e225c3bd0ea1184127382023-12-11 0:12:24128 days 12 hrs ago 0xfdb536a22ea46fcd7dce0e1b4a5fbd4a8a9a3258 0xeb52e9ae4a9fb37172978642d4c141ef53876f260.001317363443646097 ETH
0x993043632b13382f7ec56db65ea808b2745b6fc6573270359e176b10fbe8de7a184125182023-12-11 0:05:04128 days 13 hrs ago 0xeb52e9ae4a9fb37172978642d4c141ef53876f260x42000000000000000000000000000000000000060.001317363443646097 ETH
[ Download CSV Export 
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
Router

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 26000 runs

Other Settings:
default evmVersion
File 1 of 22 : Router.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity 0.8.19;

import {TypeAndVersionInterface} from "../interfaces/TypeAndVersionInterface.sol";
import {IRouterClient} from "./interfaces/IRouterClient.sol";
import {IRouter} from "./interfaces/IRouter.sol";
import {IEVM2AnyOnRamp} from "./interfaces/IEVM2AnyOnRamp.sol";
import {IARM} from "./interfaces/IARM.sol";
import {IWrappedNative} from "./interfaces/IWrappedNative.sol";
import {IAny2EVMMessageReceiver} from "./interfaces/IAny2EVMMessageReceiver.sol";

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

import {EnumerableMap} from "../vendor/openzeppelin-solidity/v4.8.0/utils/structs/EnumerableMap.sol";
import {SafeERC20} from "../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/utils/SafeERC20.sol";
import {IERC20} from "../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";

/// @title Router
/// @notice This is the entry point for the end user wishing to send data across chains.
/// @dev This contract is used as a router for both on-ramps and off-ramps
contract Router is IRouter, IRouterClient, TypeAndVersionInterface, OwnerIsCreator {
  using SafeERC20 for IERC20;
  using EnumerableMap for EnumerableMap.AddressToUintMap;

  error FailedToSendValue();
  error InvalidRecipientAddress(address to);
  error OffRampMismatch();
  error BadARMSignal();

  event OnRampSet(uint64 indexed destChainSelector, address onRamp);
  event OffRampAdded(uint64 indexed sourceChainSelector, address offRamp);
  event OffRampRemoved(uint64 indexed sourceChainSelector, address offRamp);
  event MessageExecuted(bytes32 messageId, uint64 sourceChainSelector, address offRamp, bytes32 calldataHash);

  struct OnRamp {
    uint64 destChainSelector;
    address onRamp;
  }
  struct OffRamp {
    uint64 sourceChainSelector;
    address offRamp;
  }

  // solhint-disable-next-line chainlink-solidity/all-caps-constant-storage-variables
  string public constant override typeAndVersion = "Router 1.0.0";
  // 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 public constant MAX_RET_BYTES = 4 + 4 * 32;
  // STATIC CONFIG
  // Address of arm proxy contract.
  address private immutable i_armProxy;

  // DYNAMIC CONFIG
  address private s_wrappedNative;
  // destChainSelector => onRamp address
  // Only ever one onRamp enabled at a time for a given destChainSelector.
  mapping(uint256 destChainSelector => address onRamp) private s_onRamps;
  // Mapping of offRamps to source chain ids
  // Can be multiple offRamps enabled at a time for a given sourceChainSelector,
  // for example during an no downtime upgrade while v1 messages are being flushed.
  EnumerableMap.AddressToUintMap private s_offRamps;

  constructor(address wrappedNative, address armProxy) {
    // Zero address indicates unsupported auto-wrapping, therefore, unsupported
    // native fee token payments.
    s_wrappedNative = wrappedNative;
    i_armProxy = armProxy;
  }

  // ================================================================
  // |                       Message sending                        |
  // ================================================================

  /// @inheritdoc IRouterClient
  function getFee(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage memory message
  ) external view returns (uint256 fee) {
    if (message.feeToken == address(0)) {
      // For empty feeToken return native quote.
      message.feeToken = address(s_wrappedNative);
    }
    address onRamp = s_onRamps[destinationChainSelector];
    if (onRamp == address(0)) revert UnsupportedDestinationChain(destinationChainSelector);
    return IEVM2AnyOnRamp(onRamp).getFee(message);
  }

  /// @inheritdoc IRouterClient
  function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory) {
    if (!isChainSupported(chainSelector)) {
      return new address[](0);
    }
    return IEVM2AnyOnRamp(s_onRamps[uint256(chainSelector)]).getSupportedTokens();
  }

  /// @inheritdoc IRouterClient
  function isChainSupported(uint64 chainSelector) public view returns (bool) {
    return s_onRamps[chainSelector] != address(0);
  }

  /// @inheritdoc IRouterClient
  function ccipSend(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage memory message
  ) external payable whenHealthy returns (bytes32) {
    address onRamp = s_onRamps[destinationChainSelector];
    if (onRamp == address(0)) revert UnsupportedDestinationChain(destinationChainSelector);
    uint256 feeTokenAmount;
    // address(0) signals payment in true native
    if (message.feeToken == address(0)) {
      // for fee calculation we check the wrapped native price as we wrap
      // as part of the native fee coin payment.
      message.feeToken = s_wrappedNative;
      feeTokenAmount = IEVM2AnyOnRamp(onRamp).getFee(message);
      // Ensure sufficient native.
      if (msg.value < feeTokenAmount) revert InsufficientFeeTokenAmount();
      // Wrap and send native payment.
      // Note we take the whole msg.value regardless if its larger.
      feeTokenAmount = msg.value;
      IWrappedNative(message.feeToken).deposit{value: feeTokenAmount}();
      IERC20(message.feeToken).safeTransfer(onRamp, feeTokenAmount);
    } else {
      if (msg.value > 0) revert InvalidMsgValue();
      feeTokenAmount = IEVM2AnyOnRamp(onRamp).getFee(message);
      IERC20(message.feeToken).safeTransferFrom(msg.sender, onRamp, feeTokenAmount);
    }

    // Transfer the tokens to the token pools.
    for (uint256 i = 0; i < message.tokenAmounts.length; ++i) {
      IERC20 token = IERC20(message.tokenAmounts[i].token);
      token.safeTransferFrom(
        msg.sender,
        address(IEVM2AnyOnRamp(onRamp).getPoolBySourceToken(token)),
        message.tokenAmounts[i].amount
      );
    }

    return IEVM2AnyOnRamp(onRamp).forwardFromRouter(message, feeTokenAmount, msg.sender);
  }

  // ================================================================
  // |                      Message execution                       |
  // ================================================================

  /// @inheritdoc IRouter
  /// @dev Handles the edge case where we want to pass a specific amount of gas,
  /// @dev but EIP-150 sends all but 1/64 of the remaining gas instead so the user gets
  /// @dev less gas than they paid for. The other 2 parts of EIP-150 do not apply since
  /// @dev a) we hard code value=0 and b) we ensure code already exists.
  /// @dev If we revert instead, then that will never happen.
  /// @dev Separately we capture the return data up to a maximum size to avoid return bombs,
  /// @dev borrowed from https://github.com/nomad-xyz/ExcessivelySafeCall/blob/main/src/ExcessivelySafeCall.sol.
  function routeMessage(
    Client.Any2EVMMessage calldata message,
    uint16 gasForCallExactCheck,
    uint256 gasLimit,
    address receiver
  )
    external
    override
    onlyOffRamp(message.sourceChainSelector)
    whenHealthy
    returns (bool success, bytes memory retData)
  {
    // We encode here instead of the offRamps to constrain specifically what functions
    // can be called from the router.
    bytes memory data = abi.encodeWithSelector(IAny2EVMMessageReceiver.ccipReceive.selector, message);
    // allocate retData memory ahead of time
    retData = new bytes(MAX_RET_BYTES);

    // solhint-disable-next-line no-inline-assembly
    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(receiver)) {
        revert(0, 0)
      }

      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) {
        revert(0, 0)
      }
      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)) {
        revert(0, 0)
      }
      // call and return whether we succeeded. ignore return data
      // call(gas,addr,value,argsOffset,argsLength,retOffset,retLength)
      success := call(gasLimit, receiver, 0, add(data, 0x20), mload(data), 0, 0)

      // limit our copy to MAX_RET_BYTES bytes
      let toCopy := returndatasize()
      if gt(toCopy, MAX_RET_BYTES) {
        toCopy := MAX_RET_BYTES
      }
      // Store the length of the copied bytes
      mstore(retData, toCopy)
      // copy the bytes from retData[0:_toCopy]
      returndatacopy(add(retData, 0x20), 0, toCopy)
    }
    emit MessageExecuted(message.messageId, message.sourceChainSelector, msg.sender, keccak256(data));
    return (success, retData);
  }

  // ================================================================
  // |                           Config                             |
  // ================================================================

  /// @notice Gets the wrapped representation of the native fee coin.
  /// @return The address of the ERC20 wrapped native.
  function getWrappedNative() external view returns (address) {
    return s_wrappedNative;
  }

  /// @notice Sets a new wrapped native token.
  /// @param wrappedNative The address of the new wrapped native ERC20 token.
  function setWrappedNative(address wrappedNative) external onlyOwner {
    s_wrappedNative = wrappedNative;
  }

  /// @notice Gets the arm address
  /// @return The address of the ARM proxy contract.
  function getArmProxy() external view returns (address) {
    return i_armProxy;
  }

  /// @notice Return the configured onramp for specific a destination chain.
  /// @param destChainSelector The destination chain Id to get the onRamp for.
  /// @return The address of the onRamp.
  function getOnRamp(uint64 destChainSelector) external view returns (address) {
    return s_onRamps[destChainSelector];
  }

  /// @notice Return a full list of configured offRamps.
  function getOffRamps() external view returns (OffRamp[] memory) {
    OffRamp[] memory offRamps = new OffRamp[](s_offRamps.length());
    for (uint256 i = 0; i < offRamps.length; ++i) {
      (address offRamp, uint256 sourceChainSelector) = s_offRamps.at(i);
      offRamps[i] = OffRamp({sourceChainSelector: uint64(sourceChainSelector), offRamp: offRamp});
    }
    return offRamps;
  }

  /// @notice Returns true if the given address is a permissioned offRamp
  /// and sourceChainSelector if so.
  function isOffRamp(address offRamp) external view returns (bool, uint64) {
    (bool exists, uint256 sourceChainSelector) = s_offRamps.tryGet(offRamp);
    return (exists, uint64(sourceChainSelector));
  }

  /// @notice applyRampUpdates applies a set of ramp changes which provides
  /// the ability to add new chains and upgrade ramps.
  function applyRampUpdates(
    OnRamp[] calldata onRampUpdates,
    OffRamp[] calldata offRampRemoves,
    OffRamp[] calldata offRampAdds
  ) external onlyOwner {
    // Apply egress updates.
    // We permit zero address as way to disable egress.
    for (uint256 i = 0; i < onRampUpdates.length; ++i) {
      OnRamp memory onRampUpdate = onRampUpdates[i];
      s_onRamps[onRampUpdate.destChainSelector] = onRampUpdate.onRamp;
      emit OnRampSet(onRampUpdate.destChainSelector, onRampUpdate.onRamp);
    }
    // Apply ingress updates.
    // We permit an empty list as a way to disable ingress.
    for (uint256 i = 0; i < offRampRemoves.length; ++i) {
      uint64 rampSelector = offRampRemoves[i].sourceChainSelector;
      address rampAddress = offRampRemoves[i].offRamp;

      if (s_offRamps.get(rampAddress) != uint256(rampSelector)) revert OffRampMismatch();

      if (s_offRamps.remove(rampAddress)) {
        emit OffRampRemoved(rampSelector, rampAddress);
      }
    }
    for (uint256 i = 0; i < offRampAdds.length; ++i) {
      uint64 rampSelector = offRampAdds[i].sourceChainSelector;
      address rampAddress = offRampAdds[i].offRamp;

      if (s_offRamps.set(rampAddress, rampSelector)) {
        emit OffRampAdded(rampSelector, rampAddress);
      }
    }
  }

  /// @notice Provides the ability for the owner to recover any tokens accidentally
  /// sent to this contract.
  /// @dev Must be onlyOwner to avoid malicious token contract calls.
  /// @param tokenAddress ERC20-token to recover
  /// @param to Destination address to send the tokens to.
  function recoverTokens(address tokenAddress, address to, uint256 amount) external onlyOwner {
    if (to == address(0)) revert InvalidRecipientAddress(to);

    if (tokenAddress == address(0)) {
      (bool success, ) = to.call{value: amount}("");
      if (!success) revert FailedToSendValue();
      return;
    }
    IERC20(tokenAddress).safeTransfer(to, amount);
  }

  // ================================================================
  // |                           Access                             |
  // ================================================================

  /// @notice only lets permissioned offRamps execute
  /// @dev We additionally restrict offRamps to specific source chains for defense in depth.
  modifier onlyOffRamp(uint64 expectedSourceChainSelector) {
    (bool exists, uint256 sourceChainSelector) = s_offRamps.tryGet(msg.sender);
    if (!exists || expectedSourceChainSelector != uint64(sourceChainSelector)) revert OnlyOffRamp();
    _;
  }

  /// @notice Ensure that the ARM has not emitted a bad signal, and that the latest heartbeat is not stale.
  modifier whenHealthy() {
    if (IARM(i_armProxy).isCursed()) revert BadARMSignal();
    _;
  }
}

File 2 of 22 : TypeAndVersionInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

abstract contract TypeAndVersionInterface {
  function typeAndVersion() external pure virtual returns (string memory);
}

File 3 of 22 : IRouterClient.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

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

interface IRouterClient {
  error UnsupportedDestinationChain(uint64 destChainSelector);
  error InsufficientFeeTokenAmount();
  error InvalidMsgValue();

  /// @notice Checks if the given chain ID is supported for sending/receiving.
  /// @param chainSelector The chain to check.
  /// @return supported is true if it is supported, false if not.
  function isChainSupported(uint64 chainSelector) external view returns (bool supported);

  /// @notice Gets a list of all supported tokens which can be sent or received
  /// to/from a given chain id.
  /// @param chainSelector The chainSelector.
  /// @return tokens The addresses of all tokens that are supported.
  function getSupportedTokens(uint64 chainSelector) external view returns (address[] memory tokens);

  /// @param destinationChainSelector The destination chainSelector
  /// @param message The cross-chain CCIP message including data and/or tokens
  /// @return fee returns guaranteed execution fee for the specified message
  /// delivery to destination chain
  /// @dev returns 0 fee on invalid message.
  function getFee(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage memory message
  ) external view returns (uint256 fee);

  /// @notice Request a message to be sent to the destination chain
  /// @param destinationChainSelector The destination chain ID
  /// @param message The cross-chain CCIP message including data and/or tokens
  /// @return messageId The message ID
  /// @dev Note if msg.value is larger than the required fee (from getFee) we accept
  /// the overpayment with no refund.
  function ccipSend(
    uint64 destinationChainSelector,
    Client.EVM2AnyMessage calldata message
  ) external payable returns (bytes32);
}

File 4 of 22 : IRouter.sol
// SPDX-License-Identifier: BUSL-1.1
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.
  function routeMessage(
    Client.Any2EVMMessage calldata message,
    uint16 gasForCallExactCheck,
    uint256 gasLimit,
    address receiver
  ) external returns (bool success, bytes memory retBytes);
}

File 5 of 22 : IEVM2AnyOnRamp.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

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

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

import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";

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

  /// @notice Get the pool for a specific token
  /// @param sourceToken The source chain token to get the pool for
  /// @return pool Token pool
  function getPoolBySourceToken(IERC20 sourceToken) external view returns (IPool);

  /// @notice Gets a list of all supported source chain tokens.
  /// @return tokens The addresses of all tokens that this onRamp supports for sending.
  function getSupportedTokens() external view returns (address[] memory tokens);

  /// @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 next nonce for a given sender
  /// @param sender The sender to get the nonce for
  /// @return nonce The next nonce for the sender
  function getSenderNonce(address sender) external view returns (uint64 nonce);

  /// @notice Adds and removed token pools.
  /// @param removes The tokens and pools to be removed
  /// @param adds The tokens and pools to be added.
  function applyPoolUpdates(Internal.PoolUpdate[] memory removes, Internal.PoolUpdate[] memory adds) external;

  /// @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 message Message struct to send
  /// @param originalSender The original initiator of the CCIP request
  function forwardFromRouter(
    Client.EVM2AnyMessage memory message,
    uint256 feeTokenAmount,
    address originalSender
  ) external returns (bytes32);
}

File 6 of 22 : IARM.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

/// @notice This interface contains the only ARM-related functions that might be used on-chain by other CCIP contracts.
interface IARM {
  /// @notice A Merkle root tagged with the address of the commit store contract it is destined for.
  struct TaggedRoot {
    address commitStore;
    bytes32 root;
  }

  /// @notice Callers MUST NOT cache the return value as a blessed tagged root could become unblessed.
  function isBlessed(TaggedRoot calldata taggedRoot) external view returns (bool);

  /// @notice When the ARM is "cursed", CCIP pauses until the curse is lifted.
  function isCursed() external view returns (bool);
}

File 7 of 22 : IWrappedNative.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {IERC20} from "../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";

interface IWrappedNative is IERC20 {
  function deposit() external payable;
}

File 8 of 22 : IAny2EVMMessageReceiver.sol
// SPDX-License-Identifier: BUSL-1.1
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;
}

File 9 of 22 : Client.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

// End consumer library.
library Client {
  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 and strict = false.
  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(EVMExtraArgsV1)
  }

  // extraArgs will evolve to support new features
  // bytes4(keccak256("CCIP EVMExtraArgsV1"));
  bytes4 public constant EVM_EXTRA_ARGS_V1_TAG = 0x97a657c9;
  struct EVMExtraArgsV1 {
    uint256 gasLimit; // ATTENTION!!! MAX GAS LIMIT 4M FOR BETA TESTING
    bool strict; // See strict sequencing details below.
  }

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

File 10 of 22 : OwnerIsCreator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

/// @title The OwnerIsCreator contract
/// @notice A contract with helpers for basic contract ownership.
contract OwnerIsCreator is ConfirmedOwner {
  constructor() ConfirmedOwner(msg.sender) {}
}

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

pragma solidity ^0.8.0;

import "./EnumerableSet.sol";

/**
 * @dev Library for managing an enumerable variant of Solidity's
 * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
 * type.
 *
 * Maps have the following properties:
 *
 * - Entries are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Entries are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableMap for EnumerableMap.UintToAddressMap;
 *
 *     // Declare a set state variable
 *     EnumerableMap.UintToAddressMap private myMap;
 * }
 * ```
 *
 * The following map types are supported:
 *
 * - `uint256 -> address` (`UintToAddressMap`) since v3.0.0
 * - `address -> uint256` (`AddressToUintMap`) since v4.6.0
 * - `bytes32 -> bytes32` (`Bytes32ToBytes32Map`) since v4.6.0
 * - `uint256 -> uint256` (`UintToUintMap`) since v4.7.0
 * - `bytes32 -> uint256` (`Bytes32ToUintMap`) since v4.7.0
 *
 * [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 EnumerableMap, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableMap.
 * ====
 */
library EnumerableMap {
  using EnumerableSet for EnumerableSet.Bytes32Set;

  // To implement this library for multiple types with as little code
  // repetition as possible, we write it in terms of a generic Map type with
  // bytes32 keys and values.
  // The Map implementation uses private functions, and user-facing
  // implementations (such as Uint256ToAddressMap) are just wrappers around
  // the underlying Map.
  // This means that we can only create new EnumerableMaps for types that fit
  // in bytes32.

  struct Bytes32ToBytes32Map {
    // Storage of keys
    EnumerableSet.Bytes32Set _keys;
    mapping(bytes32 => bytes32) _values;
  }

  /**
   * @dev Adds a key-value pair to a map, or updates the value for an existing
   * key. O(1).
   *
   * Returns true if the key was added to the map, that is if it was not
   * already present.
   */
  function set(
    Bytes32ToBytes32Map storage map,
    bytes32 key,
    bytes32 value
  ) internal returns (bool) {
    map._values[key] = value;
    return map._keys.add(key);
  }

  /**
   * @dev Removes a key-value pair from a map. O(1).
   *
   * Returns true if the key was removed from the map, that is if it was present.
   */
  function remove(Bytes32ToBytes32Map storage map, bytes32 key) internal returns (bool) {
    delete map._values[key];
    return map._keys.remove(key);
  }

  /**
   * @dev Returns true if the key is in the map. O(1).
   */
  function contains(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool) {
    return map._keys.contains(key);
  }

  /**
   * @dev Returns the number of key-value pairs in the map. O(1).
   */
  function length(Bytes32ToBytes32Map storage map) internal view returns (uint256) {
    return map._keys.length();
  }

  /**
   * @dev Returns the key-value pair stored at position `index` in the map. O(1).
   *
   * Note that there are no guarantees on the ordering of entries inside the
   * array, and it may change when more entries are added or removed.
   *
   * Requirements:
   *
   * - `index` must be strictly less than {length}.
   */
  function at(Bytes32ToBytes32Map storage map, uint256 index) internal view returns (bytes32, bytes32) {
    bytes32 key = map._keys.at(index);
    return (key, map._values[key]);
  }

  /**
   * @dev Tries to returns the value associated with `key`. O(1).
   * Does not revert if `key` is not in the map.
   */
  function tryGet(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bool, bytes32) {
    bytes32 value = map._values[key];
    if (value == bytes32(0)) {
      return (contains(map, key), bytes32(0));
    } else {
      return (true, value);
    }
  }

  /**
   * @dev Returns the value associated with `key`. O(1).
   *
   * Requirements:
   *
   * - `key` must be in the map.
   */
  function get(Bytes32ToBytes32Map storage map, bytes32 key) internal view returns (bytes32) {
    bytes32 value = map._values[key];
    require(value != 0 || contains(map, key), "EnumerableMap: nonexistent key");
    return value;
  }

  /**
   * @dev Same as {get}, with a custom error message when `key` is not in the map.
   *
   * CAUTION: This function is deprecated because it requires allocating memory for the error
   * message unnecessarily. For custom revert reasons use {tryGet}.
   */
  function get(
    Bytes32ToBytes32Map storage map,
    bytes32 key,
    string memory errorMessage
  ) internal view returns (bytes32) {
    bytes32 value = map._values[key];
    require(value != 0 || contains(map, key), errorMessage);
    return value;
  }

  // UintToUintMap

  struct UintToUintMap {
    Bytes32ToBytes32Map _inner;
  }

  /**
   * @dev Adds a key-value pair to a map, or updates the value for an existing
   * key. O(1).
   *
   * Returns true if the key was added to the map, that is if it was not
   * already present.
   */
  function set(
    UintToUintMap storage map,
    uint256 key,
    uint256 value
  ) internal returns (bool) {
    return set(map._inner, bytes32(key), bytes32(value));
  }

  /**
   * @dev Removes a value from a set. O(1).
   *
   * Returns true if the key was removed from the map, that is if it was present.
   */
  function remove(UintToUintMap storage map, uint256 key) internal returns (bool) {
    return remove(map._inner, bytes32(key));
  }

  /**
   * @dev Returns true if the key is in the map. O(1).
   */
  function contains(UintToUintMap storage map, uint256 key) internal view returns (bool) {
    return contains(map._inner, bytes32(key));
  }

  /**
   * @dev Returns the number of elements in the map. O(1).
   */
  function length(UintToUintMap storage map) internal view returns (uint256) {
    return length(map._inner);
  }

  /**
   * @dev Returns the element 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(UintToUintMap storage map, uint256 index) internal view returns (uint256, uint256) {
    (bytes32 key, bytes32 value) = at(map._inner, index);
    return (uint256(key), uint256(value));
  }

  /**
   * @dev Tries to returns the value associated with `key`. O(1).
   * Does not revert if `key` is not in the map.
   */
  function tryGet(UintToUintMap storage map, uint256 key) internal view returns (bool, uint256) {
    (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
    return (success, uint256(value));
  }

  /**
   * @dev Returns the value associated with `key`. O(1).
   *
   * Requirements:
   *
   * - `key` must be in the map.
   */
  function get(UintToUintMap storage map, uint256 key) internal view returns (uint256) {
    return uint256(get(map._inner, bytes32(key)));
  }

  /**
   * @dev Same as {get}, with a custom error message when `key` is not in the map.
   *
   * CAUTION: This function is deprecated because it requires allocating memory for the error
   * message unnecessarily. For custom revert reasons use {tryGet}.
   */
  function get(
    UintToUintMap storage map,
    uint256 key,
    string memory errorMessage
  ) internal view returns (uint256) {
    return uint256(get(map._inner, bytes32(key), errorMessage));
  }

  // UintToAddressMap

  struct UintToAddressMap {
    Bytes32ToBytes32Map _inner;
  }

  /**
   * @dev Adds a key-value pair to a map, or updates the value for an existing
   * key. O(1).
   *
   * Returns true if the key was added to the map, that is if it was not
   * already present.
   */
  function set(
    UintToAddressMap storage map,
    uint256 key,
    address value
  ) internal returns (bool) {
    return set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
  }

  /**
   * @dev Removes a value from a set. O(1).
   *
   * Returns true if the key was removed from the map, that is if it was present.
   */
  function remove(UintToAddressMap storage map, uint256 key) internal returns (bool) {
    return remove(map._inner, bytes32(key));
  }

  /**
   * @dev Returns true if the key is in the map. O(1).
   */
  function contains(UintToAddressMap storage map, uint256 key) internal view returns (bool) {
    return contains(map._inner, bytes32(key));
  }

  /**
   * @dev Returns the number of elements in the map. O(1).
   */
  function length(UintToAddressMap storage map) internal view returns (uint256) {
    return length(map._inner);
  }

  /**
   * @dev Returns the element 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(UintToAddressMap storage map, uint256 index) internal view returns (uint256, address) {
    (bytes32 key, bytes32 value) = at(map._inner, index);
    return (uint256(key), address(uint160(uint256(value))));
  }

  /**
   * @dev Tries to returns the value associated with `key`. O(1).
   * Does not revert if `key` is not in the map.
   */
  function tryGet(UintToAddressMap storage map, uint256 key) internal view returns (bool, address) {
    (bool success, bytes32 value) = tryGet(map._inner, bytes32(key));
    return (success, address(uint160(uint256(value))));
  }

  /**
   * @dev Returns the value associated with `key`. O(1).
   *
   * Requirements:
   *
   * - `key` must be in the map.
   */
  function get(UintToAddressMap storage map, uint256 key) internal view returns (address) {
    return address(uint160(uint256(get(map._inner, bytes32(key)))));
  }

  /**
   * @dev Same as {get}, with a custom error message when `key` is not in the map.
   *
   * CAUTION: This function is deprecated because it requires allocating memory for the error
   * message unnecessarily. For custom revert reasons use {tryGet}.
   */
  function get(
    UintToAddressMap storage map,
    uint256 key,
    string memory errorMessage
  ) internal view returns (address) {
    return address(uint160(uint256(get(map._inner, bytes32(key), errorMessage))));
  }

  // AddressToUintMap

  struct AddressToUintMap {
    Bytes32ToBytes32Map _inner;
  }

  /**
   * @dev Adds a key-value pair to a map, or updates the value for an existing
   * key. O(1).
   *
   * Returns true if the key was added to the map, that is if it was not
   * already present.
   */
  function set(
    AddressToUintMap storage map,
    address key,
    uint256 value
  ) internal returns (bool) {
    return set(map._inner, bytes32(uint256(uint160(key))), bytes32(value));
  }

  /**
   * @dev Removes a value from a set. O(1).
   *
   * Returns true if the key was removed from the map, that is if it was present.
   */
  function remove(AddressToUintMap storage map, address key) internal returns (bool) {
    return remove(map._inner, bytes32(uint256(uint160(key))));
  }

  /**
   * @dev Returns true if the key is in the map. O(1).
   */
  function contains(AddressToUintMap storage map, address key) internal view returns (bool) {
    return contains(map._inner, bytes32(uint256(uint160(key))));
  }

  /**
   * @dev Returns the number of elements in the map. O(1).
   */
  function length(AddressToUintMap storage map) internal view returns (uint256) {
    return length(map._inner);
  }

  /**
   * @dev Returns the element 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(AddressToUintMap storage map, uint256 index) internal view returns (address, uint256) {
    (bytes32 key, bytes32 value) = at(map._inner, index);
    return (address(uint160(uint256(key))), uint256(value));
  }

  /**
   * @dev Tries to returns the value associated with `key`. O(1).
   * Does not revert if `key` is not in the map.
   */
  function tryGet(AddressToUintMap storage map, address key) internal view returns (bool, uint256) {
    (bool success, bytes32 value) = tryGet(map._inner, bytes32(uint256(uint160(key))));
    return (success, uint256(value));
  }

  /**
   * @dev Returns the value associated with `key`. O(1).
   *
   * Requirements:
   *
   * - `key` must be in the map.
   */
  function get(AddressToUintMap storage map, address key) internal view returns (uint256) {
    return uint256(get(map._inner, bytes32(uint256(uint160(key)))));
  }

  /**
   * @dev Same as {get}, with a custom error message when `key` is not in the map.
   *
   * CAUTION: This function is deprecated because it requires allocating memory for the error
   * message unnecessarily. For custom revert reasons use {tryGet}.
   */
  function get(
    AddressToUintMap storage map,
    address key,
    string memory errorMessage
  ) internal view returns (uint256) {
    return uint256(get(map._inner, bytes32(uint256(uint160(key))), errorMessage));
  }

  // Bytes32ToUintMap

  struct Bytes32ToUintMap {
    Bytes32ToBytes32Map _inner;
  }

  /**
   * @dev Adds a key-value pair to a map, or updates the value for an existing
   * key. O(1).
   *
   * Returns true if the key was added to the map, that is if it was not
   * already present.
   */
  function set(
    Bytes32ToUintMap storage map,
    bytes32 key,
    uint256 value
  ) internal returns (bool) {
    return set(map._inner, key, bytes32(value));
  }

  /**
   * @dev Removes a value from a set. O(1).
   *
   * Returns true if the key was removed from the map, that is if it was present.
   */
  function remove(Bytes32ToUintMap storage map, bytes32 key) internal returns (bool) {
    return remove(map._inner, key);
  }

  /**
   * @dev Returns true if the key is in the map. O(1).
   */
  function contains(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool) {
    return contains(map._inner, key);
  }

  /**
   * @dev Returns the number of elements in the map. O(1).
   */
  function length(Bytes32ToUintMap storage map) internal view returns (uint256) {
    return length(map._inner);
  }

  /**
   * @dev Returns the element 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(Bytes32ToUintMap storage map, uint256 index) internal view returns (bytes32, uint256) {
    (bytes32 key, bytes32 value) = at(map._inner, index);
    return (key, uint256(value));
  }

  /**
   * @dev Tries to returns the value associated with `key`. O(1).
   * Does not revert if `key` is not in the map.
   */
  function tryGet(Bytes32ToUintMap storage map, bytes32 key) internal view returns (bool, uint256) {
    (bool success, bytes32 value) = tryGet(map._inner, key);
    return (success, uint256(value));
  }

  /**
   * @dev Returns the value associated with `key`. O(1).
   *
   * Requirements:
   *
   * - `key` must be in the map.
   */
  function get(Bytes32ToUintMap storage map, bytes32 key) internal view returns (uint256) {
    return uint256(get(map._inner, key));
  }

  /**
   * @dev Same as {get}, with a custom error message when `key` is not in the map.
   *
   * CAUTION: This function is deprecated because it requires allocating memory for the error
   * message unnecessarily. For custom revert reasons use {tryGet}.
   */
  function get(
    Bytes32ToUintMap storage map,
    bytes32 key,
    string memory errorMessage
  ) internal view returns (uint256) {
    return uint256(get(map._inner, key, errorMessage));
  }
}

File 12 of 22 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
  using Address for address;

  function safeTransfer(
    IERC20 token,
    address to,
    uint256 value
  ) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
  }

  function safeTransferFrom(
    IERC20 token,
    address from,
    address to,
    uint256 value
  ) internal {
    _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
  }

  /**
   * @dev Deprecated. This function has issues similar to the ones found in
   * {IERC20-approve}, and its usage is discouraged.
   *
   * Whenever possible, use {safeIncreaseAllowance} and
   * {safeDecreaseAllowance} instead.
   */
  function safeApprove(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    // safeApprove should only be called when setting an initial allowance,
    // or when resetting it to zero. To increase and decrease it, use
    // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
    require(
      (value == 0) || (token.allowance(address(this), spender) == 0),
      "SafeERC20: approve from non-zero to non-zero allowance"
    );
    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
  }

  function safeIncreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    uint256 newAllowance = token.allowance(address(this), spender) + value;
    _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
  }

  function safeDecreaseAllowance(
    IERC20 token,
    address spender,
    uint256 value
  ) internal {
    unchecked {
      uint256 oldAllowance = token.allowance(address(this), spender);
      require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
      uint256 newAllowance = oldAllowance - value;
      _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }
  }

  function safePermit(
    IERC20Permit token,
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) internal {
    uint256 nonceBefore = token.nonces(owner);
    token.permit(owner, spender, value, deadline, v, r, s);
    uint256 nonceAfter = token.nonces(owner);
    require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
  }

  /**
   * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
   * on the return value: the return value is optional (but if data is returned, it must not be false).
   * @param token The token targeted by the call.
   * @param data The call data (encoded using abi.encode or one of its variants).
   */
  function _callOptionalReturn(IERC20 token, bytes memory data) private {
    // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
    // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
    // the target address contains contract code and also asserts for success in the low-level call.

    bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
    if (returndata.length > 0) {
      // Return data is optional
      require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }
  }
}

File 13 of 22 : IERC20.sol
// 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);
}

File 14 of 22 : IPool.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

import {IERC20} from "../../../vendor/openzeppelin-solidity/v4.8.0/token/ERC20/IERC20.sol";

// Shared public interface for multiple pool types.
// Each pool type handles a different child token model (lock/unlock, mint/burn.)
interface IPool {
  /// @notice Lock tokens into the pool or burn the tokens.
  /// @param originalSender Original sender of the tokens.
  /// @param receiver Receiver of the tokens on destination chain.
  /// @param amount Amount to lock or burn.
  /// @param destChainSelector Destination chain Id.
  /// @param extraArgs Additional data passed in by sender for lockOrBurn processing
  /// in custom pools on source chain.
  /// @return retData Optional field that contains bytes. Unused for now but already
  /// implemented to allow future upgrades while preserving the interface.
  function lockOrBurn(
    address originalSender,
    bytes calldata receiver,
    uint256 amount,
    uint64 destChainSelector,
    bytes calldata extraArgs
  ) external returns (bytes memory);

  /// @notice Releases or mints tokens to the receiver address.
  /// @param originalSender Original sender of the tokens.
  /// @param receiver Receiver of the tokens.
  /// @param amount Amount to release or mint.
  /// @param sourceChainSelector Source chain Id.
  /// @param extraData Additional data supplied offchain for releaseOrMint processing in
  /// custom pools on dest chain. This could be an attestation that was retrieved through a
  /// third party API.
  /// @dev offchainData can come from any untrusted source.
  function releaseOrMint(
    bytes memory originalSender,
    address receiver,
    uint256 amount,
    uint64 sourceChainSelector,
    bytes memory extraData
  ) external;

  /// @notice Gets the IERC20 token that this pool can lock or burn.
  /// @return token The IERC20 token representation.
  function getToken() external view returns (IERC20 token);
}

File 15 of 22 : Internal.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

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

// Library for CCIP internal definitions common to multiple contracts.
library Internal {
  struct PriceUpdates {
    TokenPriceUpdate[] tokenPriceUpdates;
    uint64 destChainSelector; // --┐ Destination chain selector
    uint192 usdPerUnitGas; // -----┘ 1e18 USD per smallest unit (e.g. wei) of destination chain gas
  }

  struct TokenPriceUpdate {
    address sourceToken; // Source token
    uint192 usdPerToken; // 1e18 USD per smallest unit of token
  }

  struct TimestampedUint192Value {
    uint192 value; // -------┐ The price, in 1e18 USD.
    uint64 timestamp; // ----┘ Timestamp of the most recent price update.
  }

  struct PoolUpdate {
    address token; // The IERC20 token address
    address pool; // The token pool address
  }

  struct ExecutionReport {
    EVM2EVMMessage[] messages;
    // Contains a bytes array for each message
    // each inner bytes array contains bytes per transferred token
    bytes[][] offchainTokenData;
    bytes32[] proofs;
    uint256 proofFlagBits;
  }

  // @notice The cross chain message that gets committed to EVM chains
  struct EVM2EVMMessage {
    uint64 sourceChainSelector;
    uint64 sequenceNumber;
    uint256 feeTokenAmount;
    address sender;
    uint64 nonce;
    uint256 gasLimit;
    bool strict;
    // User fields
    address receiver;
    bytes data;
    Client.EVMTokenAmount[] tokenAmounts;
    address feeToken;
    bytes32 messageId;
  }

  function _toAny2EVMMessage(
    EVM2EVMMessage memory original,
    Client.EVMTokenAmount[] memory destTokenAmounts
  ) internal pure returns (Client.Any2EVMMessage memory message) {
    message = Client.Any2EVMMessage({
      messageId: original.messageId,
      sourceChainSelector: original.sourceChainSelector,
      sender: abi.encode(original.sender),
      data: original.data,
      destTokenAmounts: destTokenAmounts
    });
  }

  bytes32 internal constant EVM_2_EVM_MESSAGE_HASH = keccak256("EVM2EVMMessageEvent");

  function _hash(EVM2EVMMessage memory original, bytes32 metadataHash) internal pure returns (bytes32) {
    return
      keccak256(
        abi.encode(
          MerkleMultiProof.LEAF_DOMAIN_SEPARATOR,
          metadataHash,
          original.sequenceNumber,
          original.nonce,
          original.sender,
          original.receiver,
          keccak256(original.data),
          keccak256(abi.encode(original.tokenAmounts)),
          original.gasLimit,
          original.strict,
          original.feeToken,
          original.feeTokenAmount
        )
      );
  }

  /// @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.
  enum MessageExecutionState {
    UNTOUCHED,
    IN_PROGRESS,
    SUCCESS,
    FAILURE
  }
}

File 16 of 22 : ConfirmedOwner.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./ConfirmedOwnerWithProposal.sol";

/**
 * @title The ConfirmedOwner contract
 * @notice A contract with helpers for basic contract ownership.
 */
contract ConfirmedOwner is ConfirmedOwnerWithProposal {
  constructor(address newOwner) ConfirmedOwnerWithProposal(newOwner, address(0)) {}
}

File 17 of 22 : EnumerableSet.sol
// 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;
  }
}

File 18 of 22 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
  /**
   * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
   * given ``owner``'s signed approval.
   *
   * IMPORTANT: The same issues {IERC20-approve} has related to transaction
   * ordering also apply here.
   *
   * Emits an {Approval} event.
   *
   * Requirements:
   *
   * - `spender` cannot be the zero address.
   * - `deadline` must be a timestamp in the future.
   * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
   * over the EIP712-formatted function arguments.
   * - the signature must use ``owner``'s current nonce (see {nonces}).
   *
   * For more information on the signature format, see the
   * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
   * section].
   */
  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) external;

  /**
   * @dev Returns the current nonce for `owner`. This value must be
   * included whenever a signature is generated for {permit}.
   *
   * Every successful call to {permit} increases ``owner``'s nonce by one. This
   * prevents a signature from being used multiple times.
   */
  function nonces(address owner) external view returns (uint256);

  /**
   * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
   */
  // solhint-disable-next-line func-name-mixedcase
  function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 19 of 22 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
  /**
   * @dev Returns true if `account` is a contract.
   *
   * [IMPORTANT]
   * ====
   * It is unsafe to assume that an address for which this function returns
   * false is an externally-owned account (EOA) and not a contract.
   *
   * Among others, `isContract` will return false for the following
   * types of addresses:
   *
   *  - an externally-owned account
   *  - a contract in construction
   *  - an address where a contract will be created
   *  - an address where a contract lived, but was destroyed
   * ====
   *
   * [IMPORTANT]
   * ====
   * You shouldn't rely on `isContract` to protect against flash loan attacks!
   *
   * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
   * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
   * constructor.
   * ====
   */
  function isContract(address account) internal view returns (bool) {
    // This method relies on extcodesize/address.code.length, which returns 0
    // for contracts in construction, since the code is only stored at the end
    // of the constructor execution.

    return account.code.length > 0;
  }

  /**
   * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
   * `recipient`, forwarding all available gas and reverting on errors.
   *
   * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
   * of certain opcodes, possibly making contracts go over the 2300 gas limit
   * imposed by `transfer`, making them unable to receive funds via
   * `transfer`. {sendValue} removes this limitation.
   *
   * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
   *
   * IMPORTANT: because control is transferred to `recipient`, care must be
   * taken to not create reentrancy vulnerabilities. Consider using
   * {ReentrancyGuard} or the
   * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
   */
  function sendValue(address payable recipient, uint256 amount) internal {
    require(address(this).balance >= amount, "Address: insufficient balance");

    (bool success, ) = recipient.call{value: amount}("");
    require(success, "Address: unable to send value, recipient may have reverted");
  }

  /**
   * @dev Performs a Solidity function call using a low level `call`. A
   * plain `call` is an unsafe replacement for a function call: use this
   * function instead.
   *
   * If `target` reverts with a revert reason, it is bubbled up by this
   * function (like regular Solidity function calls).
   *
   * Returns the raw returned data. To convert to the expected return value,
   * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
   *
   * Requirements:
   *
   * - `target` must be a contract.
   * - calling `target` with `data` must not revert.
   *
   * _Available since v3.1._
   */
  function functionCall(address target, bytes memory data) internal returns (bytes memory) {
    return functionCallWithValue(target, data, 0, "Address: low-level call failed");
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
   * `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
  function functionCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal returns (bytes memory) {
    return functionCallWithValue(target, data, 0, errorMessage);
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but also transferring `value` wei to `target`.
   *
   * Requirements:
   *
   * - the calling contract must have an ETH balance of at least `value`.
   * - the called Solidity function must be `payable`.
   *
   * _Available since v3.1._
   */
  function functionCallWithValue(
    address target,
    bytes memory data,
    uint256 value
  ) internal returns (bytes memory) {
    return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
  }

  /**
   * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
   * with `errorMessage` as a fallback revert reason when `target` reverts.
   *
   * _Available since v3.1._
   */
  function functionCallWithValue(
    address target,
    bytes memory data,
    uint256 value,
    string memory errorMessage
  ) internal returns (bytes memory) {
    require(address(this).balance >= value, "Address: insufficient balance for call");
    (bool success, bytes memory returndata) = target.call{value: value}(data);
    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
  function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
    return functionStaticCall(target, data, "Address: low-level static call failed");
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a static call.
   *
   * _Available since v3.3._
   */
  function functionStaticCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal view returns (bytes memory) {
    (bool success, bytes memory returndata) = target.staticcall(data);
    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
   * but performing a delegate call.
   *
   * _Available since v3.4._
   */
  function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
    return functionDelegateCall(target, data, "Address: low-level delegate call failed");
  }

  /**
   * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
   * but performing a delegate call.
   *
   * _Available since v3.4._
   */
  function functionDelegateCall(
    address target,
    bytes memory data,
    string memory errorMessage
  ) internal returns (bytes memory) {
    (bool success, bytes memory returndata) = target.delegatecall(data);
    return verifyCallResultFromTarget(target, success, returndata, errorMessage);
  }

  /**
   * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
   * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
   *
   * _Available since v4.8._
   */
  function verifyCallResultFromTarget(
    address target,
    bool success,
    bytes memory returndata,
    string memory errorMessage
  ) internal view returns (bytes memory) {
    if (success) {
      if (returndata.length == 0) {
        // only check isContract if the call was successful and the return data is empty
        // otherwise we already know that it was a contract
        require(isContract(target), "Address: call to non-contract");
      }
      return returndata;
    } else {
      _revert(returndata, errorMessage);
    }
  }

  /**
   * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
   * revert reason or using the provided one.
   *
   * _Available since v4.3._
   */
  function verifyCallResult(
    bool success,
    bytes memory returndata,
    string memory errorMessage
  ) internal pure returns (bytes memory) {
    if (success) {
      return returndata;
    } else {
      _revert(returndata, errorMessage);
    }
  }

  function _revert(bytes memory returndata, string memory errorMessage) private pure {
    // Look for revert reason and bubble it up if present
    if (returndata.length > 0) {
      // The easiest way to bubble the revert reason is using memory via assembly
      /// @solidity memory-safe-assembly
      assembly {
        let returndata_size := mload(returndata)
        revert(add(32, returndata), returndata_size)
      }
    } else {
      revert(errorMessage);
    }
  }
}

File 20 of 22 : MerkleMultiProof.sol
// SPDX-License-Identifier: BUSL-1.1
pragma solidity ^0.8.0;

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 preiimage.
  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 The 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.
  // solhint-disable-next-line chainlink-solidity/prefix-internal-functions-with-underscore
  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);
  }
}

File 21 of 22 : ConfirmedOwnerWithProposal.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "./interfaces/OwnableInterface.sol";

/**
 * @title The ConfirmedOwner contract
 * @notice A contract with helpers for basic contract ownership.
 */
contract ConfirmedOwnerWithProposal is OwnableInterface {
  address private s_owner;
  address private s_pendingOwner;

  event OwnershipTransferRequested(address indexed from, address indexed to);
  event OwnershipTransferred(address indexed from, address indexed to);

  constructor(address newOwner, address pendingOwner) {
    require(newOwner != address(0), "Cannot set owner to zero");

    s_owner = newOwner;
    if (pendingOwner != address(0)) {
      _transferOwnership(pendingOwner);
    }
  }

  /**
   * @notice Allows an owner to begin transferring ownership to a new address,
   * pending.
   */
  function transferOwnership(address to) public override onlyOwner {
    _transferOwnership(to);
  }

  /**
   * @notice Allows an ownership transfer to be completed by the recipient.
   */
  function acceptOwnership() external override {
    require(msg.sender == s_pendingOwner, "Must be proposed owner");

    address oldOwner = s_owner;
    s_owner = msg.sender;
    s_pendingOwner = address(0);

    emit OwnershipTransferred(oldOwner, msg.sender);
  }

  /**
   * @notice Get the current owner
   */
  function owner() public view override returns (address) {
    return s_owner;
  }

  /**
   * @notice validate, transfer ownership, and emit relevant events
   */
  function _transferOwnership(address to) private {
    require(to != msg.sender, "Cannot transfer to self");

    s_pendingOwner = to;

    emit OwnershipTransferRequested(s_owner, to);
  }

  /**
   * @notice validate access
   */
  function _validateOwnership() internal view {
    require(msg.sender == s_owner, "Only callable by owner");
  }

  /**
   * @notice Reverts if called by anyone other than the contract owner.
   */
  modifier onlyOwner() {
    _validateOwnership();
    _;
  }
}

File 22 of 22 : OwnableInterface.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

  function transferOwnership(address recipient) external;

  function acceptOwnership() external;
}

Settings
{
  "remappings": [
    "@eth-optimism/=node_modules/@eth-optimism/",
    "@openzeppelin/=node_modules/@openzeppelin/",
    "ds-test/=foundry-lib/forge-std/lib/ds-test/src/",
    "erc4626-tests/=foundry-lib/openzeppelin-contracts/lib/erc4626-tests/",
    "forge-std/=foundry-lib/forge-std/src/",
    "hardhat/=node_modules/hardhat/",
    "openzeppelin-contracts/=foundry-lib/openzeppelin-contracts/contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 26000
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "none",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"wrappedNative","type":"address"},{"internalType":"address","name":"armProxy","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"BadARMSignal","type":"error"},{"inputs":[],"name":"FailedToSendValue","type":"error"},{"inputs":[],"name":"InsufficientFeeTokenAmount","type":"error"},{"inputs":[],"name":"InvalidMsgValue","type":"error"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"InvalidRecipientAddress","type":"error"},{"inputs":[],"name":"OffRampMismatch","type":"error"},{"inputs":[],"name":"OnlyOffRamp","type":"error"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"}],"name":"UnsupportedDestinationChain","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"messageId","type":"bytes32"},{"indexed":false,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"offRamp","type":"address"},{"indexed":false,"internalType":"bytes32","name":"calldataHash","type":"bytes32"}],"name":"MessageExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"offRamp","type":"address"}],"name":"OffRampAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"offRamp","type":"address"}],"name":"OffRampRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"indexed":false,"internalType":"address","name":"onRamp","type":"address"}],"name":"OnRampSet","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"},{"inputs":[],"name":"MAX_RET_BYTES","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"},{"internalType":"address","name":"onRamp","type":"address"}],"internalType":"struct Router.OnRamp[]","name":"onRampUpdates","type":"tuple[]"},{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"offRamp","type":"address"}],"internalType":"struct Router.OffRamp[]","name":"offRampRemoves","type":"tuple[]"},{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"offRamp","type":"address"}],"internalType":"struct Router.OffRamp[]","name":"offRampAdds","type":"tuple[]"}],"name":"applyRampUpdates","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"destinationChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","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":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"}],"name":"ccipSend","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getArmProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destinationChainSelector","type":"uint64"},{"components":[{"internalType":"bytes","name":"receiver","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":"tokenAmounts","type":"tuple[]"},{"internalType":"address","name":"feeToken","type":"address"},{"internalType":"bytes","name":"extraArgs","type":"bytes"}],"internalType":"struct Client.EVM2AnyMessage","name":"message","type":"tuple"}],"name":"getFee","outputs":[{"internalType":"uint256","name":"fee","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOffRamps","outputs":[{"components":[{"internalType":"uint64","name":"sourceChainSelector","type":"uint64"},{"internalType":"address","name":"offRamp","type":"address"}],"internalType":"struct Router.OffRamp[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"destChainSelector","type":"uint64"}],"name":"getOnRamp","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"getSupportedTokens","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getWrappedNative","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"chainSelector","type":"uint64"}],"name":"isChainSupported","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"offRamp","type":"address"}],"name":"isOffRamp","outputs":[{"internalType":"bool","name":"","type":"bool"},{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenAddress","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"recoverTokens","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":"message","type":"tuple"},{"internalType":"uint16","name":"gasForCallExactCheck","type":"uint16"},{"internalType":"uint256","name":"gasLimit","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"routeMessage","outputs":[{"internalType":"bool","name":"success","type":"bool"},{"internalType":"bytes","name":"retData","type":"bytes"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"wrappedNative","type":"address"}],"name":"setWrappedNative","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"}]

60a06040523480156200001157600080fd5b5060405162002dd438038062002dd48339810160408190526200003491620001af565b33806000816200008b5760405162461bcd60e51b815260206004820152601860248201527f43616e6e6f7420736574206f776e657220746f207a65726f000000000000000060448201526064015b60405180910390fd5b600080546001600160a01b0319166001600160a01b0384811691909117909155811615620000be57620000be81620000e7565b5050600280546001600160a01b0319166001600160a01b039485161790555016608052620001e7565b336001600160a01b03821603620001415760405162461bcd60e51b815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640162000082565b600180546001600160a01b0319166001600160a01b0383811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b80516001600160a01b0381168114620001aa57600080fd5b919050565b60008060408385031215620001c357600080fd5b620001ce8362000192565b9150620001de6020840162000192565b90509250929050565b608051612bc36200021160003960008181610238015281816106920152610b9b0152612bc36000f3fe6080604052600436106101295760003560e01c80638da5cb5b116100a5578063a8d87a3b11610074578063e861e90711610059578063e861e90714610428578063f2fde38b14610453578063fbca3b741461047357600080fd5b8063a8d87a3b146103bb578063da5fcac81461040857600080fd5b80638da5cb5b146102fc57806396f4e9f914610327578063a40e69c71461033a578063a48a90581461035c57600080fd5b80635246492f116100fc5780635f3e849f116100e15780635f3e849f1461029f578063787350e3146102bf57806379ba5097146102e757600080fd5b80635246492f1461022957806352cb60ca1461027d57600080fd5b8063181f5a771461012e5780631d7a74a01461018d57806320487ded146101cd5780633cf97983146101fb575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280600c81526020017f526f7574657220312e302e30000000000000000000000000000000000000000081525081565b6040516101849190612032565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004612077565b6104a0565b60408051921515835267ffffffffffffffff909116602083015201610184565b3480156101d957600080fd5b506101ed6101e83660046122c0565b6104bc565b604051908152602001610184565b34801561020757600080fd5b5061021b6102163660046123bd565b610612565b604051610184929190612435565b34801561023557600080fd5b507f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561028957600080fd5b5061029d610298366004612077565b6108fd565b005b3480156102ab57600080fd5b5061029d6102ba366004612450565b61094c565b3480156102cb57600080fd5b506102d4608481565b60405161ffff9091168152602001610184565b3480156102f357600080fd5b5061029d610a9a565b34801561030857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610258565b6101ed6103353660046122c0565b610b97565b34801561034657600080fd5b5061034f611122565b6040516101849190612491565b34801561036857600080fd5b506103ab610377366004612500565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b6040519015158152602001610184565b3480156103c757600080fd5b506102586103d6366004612500565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b34801561041457600080fd5b5061029d610423366004612560565b611219565b34801561043457600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff16610258565b34801561045f57600080fd5b5061029d61046e366004612077565b611524565b34801561047f57600080fd5b5061049361048e366004612500565b611538565b60405161018491906125fa565b60008080806104b0600486611651565b90969095509350505050565b606081015160009073ffffffffffffffffffffffffffffffffffffffff166104fd5760025473ffffffffffffffffffffffffffffffffffffffff1660608301525b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610575576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024015b60405180910390fd5b6040517f38724a9500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906338724a95906105c7908690600401612731565b602060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612744565b9150505b92915050565b600060606106266040870160208801612500565b600080610634600433611651565b9150915081158061065957508067ffffffffffffffff168367ffffffffffffffff1614155b15610690576040517fd2316ede00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071f919061275d565b15610756576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006385572ffb60e01b8a604051602401610771919061288c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000095909516949094179093528051608480825260c08201909252919350909182018180368337019050509450863b61081b57600080fd5b5a8981101561082957600080fd5b899003604081048103891061083d57600080fd5b5060008082516020840160008b8df195503d608481111561085c575060845b808652806000602088013e507f9b877de93ea9895756e337442c657f95a34fc68e7eb988bdfa693d5be83016b68a3561089b60408d0160208e01612500565b835160208501206040516108e8939291339193845267ffffffffffffffff92909216602084015273ffffffffffffffffffffffffffffffffffffffff166040830152606082015260800190565b60405180910390a15050505094509492505050565b610905611685565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610954611685565b73ffffffffffffffffffffffffffffffffffffffff82166109b9576040517f26a78f8f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161056c565b73ffffffffffffffffffffffffffffffffffffffff8316610a745760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610a2e576040519150601f19603f3d011682016040523d82523d6000602084013e610a33565b606091505b5050905080610a6e576040517fe417b80b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b610a9573ffffffffffffffffffffffffffffffffffffffff84168383611708565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161056c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c28919061275d565b15610c5f576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610cd2576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8516600482015260240161056c565b606083015160009073ffffffffffffffffffffffffffffffffffffffff16610e625760025473ffffffffffffffffffffffffffffffffffffffff90811660608601526040517f38724a95000000000000000000000000000000000000000000000000000000008152908316906338724a9590610d52908790600401612731565b602060405180830381865afa158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190612744565b905080341015610dcf576040517f07da6ee600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b349050836060015173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1e57600080fd5b505af1158015610e32573d6000803e3d6000fd5b505050506060850151610e5d915073ffffffffffffffffffffffffffffffffffffffff168383611708565b610f57565b3415610e9a576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f38724a9500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906338724a9590610eec908790600401612731565b602060405180830381865afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2d9190612744565b6060850151909150610f579073ffffffffffffffffffffffffffffffffffffffff163384846117dc565b60005b84604001515181101561107f57600085604001518281518110610f7f57610f7f612998565b6020908102919091010151516040517f5d86f14100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808316600483015291925061106e91339190871690635d86f14190602401602060405180830381865afa158015611001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102591906129c7565b8860400151858151811061103b5761103b612998565b6020026020010151602001518473ffffffffffffffffffffffffffffffffffffffff166117dc909392919063ffffffff16565b5061107881612a13565b9050610f5a565b506040517fa7d3e02f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063a7d3e02f906110d690879085903390600401612a4b565b6020604051808303816000875af11580156110f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111199190612744565b95945050505050565b60606000611130600461183a565b67ffffffffffffffff811115611148576111486120ac565b60405190808252806020026020018201604052801561118d57816020015b60408051808201909152600080825260208201528152602001906001900390816111665790505b50905060005b8151811015611213576000806111aa600484611845565b9150915060405180604001604052808267ffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff168152508484815181106111f5576111f5612998565b602002602001018190525050508061120c90612a13565b9050611193565b50919050565b611221611685565b60005b8581101561130557600087878381811061124057611240612998565b9050604002018036038101906112569190612a8a565b60208181018051835167ffffffffffffffff90811660009081526003855260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055855193519051921682529394509216917f1f7d0ec248b80e5c0dde0ee531c4fc8fdb6ce9a2b3d90f560c74acd6a7202f23910160405180910390a2506112fe81612a13565b9050611224565b5060005b8381101561143157600085858381811061132557611325612998565b61133b9260206040909202019081019150612500565b9050600086868481811061135157611351612998565b90506040020160200160208101906113699190612077565b905067ffffffffffffffff8216611381600483611854565b146113b8576040517f5737980600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113c360048261187d565b1561141e5760405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa823809efda3ba66c873364eec120fa0923d9fabda73bc97dd5663341e2d9bcb9060200160405180910390a25b50508061142a90612a13565b9050611309565b5060005b8181101561151b57600083838381811061145157611451612998565b6114679260206040909202019081019150612500565b9050600084848481811061147d5761147d612998565b90506040020160200160208101906114959190612077565b90506114ad60048267ffffffffffffffff851661189f565b156115085760405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa4bdf64ebdf3316320601a081916a75aa144bcef6c4beeb0e9fb1982cacc6b949060200160405180910390a25b50508061151490612a13565b9050611435565b50505050505050565b61152c611685565b611535816118ca565b50565b60606115728267ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b61158a57505060408051600081526020810190915290565b67ffffffffffffffff82166000908152600360205260408082205481517fd3c7c2c7000000000000000000000000000000000000000000000000000000008152915173ffffffffffffffffffffffffffffffffffffffff9091169263d3c7c2c792600480820193918290030181865afa15801561160b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261060c9190810190612ac9565b60008080806116768673ffffffffffffffffffffffffffffffffffffffff87166119bf565b909450925050505b9250929050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161056c565b565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a959084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526119f9565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610a6e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161175a565b600061060c82611b05565b60008080806116768686611b10565b60006118768373ffffffffffffffffffffffffffffffffffffffff8416611b3b565b9392505050565b60006118768373ffffffffffffffffffffffffffffffffffffffff8416611bc5565b60006118c28473ffffffffffffffffffffffffffffffffffffffff851684611be2565b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611949576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161056c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008181526002830160205260408120548190806119ee576119e18585611bff565b92506000915061167e9050565b60019250905061167e565b6000611a5b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611c0b9092919063ffffffff16565b805190915015610a955780806020019051810190611a79919061275d565b610a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161056c565b600061060c82611c1a565b60008080611b1e8585611c24565b600081815260029690960160205260409095205494959350505050565b600081815260028301602052604081205480151580611b5f5750611b5f8484611bff565b611876576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640161056c565b600081815260028301602052604081208190556118768383611c30565b600082815260028401602052604081208290556118c28484611c3c565b60006118768383611c48565b60606118c28484600085611c60565b600061060c825490565b60006118768383611d79565b60006118768383611da3565b60006118768383611e96565b60008181526001830160205260408120541515611876565b606082471015611cf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161056c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611d1b9190612b58565b60006040518083038185875af1925050503d8060008114611d58576040519150601f19603f3d011682016040523d82523d6000602084013e611d5d565b606091505b5091509150611d6e87838387611ee5565b979650505050505050565b6000826000018281548110611d9057611d90612998565b9060005260206000200154905092915050565b60008181526001830160205260408120548015611e8c576000611dc7600183612b74565b8554909150600090611ddb90600190612b74565b9050818114611e40576000866000018281548110611dfb57611dfb612998565b9060005260206000200154905080876000018481548110611e1e57611e1e612998565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611e5157611e51612b87565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061060c565b600091505061060c565b6000818152600183016020526040812054611edd5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561060c565b50600061060c565b60608315611f7b578251600003611f745773ffffffffffffffffffffffffffffffffffffffff85163b611f74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161056c565b50816118c2565b6118c28383815115611f905781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056c9190612032565b60005b83811015611fdf578181015183820152602001611fc7565b50506000910152565b60008151808452612000816020860160208601611fc4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006118766020830184611fe8565b73ffffffffffffffffffffffffffffffffffffffff8116811461153557600080fd5b803561207281612045565b919050565b60006020828403121561208957600080fd5b813561187681612045565b803567ffffffffffffffff8116811461207257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156120fe576120fe6120ac565b60405290565b60405160a0810167ffffffffffffffff811182821017156120fe576120fe6120ac565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561216e5761216e6120ac565b604052919050565b600082601f83011261218757600080fd5b813567ffffffffffffffff8111156121a1576121a16120ac565b6121d260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612127565b8181528460208386010111156121e757600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff82111561221e5761221e6120ac565b5060051b60200190565b600082601f83011261223957600080fd5b8135602061224e61224983612204565b612127565b82815260069290921b8401810191818101908684111561226d57600080fd5b8286015b848110156122b5576040818903121561228a5760008081fd5b6122926120db565b813561229d81612045565b81528185013585820152835291830191604001612271565b509695505050505050565b600080604083850312156122d357600080fd5b6122dc83612094565b9150602083013567ffffffffffffffff808211156122f957600080fd5b9084019060a0828703121561230d57600080fd5b612315612104565b82358281111561232457600080fd5b61233088828601612176565b82525060208301358281111561234557600080fd5b61235188828601612176565b60208301525060408301358281111561236957600080fd5b61237588828601612228565b60408301525061238760608401612067565b606082015260808301358281111561239e57600080fd5b6123aa88828601612176565b6080830152508093505050509250929050565b600080600080608085870312156123d357600080fd5b843567ffffffffffffffff8111156123ea57600080fd5b850160a081880312156123fc57600080fd5b9350602085013561ffff8116811461241357600080fd5b925060408501359150606085013561242a81612045565b939692955090935050565b82151581526040602082015260006118c26040830184611fe8565b60008060006060848603121561246557600080fd5b833561247081612045565b9250602084013561248081612045565b929592945050506040919091013590565b602080825282518282018190526000919060409081850190868401855b828110156124f3578151805167ffffffffffffffff16855286015173ffffffffffffffffffffffffffffffffffffffff168685015292840192908501906001016124ae565b5091979650505050505050565b60006020828403121561251257600080fd5b61187682612094565b60008083601f84011261252d57600080fd5b50813567ffffffffffffffff81111561254557600080fd5b6020830191508360208260061b850101111561167e57600080fd5b6000806000806000806060878903121561257957600080fd5b863567ffffffffffffffff8082111561259157600080fd5b61259d8a838b0161251b565b909850965060208901359150808211156125b657600080fd5b6125c28a838b0161251b565b909650945060408901359150808211156125db57600080fd5b506125e889828a0161251b565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b8181101561264857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612616565b50909695505050505050565b6000815160a0845261266960a0850182611fe8565b9050602080840151858303828701526126828382611fe8565b60408681015188830389830152805180845290850195509092506000918401905b808310156126e2578551805173ffffffffffffffffffffffffffffffffffffffff168352850151858301529484019460019290920191908301906126a3565b506060870151945061270c606089018673ffffffffffffffffffffffffffffffffffffffff169052565b6080870151945087810360808901526127258186611fe8565b98975050505050505050565b6020815260006118766020830184612654565b60006020828403121561275657600080fd5b5051919050565b60006020828403121561276f57600080fd5b8151801515811461187657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126127b457600080fd5b830160208101925035905067ffffffffffffffff8111156127d457600080fd5b80360382131561167e57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526000602080850194508260005b8581101561288157813561284f81612045565b73ffffffffffffffffffffffffffffffffffffffff16875281830135838801526040968701969091019060010161283c565b509495945050505050565b602081528135602082015260006128a560208401612094565b67ffffffffffffffff80821660408501526128c3604086018661277f565b925060a060608601526128da60c0860184836127e3565b9250506128ea606086018661277f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808786030160808801526129208583856127e3565b9450608088013592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301831261295957600080fd5b6020928801928301923591508382111561297257600080fd5b8160061b360383131561298457600080fd5b8685030160a0870152611d6e84828461282c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156129d957600080fd5b815161187681612045565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612a4457612a446129e4565b5060010190565b606081526000612a5e6060830186612654565b905083602083015273ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b600060408284031215612a9c57600080fd5b612aa46120db565b612aad83612094565b81526020830135612abd81612045565b60208201529392505050565b60006020808385031215612adc57600080fd5b825167ffffffffffffffff811115612af357600080fd5b8301601f81018513612b0457600080fd5b8051612b1261224982612204565b81815260059190911b82018301908381019087831115612b3157600080fd5b928401925b82841015611d6e578351612b4981612045565b82529284019290840190612b36565b60008251612b6a818460208701611fc4565b9190910192915050565b8181038181111561060c5761060c6129e4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a00000000000000000000000042000000000000000000000000000000000000060000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d0

Deployed Bytecode

0x6080604052600436106101295760003560e01c80638da5cb5b116100a5578063a8d87a3b11610074578063e861e90711610059578063e861e90714610428578063f2fde38b14610453578063fbca3b741461047357600080fd5b8063a8d87a3b146103bb578063da5fcac81461040857600080fd5b80638da5cb5b146102fc57806396f4e9f914610327578063a40e69c71461033a578063a48a90581461035c57600080fd5b80635246492f116100fc5780635f3e849f116100e15780635f3e849f1461029f578063787350e3146102bf57806379ba5097146102e757600080fd5b80635246492f1461022957806352cb60ca1461027d57600080fd5b8063181f5a771461012e5780631d7a74a01461018d57806320487ded146101cd5780633cf97983146101fb575b600080fd5b34801561013a57600080fd5b506101776040518060400160405280600c81526020017f526f7574657220312e302e30000000000000000000000000000000000000000081525081565b6040516101849190612032565b60405180910390f35b34801561019957600080fd5b506101ad6101a8366004612077565b6104a0565b60408051921515835267ffffffffffffffff909116602083015201610184565b3480156101d957600080fd5b506101ed6101e83660046122c0565b6104bc565b604051908152602001610184565b34801561020757600080fd5b5061021b6102163660046123bd565b610612565b604051610184929190612435565b34801561023557600080fd5b507f0000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d05b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610184565b34801561028957600080fd5b5061029d610298366004612077565b6108fd565b005b3480156102ab57600080fd5b5061029d6102ba366004612450565b61094c565b3480156102cb57600080fd5b506102d4608481565b60405161ffff9091168152602001610184565b3480156102f357600080fd5b5061029d610a9a565b34801561030857600080fd5b5060005473ffffffffffffffffffffffffffffffffffffffff16610258565b6101ed6103353660046122c0565b610b97565b34801561034657600080fd5b5061034f611122565b6040516101849190612491565b34801561036857600080fd5b506103ab610377366004612500565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b6040519015158152602001610184565b3480156103c757600080fd5b506102586103d6366004612500565b67ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1690565b34801561041457600080fd5b5061029d610423366004612560565b611219565b34801561043457600080fd5b5060025473ffffffffffffffffffffffffffffffffffffffff16610258565b34801561045f57600080fd5b5061029d61046e366004612077565b611524565b34801561047f57600080fd5b5061049361048e366004612500565b611538565b60405161018491906125fa565b60008080806104b0600486611651565b90969095509350505050565b606081015160009073ffffffffffffffffffffffffffffffffffffffff166104fd5760025473ffffffffffffffffffffffffffffffffffffffff1660608301525b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610575576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff851660048201526024015b60405180910390fd5b6040517f38724a9500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216906338724a95906105c7908690600401612731565b602060405180830381865afa1580156105e4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906106089190612744565b9150505b92915050565b600060606106266040870160208801612500565b600080610634600433611651565b9150915081158061065957508067ffffffffffffffff168367ffffffffffffffff1614155b15610690576040517fd2316ede00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7f0000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa1580156106fb573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061071f919061275d565b15610756576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60006385572ffb60e01b8a604051602401610771919061288c565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0818403018152918152602080830180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff0000000000000000000000000000000000000000000000000000000095909516949094179093528051608480825260c08201909252919350909182018180368337019050509450863b61081b57600080fd5b5a8981101561082957600080fd5b899003604081048103891061083d57600080fd5b5060008082516020840160008b8df195503d608481111561085c575060845b808652806000602088013e507f9b877de93ea9895756e337442c657f95a34fc68e7eb988bdfa693d5be83016b68a3561089b60408d0160208e01612500565b835160208501206040516108e8939291339193845267ffffffffffffffff92909216602084015273ffffffffffffffffffffffffffffffffffffffff166040830152606082015260800190565b60405180910390a15050505094509492505050565b610905611685565b600280547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b610954611685565b73ffffffffffffffffffffffffffffffffffffffff82166109b9576040517f26a78f8f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161056c565b73ffffffffffffffffffffffffffffffffffffffff8316610a745760008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d8060008114610a2e576040519150601f19603f3d011682016040523d82523d6000602084013e610a33565b606091505b5050905080610a6e576040517fe417b80b00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b50505050565b610a9573ffffffffffffffffffffffffffffffffffffffff84168383611708565b505050565b60015473ffffffffffffffffffffffffffffffffffffffff163314610b1b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4d7573742062652070726f706f736564206f776e657200000000000000000000604482015260640161056c565b60008054337fffffffffffffffffffffffff00000000000000000000000000000000000000008083168217845560018054909116905560405173ffffffffffffffffffffffffffffffffffffffff90921692909183917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e091a350565b60007f0000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d073ffffffffffffffffffffffffffffffffffffffff1663397796f76040518163ffffffff1660e01b8152600401602060405180830381865afa158015610c04573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610c28919061275d565b15610c5f576040517fc148371500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b67ffffffffffffffff831660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff1680610cd2576040517fae236d9c00000000000000000000000000000000000000000000000000000000815267ffffffffffffffff8516600482015260240161056c565b606083015160009073ffffffffffffffffffffffffffffffffffffffff16610e625760025473ffffffffffffffffffffffffffffffffffffffff90811660608601526040517f38724a95000000000000000000000000000000000000000000000000000000008152908316906338724a9590610d52908790600401612731565b602060405180830381865afa158015610d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d939190612744565b905080341015610dcf576040517f07da6ee600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b349050836060015173ffffffffffffffffffffffffffffffffffffffff1663d0e30db0826040518263ffffffff1660e01b81526004016000604051808303818588803b158015610e1e57600080fd5b505af1158015610e32573d6000803e3d6000fd5b505050506060850151610e5d915073ffffffffffffffffffffffffffffffffffffffff168383611708565b610f57565b3415610e9a576040517f1841b4e100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517f38724a9500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316906338724a9590610eec908790600401612731565b602060405180830381865afa158015610f09573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2d9190612744565b6060850151909150610f579073ffffffffffffffffffffffffffffffffffffffff163384846117dc565b60005b84604001515181101561107f57600085604001518281518110610f7f57610f7f612998565b6020908102919091010151516040517f5d86f14100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808316600483015291925061106e91339190871690635d86f14190602401602060405180830381865afa158015611001573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061102591906129c7565b8860400151858151811061103b5761103b612998565b6020026020010151602001518473ffffffffffffffffffffffffffffffffffffffff166117dc909392919063ffffffff16565b5061107881612a13565b9050610f5a565b506040517fa7d3e02f00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff83169063a7d3e02f906110d690879085903390600401612a4b565b6020604051808303816000875af11580156110f5573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111199190612744565b95945050505050565b60606000611130600461183a565b67ffffffffffffffff811115611148576111486120ac565b60405190808252806020026020018201604052801561118d57816020015b60408051808201909152600080825260208201528152602001906001900390816111665790505b50905060005b8151811015611213576000806111aa600484611845565b9150915060405180604001604052808267ffffffffffffffff1681526020018373ffffffffffffffffffffffffffffffffffffffff168152508484815181106111f5576111f5612998565b602002602001018190525050508061120c90612a13565b9050611193565b50919050565b611221611685565b60005b8581101561130557600087878381811061124057611240612998565b9050604002018036038101906112569190612a8a565b60208181018051835167ffffffffffffffff90811660009081526003855260409081902080547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff948516179055855193519051921682529394509216917f1f7d0ec248b80e5c0dde0ee531c4fc8fdb6ce9a2b3d90f560c74acd6a7202f23910160405180910390a2506112fe81612a13565b9050611224565b5060005b8381101561143157600085858381811061132557611325612998565b61133b9260206040909202019081019150612500565b9050600086868481811061135157611351612998565b90506040020160200160208101906113699190612077565b905067ffffffffffffffff8216611381600483611854565b146113b8576040517f5737980600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6113c360048261187d565b1561141e5760405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa823809efda3ba66c873364eec120fa0923d9fabda73bc97dd5663341e2d9bcb9060200160405180910390a25b50508061142a90612a13565b9050611309565b5060005b8181101561151b57600083838381811061145157611451612998565b6114679260206040909202019081019150612500565b9050600084848481811061147d5761147d612998565b90506040020160200160208101906114959190612077565b90506114ad60048267ffffffffffffffff851661189f565b156115085760405173ffffffffffffffffffffffffffffffffffffffff8216815267ffffffffffffffff8316907fa4bdf64ebdf3316320601a081916a75aa144bcef6c4beeb0e9fb1982cacc6b949060200160405180910390a25b50508061151490612a13565b9050611435565b50505050505050565b61152c611685565b611535816118ca565b50565b60606115728267ffffffffffffffff1660009081526003602052604090205473ffffffffffffffffffffffffffffffffffffffff16151590565b61158a57505060408051600081526020810190915290565b67ffffffffffffffff82166000908152600360205260408082205481517fd3c7c2c7000000000000000000000000000000000000000000000000000000008152915173ffffffffffffffffffffffffffffffffffffffff9091169263d3c7c2c792600480820193918290030181865afa15801561160b573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016820160405261060c9190810190612ac9565b60008080806116768673ffffffffffffffffffffffffffffffffffffffff87166119bf565b909450925050505b9250929050565b60005473ffffffffffffffffffffffffffffffffffffffff163314611706576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4f6e6c792063616c6c61626c65206279206f776e657200000000000000000000604482015260640161056c565b565b60405173ffffffffffffffffffffffffffffffffffffffff8316602482015260448101829052610a959084907fa9059cbb00000000000000000000000000000000000000000000000000000000906064015b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529190526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fffffffff00000000000000000000000000000000000000000000000000000000909316929092179091526119f9565b60405173ffffffffffffffffffffffffffffffffffffffff80851660248301528316604482015260648101829052610a6e9085907f23b872dd000000000000000000000000000000000000000000000000000000009060840161175a565b600061060c82611b05565b60008080806116768686611b10565b60006118768373ffffffffffffffffffffffffffffffffffffffff8416611b3b565b9392505050565b60006118768373ffffffffffffffffffffffffffffffffffffffff8416611bc5565b60006118c28473ffffffffffffffffffffffffffffffffffffffff851684611be2565b949350505050565b3373ffffffffffffffffffffffffffffffffffffffff821603611949576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f43616e6e6f74207472616e7366657220746f2073656c66000000000000000000604482015260640161056c565b600180547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff83811691821790925560008054604051929316917fed8889f560326eb138920d842192f0eb3dd22b4f139c87a2c57538e05bae12789190a350565b60008181526002830160205260408120548190806119ee576119e18585611bff565b92506000915061167e9050565b60019250905061167e565b6000611a5b826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff16611c0b9092919063ffffffff16565b805190915015610a955780806020019051810190611a79919061275d565b610a95576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161056c565b600061060c82611c1a565b60008080611b1e8585611c24565b600081815260029690960160205260409095205494959350505050565b600081815260028301602052604081205480151580611b5f5750611b5f8484611bff565b611876576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601e60248201527f456e756d657261626c654d61703a206e6f6e6578697374656e74206b65790000604482015260640161056c565b600081815260028301602052604081208190556118768383611c30565b600082815260028401602052604081208290556118c28484611c3c565b60006118768383611c48565b60606118c28484600085611c60565b600061060c825490565b60006118768383611d79565b60006118768383611da3565b60006118768383611e96565b60008181526001830160205260408120541515611876565b606082471015611cf2576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f416464726573733a20696e73756666696369656e742062616c616e636520666f60448201527f722063616c6c0000000000000000000000000000000000000000000000000000606482015260840161056c565b6000808673ffffffffffffffffffffffffffffffffffffffff168587604051611d1b9190612b58565b60006040518083038185875af1925050503d8060008114611d58576040519150601f19603f3d011682016040523d82523d6000602084013e611d5d565b606091505b5091509150611d6e87838387611ee5565b979650505050505050565b6000826000018281548110611d9057611d90612998565b9060005260206000200154905092915050565b60008181526001830160205260408120548015611e8c576000611dc7600183612b74565b8554909150600090611ddb90600190612b74565b9050818114611e40576000866000018281548110611dfb57611dfb612998565b9060005260206000200154905080876000018481548110611e1e57611e1e612998565b6000918252602080832090910192909255918252600188019052604090208390555b8554869080611e5157611e51612b87565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061060c565b600091505061060c565b6000818152600183016020526040812054611edd5750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561060c565b50600061060c565b60608315611f7b578251600003611f745773ffffffffffffffffffffffffffffffffffffffff85163b611f74576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161056c565b50816118c2565b6118c28383815115611f905781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161056c9190612032565b60005b83811015611fdf578181015183820152602001611fc7565b50506000910152565b60008151808452612000816020860160208601611fc4565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006118766020830184611fe8565b73ffffffffffffffffffffffffffffffffffffffff8116811461153557600080fd5b803561207281612045565b919050565b60006020828403121561208957600080fd5b813561187681612045565b803567ffffffffffffffff8116811461207257600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b6040805190810167ffffffffffffffff811182821017156120fe576120fe6120ac565b60405290565b60405160a0810167ffffffffffffffff811182821017156120fe576120fe6120ac565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff8111828210171561216e5761216e6120ac565b604052919050565b600082601f83011261218757600080fd5b813567ffffffffffffffff8111156121a1576121a16120ac565b6121d260207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f84011601612127565b8181528460208386010111156121e757600080fd5b816020850160208301376000918101602001919091529392505050565b600067ffffffffffffffff82111561221e5761221e6120ac565b5060051b60200190565b600082601f83011261223957600080fd5b8135602061224e61224983612204565b612127565b82815260069290921b8401810191818101908684111561226d57600080fd5b8286015b848110156122b5576040818903121561228a5760008081fd5b6122926120db565b813561229d81612045565b81528185013585820152835291830191604001612271565b509695505050505050565b600080604083850312156122d357600080fd5b6122dc83612094565b9150602083013567ffffffffffffffff808211156122f957600080fd5b9084019060a0828703121561230d57600080fd5b612315612104565b82358281111561232457600080fd5b61233088828601612176565b82525060208301358281111561234557600080fd5b61235188828601612176565b60208301525060408301358281111561236957600080fd5b61237588828601612228565b60408301525061238760608401612067565b606082015260808301358281111561239e57600080fd5b6123aa88828601612176565b6080830152508093505050509250929050565b600080600080608085870312156123d357600080fd5b843567ffffffffffffffff8111156123ea57600080fd5b850160a081880312156123fc57600080fd5b9350602085013561ffff8116811461241357600080fd5b925060408501359150606085013561242a81612045565b939692955090935050565b82151581526040602082015260006118c26040830184611fe8565b60008060006060848603121561246557600080fd5b833561247081612045565b9250602084013561248081612045565b929592945050506040919091013590565b602080825282518282018190526000919060409081850190868401855b828110156124f3578151805167ffffffffffffffff16855286015173ffffffffffffffffffffffffffffffffffffffff168685015292840192908501906001016124ae565b5091979650505050505050565b60006020828403121561251257600080fd5b61187682612094565b60008083601f84011261252d57600080fd5b50813567ffffffffffffffff81111561254557600080fd5b6020830191508360208260061b850101111561167e57600080fd5b6000806000806000806060878903121561257957600080fd5b863567ffffffffffffffff8082111561259157600080fd5b61259d8a838b0161251b565b909850965060208901359150808211156125b657600080fd5b6125c28a838b0161251b565b909650945060408901359150808211156125db57600080fd5b506125e889828a0161251b565b979a9699509497509295939492505050565b6020808252825182820181905260009190848201906040850190845b8181101561264857835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101612616565b50909695505050505050565b6000815160a0845261266960a0850182611fe8565b9050602080840151858303828701526126828382611fe8565b60408681015188830389830152805180845290850195509092506000918401905b808310156126e2578551805173ffffffffffffffffffffffffffffffffffffffff168352850151858301529484019460019290920191908301906126a3565b506060870151945061270c606089018673ffffffffffffffffffffffffffffffffffffffff169052565b6080870151945087810360808901526127258186611fe8565b98975050505050505050565b6020815260006118766020830184612654565b60006020828403121561275657600080fd5b5051919050565b60006020828403121561276f57600080fd5b8151801515811461187657600080fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe18436030181126127b457600080fd5b830160208101925035905067ffffffffffffffff8111156127d457600080fd5b80360382131561167e57600080fd5b8183528181602085013750600060208284010152600060207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116840101905092915050565b8183526000602080850194508260005b8581101561288157813561284f81612045565b73ffffffffffffffffffffffffffffffffffffffff16875281830135838801526040968701969091019060010161283c565b509495945050505050565b602081528135602082015260006128a560208401612094565b67ffffffffffffffff80821660408501526128c3604086018661277f565b925060a060608601526128da60c0860184836127e3565b9250506128ea606086018661277f565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0808786030160808801526129208583856127e3565b9450608088013592507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe188360301831261295957600080fd5b6020928801928301923591508382111561297257600080fd5b8160061b360383131561298457600080fd5b8685030160a0870152611d6e84828461282c565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b6000602082840312156129d957600080fd5b815161187681612045565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b60007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8203612a4457612a446129e4565b5060010190565b606081526000612a5e6060830186612654565b905083602083015273ffffffffffffffffffffffffffffffffffffffff83166040830152949350505050565b600060408284031215612a9c57600080fd5b612aa46120db565b612aad83612094565b81526020830135612abd81612045565b60208201529392505050565b60006020808385031215612adc57600080fd5b825167ffffffffffffffff811115612af357600080fd5b8301601f81018513612b0457600080fd5b8051612b1261224982612204565b81815260059190911b82018301908381019087831115612b3157600080fd5b928401925b82841015611d6e578351612b4981612045565b82529284019290840190612b36565b60008251612b6a818460208701611fc4565b9190910192915050565b8181038181111561060c5761060c6129e4565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea164736f6c6343000813000a

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

00000000000000000000000042000000000000000000000000000000000000060000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d0

-----Decoded View---------------
Arg [0] : wrappedNative (address): 0x4200000000000000000000000000000000000006
Arg [1] : armProxy (address): 0x4eb4dbDb3C3B56E5E209ABf9c424a3834f2087D0

-----Encoded View---------------
2 Constructor Arguments found :
Arg [0] : 0000000000000000000000004200000000000000000000000000000000000006
Arg [1] : 0000000000000000000000004eb4dbdb3c3b56e5e209abf9c424a3834f2087d0


Block Transaction Difficulty Gas Used Reward
Block Uncle Number Difficulty Gas Used Reward
Loading