GLMR Price: $0.020748 (-1.59%)

Contract

0xF6b9616C63Fa48D07D82c93CE02B5d9111c51a3d

Overview

GLMR Balance

Moonbeam Chain LogoMoonbeam Chain LogoMoonbeam Chain Logo0 GLMR

GLMR Value

$0.00

More Info

Private Name Tags

Multichain Info

No addresses found
Transaction Hash
Block
From
To
0x809c4177117757652025-07-18 5:54:18192 days ago1752818058IN
0xF6b9616C...111c51a3d
10 GLMR0.0023517531.25
Wrap And Transfe...117711382025-07-17 22:05:42192 days ago1752789942IN
0xF6b9616C...111c51a3d
28.83181934 GLMR0.0023277531.25
Wrap And Transfe...117710722025-07-17 21:59:00192 days ago1752789540IN
0xF6b9616C...111c51a3d
28.83181934 GLMR0.0023277531.25
Wrap And Transfe...117709722025-07-17 21:48:54192 days ago1752788934IN
0xF6b9616C...111c51a3d
28.83181934 GLMR0.0023277531.25
Execute VA Av1116670112025-07-10 13:11:48199 days ago1752153108IN
0xF6b9616C...111c51a3d
0 GLMR0.0178450833
Execute VA Av1116640542025-07-10 8:07:18199 days ago1752134838IN
0xF6b9616C...111c51a3d
0 GLMR0.0178450833

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
142217882026-01-25 12:32:2418 hrs ago1769344344
0xF6b9616C...111c51a3d
6.80206737 GLMR
142217882026-01-25 12:32:2418 hrs ago1769344344
0xF6b9616C...111c51a3d
6.80206737 GLMR
141953172026-01-23 10:38:482 days ago1769164728
0xF6b9616C...111c51a3d
11.16092439 GLMR
141953172026-01-23 10:38:482 days ago1769164728
0xF6b9616C...111c51a3d
11.16092439 GLMR
141951862026-01-23 10:24:492 days ago1769163889
0xF6b9616C...111c51a3d
15.4540355 GLMR
141951862026-01-23 10:24:492 days ago1769163889
0xF6b9616C...111c51a3d
15.4540355 GLMR
141951322026-01-23 10:18:062 days ago1769163486
0xF6b9616C...111c51a3d
10.82281708 GLMR
141951322026-01-23 10:18:062 days ago1769163486
0xF6b9616C...111c51a3d
10.82281708 GLMR
141950452026-01-23 10:08:182 days ago1769162898
0xF6b9616C...111c51a3d
4.57037443 GLMR
141950452026-01-23 10:08:182 days ago1769162898
0xF6b9616C...111c51a3d
4.57037443 GLMR
141950202026-01-23 10:05:122 days ago1769162712
0xF6b9616C...111c51a3d
3.16789714 GLMR
141950202026-01-23 10:05:122 days ago1769162712
0xF6b9616C...111c51a3d
3.16789714 GLMR
141610772026-01-20 18:21:245 days ago1768933284
0xF6b9616C...111c51a3d
56.82050786 GLMR
141610772026-01-20 18:21:245 days ago1768933284
0xF6b9616C...111c51a3d
56.82050786 GLMR
141610462026-01-20 18:17:305 days ago1768933050
0xF6b9616C...111c51a3d
58.61670931 GLMR
141610462026-01-20 18:17:305 days ago1768933050
0xF6b9616C...111c51a3d
58.61670931 GLMR
141610132026-01-20 18:13:545 days ago1768932834
0xF6b9616C...111c51a3d
58.61670931 GLMR
141610132026-01-20 18:13:545 days ago1768932834
0xF6b9616C...111c51a3d
58.61670931 GLMR
141601792026-01-20 16:37:545 days ago1768927074
0xF6b9616C...111c51a3d
59.91123109 GLMR
141601792026-01-20 16:37:545 days ago1768927074
0xF6b9616C...111c51a3d
59.91123109 GLMR
141600372026-01-20 16:19:485 days ago1768925988
0xF6b9616C...111c51a3d
59.75401619 GLMR
141600372026-01-20 16:19:485 days ago1768925988
0xF6b9616C...111c51a3d
59.75401619 GLMR
141498092026-01-19 21:06:066 days ago1768856766
0xF6b9616C...111c51a3d
57.97168344 GLMR
141498092026-01-19 21:06:066 days ago1768856766
0xF6b9616C...111c51a3d
57.97168344 GLMR
140913452026-01-15 6:47:2411 days ago1768459644
0xF6b9616C...111c51a3d
4.55669868 GLMR
View All Internal Transactions
Cross-Chain Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
TokenBridgeRelayer

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.17;

import {IWETH} from "../interfaces/IWETH.sol";
import {IWormhole} from "../interfaces/IWormhole.sol";
import {ITokenBridge} from "../interfaces/ITokenBridge.sol";

import "../libraries/BytesLib.sol";
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

import "example-messaging-executor/evm/src/interfaces/IExecutor.sol";
import "example-messaging-executor/evm/src/interfaces/IVaaV1Receiver.sol";
import "example-messaging-executor/evm/src/libraries/ExecutorMessages.sol";

import "./TokenBridgeRelayerMessages.sol";
import "./TokenBridgeRelayerGetters.sol";

string constant tokenBridgeRelayerVersion = "TokenBridgeRelayer-0.4.0";

/**
 * @title Wormhole Token Bridge Relayer
 * @notice This contract composes on Wormhole's Token Bridge contracts to facilitate
 * one-click transfers of Token Bridge supported assets cross chain.
 */
contract TokenBridgeRelayer is
    TokenBridgeRelayerGetters,
    TokenBridgeRelayerMessages,
    ReentrancyGuard,
    IVaaV1Receiver
{
    using BytesLib for bytes;

    // contract version
    string public constant VERSION = tokenBridgeRelayerVersion;

    // Wormhole chain ID of this contract
    uint16 public immutable chainId;
    // boolean to determine if weth is unwrappable
    bool public immutable unwrapWeth;
    // address of WETH on this chain
    IWETH public immutable weth;
    // address of the Wormhole contract on this chain
    IWormhole public immutable wormhole;
    // address of the Wormhole TokenBridge contract on this chain
    ITokenBridge public immutable tokenBridge;
    bytes32 public immutable tokenBridgeEmitter;
    // address of the Executor contract on this chain
    IExecutor public immutable executor;

    constructor(address tokenBridge_, bool unwrapWeth_, address executor_) {
        assert(tokenBridge_ != address(0));
        assert(executor_ != address(0));

        tokenBridge = ITokenBridge(payable(tokenBridge_));
        tokenBridgeEmitter = bytes32(uint256(uint160(tokenBridge_)));
        weth = tokenBridge.WETH();
        unwrapWeth = unwrapWeth_;

        if (unwrapWeth) {
            assert(address(weth) != address(0));
        }

        chainId = tokenBridge.chainId();
        wormhole = tokenBridge.wormhole();

        executor = IExecutor(payable(executor_));
    }

    /**
     * @notice Emitted when a transfer is completed by the Wormhole token bridge
     * @param emitterChainId Wormhole chain ID of emitter contract on the source chain
     * @param emitterAddress Address (bytes32 zero-left-padded) of emitter on the source chain
     * @param sequence Sequence of the Wormhole message
     */
    event TransferRedeemed(uint16 indexed emitterChainId, bytes32 indexed emitterAddress, uint64 indexed sequence);

    /**
     * @notice Calls Wormhole's Token Bridge contract to emit a contract-controlled
     * transfer. The transfer message includes the target recipient on the destination chain.
     * @param token ERC20 token address to transfer cross chain.
     * @param amount Quantity of tokens to be transferred.
     * @param targetChain Wormhole chain ID of the target blockchain.
     * @param targetRecipient User's wallet address on the target blockchain in bytes32 format
     * (zero-left-padded).
     * @param nonce Wormhole message nonce
     * @param dstTransferRecipient Token Bridge payload 3 recipient
     * @param dstExecutionAddress Executor destination address
     * @param executionAmount msg.value to be sent to the execution payee
     * @param refundAddr Executor refund address on this chain
     * @param signedQuoteBytes Executor signed quote
     * @param relayInstructions Executor relay instructions
     * @return messageSequence Wormhole sequence for emitted TransferTokensWithRelay message.
     */
    function transferTokensWithRelay(
        address token,
        uint256 amount,
        uint16 targetChain,
        bytes32 targetRecipient,
        uint32 nonce,
        bytes32 dstTransferRecipient,
        bytes32 dstExecutionAddress,
        uint256 executionAmount,
        address refundAddr,
        bytes calldata signedQuoteBytes,
        bytes calldata relayInstructions
    ) public payable nonReentrant returns (uint64 messageSequence) {
        // Cache wormhole fee and confirm that the user has passed enough
        // value to cover the wormhole protocol fee.
        uint256 wormholeFee = wormhole.messageFee();
        require(msg.value == wormholeFee + executionAmount, "insufficient value");

        // Cache token decimals, and remove dust from the amount argument. This
        // ensures that the dust is never transferred to this contract.
        uint8 tokenDecimals = getDecimals(token);
        amount = denormalizeAmount(normalizeAmount(amount, tokenDecimals), tokenDecimals);

        // Transfer tokens from user to the this contract, and
        // override amount with actual amount received.
        amount = custodyTokens(token, amount);

        // call the internal _transferTokensWithRelay function
        messageSequence = _transferTokensWithRelay(
            InternalTransferParams({
                token: token,
                tokenDecimals: tokenDecimals,
                amount: amount,
                targetChain: targetChain,
                targetRecipient: targetRecipient,
                nonce: nonce,
                wormholeFee: wormholeFee,
                dstTransferRecipient: dstTransferRecipient,
                dstExecutionAddress: dstExecutionAddress,
                executionAmount: executionAmount,
                refundAddr: refundAddr
            }),
            signedQuoteBytes,
            relayInstructions
        );
    }

    /**
     * @notice Wraps Ether and calls Wormhole's Token Bridge contract to emit
     * a contract-controlled transfer. The transfer message includes an arbitrary
     * payload with instructions for how to handle relayer payments on the target
     * contract and the quantity of tokens to convert into native assets for the user.
     * @param targetChain Wormhole chain ID of the target blockchain.
     * @param targetRecipient User's wallet address on the target blockchain in bytes32 format
     * (zero-left-padded).
     * @param nonce Wormhole message nonce
     * @return messageSequence Wormhole sequence for emitted TransferTokensWithRelay message.
     */
    function wrapAndTransferEthWithRelay(
        uint16 targetChain,
        bytes32 targetRecipient,
        uint32 nonce,
        bytes32 dstTransferRecipient,
        bytes32 dstExecutionAddress,
        uint256 executionAmount,
        address refundAddr,
        bytes calldata signedQuoteBytes,
        bytes calldata relayInstructions
    ) public payable returns (uint64 messageSequence) {
        require(unwrapWeth, "WETH functionality not supported");

        // Cache wormhole fee and confirm that the user has passed enough
        // value to cover the wormhole protocol fee.
        uint256 wormholeFee = wormhole.messageFee();
        uint256 fees = wormholeFee + executionAmount;
        require(msg.value > fees, "insufficient value");

        // remove the wormhole protocol fee and execution payment from the amount
        uint256 amount = msg.value - fees;

        // refund dust
        uint256 dust = amount - denormalizeAmount(normalizeAmount(amount, 18), 18);
        if (dust > 0) {
            (bool success,) = payable(msg.sender).call{value: dust}("");
            require(success, "Failed to refund dust");
        }

        // remove dust from amount and cache WETH
        uint256 amountLessDust = amount - dust;

        // deposit into the WETH contract
        weth.deposit{value: amountLessDust}();

        // call the internal _transferTokensWithRelay function
        messageSequence = _transferTokensWithRelay(
            InternalTransferParams({
                token: address(weth),
                tokenDecimals: 18,
                amount: amountLessDust,
                targetChain: targetChain,
                targetRecipient: targetRecipient,
                nonce: nonce,
                wormholeFee: wormholeFee,
                dstTransferRecipient: dstTransferRecipient,
                dstExecutionAddress: dstExecutionAddress,
                executionAmount: executionAmount,
                refundAddr: refundAddr
            }),
            signedQuoteBytes,
            relayInstructions
        );
    }

    function _transferTokensWithRelay(
        InternalTransferParams memory params,
        bytes calldata signedQuoteBytes,
        bytes calldata relayInstructions
    ) internal returns (uint64 messageSequence) {
        // sanity check function arguments
        require(params.targetRecipient != bytes32(0), "targetRecipient cannot be bytes32(0)");

        /**
         * Cache the normalized amount and verify that it's nonzero.
         * The token bridge performs the same operation before encoding
         * the amount in the `TransferWithPayload` message.
         */
        uint256 normalizedAmount = normalizeAmount(params.amount, params.tokenDecimals);
        require(normalizedAmount > 0, "normalized amount must be > 0");

        /**
         * Encode instructions (TransferWithRelay) to send with the token transfer.
         * The `targetRecipient` address is in bytes32 format (zero-left-padded) to
         * support non-evm smart contracts that have addresses that are longer
         * than 20 bytes.
         *
         * We normalize the relayerFee and toNativeTokenAmount to support
         * non-evm smart contracts that can only handle uint64.max values.
         */
        bytes memory messagePayload =
            encodeTransferWithRelay(TransferWithRelay({targetRecipient: params.targetRecipient}));

        // approve the token bridge to spend the specified tokens
        SafeERC20.safeApprove(IERC20(params.token), address(tokenBridge), params.amount);

        /**
         * Call `transferTokensWithPayload` method on the token bridge and pay
         * the Wormhole network fee. The token bridge will emit a Wormhole
         * message with an encoded `TransferWithPayload` struct (see the
         * ITokenBridge.sol interface file in this repo).
         */
        messageSequence = tokenBridge.transferTokensWithPayload{value: params.wormholeFee}(
            params.token, params.amount, params.targetChain, params.dstTransferRecipient, params.nonce, messagePayload
        );

        executor.requestExecution{value: params.executionAmount}(
            params.targetChain,
            params.dstExecutionAddress,
            params.refundAddr,
            signedQuoteBytes,
            ExecutorMessages.makeVAAv1Request(chainId, tokenBridgeEmitter, messageSequence),
            relayInstructions
        );
    }

    /**
     * @notice Calls Wormhole's Token Bridge contract to complete token transfers. Takes
     * custody of the wrapped (or released) tokens and sends the tokens to the target recipient.
     * It pays the fee recipient in the minted token denomination. If requested by the user,
     * it will perform a swap with the off-chain relayer to provide the user with native assets.
     * If the `token` being transferred is WETH, the contract will unwrap native assets and send
     * the transferred amount to the recipient and pay the fee recipient in native assets.
     * @dev reverts if:
     * - the transferred token is not accepted by this contract
     * - the transferred token is not attested on this blockchain's Token Bridge contract
     * - the emitter of the transfer message is not registered with this contract
     * - the relayer fails to provide enough native assets to facilitate a native swap
     * - the recipient attempts to swap native assets when performing a self redemption
     * @param encodedTransferMessage Attested `TransferWithPayload` wormhole message.
     */
    function executeVAAv1(bytes calldata encodedTransferMessage) public payable {
        // complete the transfer by calling the token bridge
        (bytes memory payload, uint256 amount, address token) = _completeTransfer(encodedTransferMessage);

        // parse the payload into the `TransferWithRelay` struct
        TransferWithRelay memory transferWithRelay = decodeTransferWithRelay(payload);

        // cache the recipient address and unwrap weth flag
        address recipient = bytes32ToAddress(transferWithRelay.targetRecipient);

        // transfer the full amount to the recipient
        if (token == address(weth) && unwrapWeth) {
            // withdraw weth and send to the recipient
            weth.withdraw(amount);
            (bool success,) = payable(recipient).call{value: amount}("");
            require(success, "Failed to transfer to recipient");
        } else {
            SafeERC20.safeTransfer(IERC20(token), recipient, amount);
        }
    }

    function _completeTransfer(bytes memory encodedTransferMessage) internal returns (bytes memory, uint256, address) {
        /**
         * parse the encoded Wormhole message
         *
         * SECURITY: This message not been verified by the Wormhole core layer yet.
         * The encoded payload can only be trusted once the message has been verified
         * by the Wormhole core contract. In this case, the message will be verified
         * by a call to the token bridge contract in subsequent actions.
         */
        IWormhole.VM memory parsedMessage = wormhole.parseVM(encodedTransferMessage);

        /**
         * The amount encoded in the payload could be incorrect,
         * since fee-on-transfer tokens are supported by the token bridge.
         *
         * NOTE: The token bridge truncates the encoded amount for any token
         * with decimals greater than 8. This is to support blockchains that
         * cannot handle transfer amounts exceeding max(uint64).
         */
        address localTokenAddress = fetchLocalAddressFromTransferMessage(parsedMessage.payload);

        // check balance before completing the transfer
        uint256 balanceBefore = getBalance(localTokenAddress);

        /**
         * Call `completeTransferWithPayload` on the token bridge. This
         * method acts as a reentrancy protection since it does not allow
         * transfers to be redeemed more than once.
         */
        bytes memory transferPayload = tokenBridge.completeTransferWithPayload(encodedTransferMessage);

        // compute and save the balance difference after completing the transfer
        uint256 amountReceived = getBalance(localTokenAddress) - balanceBefore;

        // parse the wormhole message payload into the `TransferWithPayload` struct
        ITokenBridge.TransferWithPayload memory transfer = tokenBridge.parseTransferWithPayload(transferPayload);

        // emit event with information about the TransferWithPayload message
        emit TransferRedeemed(parsedMessage.emitterChainId, parsedMessage.emitterAddress, parsedMessage.sequence);

        return (transfer.payload, amountReceived, localTokenAddress);
    }

    /**
     * @notice Parses the encoded address and chainId from a `TransferWithPayload`
     * message. Finds the address of the wrapped token contract if the token is not
     * native to this chain.
     * @param payload Encoded `TransferWithPayload` message
     * @return localAddress Address of the encoded (bytes32 format) token address on
     * this chain.
     */
    function fetchLocalAddressFromTransferMessage(bytes memory payload) public view returns (address localAddress) {
        // parse the source token address and chainId
        bytes32 sourceAddress = payload.toBytes32(33);
        uint16 tokenChain = payload.toUint16(65);

        // Fetch the wrapped address from the token bridge if the token
        // is not from this chain.
        if (tokenChain != chainId) {
            // identify wormhole token bridge wrapper
            localAddress = tokenBridge.wrappedAsset(tokenChain, sourceAddress);
            require(localAddress != address(0), "token not attested");
        } else {
            // return the encoded address if the token is native to this chain
            localAddress = bytes32ToAddress(sourceAddress);
        }
    }

    function custodyTokens(address token, uint256 amount) internal returns (uint256) {
        // query own token balance before transfer
        uint256 balanceBefore = getBalance(token);

        // deposit tokens
        SafeERC20.safeTransferFrom(IERC20(token), msg.sender, address(this), amount);

        // return the balance difference
        return getBalance(token) - balanceBefore;
    }

    function bytes32ToAddress(bytes32 address_) internal pure returns (address) {
        require(bytes12(address_) == 0, "invalid EVM address");
        return address(uint160(uint256(address_)));
    }

    // necessary for receiving native assets
    receive() external payable {}
}

// contracts/Bridge.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

interface IWETH is IERC20 {
    function deposit() external payable;
    function withdraw(uint256 amount) external;
    function balanceOf() external returns (uint256);
}

// contracts/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.17;

interface IWormhole {
    struct GuardianSet {
        address[] keys;
        uint32 expirationTime;
    }

    struct Signature {
        bytes32 r;
        bytes32 s;
        uint8 v;
        uint8 guardianIndex;
    }

    struct VM {
        uint8 version;
        uint32 timestamp;
        uint32 nonce;
        uint16 emitterChainId;
        bytes32 emitterAddress;
        uint64 sequence;
        uint8 consistencyLevel;
        bytes payload;
        uint32 guardianSetIndex;
        Signature[] signatures;
        bytes32 hash;
    }

    event LogMessagePublished(
        address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel
    );

    function publishMessage(uint32 nonce, bytes memory payload, uint8 consistencyLevel)
        external
        payable
        returns (uint64 sequence);

    function parseAndVerifyVM(bytes calldata encodedVM)
        external
        view
        returns (VM memory vm, bool valid, string memory reason);

    function verifyVM(VM memory vm) external view returns (bool valid, string memory reason);

    function verifySignatures(bytes32 hash, Signature[] memory signatures, GuardianSet memory guardianSet)
        external
        pure
        returns (bool valid, string memory reason);

    function parseVM(bytes memory encodedVM) external pure returns (VM memory vm);

    function getGuardianSet(uint32 index) external view returns (GuardianSet memory);

    function getCurrentGuardianSetIndex() external view returns (uint32);

    function getGuardianSetExpiry() external view returns (uint32);

    function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

    function isInitialized(address impl) external view returns (bool);

    function chainId() external view returns (uint16);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function messageFee() external view returns (uint256);

    function evmChainId() external view returns (uint256);

    function nextSequence(address emitter) external view returns (uint64);
}

File 4 of 16 : ITokenBridge.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.17;

import "./IWETH.sol";
import "./IWormhole.sol";

interface ITokenBridge {
    struct Transfer {
        uint8 payloadID;
        uint256 amount;
        bytes32 tokenAddress;
        uint16 tokenChain;
        bytes32 to;
        uint16 toChain;
        uint256 fee;
    }

    struct TransferWithPayload {
        uint8 payloadID;
        uint256 amount;
        bytes32 tokenAddress;
        uint16 tokenChain;
        bytes32 to;
        uint16 toChain;
        bytes32 fromAddress;
        bytes payload;
    }

    struct AssetMeta {
        uint8 payloadID;
        bytes32 tokenAddress;
        uint16 tokenChain;
        uint8 decimals;
        bytes32 symbol;
        bytes32 name;
    }

    struct RegisterChain {
        bytes32 module;
        uint8 action;
        uint16 chainId;
        uint16 emitterChainID;
        bytes32 emitterAddress;
    }

    struct UpgradeContract {
        bytes32 module;
        uint8 action;
        uint16 chainId;
        bytes32 newContract;
    }

    struct RecoverChainId {
        bytes32 module;
        uint8 action;
        uint256 evmChainId;
        uint16 newChainId;
    }

    event ContractUpgraded(address indexed oldContract, address indexed newContract);

    function _parseTransferCommon(bytes memory encoded) external pure returns (Transfer memory transfer);

    function attestToken(address tokenAddress, uint32 nonce) external payable returns (uint64 sequence);

    function wrapAndTransferETH(uint16 recipientChain, bytes32 recipient, uint256 arbiterFee, uint32 nonce)
        external
        payable
        returns (uint64 sequence);

    function wrapAndTransferETHWithPayload(uint16 recipientChain, bytes32 recipient, uint32 nonce, bytes memory payload)
        external
        payable
        returns (uint64 sequence);

    function transferTokens(
        address token,
        uint256 amount,
        uint16 recipientChain,
        bytes32 recipient,
        uint256 arbiterFee,
        uint32 nonce
    ) external payable returns (uint64 sequence);

    function transferTokensWithPayload(
        address token,
        uint256 amount,
        uint16 recipientChain,
        bytes32 recipient,
        uint32 nonce,
        bytes memory payload
    ) external payable returns (uint64 sequence);

    function updateWrapped(bytes memory encodedVm) external returns (address token);

    function createWrapped(bytes memory encodedVm) external returns (address token);

    function completeTransferWithPayload(bytes memory encodedVm) external returns (bytes memory);

    function completeTransferAndUnwrapETHWithPayload(bytes memory encodedVm) external returns (bytes memory);

    function completeTransfer(bytes memory encodedVm) external;

    function completeTransferAndUnwrapETH(bytes memory encodedVm) external;

    function encodeAssetMeta(AssetMeta memory meta) external pure returns (bytes memory encoded);

    function encodeTransfer(Transfer memory transfer) external pure returns (bytes memory encoded);

    function encodeTransferWithPayload(TransferWithPayload memory transfer)
        external
        pure
        returns (bytes memory encoded);

    function parsePayloadID(bytes memory encoded) external pure returns (uint8 payloadID);

    function parseAssetMeta(bytes memory encoded) external pure returns (AssetMeta memory meta);

    function parseTransfer(bytes memory encoded) external pure returns (Transfer memory transfer);

    function parseTransferWithPayload(bytes memory encoded)
        external
        pure
        returns (TransferWithPayload memory transfer);

    function governanceActionIsConsumed(bytes32 hash) external view returns (bool);

    function isInitialized(address impl) external view returns (bool);

    function isTransferCompleted(bytes32 hash) external view returns (bool);

    function wormhole() external view returns (IWormhole);

    function chainId() external view returns (uint16);

    function evmChainId() external view returns (uint256);

    function isFork() external view returns (bool);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function wrappedAsset(uint16 tokenChainId, bytes32 tokenAddress) external view returns (address);

    function bridgeContracts(uint16 chainId_) external view returns (bytes32);

    function tokenImplementation() external view returns (address);

    function WETH() external view returns (IWETH);

    function outstandingBridged(address token) external view returns (uint256);

    function isWrappedAsset(address token) external view returns (bool);

    function finality() external view returns (uint8);

    function implementation() external view returns (address);

    function initialize() external;

    function registerChain(bytes memory encodedVM) external;

    function upgrade(bytes memory encodedVM) external;

    function submitRecoverChainId(bytes memory encodedVM) external;

    function parseRegisterChain(bytes memory encoded) external pure returns (RegisterChain memory chain);

    function parseUpgrade(bytes memory encoded) external pure returns (UpgradeContract memory chain);

    function parseRecoverChainId(bytes memory encodedRecoverChainId)
        external
        pure
        returns (RecoverChainId memory rci);
}

// SPDX-License-Identifier: Unlicense
/*
 * @title Solidity Bytes Arrays Utils
 * @author Gonçalo Sá <[email protected]>
 *
 * @dev Bytes tightly packed arrays utility library for ethereum contracts written in Solidity.
 *      The library lets you concatenate, slice and type cast bytes arrays both in memory and storage.
 */
pragma solidity >=0.8.0 <0.9.0;

library BytesLib {
    function concat(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bytes memory) {
        bytes memory tempBytes;

        assembly {
            // Get a location of some free memory and store it in tempBytes as
            // Solidity does for memory variables.
            tempBytes := mload(0x40)

            // Store the length of the first bytes array at the beginning of
            // the memory for tempBytes.
            let length := mload(_preBytes)
            mstore(tempBytes, length)

            // Maintain a memory counter for the current write location in the
            // temp bytes array by adding the 32 bytes for the array length to
            // the starting location.
            let mc := add(tempBytes, 0x20)
            // Stop copying when the memory counter reaches the length of the
            // first bytes array.
            let end := add(mc, length)

            for {
                // Initialize a copy counter to the start of the _preBytes data,
                // 32 bytes into its memory.
                let cc := add(_preBytes, 0x20)
            } lt(mc, end) {
                // Increase both counters by 32 bytes each iteration.
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } {
                // Write the _preBytes data into the tempBytes memory 32 bytes
                // at a time.
                mstore(mc, mload(cc))
            }

            // Add the length of _postBytes to the current length of tempBytes
            // and store it as the new length in the first 32 bytes of the
            // tempBytes memory.
            length := mload(_postBytes)
            mstore(tempBytes, add(length, mload(tempBytes)))

            // Move the memory counter back from a multiple of 0x20 to the
            // actual end of the _preBytes data.
            mc := end
            // Stop copying when the memory counter reaches the new combined
            // length of the arrays.
            end := add(mc, length)

            for { let cc := add(_postBytes, 0x20) } lt(mc, end) {
                mc := add(mc, 0x20)
                cc := add(cc, 0x20)
            } { mstore(mc, mload(cc)) }

            // Update the free-memory pointer by padding our last write location
            // to 32 bytes: add 31 bytes to the end of tempBytes to move to the
            // next 32 byte block, then round down to the nearest multiple of
            // 32. If the sum of the length of the two arrays is zero then add
            // one before rounding down to leave a blank 32 bytes (the length block with 0).
            mstore(
                0x40,
                and(
                    add(add(end, iszero(add(length, mload(_preBytes)))), 31),
                    not(31) // Round down to the nearest 32 bytes.
                )
            )
        }

        return tempBytes;
    }

    function concatStorage(bytes storage _preBytes, bytes memory _postBytes) internal {
        assembly {
            // Read the first 32 bytes of _preBytes storage, which is the length
            // of the array. (We don't need to use the offset into the slot
            // because arrays use the entire slot.)
            let fslot := sload(_preBytes.slot)
            // Arrays of 31 bytes or less have an even value in their slot,
            // while longer arrays have an odd value. The actual length is
            // the slot divided by two for odd values, and the lowest order
            // byte divided by two for even values.
            // If the slot is even, bitwise and the slot with 255 and divide by
            // two to get the length. If the slot is odd, bitwise and the slot
            // with -1 and divide by two.
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)
            let newlength := add(slength, mlength)
            // slength can contain both the length and contents of the array
            // if length < 32 bytes so let's prepare for that
            // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
            switch add(lt(slength, 32), lt(newlength, 32))
            case 2 {
                // Since the new array still fits in the slot, we just need to
                // update the contents of the slot.
                // uint256(bytes_storage) = uint256(bytes_storage) + uint256(bytes_memory) + new_length
                sstore(
                    _preBytes.slot,
                    // all the modifications to the slot are inside this
                    // next block
                    add(
                        // we can just add to the slot contents because the
                        // bytes we want to change are the LSBs
                        fslot,
                        add(
                            mul(
                                div(
                                    // load the bytes from memory
                                    mload(add(_postBytes, 0x20)),
                                    // zero all bytes to the right
                                    exp(0x100, sub(32, mlength))
                                ),
                                // and now shift left the number of bytes to
                                // leave space for the length in the slot
                                exp(0x100, sub(32, newlength))
                            ),
                            // increase length by the double of the memory
                            // bytes length
                            mul(mlength, 2)
                        )
                    )
                )
            }
            case 1 {
                // The stored value fits in the slot, but the combined value
                // will exceed it.
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // The contents of the _postBytes array start 32 bytes into
                // the structure. Our first read should obtain the `submod`
                // bytes that can fit into the unused space in the last word
                // of the stored array. To get this, we read 32 bytes starting
                // from `submod`, so the data we read overlaps with the array
                // contents by `submod` bytes. Masking the lowest-order
                // `submod` bytes allows us to add that value directly to the
                // stored value.

                let submod := sub(32, slength)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(
                    sc,
                    add(
                        and(fslot, 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00),
                        and(mload(mc), mask)
                    )
                )

                for {
                    mc := add(mc, 0x20)
                    sc := add(sc, 1)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } { sstore(sc, mload(mc)) }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
            default {
                // get the keccak hash to get the contents of the array
                mstore(0x0, _preBytes.slot)
                // Start copying to the last used word of the stored array.
                let sc := add(keccak256(0x0, 0x20), div(slength, 32))

                // save new length
                sstore(_preBytes.slot, add(mul(newlength, 2), 1))

                // Copy over the first `submod` bytes of the new data as in
                // case 1 above.
                let slengthmod := mod(slength, 32)
                let mlengthmod := mod(mlength, 32)
                let submod := sub(32, slengthmod)
                let mc := add(_postBytes, submod)
                let end := add(_postBytes, mlength)
                let mask := sub(exp(0x100, submod), 1)

                sstore(sc, add(sload(sc), and(mload(mc), mask)))

                for {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } lt(mc, end) {
                    sc := add(sc, 1)
                    mc := add(mc, 0x20)
                } { sstore(sc, mload(mc)) }

                mask := exp(0x100, sub(mc, end))

                sstore(sc, mul(div(mload(mc), mask), mask))
            }
        }
    }

    function slice(bytes memory _bytes, uint256 _start, uint256 _length) internal pure returns (bytes memory) {
        require(_length + 31 >= _length, "slice_overflow");
        require(_bytes.length >= _start + _length, "slice_outOfBounds");

        bytes memory tempBytes;

        assembly {
            switch iszero(_length)
            case 0 {
                // Get a location of some free memory and store it in tempBytes as
                // Solidity does for memory variables.
                tempBytes := mload(0x40)

                // The first word of the slice result is potentially a partial
                // word read from the original array. To read it, we calculate
                // the length of that partial word and start copying that many
                // bytes into the array. The first word we copy will start with
                // data we don't care about, but the last `lengthmod` bytes will
                // land at the beginning of the contents of the new array. When
                // we're done copying, we overwrite the full first word with
                // the actual length of the slice.
                let lengthmod := and(_length, 31)

                // The multiplication in the next line is necessary
                // because when slicing multiples of 32 bytes (lengthmod == 0)
                // the following copy loop was copying the origin's length
                // and then ending prematurely not copying everything it should.
                let mc := add(add(tempBytes, lengthmod), mul(0x20, iszero(lengthmod)))
                let end := add(mc, _length)

                for {
                    // The multiplication in the next line has the same exact purpose
                    // as the one above.
                    let cc := add(add(add(_bytes, lengthmod), mul(0x20, iszero(lengthmod))), _start)
                } lt(mc, end) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } { mstore(mc, mload(cc)) }

                mstore(tempBytes, _length)

                //update free-memory pointer
                //allocating the array padded to 32 bytes like the compiler does now
                mstore(0x40, and(add(mc, 31), not(31)))
            }
            //if we want a zero-length slice let's just return a zero-length array
            default {
                tempBytes := mload(0x40)
                //zero out the 32 bytes slice we are about to return
                //we need to do it because Solidity does not garbage collect
                mstore(tempBytes, 0)

                mstore(0x40, add(tempBytes, 0x20))
            }
        }

        return tempBytes;
    }

    function toAddress(bytes memory _bytes, uint256 _start) internal pure returns (address) {
        require(_bytes.length >= _start + 20, "toAddress_outOfBounds");
        address tempAddress;

        assembly {
            tempAddress := div(mload(add(add(_bytes, 0x20), _start)), 0x1000000000000000000000000)
        }

        return tempAddress;
    }

    function toUint8(bytes memory _bytes, uint256 _start) internal pure returns (uint8) {
        require(_bytes.length >= _start + 1, "toUint8_outOfBounds");
        uint8 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x1), _start))
        }

        return tempUint;
    }

    function toUint16(bytes memory _bytes, uint256 _start) internal pure returns (uint16) {
        require(_bytes.length >= _start + 2, "toUint16_outOfBounds");
        uint16 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x2), _start))
        }

        return tempUint;
    }

    function toUint32(bytes memory _bytes, uint256 _start) internal pure returns (uint32) {
        require(_bytes.length >= _start + 4, "toUint32_outOfBounds");
        uint32 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x4), _start))
        }

        return tempUint;
    }

    function toUint64(bytes memory _bytes, uint256 _start) internal pure returns (uint64) {
        require(_bytes.length >= _start + 8, "toUint64_outOfBounds");
        uint64 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x8), _start))
        }

        return tempUint;
    }

    function toUint96(bytes memory _bytes, uint256 _start) internal pure returns (uint96) {
        require(_bytes.length >= _start + 12, "toUint96_outOfBounds");
        uint96 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0xc), _start))
        }

        return tempUint;
    }

    function toUint128(bytes memory _bytes, uint256 _start) internal pure returns (uint128) {
        require(_bytes.length >= _start + 16, "toUint128_outOfBounds");
        uint128 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x10), _start))
        }

        return tempUint;
    }

    function toUint256(bytes memory _bytes, uint256 _start) internal pure returns (uint256) {
        require(_bytes.length >= _start + 32, "toUint256_outOfBounds");
        uint256 tempUint;

        assembly {
            tempUint := mload(add(add(_bytes, 0x20), _start))
        }

        return tempUint;
    }

    function toBytes32(bytes memory _bytes, uint256 _start) internal pure returns (bytes32) {
        require(_bytes.length >= _start + 32, "toBytes32_outOfBounds");
        bytes32 tempBytes32;

        assembly {
            tempBytes32 := mload(add(add(_bytes, 0x20), _start))
        }

        return tempBytes32;
    }

    function equal(bytes memory _preBytes, bytes memory _postBytes) internal pure returns (bool) {
        bool success = true;

        assembly {
            let length := mload(_preBytes)

            // if lengths don't match the arrays are not equal
            switch eq(length, mload(_postBytes))
            case 1 {
                // cb is a circuit breaker in the for loop since there's
                //  no said feature for inline assembly loops
                // cb = 1 - don't breaker
                // cb = 0 - break
                let cb := 1

                let mc := add(_preBytes, 0x20)
                let end := add(mc, length)

                for { let cc := add(_postBytes, 0x20) }
                // the next line is the loop condition:
                // while(uint256(mc < end) + cb == 2)
                eq(add(lt(mc, end), cb), 2) {
                    mc := add(mc, 0x20)
                    cc := add(cc, 0x20)
                } {
                    // if any of these checks fails then arrays are not equal
                    if iszero(eq(mload(mc), mload(cc))) {
                        // unsuccess:
                        success := 0
                        cb := 0
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }

    function equalStorage(bytes storage _preBytes, bytes memory _postBytes) internal view returns (bool) {
        bool success = true;

        assembly {
            // we know _preBytes_offset is 0
            let fslot := sload(_preBytes.slot)
            // Decode the length of the stored array like in concatStorage().
            let slength := div(and(fslot, sub(mul(0x100, iszero(and(fslot, 1))), 1)), 2)
            let mlength := mload(_postBytes)

            // if lengths don't match the arrays are not equal
            switch eq(slength, mlength)
            case 1 {
                // slength can contain both the length and contents of the array
                // if length < 32 bytes so let's prepare for that
                // v. http://solidity.readthedocs.io/en/latest/miscellaneous.html#layout-of-state-variables-in-storage
                if iszero(iszero(slength)) {
                    switch lt(slength, 32)
                    case 1 {
                        // blank the last byte which is the length
                        fslot := mul(div(fslot, 0x100), 0x100)

                        if iszero(eq(fslot, mload(add(_postBytes, 0x20)))) {
                            // unsuccess:
                            success := 0
                        }
                    }
                    default {
                        // cb is a circuit breaker in the for loop since there's
                        //  no said feature for inline assembly loops
                        // cb = 1 - don't breaker
                        // cb = 0 - break
                        let cb := 1

                        // get the keccak hash to get the contents of the array
                        mstore(0x0, _preBytes.slot)
                        let sc := keccak256(0x0, 0x20)

                        let mc := add(_postBytes, 0x20)
                        let end := add(mc, mlength)

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {} eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol)

pragma solidity ^0.8.0;

/**
 * @dev Contract module that helps prevent reentrant calls to a function.
 *
 * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
 * available, which can be applied to functions to make sure there are no nested
 * (reentrant) calls to them.
 *
 * Note that because there is a single `nonReentrant` guard, functions marked as
 * `nonReentrant` may not call one another. This can be worked around by making
 * those functions `private`, and then adding `external` `nonReentrant` entry
 * points to them.
 *
 * TIP: If you would like to learn more about reentrancy and alternative ways
 * to protect against it, check out our blog post
 * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
 */
abstract contract ReentrancyGuard {
    // Booleans are more expensive than uint256 or any type that takes up a full
    // word because each write operation emits an extra SLOAD to first read the
    // slot's contents, replace the bits taken up by the boolean, and then write
    // back. This is the compiler's defense against contract upgrades and
    // pointer aliasing, and it cannot be disabled.

    // The values being non-zero value makes deployment a bit more expensive,
    // but in exchange the refund on every call to nonReentrant will be lower in
    // amount. Since refunds are capped to a percentage of the total
    // transaction's gas, it is best to keep them low in cases like this one, to
    // increase the likelihood of the full refund coming into effect.
    uint256 private constant _NOT_ENTERED = 1;
    uint256 private constant _ENTERED = 2;

    uint256 private _status;

    constructor() {
        _status = _NOT_ENTERED;
    }

    /**
     * @dev Prevents a contract from calling itself, directly or indirectly.
     * Calling a `nonReentrant` function from another `nonReentrant`
     * function is not supported. It is possible to prevent this from happening
     * by making the `nonReentrant` function external, and making it call a
     * `private` function that does the actual work.
     */
    modifier nonReentrant() {
        _nonReentrantBefore();
        _;
        _nonReentrantAfter();
    }

    function _nonReentrantBefore() private {
        // On the first call to nonReentrant, _status will be _NOT_ENTERED
        require(_status != _ENTERED, "ReentrancyGuard: reentrant call");

        // Any calls to nonReentrant after this point will fail
        _status = _ENTERED;
    }

    function _nonReentrantAfter() private {
        // By storing the original value once again, a refund is triggered (see
        // https://eips.ethereum.org/EIPS/eip-2200)
        _status = _NOT_ENTERED;
    }
}

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

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (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");
        }
    }
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

interface IExecutor {
    struct SignedQuoteHeader {
        bytes4 prefix;
        address quoterAddress;
        bytes32 payeeAddress;
        uint16 srcChain;
        uint16 dstChain;
        uint64 expiryTime;
    }

    event RequestForExecution(
        address indexed quoterAddress,
        uint256 amtPaid,
        uint16 dstChain,
        bytes32 dstAddr,
        address refundAddr,
        bytes signedQuote,
        bytes requestBytes,
        bytes relayInstructions
    );

    function requestExecution(
        uint16 dstChain,
        bytes32 dstAddr,
        address refundAddr,
        bytes calldata signedQuote,
        bytes calldata requestBytes,
        bytes calldata relayInstructions
    ) external payable;
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

/// @notice Any contract that wishes to receive V1 VAAs from the executor needs to implement `IVaaV1Receiver`.
interface IVaaV1Receiver {
    /// @notice Receive an attested message from the executor relayer.
    /// @param msg The attested message payload.
    function executeVAAv1(bytes memory msg) external payable;
}

// SPDX-License-Identifier: Apache-2.0
pragma solidity ^0.8.19;

library ExecutorMessages {
    bytes4 private constant REQ_MM = "ERM1";
    bytes4 private constant REQ_VAA_V1 = "ERV1";
    bytes4 private constant REQ_NTT_V1 = "ERN1";
    bytes4 private constant REQ_CCTP_V1 = "ERC1";
    bytes4 private constant REQ_CCTP_V2 = "ERC2";

    /// @notice Payload length will not fit in a uint32.
    /// @dev Selector: 492f620d.
    error PayloadTooLarge();

    /// @notice Encodes a modular messaging request payload.
    /// @param srcChain The source chain for the message (usually this chain).
    /// @param srcAddr The source address for the message.
    /// @param sequence The sequence number returned by `endpoint.sendMessage`.
    /// @param payload The full payload, the keccak of which was sent to `endpoint.sendMessage`.
    /// @return bytes The encoded request.
    function makeMMRequest(uint16 srcChain, address srcAddr, uint64 sequence, bytes memory payload)
        internal
        pure
        returns (bytes memory)
    {
        if (payload.length > type(uint32).max) {
            revert PayloadTooLarge();
        }
        return abi.encodePacked(
            REQ_MM, srcChain, bytes32(uint256(uint160(srcAddr))), sequence, uint32(payload.length), payload
        );
    }

    /// @notice Encodes a version 1 VAA request payload.
    /// @param emitterChain The emitter chain from the VAA.
    /// @param emitterAddress The emitter address from the VAA.
    /// @param sequence The sequence number from the VAA.
    /// @return bytes The encoded request.
    function makeVAAv1Request(uint16 emitterChain, bytes32 emitterAddress, uint64 sequence)
        internal
        pure
        returns (bytes memory)
    {
        return abi.encodePacked(REQ_VAA_V1, emitterChain, emitterAddress, sequence);
    }

    /// @notice Encodes a version 1 NTT request payload.
    /// @param srcChain The source chain for the NTT transfer.
    /// @param srcManager The source manager for the NTT transfer.
    /// @param messageId The manager message id for the NTT transfer.
    /// @return bytes The encoded request.
    function makeNTTv1Request(uint16 srcChain, bytes32 srcManager, bytes32 messageId)
        internal
        pure
        returns (bytes memory)
    {
        return abi.encodePacked(REQ_NTT_V1, srcChain, srcManager, messageId);
    }

    /// @notice Encodes a version 1 CCTP request payload.
    /// @param sourceDomain The source chain for the CCTP transfer.
    /// @param nonce The nonce of the CCTP transfer.
    /// @return bytes The encoded request.
    function makeCCTPv1Request(uint32 sourceDomain, uint64 nonce) internal pure returns (bytes memory) {
        return abi.encodePacked(REQ_CCTP_V1, sourceDomain, nonce);
    }

    /// @notice Encodes a version 2 CCTP request payload.
    ///         This request currently assumes the Executor will auto detect the event off chain.
    ///         That may change in the future, in which case this interface would change.
    /// @return bytes The encoded request.
    function makeCCTPv2Request() internal pure returns (bytes memory) {
        return abi.encodePacked(REQ_CCTP_V2, uint8(1));
    }
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.17;

import "../libraries/BytesLib.sol";

import "./TokenBridgeRelayerStructs.sol";

abstract contract TokenBridgeRelayerMessages is TokenBridgeRelayerStructs {
    using BytesLib for bytes;

    /**
     * @notice Encodes the TransferWithRelay struct into bytes.
     * @param transfer TransferWithRelay struct.
     * @return encoded TransferWithRelay struct encoded into bytes.
     */
    function encodeTransferWithRelay(TransferWithRelay memory transfer) public pure returns (bytes memory encoded) {
        encoded = abi.encodePacked(transfer.targetRecipient);
    }

    /**
     * @notice Decodes an encoded `TransferWithRelay` struct.
     * @dev reverts if:
     * - the length of the payload has an unexpected length
     * @param encoded Encoded `TransferWithRelay` struct.
     * @return transfer `TransferTokenRelay` struct.
     */
    function decodeTransferWithRelay(bytes memory encoded) public pure returns (TransferWithRelay memory transfer) {
        uint256 index = 0;

        // recipient of the transferred tokens and native assets
        transfer.targetRecipient = encoded.toBytes32(index);
        index += 32;

        require(index == encoded.length, "invalid message length");
    }
}

// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";

abstract contract TokenBridgeRelayerGetters {
    function normalizeAmount(uint256 amount, uint8 decimals) public pure returns (uint256) {
        if (decimals > 8) {
            amount /= 10 ** (decimals - 8);
        }
        return amount;
    }

    function denormalizeAmount(uint256 amount, uint8 decimals) public pure returns (uint256) {
        if (decimals > 8) {
            amount *= 10 ** (decimals - 8);
        }
        return amount;
    }

    function getDecimals(address token) internal view returns (uint8) {
        (, bytes memory queriedDecimals) = token.staticcall(abi.encodeWithSignature("decimals()"));
        return abi.decode(queriedDecimals, (uint8));
    }

    function getBalance(address token) internal view returns (uint256 balance) {
        // fetch the specified token balance for this contract
        (, bytes memory queriedBalance) =
            token.staticcall(abi.encodeWithSelector(IERC20.balanceOf.selector, address(this)));
        balance = abi.decode(queriedBalance, (uint256));
    }
}

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

// 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 16 of 16 : TokenBridgeRelayerStructs.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.17;

abstract contract TokenBridgeRelayerStructs {
    struct TransferWithRelay {
        bytes32 targetRecipient;
    }

    struct InternalTransferParams {
        address token;
        uint8 tokenDecimals;
        uint256 amount;
        uint16 targetChain;
        bytes32 targetRecipient;
        uint32 nonce;
        uint256 wormholeFee;
        bytes32 dstTransferRecipient;
        bytes32 dstExecutionAddress;
        uint256 executionAmount;
        address refundAddr;
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/",
    "ds-test/=lib/openzeppelin-contracts/lib/forge-std/lib/ds-test/src/",
    "example-messaging-executor/=lib/example-messaging-executor/",
    "forge-std/=lib/forge-std/src/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "evmVersion": "paris",
  "viaIR": true,
  "libraries": {}
}

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"address","name":"tokenBridge_","type":"address"},{"internalType":"bool","name":"unwrapWeth_","type":"bool"},{"internalType":"address","name":"executor_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"emitterChainId","type":"uint16"},{"indexed":true,"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"}],"name":"TransferRedeemed","type":"event"},{"inputs":[],"name":"VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"name":"decodeTransferWithRelay","outputs":[{"components":[{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"}],"internalType":"struct TokenBridgeRelayerStructs.TransferWithRelay","name":"transfer","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"denormalizeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"components":[{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"}],"internalType":"struct TokenBridgeRelayerStructs.TransferWithRelay","name":"transfer","type":"tuple"}],"name":"encodeTransferWithRelay","outputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedTransferMessage","type":"bytes"}],"name":"executeVAAv1","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"executor","outputs":[{"internalType":"contract IExecutor","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"}],"name":"fetchLocalAddressFromTransferMessage","outputs":[{"internalType":"address","name":"localAddress","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint8","name":"decimals","type":"uint8"}],"name":"normalizeAmount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"tokenBridge","outputs":[{"internalType":"contract ITokenBridge","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenBridgeEmitter","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"token","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"bytes32","name":"dstTransferRecipient","type":"bytes32"},{"internalType":"bytes32","name":"dstExecutionAddress","type":"bytes32"},{"internalType":"uint256","name":"executionAmount","type":"uint256"},{"internalType":"address","name":"refundAddr","type":"address"},{"internalType":"bytes","name":"signedQuoteBytes","type":"bytes"},{"internalType":"bytes","name":"relayInstructions","type":"bytes"}],"name":"transferTokensWithRelay","outputs":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"unwrapWeth","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"weth","outputs":[{"internalType":"contract IWETH","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormhole","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetRecipient","type":"bytes32"},{"internalType":"uint32","name":"nonce","type":"uint32"},{"internalType":"bytes32","name":"dstTransferRecipient","type":"bytes32"},{"internalType":"bytes32","name":"dstExecutionAddress","type":"bytes32"},{"internalType":"uint256","name":"executionAmount","type":"uint256"},{"internalType":"address","name":"refundAddr","type":"address"},{"internalType":"bytes","name":"signedQuoteBytes","type":"bytes"},{"internalType":"bytes","name":"relayInstructions","type":"bytes"}],"name":"wrapAndTransferEthWithRelay","outputs":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"stateMutability":"payable","type":"receive"}]

61016060409080825234620002e257606081620021ff8038038091620000268285620002e7565b833981010312620002e2576200003c8162000321565b90602092838201519384151592838603620002e257826200005e910162000321565b600160009081556001600160a01b03958616959160049083906200008489151562000336565b16956200009387151562000336565b61010098888a528561012099808b528851948580926315ab88c960e31b82525afa928315620002d8579085929185946200028f575b508360c05260a05262000279575b88518651634d4502c960e11b81529250859183916004918391165afa908115620002305782916200023a575b50608052600483838951168651928380926384acd1bb60e01b82525afa93841562000230578294620001e6575b5050505060e0526101409182525191611eaa93846200035585396080518481816107380152818161110e0152611a77015260a05184818161057e015281816107740152610c38015260c051848181610371015281816104c90152610cfa015260e0518481816106ee0152818161097501528181610c7801526118580152518381816107f401528181610ff2015281816118a80152611acf01525182818161083b01526110ed0152518181816107af01526110990152f35b908092939450813d831162000228575b620002028183620002e7565b810103126200022457519182168203620002215750388080806200012f565b80fd5b5080fd5b503d620001f6565b85513d84823e3d90fd5b90508381813d831162000271575b620002548183620002e7565b8101031262000224575161ffff8116810362000224573862000102565b503d62000248565b620002879116151562000336565b3882620000d6565b8780929550819394503d8311620002d0575b620002ad8183620002e7565b81010312620002cc57518481168103620002cc579084919238620000c8565b8380fd5b503d620002a1565b87513d86823e3d90fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176200030b57604052565b634e487b7160e01b600052604160045260246000fd5b51906001600160a01b0382168203620002e257565b156200033e57565b634e487b7160e01b600052600160045260246000fdfe6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806327105ab91461011b57806328ded8e3146101165780632d77e8fe146101115780633fc8cef31461010c57806350789cb51461010757806353c6f0dc14610102578063730a286b146100fd5780637c9dec7a146100f857806384acd1bb146100f35780639a8a0592146100ee5780639cf278cd146100e9578063c34c08e5146100e4578063c6328a46146100df578063d8b32910146100da578063e50e7e72146100d55763ffa1ad740361000e576108e6565b61085e565b610823565b6107de565b610799565b61075c565b61071d565b6106d8565b6106b7565b61060f565b61046b565b6103f9565b61035b565b610326565b610162565b610130565b60ff81160361012b57565b600080fd5b3461012b57604036600319011261012b57602061015a60243561015281610120565b600435611cd4565b604051908152f35b3461012b57604036600319011261012b57602061015a60243561018481610120565b600435611d30565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b038211176101bd57604052565b61018c565b6001600160401b0381116101bd57604052565b608081019081106001600160401b038211176101bd57604052565b604081019081106001600160401b038211176101bd57604052565b606081019081106001600160401b038211176101bd57604052565b90601f801991011681019081106001600160401b038211176101bd57604052565b6040519061016082018281106001600160401b038211176101bd57604052565b60405190610274826101a2565b565b6040519061010082018281106001600160401b038211176101bd57604052565b6001600160401b0381116101bd57601f01601f191660200190565b9291926102bd82610296565b916102cb6040519384610226565b82948184528183011161012b578281602093846000960137010152565b602060031982011261012b57600435906001600160401b03821161012b578060238301121561012b57816024610323936004013591016102b1565b90565b3461012b57602061033e610339366102e8565b611a5c565b6040516001600160a01b039091168152f35b600091031261012b57565b3461012b57600036600319011261012b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b60005b8381106103b35750506000910152565b81810151838201526020016103a3565b906020916103dc815180928185528580860191016103a0565b601f01601f1916010190565b9060206103239281815201906103c3565b3461012b57602036600319011261012b5761043a61042660405161041c816101a2565b6004358152611df2565b6040519182916020835260208301906103c3565b0390f35b9181601f8401121561012b578235916001600160401b03831161012b576020838186019501011161012b57565b602036600319011261012b576004356001600160401b03811161012b576104b86104ae6104a96104a26104be94369060040161043e565b36916102b1565b611825565b9391929092611e09565b51611c5a565b6001600160a01b03927f000000000000000000000000000000000000000000000000000000000000000084169084168082148061057b575b1561056f5750803b1561012b57604051632e1a7d4d60e01b815260048101849052600093909184908390602490829084905af190811561056a5761001995859485948594610551575b50165af161054b610bb5565b506114c7565b8061055e610564926101c2565b80610350565b3861053f565b610ae8565b90506100199350611513565b507f00000000000000000000000000000000000000000000000000000000000000006104f6565b6001600160a01b0381160361012b57565b60043590610274826105a2565b6101043590610274826105a2565b60c43590610274826105a2565b61ffff81160361012b57565b60443590610274826105db565b63ffffffff81160361012b57565b60843590610274826105f4565b61016036600319011261012b576106246105b3565b61062c6105e7565b610634610602565b9161063d6105c0565b6001600160401b0392906101243584811161012b5761066090369060040161043e565b916101443595861161012b5761043a9661068161069d97369060040161043e565b96909560e4359260c4359260a435926064359160243590610944565b6040516001600160401b0390911681529081906020820190565b3461012b5760206106cf6106ca366102e8565b611e09565b60405190518152f35b3461012b57600036600319011261012b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461012b57600036600319011261012b57602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b3461012b57600036600319011261012b5760206040517f000000000000000000000000000000000000000000000000000000000000000015158152f35b3461012b57600036600319011261012b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461012b57600036600319011261012b576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b3461012b57600036600319011261012b5760206040517f00000000000000000000000000000000000000000000000000000000000000008152f35b61012036600319011261012b57600435610877816105db565b604435610883816105f4565b61088b6105ce565b916001600160401b039160e43583811161012b576108ad90369060040161043e565b906101043594851161012b5761043a956108ce61069d96369060040161043e565b95909460a43591608435916064359160243590610c29565b3461012b57600036600319011261012b5761043a604051610906816101f0565b601881527f546f6b656e42726964676552656c617965722d302e342e30000000000000000060208201526040519182916020835260208301906103c3565b92909b9a9998979695949391600260005414610a94576002600055604051631a90a21960e01b8152936020856004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa94851561056a57600095610a64575b506109b98886610b0a565b34146109c490610b1c565b6109cd81611d60565b6109d9819f8290611cd4565b906109e391611d30565b6109ed9082611be7565b906109f6610247565b6001600160a01b0390911681529d8e9060ff1660208201526040015261ffff1660608d015260808c015263ffffffff1660a08b015260c08a015260e08901526101008801526101208701526001600160a01b0316610140860152610a5994610f85565b906102746001600055565b610a8691955060203d8111610a8d575b610a7e8183610226565b810190610ad9565b93386109ae565b503d610a74565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b9081602091031261012b575190565b6040513d6000823e3d90fd5b634e487b7160e01b600052601160045260246000fd5b91908201809211610b1757565b610af4565b15610b2357565b60405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606490fd5b15610b6457565b606460405162461bcd60e51b815260206004820152602060248201527f574554482066756e6374696f6e616c697479206e6f7420737570706f727465646044820152fd5b91908203918211610b1757565b3d15610be0573d90610bc682610296565b91610bd46040519384610226565b82523d6000602084013e565b606090565b15610bec57565b60405162461bcd60e51b815260206004820152601560248201527411985a5b1959081d1bc81c99599d5b9908191d5cdd605a1b6044820152606490fd5b90999897969594939291610c5c7f0000000000000000000000000000000000000000000000000000000000000000610b5d565b604051631a90a21960e01b81526001600160a01b039b909283807f00000000000000000000000000000000000000000000000000000000000000008f165a92600491602094fa93841561056a57600094610de1575b50610cf7610cd3610cc28987610b0a565b610ccd813411610b1c565b34610ba8565b610cec610ce66402540be4008304611d16565b82610ba8565b9081610dc257610ba8565b9c7f0000000000000000000000000000000000000000000000000000000000000000169c8d3b1561012b578060008f600460405180948193630d0e30db60e41b83525af1801561056a57610daf575b50610d4f610247565b6001600160a01b03909e168e52601260208f01528d6040015261ffff1660608d015260808c015263ffffffff1660a08b015260c08a015260e08901526101008801526101208701526001600160a01b031661014086015261032394610f85565b8061055e610dbc926101c2565b38610d46565b610ddc600080808086335af1610dd6610bb5565b50610be5565b610ba8565b610dfa91945060203d8111610a8d57610a7e8183610226565b9238610cb1565b15610e0857565b60405162461bcd60e51b8152602060048201526024808201527f746172676574526563697069656e742063616e6e6f74206265206279746573336044820152633228302960e01b6064820152608490fd5b15610e6057565b60405162461bcd60e51b815260206004820152601d60248201527f6e6f726d616c697a656420616d6f756e74206d757374206265203e20300000006044820152606490fd5b51906001600160401b038216820361012b57565b9081602091031261012b5761032390610ea5565b929361ffff60c09563ffffffff9461032399989460018060a01b03168752602087015216604085015260608401521660808201528160a082015201906103c3565b908060209392818452848401376000828201840152601f01601f1916010190565b9694610323989693610f699361ffff610f779794168a5260208a015260018060a01b0316604089015260c0606089015260c0880191610f0e565b9085820360808701526103c3565b9260a0818503910152610f0e565b94939092916080860195610f9b87511515610e01565b610fd76040820197610fc6610fbf8a51610fb9602087015160ff1690565b90611cd4565b1515610e59565b51610fcf610267565b908152611df2565b81519093906001600160a01b031688516001600160a01b03997f00000000000000000000000000000000000000000000000000000000000000008b169392602092611023918690611266565b60c085015185519094906001600160a01b031691516060870195611049875161ffff1690565b9361108160e08a01519b61106460a08c015163ffffffff1690565b6040516362d2f5ed60e11b81529d8e988997889660048801610ecd565b03925af194851561056a5760009561117c575b5084987f000000000000000000000000000000000000000000000000000000000000000016936110cc610120850151935161ffff1690565b916111326110ea61014061010088015197015160018060a01b031690565b977f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000006111ac565b97863b1561012b5760009861115e936040519b8c9a8b998a9863c513d43760e01b8a5260048a01610f2f565b03925af1801561056a5761116f5750565b8061055e610274926101c2565b61119e91955060203d81116111a5575b6111968183610226565b810190610eb9565b9338611094565b503d61118c565b604051634552563160e01b602082015260f09190911b6001600160f01b0319166024820152602681019190915260c09190911b6001600160c01b0319166046820152602e81526103238161020b565b1561120257565b60405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608490fd5b919091811580156112c3575b610274936112826112be926111fb565b60405163095ea7b360e01b60208201526001600160a01b039091166024820152604481019390935282606481015b03601f198101845283610226565b611341565b50604051636eb1769f60e11b81523060048201526001600160a01b038416602482015292602084806044810103816001600160a01b0386165afa90811561056a576112826112be9261027496600091611323575b50159250509350611272565b61133b915060203d8111610a8d57610a7e8183610226565b38611317565b60018060a01b0316906113a0604051611359816101f0565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af161139a610bb5565b91611432565b8051806113ae575b50505050565b8184918101031261142e578201519081159182150361142b57506113d4578080806113a8565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b80fd5b5080fd5b919290156114945750815115611446575090565b3b1561144f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156114a75750805190602001fd5b60405162461bcd60e51b81529081906114c390600483016103e8565b0390fd5b156114ce57565b60405162461bcd60e51b815260206004820152601f60248201527f4661696c656420746f207472616e7366657220746f20726563697069656e74006044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044820192909252610274916112be82606481016112b0565b519061027482610120565b5190610274826105f4565b5190610274826105db565b81601f8201121561012b57805161158381610296565b926115916040519485610226565b8184526020828401011161012b5761032391602080850191016103a0565b9080601f8301121561012b578151916001600160401b0383116101bd576040918251936020916115e4838360051b0187610226565b818652828087019260071b8501019381851161012b578301915b84831061160e5750505050505090565b60808383031261012b57836080918751611627816101d5565b8551815282860151838201528886015161164081610120565b898201526060808701519061165482610120565b8201528152019201916115fe565b9060208282031261012b5781516001600160401b039283821161012b5701906101608282031261012b57611694610247565b9261169e8361154c565b84526116ac60208401611557565b60208501526116bd60408401611557565b60408501526116ce60608401611562565b6060850152608083015160808501526116e960a08401610ea5565b60a08501526116fa60c0840161154c565b60c085015260e083015181811161012b578261171791850161156d565b60e085015261010061172a818501611557565b90850152610120918284015191821161012b576117489184016115af565b90830152610140809101519082015290565b9060208282031261012b5781516001600160401b03811161012b57610323920161156d565b9060208282031261012b5781516001600160401b039283821161012b5701906101008282031261012b576117b1610276565b926117bb8361154c565b845260208301516020850152604083015160408501526117dd60608401611562565b6060850152608083015160808501526117f860a08401611562565b60a085015260c083015160c085015260e083015190811161012b5761181d920161156d565b60e082015290565b60405163a9e1189360e01b815290916000918061184585600483016103e8565b6001600160a01b039291859183919003817f000000000000000000000000000000000000000000000000000000000000000086165afa90811561056a5784916119e4575b5061189760e0820151611a5c565b936118e3816118a587611daa565b947f000000000000000000000000000000000000000000000000000000000000000016976040518093819263c3f511c160e01b8352600483016103e8565b0381838b5af1801561056a5761192694839283926119bc575b5061190a90610ddc89611daa565b97604051808097819463ea63738d60e01b8352600483016103e8565b03915afa91821561056a5760e0938293611998575b50606081015161ffff16917fcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c16961ffff6001600160401b0361198b60a060808701519601516001600160401b031690565b1694169180a40151929190565b6119b59193503d8084833e6119ad8183610226565b81019061177f565b913861193b565b61190a9192506119dd903d8086833e6119d58183610226565b81019061175a565b91906118fc565b611a0091503d8086833e6119f88183610226565b810190611662565b38611889565b9081602091031261012b5751610323816105a2565b15611a2257565b60405162461bcd60e51b81526020600482015260126024820152711d1bdad95b881b9bdd08185d1d195cdd195960721b6044820152606490fd5b90611a6f611a6983611b9a565b92611b4e565b61ffff8181167f000000000000000000000000000000000000000000000000000000000000000090911614611b4357604051630ff8f14360e11b815261ffff91909116600482015260248101929092526001600160a01b036020836044817f000000000000000000000000000000000000000000000000000000000000000085165afa92831561056a57600093611b0f575b506102749083161515611a1b565b610274919350611b359060203d8111611b3c575b611b2d8183610226565b810190611a06565b9290611b01565b503d611b23565b509061032390611c5a565b6043815110611b5e576043015190565b60405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606490fd5b6041815110611baa576041015190565b60405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606490fd5b90611bf182611daa565b91604051916323b872dd60e01b602084015233602484015230604484015260648301526064825260a082018281106001600160401b038211176101bd57604052611c4d91611c48906001600160a01b038316611341565b611daa565b908103908111610b175790565b6001600160a01b03198116611c75576001600160a01b031690565b60405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b6044820152606490fd5b60ff6007199116019060ff8211610b1757565b60ff16604d8111610b1757600a0a90565b90600860ff821611611ce4575090565b611cf0611cf591611cb0565b611cc3565b908115611d00570490565b634e487b7160e01b600052601260045260246000fd5b6402540be40090818102918183041490151715610b175790565b90600860ff821611611d40575090565b611cf0611d4c91611cb0565b90818102918183041490151715610b175790565b60008091604051602081019063313ce56760e01b825260048152611d83816101f0565b51915afa50611d90610bb5565b60208180518101031261012b576020015161032381610120565b6000809160405160208101906370a0823160e01b825230602482015260248152611dd38161020b565b51915afa50610323611de3610bb5565b60208082518301019101610ad9565b5160405190602082015260208152610323816101f0565b9060405191611e17836101a2565b60008352826020825110611baa576020820151905251602003611e3657565b60405162461bcd60e51b81526020600482015260166024820152750d2dcecc2d8d2c840dacae6e6c2ceca40d8cadccee8d60531b6044820152606490fdfea26469706673582212206f9b8c381df396dfd8fbfa4026c1d0992a11cacccb116da3403158be96a8f98664736f6c63430008130033000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085d06449c78064c2e02d787e9dc71716786f8d19

Deployed Bytecode

0x6080604052600436101561001b575b361561001957600080fd5b005b60003560e01c806327105ab91461011b57806328ded8e3146101165780632d77e8fe146101115780633fc8cef31461010c57806350789cb51461010757806353c6f0dc14610102578063730a286b146100fd5780637c9dec7a146100f857806384acd1bb146100f35780639a8a0592146100ee5780639cf278cd146100e9578063c34c08e5146100e4578063c6328a46146100df578063d8b32910146100da578063e50e7e72146100d55763ffa1ad740361000e576108e6565b61085e565b610823565b6107de565b610799565b61075c565b61071d565b6106d8565b6106b7565b61060f565b61046b565b6103f9565b61035b565b610326565b610162565b610130565b60ff81160361012b57565b600080fd5b3461012b57604036600319011261012b57602061015a60243561015281610120565b600435611cd4565b604051908152f35b3461012b57604036600319011261012b57602061015a60243561018481610120565b600435611d30565b634e487b7160e01b600052604160045260246000fd5b602081019081106001600160401b038211176101bd57604052565b61018c565b6001600160401b0381116101bd57604052565b608081019081106001600160401b038211176101bd57604052565b604081019081106001600160401b038211176101bd57604052565b606081019081106001600160401b038211176101bd57604052565b90601f801991011681019081106001600160401b038211176101bd57604052565b6040519061016082018281106001600160401b038211176101bd57604052565b60405190610274826101a2565b565b6040519061010082018281106001600160401b038211176101bd57604052565b6001600160401b0381116101bd57601f01601f191660200190565b9291926102bd82610296565b916102cb6040519384610226565b82948184528183011161012b578281602093846000960137010152565b602060031982011261012b57600435906001600160401b03821161012b578060238301121561012b57816024610323936004013591016102b1565b90565b3461012b57602061033e610339366102e8565b611a5c565b6040516001600160a01b039091168152f35b600091031261012b57565b3461012b57600036600319011261012b576040517f000000000000000000000000acc15dc74880c9944775448304b263d191c6077f6001600160a01b03168152602090f35b60005b8381106103b35750506000910152565b81810151838201526020016103a3565b906020916103dc815180928185528580860191016103a0565b601f01601f1916010190565b9060206103239281815201906103c3565b3461012b57602036600319011261012b5761043a61042660405161041c816101a2565b6004358152611df2565b6040519182916020835260208301906103c3565b0390f35b9181601f8401121561012b578235916001600160401b03831161012b576020838186019501011161012b57565b602036600319011261012b576004356001600160401b03811161012b576104b86104ae6104a96104a26104be94369060040161043e565b36916102b1565b611825565b9391929092611e09565b51611c5a565b6001600160a01b03927f000000000000000000000000acc15dc74880c9944775448304b263d191c6077f84169084168082148061057b575b1561056f5750803b1561012b57604051632e1a7d4d60e01b815260048101849052600093909184908390602490829084905af190811561056a5761001995859485948594610551575b50165af161054b610bb5565b506114c7565b8061055e610564926101c2565b80610350565b3861053f565b610ae8565b90506100199350611513565b507f00000000000000000000000000000000000000000000000000000000000000016104f6565b6001600160a01b0381160361012b57565b60043590610274826105a2565b6101043590610274826105a2565b60c43590610274826105a2565b61ffff81160361012b57565b60443590610274826105db565b63ffffffff81160361012b57565b60843590610274826105f4565b61016036600319011261012b576106246105b3565b61062c6105e7565b610634610602565b9161063d6105c0565b6001600160401b0392906101243584811161012b5761066090369060040161043e565b916101443595861161012b5761043a9661068161069d97369060040161043e565b96909560e4359260c4359260a435926064359160243590610944565b6040516001600160401b0390911681529081906020820190565b3461012b5760206106cf6106ca366102e8565b611e09565b60405190518152f35b3461012b57600036600319011261012b576040517f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03168152602090f35b3461012b57600036600319011261012b57602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000010168152f35b3461012b57600036600319011261012b5760206040517f000000000000000000000000000000000000000000000000000000000000000115158152f35b3461012b57600036600319011261012b576040517f00000000000000000000000085d06449c78064c2e02d787e9dc71716786f8d196001600160a01b03168152602090f35b3461012b57600036600319011261012b576040517f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d926001600160a01b03168152602090f35b3461012b57600036600319011261012b5760206040517f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d928152f35b61012036600319011261012b57600435610877816105db565b604435610883816105f4565b61088b6105ce565b916001600160401b039160e43583811161012b576108ad90369060040161043e565b906101043594851161012b5761043a956108ce61069d96369060040161043e565b95909460a43591608435916064359160243590610c29565b3461012b57600036600319011261012b5761043a604051610906816101f0565b601881527f546f6b656e42726964676552656c617965722d302e342e30000000000000000060208201526040519182916020835260208301906103c3565b92909b9a9998979695949391600260005414610a94576002600055604051631a90a21960e01b8152936020856004817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03165afa94851561056a57600095610a64575b506109b98886610b0a565b34146109c490610b1c565b6109cd81611d60565b6109d9819f8290611cd4565b906109e391611d30565b6109ed9082611be7565b906109f6610247565b6001600160a01b0390911681529d8e9060ff1660208201526040015261ffff1660608d015260808c015263ffffffff1660a08b015260c08a015260e08901526101008801526101208701526001600160a01b0316610140860152610a5994610f85565b906102746001600055565b610a8691955060203d8111610a8d575b610a7e8183610226565b810190610ad9565b93386109ae565b503d610a74565b60405162461bcd60e51b815260206004820152601f60248201527f5265656e7472616e637947756172643a207265656e7472616e742063616c6c006044820152606490fd5b9081602091031261012b575190565b6040513d6000823e3d90fd5b634e487b7160e01b600052601160045260246000fd5b91908201809211610b1757565b610af4565b15610b2357565b60405162461bcd60e51b8152602060048201526012602482015271696e73756666696369656e742076616c756560701b6044820152606490fd5b15610b6457565b606460405162461bcd60e51b815260206004820152602060248201527f574554482066756e6374696f6e616c697479206e6f7420737570706f727465646044820152fd5b91908203918211610b1757565b3d15610be0573d90610bc682610296565b91610bd46040519384610226565b82523d6000602084013e565b606090565b15610bec57565b60405162461bcd60e51b815260206004820152601560248201527411985a5b1959081d1bc81c99599d5b9908191d5cdd605a1b6044820152606490fd5b90999897969594939291610c5c7f0000000000000000000000000000000000000000000000000000000000000001610b5d565b604051631a90a21960e01b81526001600160a01b039b909283807f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f38f165a92600491602094fa93841561056a57600094610de1575b50610cf7610cd3610cc28987610b0a565b610ccd813411610b1c565b34610ba8565b610cec610ce66402540be4008304611d16565b82610ba8565b9081610dc257610ba8565b9c7f000000000000000000000000acc15dc74880c9944775448304b263d191c6077f169c8d3b1561012b578060008f600460405180948193630d0e30db60e41b83525af1801561056a57610daf575b50610d4f610247565b6001600160a01b03909e168e52601260208f01528d6040015261ffff1660608d015260808c015263ffffffff1660a08b015260c08a015260e08901526101008801526101208701526001600160a01b031661014086015261032394610f85565b8061055e610dbc926101c2565b38610d46565b610ddc600080808086335af1610dd6610bb5565b50610be5565b610ba8565b610dfa91945060203d8111610a8d57610a7e8183610226565b9238610cb1565b15610e0857565b60405162461bcd60e51b8152602060048201526024808201527f746172676574526563697069656e742063616e6e6f74206265206279746573336044820152633228302960e01b6064820152608490fd5b15610e6057565b60405162461bcd60e51b815260206004820152601d60248201527f6e6f726d616c697a656420616d6f756e74206d757374206265203e20300000006044820152606490fd5b51906001600160401b038216820361012b57565b9081602091031261012b5761032390610ea5565b929361ffff60c09563ffffffff9461032399989460018060a01b03168752602087015216604085015260608401521660808201528160a082015201906103c3565b908060209392818452848401376000828201840152601f01601f1916010190565b9694610323989693610f699361ffff610f779794168a5260208a015260018060a01b0316604089015260c0606089015260c0880191610f0e565b9085820360808701526103c3565b9260a0818503910152610f0e565b94939092916080860195610f9b87511515610e01565b610fd76040820197610fc6610fbf8a51610fb9602087015160ff1690565b90611cd4565b1515610e59565b51610fcf610267565b908152611df2565b81519093906001600160a01b031688516001600160a01b03997f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d928b169392602092611023918690611266565b60c085015185519094906001600160a01b031691516060870195611049875161ffff1690565b9361108160e08a01519b61106460a08c015163ffffffff1690565b6040516362d2f5ed60e11b81529d8e988997889660048801610ecd565b03925af194851561056a5760009561117c575b5084987f00000000000000000000000085d06449c78064c2e02d787e9dc71716786f8d1916936110cc610120850151935161ffff1690565b916111326110ea61014061010088015197015160018060a01b031690565b977f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d927f00000000000000000000000000000000000000000000000000000000000000106111ac565b97863b1561012b5760009861115e936040519b8c9a8b998a9863c513d43760e01b8a5260048a01610f2f565b03925af1801561056a5761116f5750565b8061055e610274926101c2565b61119e91955060203d81116111a5575b6111968183610226565b810190610eb9565b9338611094565b503d61118c565b604051634552563160e01b602082015260f09190911b6001600160f01b0319166024820152602681019190915260c09190911b6001600160c01b0319166046820152602e81526103238161020b565b1561120257565b60405162461bcd60e51b815260206004820152603660248201527f5361666545524332303a20617070726f76652066726f6d206e6f6e2d7a65726f60448201527520746f206e6f6e2d7a65726f20616c6c6f77616e636560501b6064820152608490fd5b919091811580156112c3575b610274936112826112be926111fb565b60405163095ea7b360e01b60208201526001600160a01b039091166024820152604481019390935282606481015b03601f198101845283610226565b611341565b50604051636eb1769f60e11b81523060048201526001600160a01b038416602482015292602084806044810103816001600160a01b0386165afa90811561056a576112826112be9261027496600091611323575b50159250509350611272565b61133b915060203d8111610a8d57610a7e8183610226565b38611317565b60018060a01b0316906113a0604051611359816101f0565b6020938482527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564858301526000808587829751910182855af161139a610bb5565b91611432565b8051806113ae575b50505050565b8184918101031261142e578201519081159182150361142b57506113d4578080806113a8565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b80fd5b5080fd5b919290156114945750815115611446575090565b3b1561144f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156114a75750805190602001fd5b60405162461bcd60e51b81529081906114c390600483016103e8565b0390fd5b156114ce57565b60405162461bcd60e51b815260206004820152601f60248201527f4661696c656420746f207472616e7366657220746f20726563697069656e74006044820152606490fd5b60405163a9059cbb60e01b60208201526001600160a01b0390921660248301526044820192909252610274916112be82606481016112b0565b519061027482610120565b5190610274826105f4565b5190610274826105db565b81601f8201121561012b57805161158381610296565b926115916040519485610226565b8184526020828401011161012b5761032391602080850191016103a0565b9080601f8301121561012b578151916001600160401b0383116101bd576040918251936020916115e4838360051b0187610226565b818652828087019260071b8501019381851161012b578301915b84831061160e5750505050505090565b60808383031261012b57836080918751611627816101d5565b8551815282860151838201528886015161164081610120565b898201526060808701519061165482610120565b8201528152019201916115fe565b9060208282031261012b5781516001600160401b039283821161012b5701906101608282031261012b57611694610247565b9261169e8361154c565b84526116ac60208401611557565b60208501526116bd60408401611557565b60408501526116ce60608401611562565b6060850152608083015160808501526116e960a08401610ea5565b60a08501526116fa60c0840161154c565b60c085015260e083015181811161012b578261171791850161156d565b60e085015261010061172a818501611557565b90850152610120918284015191821161012b576117489184016115af565b90830152610140809101519082015290565b9060208282031261012b5781516001600160401b03811161012b57610323920161156d565b9060208282031261012b5781516001600160401b039283821161012b5701906101008282031261012b576117b1610276565b926117bb8361154c565b845260208301516020850152604083015160408501526117dd60608401611562565b6060850152608083015160808501526117f860a08401611562565b60a085015260c083015160c085015260e083015190811161012b5761181d920161156d565b60e082015290565b60405163a9e1189360e01b815290916000918061184585600483016103e8565b6001600160a01b039291859183919003817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f386165afa90811561056a5784916119e4575b5061189760e0820151611a5c565b936118e3816118a587611daa565b947f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d9216976040518093819263c3f511c160e01b8352600483016103e8565b0381838b5af1801561056a5761192694839283926119bc575b5061190a90610ddc89611daa565b97604051808097819463ea63738d60e01b8352600483016103e8565b03915afa91821561056a5760e0938293611998575b50606081015161ffff16917fcaf280c8cfeba144da67230d9b009c8f868a75bac9a528fa0474be1ba317c16961ffff6001600160401b0361198b60a060808701519601516001600160401b031690565b1694169180a40151929190565b6119b59193503d8084833e6119ad8183610226565b81019061177f565b913861193b565b61190a9192506119dd903d8086833e6119d58183610226565b81019061175a565b91906118fc565b611a0091503d8086833e6119f88183610226565b810190611662565b38611889565b9081602091031261012b5751610323816105a2565b15611a2257565b60405162461bcd60e51b81526020600482015260126024820152711d1bdad95b881b9bdd08185d1d195cdd195960721b6044820152606490fd5b90611a6f611a6983611b9a565b92611b4e565b61ffff8181167f000000000000000000000000000000000000000000000000000000000000001090911614611b4357604051630ff8f14360e11b815261ffff91909116600482015260248101929092526001600160a01b036020836044817f000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d9285165afa92831561056a57600093611b0f575b506102749083161515611a1b565b610274919350611b359060203d8111611b3c575b611b2d8183610226565b810190611a06565b9290611b01565b503d611b23565b509061032390611c5a565b6043815110611b5e576043015190565b60405162461bcd60e51b8152602060048201526014602482015273746f55696e7431365f6f75744f66426f756e647360601b6044820152606490fd5b6041815110611baa576041015190565b60405162461bcd60e51b8152602060048201526015602482015274746f427974657333325f6f75744f66426f756e647360581b6044820152606490fd5b90611bf182611daa565b91604051916323b872dd60e01b602084015233602484015230604484015260648301526064825260a082018281106001600160401b038211176101bd57604052611c4d91611c48906001600160a01b038316611341565b611daa565b908103908111610b175790565b6001600160a01b03198116611c75576001600160a01b031690565b60405162461bcd60e51b8152602060048201526013602482015272696e76616c69642045564d206164647265737360681b6044820152606490fd5b60ff6007199116019060ff8211610b1757565b60ff16604d8111610b1757600a0a90565b90600860ff821611611ce4575090565b611cf0611cf591611cb0565b611cc3565b908115611d00570490565b634e487b7160e01b600052601260045260246000fd5b6402540be40090818102918183041490151715610b175790565b90600860ff821611611d40575090565b611cf0611d4c91611cb0565b90818102918183041490151715610b175790565b60008091604051602081019063313ce56760e01b825260048152611d83816101f0565b51915afa50611d90610bb5565b60208180518101031261012b576020015161032381610120565b6000809160405160208101906370a0823160e01b825230602482015260248152611dd38161020b565b51915afa50610323611de3610bb5565b60208082518301019101610ad9565b5160405190602082015260208152610323816101f0565b9060405191611e17836101a2565b60008352826020825110611baa576020820151905251602003611e3657565b60405162461bcd60e51b81526020600482015260166024820152750d2dcecc2d8d2c840dacae6e6c2ceca40d8cadccee8d60531b6044820152606490fdfea26469706673582212206f9b8c381df396dfd8fbfa4026c1d0992a11cacccb116da3403158be96a8f98664736f6c63430008130033

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

000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92000000000000000000000000000000000000000000000000000000000000000100000000000000000000000085d06449c78064c2e02d787e9dc71716786f8d19

-----Decoded View---------------
Arg [0] : tokenBridge_ (address): 0xB1731c586ca89a23809861c6103F0b96B3F57D92
Arg [1] : unwrapWeth_ (bool): True
Arg [2] : executor_ (address): 0x85D06449C78064c2E02d787e9DC71716786F8D19

-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000b1731c586ca89a23809861c6103f0b96b3f57d92
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [2] : 00000000000000000000000085d06449c78064c2e02d787e9dc71716786f8d19


Block Transaction Gas Used Reward
view all blocks collator

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.