GLMR Price: $0.092227 (-4.35%)

Contract

0x1a8dD0FA61990Db5aef353DC122bc17Ac4F10358

Overview

GLMR Balance

Moonbeam Chain LogoMoonbeam Chain LogoMoonbeam Chain Logo0 GLMR

GLMR Value

$0.00

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To

There are no matching entries

> 10 Internal Transactions found.

Latest 25 internal transactions (View All)

Parent Transaction Hash Block From To
101821932025-03-26 10:12:541 hr ago1742983974
0x1a8dD0FA...Ac4F10358
0.03664969 GLMR
101821892025-03-26 10:12:301 hr ago1742983950
0x1a8dD0FA...Ac4F10358
0.03664969 GLMR
101821862025-03-26 10:12:121 hr ago1742983932
0x1a8dD0FA...Ac4F10358
0.01606854 GLMR
101821862025-03-26 10:12:121 hr ago1742983932
0x1a8dD0FA...Ac4F10358
0.02857431 GLMR
101821862025-03-26 10:12:121 hr ago1742983932
0x1a8dD0FA...Ac4F10358
0.02857431 GLMR
101821862025-03-26 10:12:121 hr ago1742983932
0x1a8dD0FA...Ac4F10358
0.08711954 GLMR
101821862025-03-26 10:12:121 hr ago1742983932
0x1a8dD0FA...Ac4F10358
0.08711954 GLMR
101821802025-03-26 10:11:361 hr ago1742983896
0x1a8dD0FA...Ac4F10358
0.01606854 GLMR
101821802025-03-26 10:11:361 hr ago1742983896
0x1a8dD0FA...Ac4F10358
0.02857431 GLMR
101821802025-03-26 10:11:361 hr ago1742983896
0x1a8dD0FA...Ac4F10358
0.02857431 GLMR
101821802025-03-26 10:11:361 hr ago1742983896
0x1a8dD0FA...Ac4F10358
0.08711954 GLMR
101821802025-03-26 10:11:361 hr ago1742983896
0x1a8dD0FA...Ac4F10358
0.08711954 GLMR
101741012025-03-25 20:34:3615 hrs ago1742934876
0x1a8dD0FA...Ac4F10358
0.00892857 GLMR
101739722025-03-25 20:21:3015 hrs ago1742934090
0x1a8dD0FA...Ac4F10358
10.38796396 GLMR
101738142025-03-25 20:05:3015 hrs ago1742933130
0x1a8dD0FA...Ac4F10358
0.00892857 GLMR
101730612025-03-25 18:48:3017 hrs ago1742928510
0x1a8dD0FA...Ac4F10358
0.00892857 GLMR
101705272025-03-25 14:31:1221 hrs ago1742913072
0x1a8dD0FA...Ac4F10358
10.38796396 GLMR
101704952025-03-25 14:28:0021 hrs ago1742912880
0x1a8dD0FA...Ac4F10358
0.00184357 GLMR
101704952025-03-25 14:28:0021 hrs ago1742912880
0x1a8dD0FA...Ac4F10358
0.00172785 GLMR
101677712025-03-25 9:48:0026 hrs ago1742896080
0x1a8dD0FA...Ac4F10358
10.38796396 GLMR
101675872025-03-25 9:28:4226 hrs ago1742894922
0x1a8dD0FA...Ac4F10358
0.02905085 GLMR
101675762025-03-25 9:27:3626 hrs ago1742894856
0x1a8dD0FA...Ac4F10358
0.01239958 GLMR
101675762025-03-25 9:27:3626 hrs ago1742894856
0x1a8dD0FA...Ac4F10358
0.03224327 GLMR
101675762025-03-25 9:27:3626 hrs ago1742894856
0x1a8dD0FA...Ac4F10358
0.03224327 GLMR
101675762025-03-25 9:27:3626 hrs ago1742894856
0x1a8dD0FA...Ac4F10358
0.06912394 GLMR
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
WormholeRelayer

Compiler Version
v0.8.19+commit.7dd6d404

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 20 : WormholeRelayer.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import {IWormholeRelayer} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";

import {getDefaultDeliveryProviderState} from "./WormholeRelayerStorage.sol";
import {WormholeRelayerGovernance} from "./WormholeRelayerGovernance.sol";
import {WormholeRelayerSend} from "./WormholeRelayerSend.sol";
import {WormholeRelayerDelivery} from "./WormholeRelayerDelivery.sol";
import {WormholeRelayerBase} from "./WormholeRelayerBase.sol";

//WormholeRelayerGovernance inherits from ERC1967Upgrade, i.e. this is a proxy contract!
contract WormholeRelayer is
    WormholeRelayerGovernance,
    WormholeRelayerSend,
    WormholeRelayerDelivery,
    IWormholeRelayer
{
    //the only normal storage variable - everything else uses slot pattern
    //no point doing it for this one since it is entirely one-off and of no interest to the rest
    //  of the contract and it also can't accidentally be moved because we are at the bottom of
    //  the inheritance hierarchy here
    bool private initialized;

    constructor(address wormhole) WormholeRelayerBase(wormhole) {}

    //needs to be called upon construction of the EC1967 proxy
    function initialize(address defaultDeliveryProvider) public {
        assert(!initialized);
        initialized = true;
        getDefaultDeliveryProviderState().defaultDeliveryProvider = defaultDeliveryProvider;
    }
}

File 2 of 20 : IWormholeRelayerTyped.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import "./TypedUnits.sol";

/**
 * @title WormholeRelayer
 * @author 
 * @notice This project allows developers to build cross-chain applications powered by Wormhole without needing to 
 * write and run their own relaying infrastructure
 * 
 * We implement the IWormholeRelayer interface that allows users to request a delivery provider to relay a payload (and/or additional messages) 
 * to a chain and address of their choice.
 */

/**
 * @notice VaaKey identifies a wormhole message
 *
 * @custom:member chainId Wormhole chain ID of the chain where this VAA was emitted from
 * @custom:member emitterAddress Address of the emitter of the VAA, in Wormhole bytes32 format
 * @custom:member sequence Sequence number of the VAA
 */
struct VaaKey {
    uint16 chainId;
    bytes32 emitterAddress;
    uint64 sequence;
}

// 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
uint8 constant VAA_KEY_TYPE = 1;

struct MessageKey {
    uint8 keyType; // 0-127 are reserved for standardized KeyTypes, 128-255 are for custom use
    bytes encodedKey;
}


interface IWormholeRelayerBase {
    event SendEvent(
        uint64 indexed sequence, LocalNative deliveryQuote, LocalNative paymentForExtraReceiverValue
    );

    function getRegisteredWormholeRelayerContract(uint16 chainId) external view returns (bytes32);

    /**
     * @notice Returns true if a delivery has been attempted for the given deliveryHash
     * Note: invalid deliveries where the tx reverts are not considered attempted
     */
    function deliveryAttempted(bytes32 deliveryHash) external view returns (bool attempted);

    /**
     * @notice block number at which a delivery was successfully executed
     */
    function deliverySuccessBlock(bytes32 deliveryHash) external view returns (uint256 blockNumber);

    /**
     * @notice block number of the latest attempt to execute a delivery that failed
     */
    function deliveryFailureBlock(bytes32 deliveryHash) external view returns (uint256 blockNumber);
}

/**
 * @title IWormholeRelayerSend
 * @notice The interface to request deliveries
 */
interface IWormholeRelayerSend is IWormholeRelayerBase {

    /**
     * @notice Publishes an instruction for the default delivery provider
     * to relay a payload to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
     * 
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
     * 
     * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendPayloadToEvm` function 
     * with `refundChain` and `refundAddress` as parameters
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`.
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the default delivery provider
     * to relay a payload to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the
     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the default delivery provider
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
     * 
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
     * 
     * Any refunds (from leftover gas) will be paid to the delivery provider. In order to receive the refunds, use the `sendVaasToEvm` function 
     * with `refundChain` and `refundAddress` as parameters
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`. 
     * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        VaaKey[] memory vaaKeys
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the default delivery provider
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to `receiverValue`
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to `quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit)`
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the 
     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
     * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        VaaKey[] memory vaaKeys,
        uint16 refundChain,
        address refundAddress
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` 
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to 
     * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to 
     * quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue 
     *        (in addition to the `receiverValue` specified)
     * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the  
     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
     * @param consistencyLevel Consistency level with which to publish the delivery instructions - see 
     *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` 
     * to relay a payload and external messages specified by `messageKeys` to the address `targetAddress` on chain `targetChain` 
     * with gas limit `gasLimit` and `msg.value` equal to 
     * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to 
     * quoteEVMDeliveryPrice(targetChain, receiverValue, gasLimit, deliveryProviderAddress) + paymentForExtraReceiverValue
     *
     * Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected 
     * DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver) 
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue 
     *        (in addition to the `receiverValue` specified)
     * @param gasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the  
     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
     * @param consistencyLevel Consistency level with which to publish the delivery instructions - see 
     *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function sendToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress,
        address deliveryProviderAddress,
        MessageKey[] memory messageKeys,
        uint8 consistencyLevel
    ) external payable returns (uint64 sequence);
    
    /**
     * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` 
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` 
     * with `msg.value` equal to 
     * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to 
     * quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue  
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue 
     *        (in addition to the `receiverValue` specified)
     * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
     *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
     * @param consistencyLevel Consistency level with which to publish the delivery instructions - see 
     *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function send(
        uint16 targetChain,
        bytes32 targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        bytes memory encodedExecutionParameters,
        uint16 refundChain,
        bytes32 refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) external payable returns (uint64 sequence);

    /**
     * @notice Publishes an instruction for the delivery provider at `deliveryProviderAddress` 
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain` 
     * with `msg.value` equal to 
     * receiverValue + (arbitrary amount that is paid for by paymentForExtraReceiverValue of this chain's wei) in targetChain wei.
     * 
     * Any refunds (from leftover gas) will be sent to `refundAddress` on chain `refundChain`
     * `targetAddress` must implement the IWormholeReceiver interface
     * 
     * This function must be called with `msg.value` equal to 
     * quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress) + paymentForExtraReceiverValue  
     *
     * Note: MessageKeys can specify wormhole messages (VaaKeys) or other types of messages (ex. USDC CCTP attestations). Ensure the selected 
     * DeliveryProvider supports all the MessageKey.keyType values specified or it will not be delivered!
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param targetAddress address to call on targetChain (that implements IWormholeReceiver), in Wormhole bytes32 format
     * @param payload arbitrary bytes to pass in as parameter in call to `targetAddress`
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param paymentForExtraReceiverValue amount (in current chain currency units) to spend on extra receiverValue 
     *        (in addition to the `receiverValue` specified)
     * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
     *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
     * @param refundChain The chain to deliver any refund to, in Wormhole Chain ID format
     * @param refundAddress The address on `refundChain` to deliver any refund to, in Wormhole bytes32 format
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @param messageKeys Additional messagess to pass in as parameter in call to `targetAddress`
     * @param consistencyLevel Consistency level with which to publish the delivery instructions - see 
     *        https://book.wormhole.com/wormhole/3_coreLayerContracts.html?highlight=consistency#consistency-levels
     * @return sequence sequence number of published VAA containing delivery instructions
     */
    function send(
        uint16 targetChain,
        bytes32 targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        bytes memory encodedExecutionParameters,
        uint16 refundChain,
        bytes32 refundAddress,
        address deliveryProviderAddress,
        MessageKey[] memory messageKeys,
        uint8 consistencyLevel
    ) external payable returns (uint64 sequence);

    /**
     * @notice Requests a previously published delivery instruction to be redelivered 
     * (e.g. with a different delivery provider)
     *
     * This function must be called with `msg.value` equal to 
     * quoteEVMDeliveryPrice(targetChain, newReceiverValue, newGasLimit, newDeliveryProviderAddress)
     * 
     *  @notice *** This will only be able to succeed if the following is true **
     *         - newGasLimit >= gas limit of the old instruction
     *         - newReceiverValue >= receiver value of the old instruction
     *         - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
     * 
     * @param deliveryVaaKey VaaKey identifying the wormhole message containing the 
     *        previously published delivery instructions
     * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
     * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param newGasLimit gas limit with which to call `targetAddress`. Any units of gas unused will be refunded according to the  
     *        `targetChainRefundPerGasUnused` rate quoted by the delivery provider, to the refund chain and address specified in the original request
     * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @return sequence sequence number of published VAA containing redelivery instructions
     *
     * @notice *** This will only be able to succeed if the following is true **
     *         - newGasLimit >= gas limit of the old instruction
     *         - newReceiverValue >= receiver value of the old instruction
     */
    function resendToEvm(
        VaaKey memory deliveryVaaKey,
        uint16 targetChain,
        TargetNative newReceiverValue,
        Gas newGasLimit,
        address newDeliveryProviderAddress
    ) external payable returns (uint64 sequence);

    /**
     * @notice Requests a previously published delivery instruction to be redelivered 
     * 
     *
     * This function must be called with `msg.value` equal to 
     * quoteDeliveryPrice(targetChain, newReceiverValue, newEncodedExecutionParameters, newDeliveryProviderAddress)
     * 
     * @param deliveryVaaKey VaaKey identifying the wormhole message containing the 
     *        previously published delivery instructions
     * @param targetChain The target chain that the original delivery targeted. Must match targetChain from original delivery instructions
     * @param newReceiverValue new msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param newEncodedExecutionParameters new encoded information on how to execute delivery that may impact pricing
     *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
     * @param newDeliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @return sequence sequence number of published VAA containing redelivery instructions
     * 
     *  @notice *** This will only be able to succeed if the following is true **
     *         - (For EVM_V1) newGasLimit >= gas limit of the old instruction
     *         - newReceiverValue >= receiver value of the old instruction
     *         - (For EVM_V1) newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
     */
    function resend(
        VaaKey memory deliveryVaaKey,
        uint16 targetChain,
        TargetNative newReceiverValue,
        bytes memory newEncodedExecutionParameters,
        address newDeliveryProviderAddress
    ) external payable returns (uint64 sequence);

    /**
     * @notice Returns the price to request a relay to chain `targetChain`, using the default delivery provider
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`. 
     * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
     * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused, 
     *         if a refundAddress is specified. 
     *         Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a 
     *         promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain. 
     *         If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain. 
     */
    function quoteEVMDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        Gas gasLimit
    ) external view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused);

    /**
     * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param gasLimit gas limit with which to call `targetAddress`. 
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
     * @return targetChainRefundPerGasUnused amount of target chain currency that will be refunded per unit of gas unused, 
     *         if a refundAddress is specified
     *         Note: This value can be overridden by the delivery provider on the target chain. The returned value here should be considered to be a 
     *         promise by the delivery provider of the amount of refund per gas unused that will be returned to the refundAddress at the target chain. 
     *         If a delivery provider decides to override, this will be visible as part of the emitted Delivery event on the target chain.
     */
    function quoteEVMDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        Gas gasLimit,
        address deliveryProviderAddress
    ) external view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused);

    /**
     * @notice Returns the price to request a relay to chain `targetChain`, using delivery provider `deliveryProviderAddress`
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param receiverValue msg.value that delivery provider should pass in for call to `targetAddress` (in targetChain currency units)
     * @param encodedExecutionParameters encoded information on how to execute delivery that may impact pricing
     *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` with which to call `targetAddress`
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @return nativePriceQuote Price, in units of current chain currency, that the delivery provider charges to perform the relay
     * @return encodedExecutionInfo encoded information on how the delivery will be executed
     *        e.g. for version EVM_V1, this is a struct that encodes the `gasLimit` and `targetChainRefundPerGasUnused`
     *             (which is the amount of target chain currency that will be refunded per unit of gas unused, 
     *              if a refundAddress is specified)
     */
    function quoteDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        bytes memory encodedExecutionParameters,
        address deliveryProviderAddress
    ) external view returns (LocalNative nativePriceQuote, bytes memory encodedExecutionInfo);

    /**
     * @notice Returns the (extra) amount of target chain currency that `targetAddress`
     * will be called with, if the `paymentForExtraReceiverValue` field is set to `currentChainAmount`
     * 
     * @param targetChain in Wormhole Chain ID format
     * @param currentChainAmount The value that `paymentForExtraReceiverValue` will be set to
     * @param deliveryProviderAddress The address of the desired delivery provider's implementation of IDeliveryProvider
     * @return targetChainAmount The amount such that if `targetAddress` will be called with `msg.value` equal to
     *         receiverValue + targetChainAmount
     */
    function quoteNativeForChain(
        uint16 targetChain,
        LocalNative currentChainAmount,
        address deliveryProviderAddress
    ) external view returns (TargetNative targetChainAmount);

    /**
     * @notice Returns the address of the current default delivery provider
     * @return deliveryProvider The address of (the default delivery provider)'s contract on this source
     *   chain. This must be a contract that implements IDeliveryProvider.
     */
    function getDefaultDeliveryProvider() external view returns (address deliveryProvider);
}

/**
 * @title IWormholeRelayerDelivery
 * @notice The interface to execute deliveries. Only relevant for Delivery Providers 
 */
interface IWormholeRelayerDelivery is IWormholeRelayerBase {
    enum DeliveryStatus {
        SUCCESS,
        RECEIVER_FAILURE
    }

    enum RefundStatus {
        REFUND_SENT,
        REFUND_FAIL,
        CROSS_CHAIN_REFUND_SENT,
        CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED,
        CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH,
        NO_REFUND_REQUESTED
    }

    /**
     * @custom:member recipientContract - The target contract address
     * @custom:member sourceChain - The chain which this delivery was requested from (in wormhole
     *     ChainID format)
     * @custom:member sequence - The wormhole sequence number of the delivery VAA on the source chain
     *     corresponding to this delivery request
     * @custom:member deliveryVaaHash - The hash of the delivery VAA corresponding to this delivery
     *     request
     * @custom:member gasUsed - The amount of gas that was used to call your target contract 
     * @custom:member status:
     *   - RECEIVER_FAILURE, if the target contract reverts
     *   - SUCCESS, if the target contract doesn't revert
     * @custom:member additionalStatusInfo:
     *   - If status is SUCCESS, then this is empty.
     *   - If status is RECEIVER_FAILURE, this is `RETURNDATA_TRUNCATION_THRESHOLD` bytes of the
     *       return data (i.e. potentially truncated revert reason information).
     * @custom:member refundStatus - Result of the refund. REFUND_SUCCESS or REFUND_FAIL are for
     *     refunds where targetChain=refundChain; the others are for targetChain!=refundChain,
     *     where a cross chain refund is necessary, or if the default code path is used where no refund is requested (NO_REFUND_REQUESTED)
     * @custom:member overridesInfo:
     *   - If not an override: empty bytes array
     *   - Otherwise: An encoded `DeliveryOverride`
     */
    event Delivery(
        address indexed recipientContract,
        uint16 indexed sourceChain,
        uint64 indexed sequence,
        bytes32 deliveryVaaHash,
        DeliveryStatus status,
        Gas gasUsed,
        RefundStatus refundStatus,
        bytes additionalStatusInfo,
        bytes overridesInfo
    );

    /**
     * @notice The delivery provider calls `deliver` to relay messages as described by one delivery instruction
     * 
     * The delivery provider must pass in the specified (by VaaKeys[]) signed wormhole messages (VAAs) from the source chain
     * as well as the signed wormhole message with the delivery instructions (the delivery VAA)
     *
     * The messages will be relayed to the target address (with the specified gas limit and receiver value) iff the following checks are met:
     * - the delivery VAA has a valid signature
     * - the delivery VAA's emitter is one of these WormholeRelayer contracts
     * - the delivery provider passed in at least enough of this chain's currency as msg.value (enough meaning the maximum possible refund)     
     * - the instruction's target chain is this chain
     * - the relayed signed VAAs match the descriptions in container.messages (the VAA hashes match, or the emitter address, sequence number pair matches, depending on the description given)
     *
     * @param encodedVMs - An array of signed wormhole messages (all from the same source chain
     *     transaction)
     * @param encodedDeliveryVAA - Signed wormhole message from the source chain's WormholeRelayer
     *     contract with payload being the encoded delivery instruction container
     * @param relayerRefundAddress - The address to which any refunds to the delivery provider
     *     should be sent
     * @param deliveryOverrides - Optional overrides field which must be either an empty bytes array or
     *     an encoded DeliveryOverride struct
     */
    function deliver(
        bytes[] memory encodedVMs,
        bytes memory encodedDeliveryVAA,
        address payable relayerRefundAddress,
        bytes memory deliveryOverrides
    ) external payable;
}

interface IWormholeRelayer is IWormholeRelayerDelivery, IWormholeRelayerSend {}

/*
 *  Errors thrown by IWormholeRelayer contract
 */

// Bound chosen by the following formula: `memoryWord * 4 + selectorSize`.
// This means that an error identifier plus four fixed size arguments should be available to developers.
// In the case of a `require` revert with error message, this should provide 2 memory word's worth of data.
uint256 constant RETURNDATA_TRUNCATION_THRESHOLD = 132;

//When msg.value was not equal to `delivery provider's quoted delivery price` + `paymentForExtraReceiverValue`
error InvalidMsgValue(LocalNative msgValue, LocalNative totalFee);

error RequestedGasLimitTooLow();

error DeliveryProviderDoesNotSupportTargetChain(address relayer, uint16 chainId);
error DeliveryProviderCannotReceivePayment();
error DeliveryProviderDoesNotSupportMessageKeyType(uint8 keyType);

//When calling `delivery()` a second time even though a delivery is already in progress
error ReentrantDelivery(address msgSender, address lockedBy);

error InvalidPayloadId(uint8 parsed, uint8 expected);
error InvalidPayloadLength(uint256 received, uint256 expected);
error InvalidVaaKeyType(uint8 parsed);
error TooManyMessageKeys(uint256 numMessageKeys);

error InvalidDeliveryVaa(string reason);
//When the delivery VAA (signed wormhole message with delivery instructions) was not emitted by the
//  registered WormholeRelayer contract
error InvalidEmitter(bytes32 emitter, bytes32 registered, uint16 chainId);
error MessageKeysLengthDoesNotMatchMessagesLength(uint256 keys, uint256 vaas);
error VaaKeysDoNotMatchVaas(uint8 index);
//When someone tries to call an external function of the WormholeRelayer that is only intended to be
//  called by the WormholeRelayer itself (to allow retroactive reverts for atomicity)
error RequesterNotWormholeRelayer();

//When trying to relay a `DeliveryInstruction` to any other chain but the one it was specified for
error TargetChainIsNotThisChain(uint16 targetChain);
//When a `DeliveryOverride` contains a gas limit that's less than the original
error InvalidOverrideGasLimit();
//When a `DeliveryOverride` contains a receiver value that's less than the original
error InvalidOverrideReceiverValue();
//When a `DeliveryOverride` contains a 'refund per unit of gas unused' that's less than the original
error InvalidOverrideRefundPerGasUnused();

//When the delivery provider doesn't pass in sufficient funds (i.e. msg.value does not cover the
// maximum possible refund to the user)
error InsufficientRelayerFunds(LocalNative msgValue, LocalNative minimum);

//When a bytes32 field can't be converted into a 20 byte EVM address, because the 12 padding bytes
//  are non-zero (duplicated from Utils.sol)
error NotAnEvmAddress(bytes32);

File 3 of 20 : WormholeRelayerStorage.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import "../../interfaces/relayer/TypedUnits.sol";

// -------------------------------------- Persistent Storage ---------------------------------------

//We have to hardcode the keccak256 values by hand rather than having them calculated because:
//  solc: TypeError: Only direct number constants and references to such constants are supported by
//          inline assembly.
//And presumably what they mean by "direct number constants" is number literals...

struct GovernanceState {
    // mapping of IWormhole.VM.hash of previously executed governance VMs
    mapping(bytes32 => bool) consumedGovernanceActions;
}

//keccak256("GovernanceState") - 1
bytes32 constant GOVERNANCE_STORAGE_SLOT =
    0x970ad24d4754c92e299cabb86552091f5df0a15abc0f1b71f37d3e30031585dc;

function getGovernanceState() pure returns (GovernanceState storage state) {
    assembly ("memory-safe") {
        state.slot := GOVERNANCE_STORAGE_SLOT
    }
}

struct DefaultDeliveryProviderState {
    // address of the default relay provider on this chain
    address defaultDeliveryProvider;
}

//keccak256("DefaultRelayProviderState") - 1
bytes32 constant DEFAULT_RELAY_PROVIDER_STORAGE_SLOT =
    0xebc28a1927f62765bfb7ada566eeab2d31a98c65dbd1e8cad64acae2a3ae45d4;

function getDefaultDeliveryProviderState()
    pure
    returns (DefaultDeliveryProviderState storage state)
{
    assembly ("memory-safe") {
        state.slot := DEFAULT_RELAY_PROVIDER_STORAGE_SLOT
    }
}

struct RegisteredWormholeRelayersState {
    // chainId => wormhole address mapping of relayer contracts on other chains
    mapping(uint16 => bytes32) registeredWormholeRelayers;
}

//keccak256("RegisteredCoreRelayersState") - 1
bytes32 constant REGISTERED_CORE_RELAYERS_STORAGE_SLOT =
    0x9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d;

function getRegisteredWormholeRelayersState()
    pure
    returns (RegisteredWormholeRelayersState storage state)
{
    assembly ("memory-safe") {
        state.slot := REGISTERED_CORE_RELAYERS_STORAGE_SLOT
    }
}

// Replay Protection and Indexing

struct DeliverySuccessState {
    mapping(bytes32 => uint256) deliverySuccessBlock;
}

struct DeliveryFailureState {
    mapping(bytes32 => uint256) deliveryFailureBlock;
}

//keccak256("DeliverySuccessState") - 1
bytes32 constant DELIVERY_SUCCESS_STATE_STORAGE_SLOT =
    0x1b988580e74603c035f5a7f71f2ae4647578af97cd0657db620836b9955fd8f5;

//keccak256("DeliveryFailureState") - 1
bytes32 constant DELIVERY_FAILURE_STATE_STORAGE_SLOT =
    0x6c615753402911c4de18a758def0565f37c41834d6eff72b16cb37cfb697f2a5;

function getDeliverySuccessState() pure returns (DeliverySuccessState storage state) {
    assembly ("memory-safe") {
        state.slot := DELIVERY_SUCCESS_STATE_STORAGE_SLOT
    }
}

function getDeliveryFailureState() pure returns (DeliveryFailureState storage state) {
    assembly ("memory-safe") {
        state.slot := DELIVERY_FAILURE_STATE_STORAGE_SLOT
    }
}

struct ReentrancyGuardState {
    // if 0 address, no reentrancy guard is active
    // otherwise, the address of the contract that has locked the reentrancy guard (msg.sender)
    address lockedBy;
}

//keccak256("ReentrancyGuardState") - 1
bytes32 constant REENTRANCY_GUARD_STORAGE_SLOT =
    0x44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a67;

function getReentrancyGuardState() pure returns (ReentrancyGuardState storage state) {
    assembly ("memory-safe") {
        state.slot := REENTRANCY_GUARD_STORAGE_SLOT
    }
}

struct DeliveryTmpState {
    // the refund chain for the in-progress delivery
    uint16 refundChain;
    // the refund address for the in-progress delivery
    bytes32 refundAddress;
}

//keccak256("DeliveryTmpState") - 1
bytes32 constant DELIVERY_TMP_STORAGE_SLOT =
    0x1a2a8eb52f1d00a1242a3f8cc031e30a32870ff64f69009c4e06f75bd842fd22;

function getDeliveryTmpState() pure returns (DeliveryTmpState storage state) {
    assembly ("memory-safe") {
        state.slot := DELIVERY_TMP_STORAGE_SLOT
    }
}

File 4 of 20 : WormholeRelayerGovernance.sol
// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.19;

import "@openzeppelin/contracts/proxy/ERC1967/ERC1967Upgrade.sol";

import {IWormhole} from "../../interfaces/IWormhole.sol";
import {InvalidPayloadLength} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {fromWormholeFormat} from "../../relayer/libraries/Utils.sol";
import {BytesParsing} from "../../relayer/libraries/BytesParsing.sol";
import {
    getGovernanceState,
    getRegisteredWormholeRelayersState,
    getDefaultDeliveryProviderState
} from "./WormholeRelayerStorage.sol";
import {WormholeRelayerBase} from "./WormholeRelayerBase.sol";

error GovernanceActionAlreadyConsumed(bytes32 hash);
error InvalidGovernanceVM(string reason);
error InvalidGovernanceChainId(uint16 parsed, uint16 expected);
error InvalidGovernanceContract(bytes32 parsed, bytes32 expected);

error InvalidPayloadChainId(uint16 parsed, uint16 expected);
error InvalidPayloadAction(uint8 parsed, uint8 expected);
error InvalidPayloadModule(bytes32 parsed, bytes32 expected);
error InvalidFork();
error ContractUpgradeFailed(bytes failure);
error ChainAlreadyRegistered(uint16 chainId, bytes32 registeredWormholeRelayerContract);
error InvalidDefaultDeliveryProvider(bytes32 defaultDeliveryProvider);

abstract contract WormholeRelayerGovernance is WormholeRelayerBase, ERC1967Upgrade {
    //This constant should actually be defined in IWormhole. Alas, it isn't.
    uint16 private constant WORMHOLE_CHAINID_UNSET = 0;

    /**
     * Governance VMs are encoded in a packed fashion using the general wormhole scheme:
     *   GovernancePacket = <Common Header|Action Parameters>
     *
     * For a more detailed explanation see here:
     *   - https://docs.wormhole.com/wormhole/governance
     *   - https://github.com/wormhole-foundation/wormhole/blob/main/whitepapers/0002_governance_messaging.md
     */

    //Right shifted ascii encoding of "WormholeRelayer"
    bytes32 private constant module =
        0x0000000000000000000000000000000000576f726d686f6c6552656c61796572;

    /**
     * The choice of action enumeration and parameters follows the scheme of the core bridge:
     *   - https://github.com/wormhole-foundation/wormhole/blob/main/ethereum/contracts/bridge/BridgeGovernance.sol#L115
     */

    /**
     * Registers a wormhole relayer contract that was deployed on another chain with the WormholeRelayer on
     *   this chain. The equivalent to the core bridge's registerChain action.
     *
     * Action Parameters:
     *   - uint16 foreignChainId
     *   - bytes32 foreignContractAddress
     */
    uint8 private constant GOVERNANCE_ACTION_REGISTER_WORMHOLE_RELAYER_CONTRACT = 1;

    /**
     * Upgrades the WormholeRelayer contract to a new implementation. The equivalent to the core bridge's
     *   upgrade action.
     *
     * Action Parameters:
     *   - bytes32 newImplementation
     */
    uint8 private constant GOVERNANCE_ACTION_CONTRACT_UPGRADE = 2;

    /**
     * Sets the default relay provider for the WormholeRelayer. Has no equivalent in the core bridge.
     *
     * Action Parameters:
     *   - bytes32 newProvider
     */
    uint8 private constant GOVERNANCE_ACTION_UPDATE_DEFAULT_PROVIDER = 3;

    //By checking that only the contract can call itself, we can enforce that the migration code is
    //  executed upon program upgrade and that it can't be called externally by anyone else.
    function checkAndExecuteUpgradeMigration() external {
        assert(msg.sender == address(this));
        executeUpgradeMigration();
    }

    function executeUpgradeMigration() internal virtual {
        //override and implement in WormholeRelayer upon contract upgrade (if required)
    }

    function registerWormholeRelayerContract(bytes memory encodedVm) external {
        (uint16 foreignChainId, bytes32 foreignAddress) =
            parseAndCheckRegisterWormholeRelayerContractVm(encodedVm);

        getRegisteredWormholeRelayersState().registeredWormholeRelayers[foreignChainId] =
            foreignAddress;
    }

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

    function submitContractUpgrade(bytes memory encodedVm) external {
        address currentImplementation = _getImplementation();
        address newImplementation = parseAndCheckContractUpgradeVm(encodedVm);

        _upgradeTo(newImplementation);

        (bool success, bytes memory revertData) =
            address(this).call(abi.encodeCall(this.checkAndExecuteUpgradeMigration, ()));

        if (!success) {
            revert ContractUpgradeFailed(revertData);
        }

        emit ContractUpgraded(currentImplementation, newImplementation);
    }

    function setDefaultDeliveryProvider(bytes memory encodedVm) external {
        address newProvider = parseAndCheckRegisterDefaultDeliveryProviderVm(encodedVm);

        getDefaultDeliveryProviderState().defaultDeliveryProvider = newProvider;
    }

    // ------------------------------------------- PRIVATE -------------------------------------------
    using BytesParsing for bytes;

    function parseAndCheckRegisterWormholeRelayerContractVm(bytes memory encodedVm)
        private
        returns (uint16 foreignChainId, bytes32 foreignAddress)
    {
        bytes memory payload = verifyAndConsumeGovernanceVM(encodedVm);
        uint256 offset = parseAndCheckPayloadHeader(
            payload, GOVERNANCE_ACTION_REGISTER_WORMHOLE_RELAYER_CONTRACT, true
        );

        (foreignChainId, offset) = payload.asUint16Unchecked(offset);
        (foreignAddress, offset) = payload.asBytes32Unchecked(offset);

        checkLength(payload, offset);

        if (getRegisteredWormholeRelayerContract(foreignChainId) != bytes32(0)) {
            revert ChainAlreadyRegistered(
                foreignChainId, getRegisteredWormholeRelayerContract(foreignChainId)
            );
        }
    }

    function parseAndCheckContractUpgradeVm(bytes memory encodedVm)
        private
        returns (address newImplementation)
    {
        bytes memory payload = verifyAndConsumeGovernanceVM(encodedVm);
        uint256 offset =
            parseAndCheckPayloadHeader(payload, GOVERNANCE_ACTION_CONTRACT_UPGRADE, false);

        bytes32 newImplementationWhFmt;
        (newImplementationWhFmt, offset) = payload.asBytes32Unchecked(offset);
        //fromWormholeFormat reverts if first 12 bytes aren't zero (i.e. if it's not an EVM address)
        newImplementation = fromWormholeFormat(newImplementationWhFmt);

        checkLength(payload, offset);
    }

    function parseAndCheckRegisterDefaultDeliveryProviderVm(bytes memory encodedVm)
        private
        returns (address newProvider)
    {
        bytes memory payload = verifyAndConsumeGovernanceVM(encodedVm);
        uint256 offset =
            parseAndCheckPayloadHeader(payload, GOVERNANCE_ACTION_UPDATE_DEFAULT_PROVIDER, false);

        bytes32 newProviderWhFmt;
        (newProviderWhFmt, offset) = payload.asBytes32Unchecked(offset);
        //fromWormholeFormat reverts if first 12 bytes aren't zero (i.e. if it's not an EVM address)
        newProvider = fromWormholeFormat(newProviderWhFmt);

        checkLength(payload, offset);

        if (newProvider == address(0)) {
            revert InvalidDefaultDeliveryProvider(newProviderWhFmt);
        }
    }

    function verifyAndConsumeGovernanceVM(bytes memory encodedVm)
        private
        returns (bytes memory payload)
    {
        (IWormhole.VM memory vm, bool valid, string memory reason) =
            getWormhole().parseAndVerifyVM(encodedVm);

        if (!valid) {
            revert InvalidGovernanceVM(reason);
        }

        uint16 governanceChainId = getWormhole().governanceChainId();
        if (vm.emitterChainId != governanceChainId) {
            revert InvalidGovernanceChainId(vm.emitterChainId, governanceChainId);
        }

        bytes32 governanceContract = getWormhole().governanceContract();
        if (vm.emitterAddress != governanceContract) {
            revert InvalidGovernanceContract(vm.emitterAddress, governanceContract);
        }

        bool consumed = getGovernanceState().consumedGovernanceActions[vm.hash];
        if (consumed) {
            revert GovernanceActionAlreadyConsumed(vm.hash);
        }

        getGovernanceState().consumedGovernanceActions[vm.hash] = true;

        return vm.payload;
    }

    function parseAndCheckPayloadHeader(
        bytes memory encodedPayload,
        uint8 expectedAction,
        bool allowUnset
    ) private view returns (uint256 offset) {
        bytes32 parsedModule;
        (parsedModule, offset) = encodedPayload.asBytes32Unchecked(offset);
        if (parsedModule != module) {
            revert InvalidPayloadModule(parsedModule, module);
        }

        uint8 parsedAction;
        (parsedAction, offset) = encodedPayload.asUint8Unchecked(offset);
        if (parsedAction != expectedAction) {
            revert InvalidPayloadAction(parsedAction, expectedAction);
        }

        uint16 parsedChainId;
        (parsedChainId, offset) = encodedPayload.asUint16Unchecked(offset);
        if (!(parsedChainId == WORMHOLE_CHAINID_UNSET && allowUnset)) {
            if (getWormhole().isFork()) {
                revert InvalidFork();
            }

            if (parsedChainId != getChainId()) {
                revert InvalidPayloadChainId(parsedChainId, getChainId());
            }
        }
    }

    function checkLength(bytes memory payload, uint256 expected) private pure {
        if (payload.length != expected) {
            revert InvalidPayloadLength(payload.length, expected);
        }
    }
}

File 5 of 20 : WormholeRelayerSend.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import {
    DeliveryProviderDoesNotSupportTargetChain,
    DeliveryProviderDoesNotSupportMessageKeyType,
    InvalidMsgValue,
    DeliveryProviderCannotReceivePayment,
    MessageKey,
    VaaKey,
    IWormholeRelayerSend
} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {IDeliveryProvider} from "../../interfaces/relayer/IDeliveryProviderTyped.sol";

import {toWormholeFormat, fromWormholeFormat} from "../../relayer/libraries/Utils.sol";
import {
    DeliveryInstruction,
    RedeliveryInstruction
} from "../../relayer/libraries/RelayerInternalStructs.sol";
import {WormholeRelayerSerde} from "./WormholeRelayerSerde.sol";
import {getDefaultDeliveryProviderState} from "./WormholeRelayerStorage.sol";
import {WormholeRelayerBase} from "./WormholeRelayerBase.sol";
import "../../interfaces/relayer/TypedUnits.sol";
import "../../relayer/libraries/ExecutionParameters.sol";

abstract contract WormholeRelayerSend is WormholeRelayerBase, IWormholeRelayerSend {
    using WormholeRelayerSerde for *;
    using WeiLib for Wei;
    using GasLib for Gas;
    using TargetNativeLib for TargetNative;
    using LocalNativeLib for LocalNative;

    /*
    * Public convenience overloads
    */

    function sendPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit
    ) external payable returns (uint64 sequence) {
        return sendToEvm(
            targetChain,
            targetAddress,
            payload,
            receiverValue,
            LocalNative.wrap(0),
            gasLimit,
            targetChain,
            address(0x0),
            getDefaultDeliveryProvider(),
            new VaaKey[](0),
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function sendPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress
    ) external payable returns (uint64 sequence) {
        return sendToEvm(
            targetChain,
            targetAddress,
            payload,
            receiverValue,
            LocalNative.wrap(0),
            gasLimit,
            refundChain,
            refundAddress,
            getDefaultDeliveryProvider(),
            new VaaKey[](0),
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function sendVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        VaaKey[] memory vaaKeys
    ) external payable returns (uint64 sequence) {
        return sendToEvm(
            targetChain,
            targetAddress,
            payload,
            receiverValue,
            LocalNative.wrap(0),
            gasLimit,
            targetChain,
            address(0x0),
            getDefaultDeliveryProvider(),
            vaaKeys,
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function sendVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        VaaKey[] memory vaaKeys,
        uint16 refundChain,
        address refundAddress
    ) external payable returns (uint64 sequence) {
        return sendToEvm(
            targetChain,
            targetAddress,
            payload,
            receiverValue,
            LocalNative.wrap(0),
            gasLimit,
            refundChain,
            refundAddress,
            getDefaultDeliveryProvider(),
            vaaKeys,
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function sendToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) public payable returns (uint64 sequence) {
        sequence = send(
            targetChain,
            toWormholeFormat(targetAddress),
            payload,
            receiverValue,
            paymentForExtraReceiverValue,
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            refundChain,
            toWormholeFormat(refundAddress),
            deliveryProviderAddress,
            vaaKeys,
            consistencyLevel
        );
    }

    function sendToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress,
        address deliveryProviderAddress,
        MessageKey[] memory messageKeys,
        uint8 consistencyLevel
    ) public payable returns (uint64 sequence) {
        sequence = send(
            targetChain,
            toWormholeFormat(targetAddress),
            payload,
            receiverValue,
            paymentForExtraReceiverValue,
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            refundChain,
            toWormholeFormat(refundAddress),
            deliveryProviderAddress,
            messageKeys,
            consistencyLevel
        );
    }

    function resendToEvm(
        VaaKey memory deliveryVaaKey,
        uint16 targetChain,
        TargetNative newReceiverValue,
        Gas newGasLimit,
        address newDeliveryProviderAddress
    ) public payable returns (uint64 sequence) {
        sequence = resend(
            deliveryVaaKey,
            targetChain,
            newReceiverValue,
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(newGasLimit)),
            newDeliveryProviderAddress
        );
    }

    function send(
        uint16 targetChain,
        bytes32 targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        bytes memory encodedExecutionParameters,
        uint16 refundChain,
        bytes32 refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) public payable returns (uint64 sequence) {
        sequence = send(
            Send(
                targetChain,
                targetAddress,
                payload,
                receiverValue,
                paymentForExtraReceiverValue,
                encodedExecutionParameters,
                refundChain,
                refundAddress,
                deliveryProviderAddress,
                WormholeRelayerSerde.vaaKeyArrayToMessageKeyArray(vaaKeys),
                consistencyLevel
            )
        );
    }

    function send(
        uint16 targetChain,
        bytes32 targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        bytes memory encodedExecutionParameters,
        uint16 refundChain,
        bytes32 refundAddress,
        address deliveryProviderAddress,
        MessageKey[] memory messageKeys,
        uint8 consistencyLevel
    ) public payable returns (uint64 sequence) {
        sequence = send(
            Send(
                targetChain,
                targetAddress,
                payload,
                receiverValue,
                paymentForExtraReceiverValue,
                encodedExecutionParameters,
                refundChain,
                refundAddress,
                deliveryProviderAddress,
                messageKeys,
                consistencyLevel
            )
        );
    }

    /* 
    * Non overload logic 
    */

    struct Send {
        uint16 targetChain;
        bytes32 targetAddress;
        bytes payload;
        TargetNative receiverValue;
        LocalNative paymentForExtraReceiverValue;
        bytes encodedExecutionParameters;
        uint16 refundChain;
        bytes32 refundAddress;
        address deliveryProviderAddress;
        MessageKey[] messageKeys;
        uint8 consistencyLevel;
    }

    function send(Send memory sendParams) internal returns (uint64 sequence) {
        IDeliveryProvider provider = IDeliveryProvider(sendParams.deliveryProviderAddress);

        // Revert if delivery provider does not support the target chain
        if (!provider.isChainSupported(sendParams.targetChain)) {
            revert DeliveryProviderDoesNotSupportTargetChain(
                sendParams.deliveryProviderAddress, sendParams.targetChain
            );
        }

        // Obtain the delivery provider's fee for this delivery, as well as some encoded info (e.g. refund per unit of gas unused)
        (LocalNative deliveryPrice, bytes memory encodedExecutionInfo) = provider.quoteDeliveryPrice(
            sendParams.targetChain, sendParams.receiverValue, sendParams.encodedExecutionParameters
        );

        // Check if user passed in 'one wormhole message fee' + 'delivery provider's fee'
        LocalNative wormholeMessageFee = getWormholeMessageFee();
        checkMsgValue(wormholeMessageFee, deliveryPrice, sendParams.paymentForExtraReceiverValue);

        checkKeyTypesSupported(provider, sendParams.messageKeys);

        // Encode all relevant info the delivery provider needs to perform the delivery as requested
        bytes memory encodedInstruction = DeliveryInstruction({
            targetChain: sendParams.targetChain,
            targetAddress: sendParams.targetAddress,
            payload: sendParams.payload,
            requestedReceiverValue: sendParams.receiverValue,
            extraReceiverValue: provider.quoteAssetConversion(
                sendParams.targetChain, sendParams.paymentForExtraReceiverValue
                ),
            encodedExecutionInfo: encodedExecutionInfo,
            refundChain: sendParams.refundChain,
            refundAddress: sendParams.refundAddress,
            refundDeliveryProvider: provider.getTargetChainAddress(sendParams.targetChain),
            sourceDeliveryProvider: toWormholeFormat(sendParams.deliveryProviderAddress),
            senderAddress: toWormholeFormat(msg.sender),
            messageKeys: sendParams.messageKeys
        }).encode();

        // Publish the encoded delivery instruction as a wormhole message
        // and pay the delivery provider their fee
        bool paymentSucceeded;
        (sequence, paymentSucceeded) = publishAndPay(
            wormholeMessageFee,
            deliveryPrice,
            sendParams.paymentForExtraReceiverValue,
            encodedInstruction,
            sendParams.consistencyLevel,
            provider.getRewardAddress()
        );

        if (!paymentSucceeded) {
            revert DeliveryProviderCannotReceivePayment();
        }
    }

    function checkKeyTypesSupported(
        IDeliveryProvider provider,
        MessageKey[] memory messageKeys
    ) internal view {
        uint256 len = messageKeys.length;
        if (len == 0) {
            return;
        }

        uint256 supportedKeyTypes = provider.getSupportedKeys();
        for (uint256 i = 0; i < len;) {
            uint8 keyType = messageKeys[i].keyType;
            if ((supportedKeyTypes & (1 << keyType)) == 0) {
                revert DeliveryProviderDoesNotSupportMessageKeyType(keyType);
            }
            unchecked {
                ++i;
            }
        }
    }

    function resend(
        VaaKey memory deliveryVaaKey,
        uint16 targetChain,
        TargetNative newReceiverValue,
        bytes memory newEncodedExecutionParameters,
        address newDeliveryProviderAddress
    ) public payable returns (uint64 sequence) {
        IDeliveryProvider provider = IDeliveryProvider(newDeliveryProviderAddress);

        // Revert if delivery provider does not support the target chain
        if (!provider.isChainSupported(targetChain)) {
            revert DeliveryProviderDoesNotSupportTargetChain(
                newDeliveryProviderAddress, targetChain
            );
        }

        // Obtain the delivery provider's fee for this delivery, as well as some encoded info (e.g. refund per unit of gas unused)
        (LocalNative deliveryPrice, bytes memory encodedExecutionInfo) = provider.quoteDeliveryPrice(
            targetChain, newReceiverValue, newEncodedExecutionParameters
        );

        // Check if user passed in 'one wormhole message fee' + 'delivery provider's fee'
        LocalNative wormholeMessageFee = getWormholeMessageFee();
        checkMsgValue(wormholeMessageFee, deliveryPrice, LocalNative.wrap(0));

        // Encode all relevant info the delivery provider needs to perform this redelivery as requested
        bytes memory encodedInstruction = RedeliveryInstruction({
            deliveryVaaKey: deliveryVaaKey,
            targetChain: targetChain,
            newRequestedReceiverValue: newReceiverValue,
            newEncodedExecutionInfo: encodedExecutionInfo,
            newSourceDeliveryProvider: toWormholeFormat(newDeliveryProviderAddress),
            newSenderAddress: toWormholeFormat(msg.sender)
        }).encode();

        // Publish the encoded redelivery instruction as a wormhole message
        // and pay the delivery provider their fee
        bool paymentSucceeded;
        (sequence, paymentSucceeded) = publishAndPay(
            wormholeMessageFee,
            deliveryPrice,
            LocalNative.wrap(0),
            encodedInstruction,
            CONSISTENCY_LEVEL_INSTANT,
            provider.getRewardAddress()
        );
        if (!paymentSucceeded) {
            revert DeliveryProviderCannotReceivePayment();
        }
    }

    function getDefaultDeliveryProvider() public view returns (address deliveryProvider) {
        deliveryProvider = getDefaultDeliveryProviderState().defaultDeliveryProvider;
    }

    function quoteEVMDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        Gas gasLimit,
        address deliveryProviderAddress
    ) public view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused) {
        (LocalNative quote, bytes memory encodedExecutionInfo) = quoteDeliveryPrice(
            targetChain,
            receiverValue,
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            deliveryProviderAddress
        );
        nativePriceQuote = quote;
        targetChainRefundPerGasUnused =
            decodeEvmExecutionInfoV1(encodedExecutionInfo).targetChainRefundPerGasUnused;
    }

    function quoteEVMDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        Gas gasLimit
    ) public view returns (LocalNative nativePriceQuote, GasPrice targetChainRefundPerGasUnused) {
        return quoteEVMDeliveryPrice(
            targetChain, receiverValue, gasLimit, getDefaultDeliveryProvider()
        );
    }

    function quoteDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        bytes memory encodedExecutionParameters,
        address deliveryProviderAddress
    ) public view returns (LocalNative nativePriceQuote, bytes memory encodedExecutionInfo) {
        IDeliveryProvider provider = IDeliveryProvider(deliveryProviderAddress);
        (LocalNative deliveryPrice, bytes memory _encodedExecutionInfo) =
            provider.quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters);
        encodedExecutionInfo = _encodedExecutionInfo;
        nativePriceQuote = deliveryPrice + getWormholeMessageFee();
    }

    function quoteNativeForChain(
        uint16 targetChain,
        LocalNative currentChainAmount,
        address deliveryProviderAddress
    ) public view returns (TargetNative targetChainAmount) {
        return IDeliveryProvider(deliveryProviderAddress).quoteAssetConversion(
            targetChain, currentChainAmount
        );
    }

    // Forwards

    function forwardPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit
    ) external payable {
        forward(
            targetChain,
            toWormholeFormat(targetAddress),
            payload,
            receiverValue,
            LocalNative.wrap(0),
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            getCurrentRefundChain(),
            getCurrentRefundAddress(),
            getDefaultDeliveryProvider(),
            new VaaKey[](0),
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function forwardVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        Gas gasLimit,
        VaaKey[] memory vaaKeys
    ) external payable {
        forward(
            targetChain,
            toWormholeFormat(targetAddress),
            payload,
            receiverValue,
            LocalNative.wrap(0),
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            getCurrentRefundChain(),
            getCurrentRefundAddress(),
            getDefaultDeliveryProvider(),
            vaaKeys,
            CONSISTENCY_LEVEL_FINALIZED
        );
    }

    function forwardToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative paymentForExtraReceiverValue,
        Gas gasLimit,
        uint16 refundChain,
        address refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) public payable {
        forward(
            targetChain,
            toWormholeFormat(targetAddress),
            payload,
            receiverValue,
            paymentForExtraReceiverValue,
            encodeEvmExecutionParamsV1(EvmExecutionParamsV1(gasLimit)),
            refundChain,
            toWormholeFormat(refundAddress),
            deliveryProviderAddress,
            vaaKeys,
            consistencyLevel
        );
    }

    function forward(
        uint16 targetChain,
        bytes32 targetAddress,
        bytes memory payload,
        TargetNative receiverValue,
        LocalNative,
        bytes memory encodedExecutionParameters,
        uint16 refundChain,
        bytes32 refundAddress,
        address deliveryProviderAddress,
        VaaKey[] memory vaaKeys,
        uint8 consistencyLevel
    ) public payable {
        (LocalNative cost,) = quoteDeliveryPrice(targetChain, receiverValue, encodedExecutionParameters, deliveryProviderAddress);
        send(
            targetChain,
            targetAddress,
            payload,
            receiverValue,
            LocalNative.wrap(msg.value) - cost, // include the extra value that is passed in
            encodedExecutionParameters,
            refundChain,
            refundAddress,
            deliveryProviderAddress,
            vaaKeys,
            consistencyLevel
        );
    }
}

File 6 of 20 : WormholeRelayerDelivery.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import {IWormhole} from "../../interfaces/IWormhole.sol";
import {
    InvalidDeliveryVaa,
    InvalidEmitter,
    InsufficientRelayerFunds,
    TargetChainIsNotThisChain,
    MessageKeysLengthDoesNotMatchMessagesLength,
    VaaKeysDoNotMatchVaas,
    InvalidOverrideGasLimit,
    InvalidOverrideReceiverValue,
    RequesterNotWormholeRelayer,
    DeliveryProviderCannotReceivePayment,
    MessageKey,
    VAA_KEY_TYPE,
    VaaKey,
    IWormholeRelayerDelivery,
    IWormholeRelayerSend,
    RETURNDATA_TRUNCATION_THRESHOLD
} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {IWormholeReceiver} from "../../interfaces/relayer/IWormholeReceiver.sol";
import {IDeliveryProvider} from "../../interfaces/relayer/IDeliveryProviderTyped.sol";

import {pay, pay, min, toWormholeFormat, fromWormholeFormat, returnLengthBoundedCall, returnLengthBoundedCall} from "../../relayer/libraries/Utils.sol";
import {
    DeliveryInstruction,
    DeliveryOverride,
    EvmDeliveryInstruction
} from "../../relayer/libraries/RelayerInternalStructs.sol";
import {BytesParsing} from "../../relayer/libraries/BytesParsing.sol";
import {WormholeRelayerSerde} from "./WormholeRelayerSerde.sol";
import {
    DeliverySuccessState,
    DeliveryFailureState,
    getDeliverySuccessState,
    getDeliveryFailureState
} from "./WormholeRelayerStorage.sol";
import {WormholeRelayerBase} from "./WormholeRelayerBase.sol";
import "../../interfaces/relayer/TypedUnits.sol";
import "../../relayer/libraries/ExecutionParameters.sol";

uint256 constant QUOTE_LENGTH_BYTES = 32;

uint256 constant GAS_LIMIT_EXTERNAL_CALL = 100_000;

abstract contract WormholeRelayerDelivery is WormholeRelayerBase, IWormholeRelayerDelivery {
    using WormholeRelayerSerde for *; 
    using BytesParsing for bytes;
    using WeiLib for Wei;
    using GasLib for Gas;
    using GasPriceLib for GasPrice;
    using TargetNativeLib for TargetNative;
    using LocalNativeLib for LocalNative;

    function deliver(
        bytes[] memory encodedVMs,
        bytes memory encodedDeliveryVAA,
        address payable relayerRefundAddress,
        bytes memory deliveryOverrides
    ) public payable nonReentrant {

        // Parse and verify VAA containing delivery instructions, revert if invalid
        (IWormhole.VM memory vm, bool valid, string memory reason) =
            getWormhole().parseAndVerifyVM(encodedDeliveryVAA);
        if (!valid) {
            revert InvalidDeliveryVaa(reason);
        }

        // Revert if the emitter of the VAA is not a Wormhole Relayer contract 
        bytes32 registeredWormholeRelayer = getRegisteredWormholeRelayerContract(vm.emitterChainId);
        if (vm.emitterAddress != registeredWormholeRelayer) {
            revert InvalidEmitter(vm.emitterAddress, registeredWormholeRelayer, vm.emitterChainId);
        }
    
        DeliveryInstruction memory instruction = vm.payload.decodeDeliveryInstruction();

        // Record information about the delivery's refund in temporary storage
        recordRefundInformation(
            instruction.refundChain,
            instruction.refundAddress
        );

        DeliveryVAAInfo memory deliveryVaaInfo = DeliveryVAAInfo({
            sourceChain: vm.emitterChainId,
            sourceSequence: vm.sequence,
            deliveryVaaHash: vm.hash,
            relayerRefundAddress: relayerRefundAddress,
            encodedVMs: encodedVMs,
            deliveryInstruction: instruction,
            gasLimit: Gas.wrap(0),
            targetChainRefundPerGasUnused: GasPrice.wrap(0),
            totalReceiverValue: TargetNative.wrap(0),
            encodedOverrides: deliveryOverrides,
            redeliveryHash: bytes32(0)
        });

        // Decode information from the execution parameters
        // (overriding them if there was an override requested)
        // Assumes execution parameters and info are of version EVM_V1
        (
            deliveryVaaInfo.gasLimit,
            deliveryVaaInfo.targetChainRefundPerGasUnused,
            deliveryVaaInfo.totalReceiverValue,
            deliveryVaaInfo.redeliveryHash
        ) = getDeliveryParametersEvmV1(instruction, deliveryOverrides);

        // Revert if msg.value is not enough to fund both the receiver value
        // as well as the maximum possible refund 
        // Note: instruction's TargetNative is delivery's LocalNative
        LocalNative requiredFunds = (deliveryVaaInfo.gasLimit.toWei(
            deliveryVaaInfo.targetChainRefundPerGasUnused
        ) + deliveryVaaInfo.totalReceiverValue.asNative()).asLocalNative();
        if (msgValue() < requiredFunds) {
            revert InsufficientRelayerFunds(msgValue(), requiredFunds);
        }

        // Revert if the instruction's target chain is not this chain
        if (getChainId() != instruction.targetChain) {
            revert TargetChainIsNotThisChain(instruction.targetChain);
        }

        // Revert if the VAAs delivered do not match the descriptions specified in the instruction
        checkMessageKeysWithMessages(instruction.messageKeys, encodedVMs);

        executeDelivery(deliveryVaaInfo);

        // Clear temporary storage of refund information
        clearRefundInformation();
    }

    // ------------------------------------------- PRIVATE -------------------------------------------

    struct DeliveryVAAInfo {
        uint16 sourceChain;
        uint64 sourceSequence;
        bytes32 deliveryVaaHash;
        address payable relayerRefundAddress;
        bytes[] encodedVMs;
        DeliveryInstruction deliveryInstruction;
        Gas gasLimit;
        GasPrice targetChainRefundPerGasUnused;
        TargetNative totalReceiverValue;
        bytes encodedOverrides;
        bytes32 redeliveryHash; //optional (0 if not present)
    }

    function getDeliveryParametersEvmV1(
        DeliveryInstruction memory instruction,
        bytes memory encodedOverrides
    )
        internal
        pure
        returns (
            Gas gasLimit,
            GasPrice targetChainRefundPerGasUnused,
            TargetNative totalReceiverValue,
            bytes32 redeliveryHash
        )
    {
        ExecutionInfoVersion instructionExecutionInfoVersion =
            decodeExecutionInfoVersion(instruction.encodedExecutionInfo);
        if (instructionExecutionInfoVersion != ExecutionInfoVersion.EVM_V1) {
            revert UnexpectedExecutionInfoVersion(
                uint8(instructionExecutionInfoVersion), uint8(ExecutionInfoVersion.EVM_V1)
            );
        }

        EvmExecutionInfoV1 memory executionInfo =
            decodeEvmExecutionInfoV1(instruction.encodedExecutionInfo);

        // If present, apply redelivery deliveryOverrides to current instruction
        if (encodedOverrides.length != 0) {
            DeliveryOverride memory deliveryOverrides = encodedOverrides.decodeDeliveryOverride();

            // Check to see if gasLimit >= original gas limit, receiver value >= original receiver value, and refund >= original refund
            // If so, replace the corresponding variables with the overriden variables
            // If not, revert
            (instruction.requestedReceiverValue, executionInfo) = decodeAndCheckOverridesEvmV1(
                instruction.requestedReceiverValue, executionInfo, deliveryOverrides
            );
            instruction.extraReceiverValue = TargetNative.wrap(0);
            redeliveryHash = deliveryOverrides.redeliveryHash;
        }

        gasLimit = executionInfo.gasLimit;
        targetChainRefundPerGasUnused = executionInfo.targetChainRefundPerGasUnused;
        totalReceiverValue = instruction.requestedReceiverValue + instruction.extraReceiverValue;
    }

    function decodeAndCheckOverridesEvmV1(
        TargetNative receiverValue,
        EvmExecutionInfoV1 memory executionInfo,
        DeliveryOverride memory deliveryOverrides
    )
        internal
        pure
        returns (
            TargetNative deliveryOverridesReceiverValue,
            EvmExecutionInfoV1 memory deliveryOverridesExecutionInfo
        )
    {
        if (deliveryOverrides.newReceiverValue.unwrap() < receiverValue.unwrap()) {
            revert InvalidOverrideReceiverValue();
        }

        ExecutionInfoVersion deliveryOverridesExecutionInfoVersion =
            decodeExecutionInfoVersion(deliveryOverrides.newExecutionInfo);
        if (ExecutionInfoVersion.EVM_V1 != deliveryOverridesExecutionInfoVersion) {
            revert VersionMismatchOverride(
                uint8(ExecutionInfoVersion.EVM_V1), uint8(deliveryOverridesExecutionInfoVersion)
            );
        }

        deliveryOverridesExecutionInfo =
            decodeEvmExecutionInfoV1(deliveryOverrides.newExecutionInfo);
        deliveryOverridesReceiverValue = deliveryOverrides.newReceiverValue;

        if (deliveryOverridesExecutionInfo.gasLimit < executionInfo.gasLimit) {
            revert InvalidOverrideGasLimit();
        }
    }

    struct DeliveryResults {
        Gas gasUsed;
        DeliveryStatus status;
        bytes additionalStatusInfo;
    }

    /**
     * Performs the following actions:
     * - Calls the `receiveWormholeMessages` method on the contract
     *     `vaaInfo.deliveryInstruction.targetAddress` (with the gas limit and value specified in
     *     vaaInfo.gasLimit and vaaInfo.totalReceiverValue, and `encodedVMs` as the input)
     *
     * - Calculates how much gas from `vaaInfo.gasLimit` is left
     * - Refund anything leftover to the relayer
     *
     * @param vaaInfo struct specifying:
     *    - sourceChain chain id that the delivery originated from
     *    - sourceSequence sequence number of the delivery VAA on the source chain
     *    - deliveryVaaHash hash of delivery VAA
     *    - relayerRefundAddress address that should be paid for relayer refunds
     *    - encodedVMs list of signed wormhole messages (VAAs)
     *    - deliveryInstruction the specific instruction which is being executed
     *    - gasLimit the gas limit to call targetAddress with
     *    - targetChainRefundPerGasUnused the amount of (this chain) wei to refund to refundAddress
     *      per unit of gas unused (from gasLimit)
     *    - totalReceiverValue the msg.value to call targetAddress with
     *    - encodedOverrides any (encoded) overrides that were applied
     *    - (optional) redeliveryHash hash of redelivery Vaa
     */

    function executeDelivery(DeliveryVAAInfo memory vaaInfo) private {

        // If the targetAddress is the 0 address
        // Then emit event and return
        // (This is used for cross-chain refunds)
        if (vaaInfo.deliveryInstruction.targetAddress == 0x0) {
            handleCrossChainRefund(vaaInfo);
            return;
        }

        DeliveryResults memory results;

        // Check replay protection - if so, set status to receiver failure
        if(getDeliverySuccessState().deliverySuccessBlock[vaaInfo.deliveryVaaHash] != 0) {
            results = DeliveryResults(
                Gas.wrap(0),
                DeliveryStatus.RECEIVER_FAILURE,
                bytes("Delivery already performed")
            );
        } else {
            results = executeInstruction(
                EvmDeliveryInstruction({
                    sourceChain: vaaInfo.sourceChain,
                    targetAddress: vaaInfo.deliveryInstruction.targetAddress,
                    payload: vaaInfo.deliveryInstruction.payload,
                    gasLimit: vaaInfo.gasLimit,
                    totalReceiverValue: vaaInfo.totalReceiverValue,
                    targetChainRefundPerGasUnused: vaaInfo.targetChainRefundPerGasUnused,
                    senderAddress: vaaInfo.deliveryInstruction.senderAddress,
                    deliveryHash: vaaInfo.deliveryVaaHash,
                    signedVaas: vaaInfo.encodedVMs
                })
            );
            setDeliveryBlock(results.status, vaaInfo.deliveryVaaHash);
        }

        

        RefundStatus refundStatus = payRefunds(
            vaaInfo.deliveryInstruction,
            vaaInfo.relayerRefundAddress,
            (vaaInfo.gasLimit - results.gasUsed).toWei(vaaInfo.targetChainRefundPerGasUnused).asLocalNative(),
            results.status
        );
        emitDeliveryEvent(vaaInfo, results, refundStatus);
    }

    function executeInstruction(EvmDeliveryInstruction memory evmInstruction)
        internal
        returns (DeliveryResults memory results)
    {

        Gas gasLimit = evmInstruction.gasLimit;
        bool success;
        {
            address payable deliveryTarget = payable(fromWormholeFormat(evmInstruction.targetAddress));
            bytes memory callData = abi.encodeCall(IWormholeReceiver.receiveWormholeMessages, (
                evmInstruction.payload,
                evmInstruction.signedVaas,
                evmInstruction.senderAddress,
                evmInstruction.sourceChain,
                evmInstruction.deliveryHash
            ));

            // Measure gas usage of call
            Gas preGas = Gas.wrap(gasleft());

            // Calls the `receiveWormholeMessages` endpoint on the contract `evmInstruction.targetAddress`
            // (with the gas limit and value specified in instruction, and `encodedVMs` as the input)
            // If it reverts, returns the first 132 bytes of the revert message
            (success, results.additionalStatusInfo) = returnLengthBoundedCall(
                deliveryTarget,
                callData,
                gasLimit.unwrap(),
                evmInstruction.totalReceiverValue.unwrap(),
                RETURNDATA_TRUNCATION_THRESHOLD
            );

            Gas postGas = Gas.wrap(gasleft());

            unchecked {
                results.gasUsed = (preGas - postGas).min(gasLimit);
            }
        }

        if (success) {
            results.additionalStatusInfo = new bytes(0);
            results.status = DeliveryStatus.SUCCESS;
        } else {
            // Call to 'receiveWormholeMessages' on targetAddress reverted
            results.status = DeliveryStatus.RECEIVER_FAILURE;
        }
    }

    function handleCrossChainRefund(DeliveryVAAInfo memory vaaInfo) internal {
        RefundStatus refundStatus = payRefunds(
            vaaInfo.deliveryInstruction,
            vaaInfo.relayerRefundAddress,
            LocalNative.wrap(0),
            DeliveryStatus.RECEIVER_FAILURE
        );
        emitDeliveryEvent(
            vaaInfo, 
            DeliveryResults(
                Gas.wrap(0),
                DeliveryStatus.SUCCESS,
                bytes("")
            ), 
            refundStatus
        );
    }

    function emitDeliveryEvent(DeliveryVAAInfo memory vaaInfo, DeliveryResults memory results, RefundStatus refundStatus) private {
        emit Delivery(
            fromWormholeFormat(vaaInfo.deliveryInstruction.targetAddress),
            vaaInfo.sourceChain,
            vaaInfo.sourceSequence,
            vaaInfo.deliveryVaaHash,
            results.status,
            results.gasUsed,
            refundStatus,
            results.additionalStatusInfo,
            (vaaInfo.redeliveryHash != 0) ? vaaInfo.encodedOverrides : new bytes(0)
        );
    }

    function payRefunds(
        DeliveryInstruction memory deliveryInstruction,
        address payable relayerRefundAddress,
        LocalNative transactionFeeRefundAmount,
        DeliveryStatus status
    ) private returns (RefundStatus refundStatus) {
        //Amount of receiverValue that is refunded to the user (0 if the call to
        //  'receiveWormholeMessages' did not revert, or the full receiverValue otherwise)
        LocalNative receiverValueRefundAmount = LocalNative.wrap(0);

        if (
            status == DeliveryStatus.RECEIVER_FAILURE
        ) {
            receiverValueRefundAmount = (
                deliveryInstruction.requestedReceiverValue + deliveryInstruction.extraReceiverValue
            ).asNative().asLocalNative(); // NOTE: instruction's target is delivery's local
        }

        // Total refund to the user
        // (If the forward succeeded, the 'transactionFeeRefundAmount' was used there already)
        LocalNative refundToRefundAddress = receiverValueRefundAmount
            + transactionFeeRefundAmount;

        //Refund the user
        refundStatus = deliveryInstruction.refundAddress == bytes32(0x0) ? RefundStatus.NO_REFUND_REQUESTED : payRefundToRefundAddress(
            deliveryInstruction.refundChain,
            deliveryInstruction.refundAddress,
            refundToRefundAddress,
            deliveryInstruction.refundDeliveryProvider
        );

        //If sending the user's refund failed, this gets added to the relayer's refund
        LocalNative leftoverUserRefund = refundToRefundAddress;
        if (
            refundStatus == RefundStatus.REFUND_SENT
                || refundStatus == RefundStatus.CROSS_CHAIN_REFUND_SENT
        ) {
            leftoverUserRefund = LocalNative.wrap(0);
        }

        // Refund the relayer all remaining funds
        LocalNative relayerRefundAmount = calcRelayerRefundAmount(deliveryInstruction, transactionFeeRefundAmount, leftoverUserRefund);

        bool paymentSucceeded = pay(relayerRefundAddress, relayerRefundAmount);
        if(!paymentSucceeded) {
            revert DeliveryProviderCannotReceivePayment();
        }
    }

    function calcRelayerRefundAmount(
        DeliveryInstruction memory deliveryInstruction,
        LocalNative transactionFeeRefundAmount,
        LocalNative leftoverUserRefund
    ) private view returns (LocalNative) {
        return msgValue()
            // Note: instruction's target is delivery's local
            - (deliveryInstruction.requestedReceiverValue + deliveryInstruction.extraReceiverValue).asNative().asLocalNative() 
            - transactionFeeRefundAmount + leftoverUserRefund;
    }

    function payRefundToRefundAddress(
        uint16 refundChain,
        bytes32 refundAddress,
        LocalNative refundAmount,
        bytes32 deliveryProvider
    ) private returns (RefundStatus) {
        // User requested refund on this chain
        if (refundChain == getChainId()) {
            return pay(payable(fromWormholeFormat(refundAddress)), refundAmount, GAS_LIMIT_EXTERNAL_CALL)
                ? RefundStatus.REFUND_SENT
                : RefundStatus.REFUND_FAIL;
        }

        // User requested refund on a different chain
        
        // Determine price of an 'empty' delivery
        // (Note: assumes refund chain is an EVM chain)
        (bool success, LocalNative baseDeliveryPrice) = untrustedBaseDeliveryPrice(fromWormholeFormat(deliveryProvider), refundChain);
        
        // If the unstrusted call failed, or the refundAmount is not greater than the 'empty delivery price', then the refund does not go through
        // Note: We first check 'refundAmount <= baseDeliveryPrice', in case an untrusted delivery provider returns a value that overflows once
        // the wormhole message fee is added to it
        unchecked {
            if (!success || (refundAmount <= baseDeliveryPrice) || (refundAmount <= getWormholeMessageFee() + baseDeliveryPrice)) {
                return RefundStatus.CROSS_CHAIN_REFUND_FAIL_NOT_ENOUGH;
            }
        }
        
        return sendCrossChainRefund(refundChain, refundAddress, refundAmount, refundAmount - getWormholeMessageFee() - baseDeliveryPrice, deliveryProvider);
    }

    function untrustedBaseDeliveryPrice(address deliveryProvider, uint16 refundChain) internal returns (bool success, LocalNative baseDeliveryPrice) {
        (bool externalCallSuccess, bytes memory returnData) = returnLengthBoundedCall(
            deliveryProvider,
            abi.encodeCall(IDeliveryProvider.quoteDeliveryPrice, (refundChain, TargetNative.wrap(0), encodeEvmExecutionParamsV1(getEmptyEvmExecutionParamsV1()))),
            GAS_LIMIT_EXTERNAL_CALL,
            QUOTE_LENGTH_BYTES
        );
        
        if(externalCallSuccess && returnData.length == QUOTE_LENGTH_BYTES) {
            baseDeliveryPrice = abi.decode(returnData, (LocalNative));
            success = true;
        } else {
            success = false;
        }
    }

    function sendCrossChainRefund(uint16 refundChain, bytes32 refundAddress, LocalNative sendAmount, LocalNative receiveAmount, bytes32 deliveryProvider) internal returns (RefundStatus status) {
        // Request a 'send' with 'paymentForExtraReceiverValue' equal to the refund minus the 'empty delivery price'
        // We limit the gas because we are within a delivery, so thus the trust assumptions on the delivery provider are different
        // Normally, in 'send', a revert is no problem; but here, we want to prevent such reverts in this try-catch
        try IWormholeRelayerSend(address(this)).send{value: sendAmount.unwrap(), gas: GAS_LIMIT_EXTERNAL_CALL}(
            refundChain,
            bytes32(0),
            bytes(""),
            TargetNative.wrap(0),
            receiveAmount,
            encodeEvmExecutionParamsV1(getEmptyEvmExecutionParamsV1()),
            refundChain,
            refundAddress,
            fromWormholeFormat(deliveryProvider),
            new VaaKey[](0),
            CONSISTENCY_LEVEL_INSTANT
        ) returns (uint64) {
            return RefundStatus.CROSS_CHAIN_REFUND_SENT;
        } catch (bytes memory) {
            return RefundStatus.CROSS_CHAIN_REFUND_FAIL_PROVIDER_NOT_SUPPORTED;
        }
    }

    function checkMessageKeysWithMessages(
        MessageKey[] memory messageKeys,
        bytes[] memory signedMessages
    ) private view {
        if (messageKeys.length != signedMessages.length) {
            revert MessageKeysLengthDoesNotMatchMessagesLength(messageKeys.length, signedMessages.length);
        }

        uint256 len = messageKeys.length;
        for (uint256 i = 0; i < len;) {
            if (messageKeys[i].keyType == VAA_KEY_TYPE) {
                IWormhole.VM memory parsedVaa = getWormhole().parseVM(signedMessages[i]);
                (VaaKey memory vaaKey,) = WormholeRelayerSerde.decodeVaaKey(messageKeys[i].encodedKey, 0);
                
                if (
                    vaaKey.chainId != parsedVaa.emitterChainId
                        || vaaKey.emitterAddress != parsedVaa.emitterAddress
                        || vaaKey.sequence != parsedVaa.sequence
                ) {
                    revert VaaKeysDoNotMatchVaas(uint8(i));
                }
            }

            unchecked {
                ++i;
            }
        }
    }

    // Ensures current block number is set to implement replay protection and for indexing purposes
    function setDeliveryBlock(DeliveryStatus status, bytes32 deliveryHash) private {
        if (status == DeliveryStatus.SUCCESS) {
            getDeliverySuccessState().deliverySuccessBlock[deliveryHash] = block.number;
            // Clear out failure block if it exists from previous delivery failure
            delete getDeliveryFailureState().deliveryFailureBlock[deliveryHash];
        } else {
            getDeliveryFailureState().deliveryFailureBlock[deliveryHash] = block.number;
        }
    }
}

File 7 of 20 : WormholeRelayerBase.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import {IWormhole} from "../../interfaces/IWormhole.sol";
import {IDeliveryProvider} from "../../interfaces/relayer/IDeliveryProviderTyped.sol";
import {toWormholeFormat, min, pay} from "../../relayer/libraries/Utils.sol";
import {
    ReentrantDelivery,
    DeliveryProviderDoesNotSupportTargetChain,
    VaaKey,
    InvalidMsgValue,
    IWormholeRelayerBase
} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {DeliveryInstruction} from "../../relayer/libraries/RelayerInternalStructs.sol";
import {
    DeliveryTmpState,
    getDeliveryTmpState,
    getDeliverySuccessState,
    getDeliveryFailureState,
    getRegisteredWormholeRelayersState,
    getReentrancyGuardState
} from "./WormholeRelayerStorage.sol";
import "../../interfaces/relayer/TypedUnits.sol";

abstract contract WormholeRelayerBase is IWormholeRelayerBase {
    using WeiLib for Wei;
    using GasLib for Gas;
    using WeiPriceLib for WeiPrice;
    using GasPriceLib for GasPrice;
    using LocalNativeLib for LocalNative;

    //see https://book.wormhole.com/wormhole/3_coreLayerContracts.html#consistency-levels
    //  15 is valid choice for now but ultimately we want something more canonical (202?)
    //  Also, these values should definitely not be defined here but should be provided by IWormhole!
    uint8 internal constant CONSISTENCY_LEVEL_FINALIZED = 15;
    uint8 internal constant CONSISTENCY_LEVEL_INSTANT = 200;

    IWormhole private immutable wormhole_;
    uint16 private immutable chainId_;

    constructor(address _wormhole) {
        wormhole_ = IWormhole(_wormhole);
        chainId_ = uint16(wormhole_.chainId());
    }

    function getRegisteredWormholeRelayerContract(uint16 chainId) public view returns (bytes32) {
        return getRegisteredWormholeRelayersState().registeredWormholeRelayers[chainId];
    }

    function deliveryAttempted(bytes32 deliveryHash) public view returns (bool attempted) {
        return getDeliverySuccessState().deliverySuccessBlock[deliveryHash] != 0 ||
            getDeliveryFailureState().deliveryFailureBlock[deliveryHash] != 0;
    }

    function deliverySuccessBlock(bytes32 deliveryHash) public view returns (uint256 blockNumber) {
        return getDeliverySuccessState().deliverySuccessBlock[deliveryHash];
    }

    function deliveryFailureBlock(bytes32 deliveryHash) public view returns (uint256 blockNumber) {
        return getDeliveryFailureState().deliveryFailureBlock[deliveryHash];
    }

    //Our get functions require view instead of pure (despite not actually reading storage) because
    //  they can't be evaluated at compile time. (https://ethereum.stackexchange.com/a/120630/103366)

    function getWormhole() internal view returns (IWormhole) {
        return wormhole_;
    }

    function getChainId() internal view returns (uint16) {
        return chainId_;
    }

    function getWormholeMessageFee() internal view returns (LocalNative) {
        return LocalNative.wrap(getWormhole().messageFee());
    }

    function msgValue() internal view returns (LocalNative) {
        return LocalNative.wrap(msg.value);
    }

    function checkMsgValue(
        LocalNative wormholeMessageFee,
        LocalNative deliveryPrice,
        LocalNative paymentForExtraReceiverValue
    ) internal view {
        if (msgValue() != deliveryPrice + paymentForExtraReceiverValue + wormholeMessageFee) {
            revert InvalidMsgValue(
                msgValue(), deliveryPrice + paymentForExtraReceiverValue + wormholeMessageFee
            );
        }
    }

    function publishAndPay(
        LocalNative wormholeMessageFee,
        LocalNative deliveryQuote,
        LocalNative paymentForExtraReceiverValue,
        bytes memory encodedInstruction,
        uint8 consistencyLevel,
        address payable rewardAddress
    ) internal returns (uint64 sequence, bool paymentSucceeded) {
        sequence = getWormhole().publishMessage{value: wormholeMessageFee.unwrap()}(
            0, encodedInstruction, consistencyLevel
        );

        paymentSucceeded = pay(
            rewardAddress,
            deliveryQuote + paymentForExtraReceiverValue
        );

        emit SendEvent(sequence, deliveryQuote, paymentForExtraReceiverValue);
    }

    modifier nonReentrant() {
        // Reentrancy guard
        if (getReentrancyGuardState().lockedBy != address(0)) {
            revert ReentrantDelivery(msg.sender, getReentrancyGuardState().lockedBy);
        }
        getReentrancyGuardState().lockedBy = msg.sender;

        _;

        getReentrancyGuardState().lockedBy = address(0);
    }

     // ----------------------- delivery transaction temorary storage functions -----------------------

    function recordRefundInformation(uint16 refundChain, bytes32 refundAddress) internal {
        DeliveryTmpState storage state = getDeliveryTmpState();
        state.refundChain = refundChain;
        state.refundAddress = refundAddress;
    }

    function clearRefundInformation() internal {
        DeliveryTmpState storage state = getDeliveryTmpState();
        state.refundChain = 0;
        state.refundAddress = bytes32(0);
    }

    function getCurrentRefundChain() internal view returns (uint16) {
        return getDeliveryTmpState().refundChain;
    }

    function getCurrentRefundAddress() internal view returns (bytes32) {
        return getDeliveryTmpState().refundAddress;
    }
}

File 8 of 20 : TypedUnits.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

type WeiPrice is uint256;

type GasPrice is uint256;

type Gas is uint256;

type Dollar is uint256;

type Wei is uint256;

type LocalNative is uint256;

type TargetNative is uint256;

using {
    addWei as +,
    subWei as -,
    lteWei as <=,
    ltWei as <,
    gtWei as >,
    eqWei as ==,
    neqWei as !=
} for Wei global;
using {addTargetNative as +, subTargetNative as -} for TargetNative global;
using {
    leLocalNative as <,
    leqLocalNative as <=,
    neqLocalNative as !=,
    addLocalNative as +,
    subLocalNative as -
} for LocalNative global;
using {
    ltGas as <,
    lteGas as <=,
    subGas as -
} for Gas global;

using WeiLib for Wei;
using GasLib for Gas;
using DollarLib for Dollar;
using WeiPriceLib for WeiPrice;
using GasPriceLib for GasPrice;

function ltWei(Wei a, Wei b) pure returns (bool) {
    return Wei.unwrap(a) < Wei.unwrap(b);
}

function eqWei(Wei a, Wei b) pure returns (bool) {
    return Wei.unwrap(a) == Wei.unwrap(b);
}

function gtWei(Wei a, Wei b) pure returns (bool) {
    return Wei.unwrap(a) > Wei.unwrap(b);
}

function lteWei(Wei a, Wei b) pure returns (bool) {
    return Wei.unwrap(a) <= Wei.unwrap(b);
}

function subWei(Wei a, Wei b) pure returns (Wei) {
    return Wei.wrap(Wei.unwrap(a) - Wei.unwrap(b));
}

function addWei(Wei a, Wei b) pure returns (Wei) {
    return Wei.wrap(Wei.unwrap(a) + Wei.unwrap(b));
}

function neqWei(Wei a, Wei b) pure returns (bool) {
    return Wei.unwrap(a) != Wei.unwrap(b);
}

function ltGas(Gas a, Gas b) pure returns (bool) {
    return Gas.unwrap(a) < Gas.unwrap(b);
}

function lteGas(Gas a, Gas b) pure returns (bool) {
    return Gas.unwrap(a) <= Gas.unwrap(b);
}

function subGas(Gas a, Gas b) pure returns (Gas) {
    return Gas.wrap(Gas.unwrap(a) - Gas.unwrap(b));
}

function addTargetNative(TargetNative a, TargetNative b) pure returns (TargetNative) {
    return TargetNative.wrap(TargetNative.unwrap(a) + TargetNative.unwrap(b));
}

function subTargetNative(TargetNative a, TargetNative b) pure returns (TargetNative) {
    return TargetNative.wrap(TargetNative.unwrap(a) - TargetNative.unwrap(b));
}

function addLocalNative(LocalNative a, LocalNative b) pure returns (LocalNative) {
    return LocalNative.wrap(LocalNative.unwrap(a) + LocalNative.unwrap(b));
}

function subLocalNative(LocalNative a, LocalNative b) pure returns (LocalNative) {
    return LocalNative.wrap(LocalNative.unwrap(a) - LocalNative.unwrap(b));
}

function neqLocalNative(LocalNative a, LocalNative b) pure returns (bool) {
    return LocalNative.unwrap(a) != LocalNative.unwrap(b);
}

function leLocalNative(LocalNative a, LocalNative b) pure returns (bool) {
    return LocalNative.unwrap(a) < LocalNative.unwrap(b);
}

function leqLocalNative(LocalNative a, LocalNative b) pure returns (bool) {
    return LocalNative.unwrap(a) <= LocalNative.unwrap(b);
}

library WeiLib {
    using {
        toDollars,
        toGas,
        convertAsset,
        min,
        max,
        scale,
        unwrap,
        asGasPrice,
        asTargetNative,
        asLocalNative
    } for Wei;

    function min(Wei x, Wei maxVal) internal pure returns (Wei) {
        return x > maxVal ? maxVal : x;
    }

    function max(Wei x, Wei maxVal) internal pure returns (Wei) {
        return x < maxVal ? maxVal : x;
    }

    function asTargetNative(Wei w) internal pure returns (TargetNative) {
        return TargetNative.wrap(Wei.unwrap(w));
    }

    function asLocalNative(Wei w) internal pure returns (LocalNative) {
        return LocalNative.wrap(Wei.unwrap(w));
    }

    function toDollars(Wei w, WeiPrice price) internal pure returns (Dollar) {
        return Dollar.wrap(Wei.unwrap(w) * WeiPrice.unwrap(price));
    }

    function toGas(Wei w, GasPrice price) internal pure returns (Gas) {
        return Gas.wrap(Wei.unwrap(w) / GasPrice.unwrap(price));
    }

    function scale(Wei w, Gas num, Gas denom) internal pure returns (Wei) {
        return Wei.wrap(Wei.unwrap(w) * Gas.unwrap(num) / Gas.unwrap(denom));
    }

    function unwrap(Wei w) internal pure returns (uint256) {
        return Wei.unwrap(w);
    }

    function asGasPrice(Wei w) internal pure returns (GasPrice) {
        return GasPrice.wrap(Wei.unwrap(w));
    }

    function convertAsset(
        Wei w,
        WeiPrice fromPrice,
        WeiPrice toPrice,
        uint32 multiplierNum,
        uint32 multiplierDenom,
        bool roundUp
    ) internal pure returns (Wei) {
        Dollar numerator = w.toDollars(fromPrice).mul(multiplierNum);
        WeiPrice denom = toPrice.mul(multiplierDenom);
        Wei res = numerator.toWei(denom, roundUp);
        return res;
    }
}

library GasLib {
    using {toWei, unwrap} for Gas;

    function min(Gas x, Gas maxVal) internal pure returns (Gas) {
        return x < maxVal ? x : maxVal;
    }

    function toWei(Gas w, GasPrice price) internal pure returns (Wei) {
        return Wei.wrap(w.unwrap() * price.unwrap());
    }

    function unwrap(Gas w) internal pure returns (uint256) {
        return Gas.unwrap(w);
    }
}

library DollarLib {
    using {toWei, mul, unwrap} for Dollar;

    function mul(Dollar a, uint256 b) internal pure returns (Dollar) {
        return Dollar.wrap(a.unwrap() * b);
    }

    function toWei(Dollar w, WeiPrice price, bool roundUp) internal pure returns (Wei) {
        return Wei.wrap((w.unwrap() + (roundUp ? price.unwrap() - 1 : 0)) / price.unwrap());
    }

    function toGas(Dollar w, GasPrice price, WeiPrice weiPrice) internal pure returns (Gas) {
        return w.toWei(weiPrice, false).toGas(price);
    }

    function unwrap(Dollar w) internal pure returns (uint256) {
        return Dollar.unwrap(w);
    }
}

library WeiPriceLib {
    using {mul, unwrap} for WeiPrice;

    function mul(WeiPrice a, uint256 b) internal pure returns (WeiPrice) {
        return WeiPrice.wrap(a.unwrap() * b);
    }

    function unwrap(WeiPrice w) internal pure returns (uint256) {
        return WeiPrice.unwrap(w);
    }
}

library GasPriceLib {
    using {unwrap, priceAsWei} for GasPrice;

    function priceAsWei(GasPrice w) internal pure returns (Wei) {
        return Wei.wrap(w.unwrap());
    }

    function unwrap(GasPrice w) internal pure returns (uint256) {
        return GasPrice.unwrap(w);
    }
}

library TargetNativeLib {
    using {unwrap, asNative} for TargetNative;

    function unwrap(TargetNative w) internal pure returns (uint256) {
        return TargetNative.unwrap(w);
    }

    function asNative(TargetNative w) internal pure returns (Wei) {
        return Wei.wrap(TargetNative.unwrap(w));
    }
}

library LocalNativeLib {
    using {unwrap, asNative} for LocalNative;

    function unwrap(LocalNative w) internal pure returns (uint256) {
        return LocalNative.unwrap(w);
    }

    function asNative(LocalNative w) internal pure returns (Wei) {
        return Wei.wrap(LocalNative.unwrap(w));
    }
}

File 9 of 20 : ERC1967Upgrade.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.2;

import "../beacon/IBeacon.sol";
import "../../utils/Address.sol";
import "../../utils/StorageSlot.sol";

/**
 * @dev This abstract contract provides getters and event emitting update functions for
 * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots.
 *
 * _Available since v4.1._
 *
 * @custom:oz-upgrades-unsafe-allow delegatecall
 */
abstract contract ERC1967Upgrade {
    // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1
    bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143;

    /**
     * @dev Storage slot with the address of the current implementation.
     * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;

    /**
     * @dev Emitted when the implementation is upgraded.
     */
    event Upgraded(address indexed implementation);

    /**
     * @dev Returns the current implementation address.
     */
    function _getImplementation() internal view returns (address) {
        return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 implementation slot.
     */
    function _setImplementation(address newImplementation) private {
        require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
        StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
    }

    /**
     * @dev Perform implementation upgrade
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeTo(address newImplementation) internal {
        _setImplementation(newImplementation);
        emit Upgraded(newImplementation);
    }

    /**
     * @dev Perform implementation upgrade with additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCall(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        _upgradeTo(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }
    }

    /**
     * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call.
     *
     * Emits an {Upgraded} event.
     */
    function _upgradeToAndCallSecure(
        address newImplementation,
        bytes memory data,
        bool forceCall
    ) internal {
        address oldImplementation = _getImplementation();

        // Initial upgrade and setup call
        _setImplementation(newImplementation);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(newImplementation, data);
        }

        // Perform rollback test if not already in progress
        StorageSlot.BooleanSlot storage rollbackTesting = StorageSlot.getBooleanSlot(_ROLLBACK_SLOT);
        if (!rollbackTesting.value) {
            // Trigger rollback using upgradeTo from the new implementation
            rollbackTesting.value = true;
            Address.functionDelegateCall(
                newImplementation,
                abi.encodeWithSignature("upgradeTo(address)", oldImplementation)
            );
            rollbackTesting.value = false;
            // Check rollback was effective
            require(oldImplementation == _getImplementation(), "ERC1967Upgrade: upgrade breaks further upgrades");
            // Finally reset to the new implementation and log the upgrade
            _upgradeTo(newImplementation);
        }
    }

    /**
     * @dev Storage slot with the admin of the contract.
     * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is
     * validated in the constructor.
     */
    bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103;

    /**
     * @dev Emitted when the admin account has changed.
     */
    event AdminChanged(address previousAdmin, address newAdmin);

    /**
     * @dev Returns the current admin.
     */
    function _getAdmin() internal view returns (address) {
        return StorageSlot.getAddressSlot(_ADMIN_SLOT).value;
    }

    /**
     * @dev Stores a new address in the EIP1967 admin slot.
     */
    function _setAdmin(address newAdmin) private {
        require(newAdmin != address(0), "ERC1967: new admin is the zero address");
        StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin;
    }

    /**
     * @dev Changes the admin of the proxy.
     *
     * Emits an {AdminChanged} event.
     */
    function _changeAdmin(address newAdmin) internal {
        emit AdminChanged(_getAdmin(), newAdmin);
        _setAdmin(newAdmin);
    }

    /**
     * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy.
     * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor.
     */
    bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50;

    /**
     * @dev Emitted when the beacon is upgraded.
     */
    event BeaconUpgraded(address indexed beacon);

    /**
     * @dev Returns the current beacon.
     */
    function _getBeacon() internal view returns (address) {
        return StorageSlot.getAddressSlot(_BEACON_SLOT).value;
    }

    /**
     * @dev Stores a new beacon in the EIP1967 beacon slot.
     */
    function _setBeacon(address newBeacon) private {
        require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract");
        require(
            Address.isContract(IBeacon(newBeacon).implementation()),
            "ERC1967: beacon implementation is not a contract"
        );
        StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon;
    }

    /**
     * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does
     * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that).
     *
     * Emits a {BeaconUpgraded} event.
     */
    function _upgradeBeaconToAndCall(
        address newBeacon,
        bytes memory data,
        bool forceCall
    ) internal {
        _setBeacon(newBeacon);
        emit BeaconUpgraded(newBeacon);
        if (data.length > 0 || forceCall) {
            Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data);
        }
    }
}

File 10 of 20 : IWormhole.sol
// contracts/Messages.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

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

    struct ContractUpgrade {
        bytes32 module;
        uint8 action;
        uint16 chain;

        address newContract;
    }

    struct GuardianSetUpgrade {
        bytes32 module;
        uint8 action;
        uint16 chain;

        GuardianSet newGuardianSet;
        uint32 newGuardianSetIndex;
    }

    struct SetMessageFee {
        bytes32 module;
        uint8 action;
        uint16 chain;

        uint256 messageFee;
    }

    struct TransferFees {
        bytes32 module;
        uint8 action;
        uint16 chain;

        uint256 amount;
        bytes32 recipient;
    }

    struct RecoverChainId {
        bytes32 module;
        uint8 action;

        uint256 evmChainId;
        uint16 newChainId;
    }

    event LogMessagePublished(address indexed sender, uint64 sequence, uint32 nonce, bytes payload, uint8 consistencyLevel);
    event ContractUpgraded(address indexed oldContract, address indexed newContract);
    event GuardianSetAdded(uint32 indexed index);

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

    function initialize() external;

    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 quorum(uint numGuardians) external pure returns (uint numSignaturesRequiredForQuorum);

    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 isFork() external view returns (bool);

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

    function parseContractUpgrade(bytes memory encodedUpgrade) external pure returns (ContractUpgrade memory cu);

    function parseGuardianSetUpgrade(bytes memory encodedUpgrade) external pure returns (GuardianSetUpgrade memory gsu);

    function parseSetMessageFee(bytes memory encodedSetMessageFee) external pure returns (SetMessageFee memory smf);

    function parseTransferFees(bytes memory encodedTransferFees) external pure returns (TransferFees memory tf);

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

    function submitContractUpgrade(bytes memory _vm) external;

    function submitSetMessageFee(bytes memory _vm) external;

    function submitNewGuardianSet(bytes memory _vm) external;

    function submitTransferFees(bytes memory _vm) external;

    function submitRecoverChainId(bytes memory _vm) external;
}

File 11 of 20 : Utils.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "../../interfaces/relayer/TypedUnits.sol";

error NotAnEvmAddress(bytes32);

function pay(address payable receiver, LocalNative amount) returns (bool success) {
  uint256 amount_ = LocalNative.unwrap(amount);
  if (amount_ != 0)
    // TODO: we currently ignore the return data. Some users of this function might want to bubble up the return value though.
    // Specifying a higher limit than 63/64 of the remaining gas caps it at that amount without throwing an exception.
    (success,) = returnLengthBoundedCall(receiver, new bytes(0), gasleft(), amount_, 0);
  else
    success = true;
}

function pay(address payable receiver, LocalNative amount, uint256 gasBound) returns (bool success) {
  uint256 amount_ = LocalNative.unwrap(amount);
  if (amount_ != 0)
    // TODO: we currently ignore the return data. Some users of this function might want to bubble up the return value though.
    // Specifying a higher limit than 63/64 of the remaining gas caps it at that amount without throwing an exception.
    (success,) = returnLengthBoundedCall(receiver, new bytes(0), gasBound, amount_, 0);
  else
    success = true;
}

function min(uint256 a, uint256 b) pure returns (uint256) {
  return a < b ? a : b;
}

function min(uint64 a, uint64 b) pure returns (uint64) {
  return a < b ? a : b;
}

function max(uint256 a, uint256 b) pure returns (uint256) {
  return a > b ? a : b;
}

function toWormholeFormat(address addr) pure returns (bytes32) {
  return bytes32(uint256(uint160(addr)));
}

function fromWormholeFormat(bytes32 whFormatAddress) pure returns (address) {
  if (uint256(whFormatAddress) >> 160 != 0)
    revert NotAnEvmAddress(whFormatAddress);
  return address(uint160(uint256(whFormatAddress)));
}

function fromWormholeFormatUnchecked(bytes32 whFormatAddress) pure returns (address) {
  return address(uint160(uint256(whFormatAddress)));
}


uint256 constant freeMemoryPtr = 0x40;
uint256 constant memoryWord = 32;
uint256 constant maskModulo32 = 0x1f;

/**
 * Overload with no 'value' and non-payable address
 */
function returnLengthBoundedCall(
  address callee,
  bytes memory callData,
  uint256 gasLimit,
  uint256 dataLengthBound
) returns (bool success, bytes memory returnedData) {
  return returnLengthBoundedCall(payable(callee), callData, gasLimit, 0, dataLengthBound);
}

/**
 * Implements call that truncates return data to a specific size to avoid excessive gas consumption for relayers
 * when a revert or unexpectedly large return value is produced by the call.
 *
 * @param returnedData Buffer of returned data truncated to the first `dataLengthBound` bytes.
 */
function returnLengthBoundedCall(
  address payable callee,
  bytes memory callData,
  uint256 gasLimit,
  uint256 value,
  uint256 dataLengthBound
) returns (bool success, bytes memory returnedData) {
  uint256 callDataLength = callData.length;
  assembly ("memory-safe") {
    returnedData := mload(freeMemoryPtr)
    let returnedDataBuffer := add(returnedData, memoryWord)
    let callDataBuffer := add(callData, memoryWord)

    success := call(gasLimit, callee, value, callDataBuffer, callDataLength, returnedDataBuffer, dataLengthBound)
    let returnedDataSize := returndatasize()
    switch lt(dataLengthBound, returnedDataSize)
    case 1 {
      returnedDataSize := dataLengthBound
    } default {}
    mstore(returnedData, returnedDataSize)

    // Here we update the free memory pointer.
    // We want to pad `returnedData` to memory word size, i.e. 32 bytes.
    // Note that negating bitwise `maskModulo32` produces a mask that aligns addressing to 32 bytes.
    // This allows us to pad the entire `bytes` structure (length + buffer) to 32 bytes at the end.
    // We add `maskModulo32` to get the next free memory "slot" in case the `returnedDataSize` is not a multiple of the memory word size.
    //
    // Rationale:
    // We do not care about the alignment of the free memory pointer. The solidity compiler documentation does not promise nor require alignment on it.
    // It does however lightly suggest to pad `bytes` structures to 32 bytes: https://docs.soliditylang.org/en/v0.8.20/assembly.html#example
    // Searching for "alignment" and "padding" in https://gitter.im/ethereum/solidity-dev
    // yielded the following at the time of writing – paraphrased:
    // > It's possible that the compiler cleans that padding in some cases. Users should not rely on the compiler never doing that.
    // This means that we want to ensure that the free memory pointer points to memory just after this padding for our `returnedData` `bytes` structure.
    let paddedPastTheEndOffset := and(add(returnedDataSize, maskModulo32), not(maskModulo32))
    let newFreeMemoryPtr := add(returnedDataBuffer, paddedPastTheEndOffset)
    mstore(freeMemoryPtr, newFreeMemoryPtr)
  }
}

File 12 of 20 : BytesParsing.sol
pragma solidity ^0.8.19;

library BytesParsing {
  uint256 private constant freeMemoryPtr = 0x40;
  uint256 private constant wordSize = 32;

  error OutOfBounds(uint256 offset, uint256 length);

  function checkBound(uint offset, uint length) internal pure {
    if (offset > length)
      revert OutOfBounds(offset, length);
  }

  function sliceUnchecked(
    bytes memory encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    //bail early for degenerate case
    if (length == 0)
      return (new bytes(0), offset);

    assembly ("memory-safe") {
      nextOffset := add(offset, length)
      ret := mload(freeMemoryPtr)

      //Explanation on how we copy data here:
      //  The bytes type has the following layout in memory:
      //    [length: 32 bytes, data: length bytes]
      //  So if we allocate `bytes memory foo = new bytes(1);` then `foo` will be a pointer to 33
      //    bytes where the first 32 bytes contain the length and the last byte is the actual data.
      //  Since mload always loads 32 bytes of memory at once, we use our shift variable to align
      //    our reads so that our last read lines up exactly with the last 32 bytes of `encoded`.
      //  However this also means that if the length of `encoded` is not a multiple of 32 bytes, our
      //    first read will necessarily partly contain bytes from `encoded`'s 32 length bytes that
      //    will be written into the length part of our `ret` slice.
      //  We remedy this issue by writing the length of our `ret` slice at the end, thus
      //    overwritting those garbage bytes.
      let shift := and(length, 31) //equivalent to `mod(length, 32)` but 2 gas cheaper
      if iszero(shift) {
        shift := wordSize
      }

      let dest := add(ret, shift)
      let end := add(dest, length)
      for {
        let src := add(add(encoded, shift), offset)
      } lt(dest, end) {
        src := add(src, wordSize)
        dest := add(dest, wordSize)
      } {
        mstore(dest, mload(src))
      }

      mstore(ret, length)
      //When compiling with --via-ir then normally allocated memory (i.e. via new) will have 32 byte
      //  memory alignment and so we enforce the same memory alignment here.
      mstore(freeMemoryPtr, and(add(dest, 31), not(31)))
    }
  }

  function slice(
    bytes memory encoded,
    uint offset,
    uint length
  ) internal pure returns (bytes memory ret, uint nextOffset) {
    (ret, nextOffset) = sliceUnchecked(encoded, offset, length);
    checkBound(nextOffset, encoded.length);
  }

  function asAddressUnchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (address, uint) {
    (uint160 ret, uint nextOffset) = asUint160(encoded, offset);
    return (address(ret), nextOffset);
  }

  function asAddress(
    bytes memory encoded,
    uint offset
  ) internal pure returns (address ret, uint nextOffset) {
    (ret, nextOffset) = asAddressUnchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBoolUnckecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bool, uint) {
    (uint8 ret, uint nextOffset) = asUint8(encoded, offset);
    return (ret != 0, nextOffset);
  }

  function asBool(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bool ret, uint nextOffset) {
    (ret, nextOffset) = asBoolUnckecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

/* -------------------------------------------------------------------------------------------------
Remaining library code below was auto-generated by via the following js/node code:

for (let bytes = 1; bytes <= 32; ++bytes) {
  const bits = bytes*8;
  console.log(
`function asUint${bits}Unchecked(
  bytes memory encoded,
  uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
  assembly ("memory-safe") {
    nextOffset := add(offset, ${bytes})
    ret := mload(add(encoded, nextOffset))
  }
  return (ret, nextOffset);
}

function asUint${bits}(
  bytes memory encoded,
  uint offset
) internal pure returns (uint${bits} ret, uint nextOffset) {
  (ret, nextOffset) = asUint${bits}Unchecked(encoded, offset);
  checkBound(nextOffset, encoded.length);
}

function asBytes${bytes}Unchecked(
  bytes memory encoded,
  uint offset
) internal pure returns (bytes${bytes}, uint) {
  (uint${bits} ret, uint nextOffset) = asUint${bits}Unchecked(encoded, offset);
  return (bytes${bytes}(ret), nextOffset);
}

function asBytes${bytes}(
  bytes memory encoded,
  uint offset
) internal pure returns (bytes${bytes}, uint) {
  (uint${bits} ret, uint nextOffset) = asUint${bits}(encoded, offset);
  return (bytes${bytes}(ret), nextOffset);
}
`
  );
}
------------------------------------------------------------------------------------------------- */

  function asUint8Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 1)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint8(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint8 ret, uint nextOffset) {
    (ret, nextOffset) = asUint8Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes1Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes1, uint) {
    (uint8 ret, uint nextOffset) = asUint8Unchecked(encoded, offset);
    return (bytes1(ret), nextOffset);
  }

  function asBytes1(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes1, uint) {
    (uint8 ret, uint nextOffset) = asUint8(encoded, offset);
    return (bytes1(ret), nextOffset);
  }

  function asUint16Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 2)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint16(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint16 ret, uint nextOffset) {
    (ret, nextOffset) = asUint16Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes2Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes2, uint) {
    (uint16 ret, uint nextOffset) = asUint16Unchecked(encoded, offset);
    return (bytes2(ret), nextOffset);
  }

  function asBytes2(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes2, uint) {
    (uint16 ret, uint nextOffset) = asUint16(encoded, offset);
    return (bytes2(ret), nextOffset);
  }

  function asUint24Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 3)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint24(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint24 ret, uint nextOffset) {
    (ret, nextOffset) = asUint24Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes3Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes3, uint) {
    (uint24 ret, uint nextOffset) = asUint24Unchecked(encoded, offset);
    return (bytes3(ret), nextOffset);
  }

  function asBytes3(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes3, uint) {
    (uint24 ret, uint nextOffset) = asUint24(encoded, offset);
    return (bytes3(ret), nextOffset);
  }

  function asUint32Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 4)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint32(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint32 ret, uint nextOffset) {
    (ret, nextOffset) = asUint32Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes4Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes4, uint) {
    (uint32 ret, uint nextOffset) = asUint32Unchecked(encoded, offset);
    return (bytes4(ret), nextOffset);
  }

  function asBytes4(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes4, uint) {
    (uint32 ret, uint nextOffset) = asUint32(encoded, offset);
    return (bytes4(ret), nextOffset);
  }

  function asUint40Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 5)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint40(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint40 ret, uint nextOffset) {
    (ret, nextOffset) = asUint40Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes5Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes5, uint) {
    (uint40 ret, uint nextOffset) = asUint40Unchecked(encoded, offset);
    return (bytes5(ret), nextOffset);
  }

  function asBytes5(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes5, uint) {
    (uint40 ret, uint nextOffset) = asUint40(encoded, offset);
    return (bytes5(ret), nextOffset);
  }

  function asUint48Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 6)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint48(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint48 ret, uint nextOffset) {
    (ret, nextOffset) = asUint48Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes6Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes6, uint) {
    (uint48 ret, uint nextOffset) = asUint48Unchecked(encoded, offset);
    return (bytes6(ret), nextOffset);
  }

  function asBytes6(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes6, uint) {
    (uint48 ret, uint nextOffset) = asUint48(encoded, offset);
    return (bytes6(ret), nextOffset);
  }

  function asUint56Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 7)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint56(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint56 ret, uint nextOffset) {
    (ret, nextOffset) = asUint56Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes7Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes7, uint) {
    (uint56 ret, uint nextOffset) = asUint56Unchecked(encoded, offset);
    return (bytes7(ret), nextOffset);
  }

  function asBytes7(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes7, uint) {
    (uint56 ret, uint nextOffset) = asUint56(encoded, offset);
    return (bytes7(ret), nextOffset);
  }

  function asUint64Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 8)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint64(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint64 ret, uint nextOffset) {
    (ret, nextOffset) = asUint64Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes8Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes8, uint) {
    (uint64 ret, uint nextOffset) = asUint64Unchecked(encoded, offset);
    return (bytes8(ret), nextOffset);
  }

  function asBytes8(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes8, uint) {
    (uint64 ret, uint nextOffset) = asUint64(encoded, offset);
    return (bytes8(ret), nextOffset);
  }

  function asUint72Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 9)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint72(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint72 ret, uint nextOffset) {
    (ret, nextOffset) = asUint72Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes9Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes9, uint) {
    (uint72 ret, uint nextOffset) = asUint72Unchecked(encoded, offset);
    return (bytes9(ret), nextOffset);
  }

  function asBytes9(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes9, uint) {
    (uint72 ret, uint nextOffset) = asUint72(encoded, offset);
    return (bytes9(ret), nextOffset);
  }

  function asUint80Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 10)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint80(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint80 ret, uint nextOffset) {
    (ret, nextOffset) = asUint80Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes10Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes10, uint) {
    (uint80 ret, uint nextOffset) = asUint80Unchecked(encoded, offset);
    return (bytes10(ret), nextOffset);
  }

  function asBytes10(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes10, uint) {
    (uint80 ret, uint nextOffset) = asUint80(encoded, offset);
    return (bytes10(ret), nextOffset);
  }

  function asUint88Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 11)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint88(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint88 ret, uint nextOffset) {
    (ret, nextOffset) = asUint88Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes11Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes11, uint) {
    (uint88 ret, uint nextOffset) = asUint88Unchecked(encoded, offset);
    return (bytes11(ret), nextOffset);
  }

  function asBytes11(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes11, uint) {
    (uint88 ret, uint nextOffset) = asUint88(encoded, offset);
    return (bytes11(ret), nextOffset);
  }

  function asUint96Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 12)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint96(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint96 ret, uint nextOffset) {
    (ret, nextOffset) = asUint96Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes12Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes12, uint) {
    (uint96 ret, uint nextOffset) = asUint96Unchecked(encoded, offset);
    return (bytes12(ret), nextOffset);
  }

  function asBytes12(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes12, uint) {
    (uint96 ret, uint nextOffset) = asUint96(encoded, offset);
    return (bytes12(ret), nextOffset);
  }

  function asUint104Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 13)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint104(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint104 ret, uint nextOffset) {
    (ret, nextOffset) = asUint104Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes13Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes13, uint) {
    (uint104 ret, uint nextOffset) = asUint104Unchecked(encoded, offset);
    return (bytes13(ret), nextOffset);
  }

  function asBytes13(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes13, uint) {
    (uint104 ret, uint nextOffset) = asUint104(encoded, offset);
    return (bytes13(ret), nextOffset);
  }

  function asUint112Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 14)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint112(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint112 ret, uint nextOffset) {
    (ret, nextOffset) = asUint112Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes14Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes14, uint) {
    (uint112 ret, uint nextOffset) = asUint112Unchecked(encoded, offset);
    return (bytes14(ret), nextOffset);
  }

  function asBytes14(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes14, uint) {
    (uint112 ret, uint nextOffset) = asUint112(encoded, offset);
    return (bytes14(ret), nextOffset);
  }

  function asUint120Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 15)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint120(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint120 ret, uint nextOffset) {
    (ret, nextOffset) = asUint120Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes15Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes15, uint) {
    (uint120 ret, uint nextOffset) = asUint120Unchecked(encoded, offset);
    return (bytes15(ret), nextOffset);
  }

  function asBytes15(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes15, uint) {
    (uint120 ret, uint nextOffset) = asUint120(encoded, offset);
    return (bytes15(ret), nextOffset);
  }

  function asUint128Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 16)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint128(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint128 ret, uint nextOffset) {
    (ret, nextOffset) = asUint128Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes16Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes16, uint) {
    (uint128 ret, uint nextOffset) = asUint128Unchecked(encoded, offset);
    return (bytes16(ret), nextOffset);
  }

  function asBytes16(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes16, uint) {
    (uint128 ret, uint nextOffset) = asUint128(encoded, offset);
    return (bytes16(ret), nextOffset);
  }

  function asUint136Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 17)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint136(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint136 ret, uint nextOffset) {
    (ret, nextOffset) = asUint136Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes17Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes17, uint) {
    (uint136 ret, uint nextOffset) = asUint136Unchecked(encoded, offset);
    return (bytes17(ret), nextOffset);
  }

  function asBytes17(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes17, uint) {
    (uint136 ret, uint nextOffset) = asUint136(encoded, offset);
    return (bytes17(ret), nextOffset);
  }

  function asUint144Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 18)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint144(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint144 ret, uint nextOffset) {
    (ret, nextOffset) = asUint144Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes18Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes18, uint) {
    (uint144 ret, uint nextOffset) = asUint144Unchecked(encoded, offset);
    return (bytes18(ret), nextOffset);
  }

  function asBytes18(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes18, uint) {
    (uint144 ret, uint nextOffset) = asUint144(encoded, offset);
    return (bytes18(ret), nextOffset);
  }

  function asUint152Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 19)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint152(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint152 ret, uint nextOffset) {
    (ret, nextOffset) = asUint152Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes19Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes19, uint) {
    (uint152 ret, uint nextOffset) = asUint152Unchecked(encoded, offset);
    return (bytes19(ret), nextOffset);
  }

  function asBytes19(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes19, uint) {
    (uint152 ret, uint nextOffset) = asUint152(encoded, offset);
    return (bytes19(ret), nextOffset);
  }

  function asUint160Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 20)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint160(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint160 ret, uint nextOffset) {
    (ret, nextOffset) = asUint160Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes20Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes20, uint) {
    (uint160 ret, uint nextOffset) = asUint160Unchecked(encoded, offset);
    return (bytes20(ret), nextOffset);
  }

  function asBytes20(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes20, uint) {
    (uint160 ret, uint nextOffset) = asUint160(encoded, offset);
    return (bytes20(ret), nextOffset);
  }

  function asUint168Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 21)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint168(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint168 ret, uint nextOffset) {
    (ret, nextOffset) = asUint168Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes21Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes21, uint) {
    (uint168 ret, uint nextOffset) = asUint168Unchecked(encoded, offset);
    return (bytes21(ret), nextOffset);
  }

  function asBytes21(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes21, uint) {
    (uint168 ret, uint nextOffset) = asUint168(encoded, offset);
    return (bytes21(ret), nextOffset);
  }

  function asUint176Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 22)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint176(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint176 ret, uint nextOffset) {
    (ret, nextOffset) = asUint176Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes22Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes22, uint) {
    (uint176 ret, uint nextOffset) = asUint176Unchecked(encoded, offset);
    return (bytes22(ret), nextOffset);
  }

  function asBytes22(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes22, uint) {
    (uint176 ret, uint nextOffset) = asUint176(encoded, offset);
    return (bytes22(ret), nextOffset);
  }

  function asUint184Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 23)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint184(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint184 ret, uint nextOffset) {
    (ret, nextOffset) = asUint184Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes23Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes23, uint) {
    (uint184 ret, uint nextOffset) = asUint184Unchecked(encoded, offset);
    return (bytes23(ret), nextOffset);
  }

  function asBytes23(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes23, uint) {
    (uint184 ret, uint nextOffset) = asUint184(encoded, offset);
    return (bytes23(ret), nextOffset);
  }

  function asUint192Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 24)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint192(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint192 ret, uint nextOffset) {
    (ret, nextOffset) = asUint192Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes24Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes24, uint) {
    (uint192 ret, uint nextOffset) = asUint192Unchecked(encoded, offset);
    return (bytes24(ret), nextOffset);
  }

  function asBytes24(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes24, uint) {
    (uint192 ret, uint nextOffset) = asUint192(encoded, offset);
    return (bytes24(ret), nextOffset);
  }

  function asUint200Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 25)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint200(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint200 ret, uint nextOffset) {
    (ret, nextOffset) = asUint200Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes25Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes25, uint) {
    (uint200 ret, uint nextOffset) = asUint200Unchecked(encoded, offset);
    return (bytes25(ret), nextOffset);
  }

  function asBytes25(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes25, uint) {
    (uint200 ret, uint nextOffset) = asUint200(encoded, offset);
    return (bytes25(ret), nextOffset);
  }

  function asUint208Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 26)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint208(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint208 ret, uint nextOffset) {
    (ret, nextOffset) = asUint208Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes26Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes26, uint) {
    (uint208 ret, uint nextOffset) = asUint208Unchecked(encoded, offset);
    return (bytes26(ret), nextOffset);
  }

  function asBytes26(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes26, uint) {
    (uint208 ret, uint nextOffset) = asUint208(encoded, offset);
    return (bytes26(ret), nextOffset);
  }

  function asUint216Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 27)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint216(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint216 ret, uint nextOffset) {
    (ret, nextOffset) = asUint216Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes27Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes27, uint) {
    (uint216 ret, uint nextOffset) = asUint216Unchecked(encoded, offset);
    return (bytes27(ret), nextOffset);
  }

  function asBytes27(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes27, uint) {
    (uint216 ret, uint nextOffset) = asUint216(encoded, offset);
    return (bytes27(ret), nextOffset);
  }

  function asUint224Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 28)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint224(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint224 ret, uint nextOffset) {
    (ret, nextOffset) = asUint224Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes28Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes28, uint) {
    (uint224 ret, uint nextOffset) = asUint224Unchecked(encoded, offset);
    return (bytes28(ret), nextOffset);
  }

  function asBytes28(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes28, uint) {
    (uint224 ret, uint nextOffset) = asUint224(encoded, offset);
    return (bytes28(ret), nextOffset);
  }

  function asUint232Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 29)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint232(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint232 ret, uint nextOffset) {
    (ret, nextOffset) = asUint232Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes29Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes29, uint) {
    (uint232 ret, uint nextOffset) = asUint232Unchecked(encoded, offset);
    return (bytes29(ret), nextOffset);
  }

  function asBytes29(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes29, uint) {
    (uint232 ret, uint nextOffset) = asUint232(encoded, offset);
    return (bytes29(ret), nextOffset);
  }

  function asUint240Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 30)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint240(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint240 ret, uint nextOffset) {
    (ret, nextOffset) = asUint240Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes30Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes30, uint) {
    (uint240 ret, uint nextOffset) = asUint240Unchecked(encoded, offset);
    return (bytes30(ret), nextOffset);
  }

  function asBytes30(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes30, uint) {
    (uint240 ret, uint nextOffset) = asUint240(encoded, offset);
    return (bytes30(ret), nextOffset);
  }

  function asUint248Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 31)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint248(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint248 ret, uint nextOffset) {
    (ret, nextOffset) = asUint248Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes31Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes31, uint) {
    (uint248 ret, uint nextOffset) = asUint248Unchecked(encoded, offset);
    return (bytes31(ret), nextOffset);
  }

  function asBytes31(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes31, uint) {
    (uint248 ret, uint nextOffset) = asUint248(encoded, offset);
    return (bytes31(ret), nextOffset);
  }

  function asUint256Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    assembly ("memory-safe") {
      nextOffset := add(offset, 32)
      ret := mload(add(encoded, nextOffset))
    }
    return (ret, nextOffset);
  }

  function asUint256(
    bytes memory encoded,
    uint offset
  ) internal pure returns (uint256 ret, uint nextOffset) {
    (ret, nextOffset) = asUint256Unchecked(encoded, offset);
    checkBound(nextOffset, encoded.length);
  }

  function asBytes32Unchecked(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes32, uint) {
    (uint256 ret, uint nextOffset) = asUint256Unchecked(encoded, offset);
    return (bytes32(ret), nextOffset);
  }

  function asBytes32(
    bytes memory encoded,
    uint offset
  ) internal pure returns (bytes32, uint) {
    (uint256 ret, uint nextOffset) = asUint256(encoded, offset);
    return (bytes32(ret), nextOffset);
  }
}

File 13 of 20 : IDeliveryProviderTyped.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "./TypedUnits.sol";

interface IDeliveryProvider {
    
    /**
     * @notice This function returns 
     *
     * 1) nativePriceQuote: the price of a delivery (by this delivery provider) to chain
     * 'targetChain', giving the user's contract 'receiverValue' target chain wei and performing the 
     * relay with the execution parameters (e.g. the gas limit) specified in 'encodedExecutionParameters'
     * 
     * 2) encodedExecutionInfo: information relating to how this delivery provider
     * will perform such a delivery (e.g. the gas limit, and the amount it will refund per gas unused)
     *
     * encodedExecutionParameters and encodedExecutionInfo both are encodings of versioned structs - 
     * version EVM_V1 of ExecutionParameters specifies the gas limit,
     * and version EVM_V1 of ExecutionInfo specifies the gas limit and the amount that this delivery provider 
     * will refund per unit of gas unused
     */
    function quoteDeliveryPrice(
        uint16 targetChain,
        TargetNative receiverValue,
        bytes memory encodedExecutionParams
    ) external view returns (LocalNative nativePriceQuote, bytes memory encodedExecutionInfo);

    /**
     * @notice This function returns the amount of extra 'receiverValue' (msg.value on the target chain) 
     * that will be sent to your contract, if you specify 'currentChainAmount' in the 
     * 'paymentForExtraReceiverValue' field on 'send'
     */
    function quoteAssetConversion(
        uint16 targetChain,
        LocalNative currentChainAmount
    ) external view returns (TargetNative targetChainAmount);

    /**
     * @notice This function should return a payable address on this (source) chain where all awards
     *     should be sent for the relay provider.
     */
    function getRewardAddress() external view returns (address payable rewardAddress);

    /**
     * @notice This function determines whether a relay provider supports deliveries to a given chain
     *     or not.
     *
     * @param targetChain - The chain which is being delivered to.
     */
    function isChainSupported(uint16 targetChain) external view returns (bool supported);

    /**
     * @notice This function determines whether a relay provider supports the given keyType.
     *      
     * Note: 0-127 are reserved for standardized keyTypes and 128-255 are allowed to be custom per DeliveryProvider
     *       Practically this means that 0-127 must mean the same thing for all DeliveryProviders,
     *       while x within 128-255 may have different meanings between DeliveryProviders 
     *       (e.g. 130 for provider A means pyth price quotes while 130 for provider B means tweets, 
     *       but 8 must mean the same for both)
     *
     * @param keyType - The keyType within MessageKey that specifies what the encodedKey within a MessageKey means
     */
    function isMessageKeyTypeSupported(uint8 keyType) external view returns (bool supported);

    /**
     * @notice This function returns a bitmap encoding all the keyTypes this provider supports
     *      
     * Note: 0-127 are reserved for standardized keyTypes and 128-255 are allowed to be custom per DeliveryProvider
     *       Practically this means that 0-127 must mean the same thing for all DeliveryProviders,
     *       while x within 128-255 may have different meanings between DeliveryProviders 
     *       (e.g. 130 for provider A means pyth price quotes while 130 for provider B means tweets, 
     *       but 8 must mean the same for both)
     */
    function getSupportedKeys() external view returns (uint256 bitmap);

    /**
     * @notice If a DeliveryProvider supports a given chain, this function should provide the contract
     *      address (in wormhole format) of the relay provider on that chain.
     *
     * @param targetChain - The chain which is being delivered to.
     */
    function getTargetChainAddress(uint16 targetChain)
        external
        view
        returns (bytes32 deliveryProviderAddress);
}

File 14 of 20 : RelayerInternalStructs.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import "../../interfaces/relayer/TypedUnits.sol";
import "../../interfaces/relayer/IWormholeRelayerTyped.sol";

struct DeliveryInstruction {
    uint16 targetChain;
    bytes32 targetAddress;
    bytes payload;
    TargetNative requestedReceiverValue;
    TargetNative extraReceiverValue;
    bytes encodedExecutionInfo;
    uint16 refundChain;
    bytes32 refundAddress;
    bytes32 refundDeliveryProvider;
    bytes32 sourceDeliveryProvider;
    bytes32 senderAddress;
    MessageKey[] messageKeys;
}

// Meant to hold all necessary values for `CoreRelayerDelivery::executeInstruction`
// Nothing more and nothing less.
struct EvmDeliveryInstruction {
  uint16 sourceChain;
  bytes32 targetAddress;
  bytes payload;
  Gas gasLimit;
  TargetNative totalReceiverValue;
  GasPrice targetChainRefundPerGasUnused;
  bytes32 senderAddress;
  bytes32 deliveryHash;
  bytes[] signedVaas;
}

struct RedeliveryInstruction {
    VaaKey deliveryVaaKey;
    uint16 targetChain;
    TargetNative newRequestedReceiverValue;
    bytes newEncodedExecutionInfo;
    bytes32 newSourceDeliveryProvider;
    bytes32 newSenderAddress;
}

/**
 * @notice When a user requests a `resend()`, a `RedeliveryInstruction` is emitted by the
 *     WormholeRelayer and in turn converted by the relay provider into an encoded (=serialized)
 *     `DeliveryOverride` struct which is then passed to `delivery()` to override the parameters of
 *     a previously failed delivery attempt.
 *
 * @custom:member newReceiverValue - must >= than the `receiverValue` specified in the original
 *     `DeliveryInstruction`
 * @custom:member newExecutionInfo - for EVM_V1, must contain a gasLimit and targetChainRefundPerGasUnused
 * such that 
 * - gasLimit is >= the `gasLimit` specified in the `executionParameters`
 *     of the original `DeliveryInstruction`
 * - targetChainRefundPerGasUnused is >=  the `targetChainRefundPerGasUnused` specified in the original
 *     `DeliveryInstruction`
 * @custom:member redeliveryHash - the hash of the redelivery which is being performed
 */
struct DeliveryOverride {
    TargetNative newReceiverValue;
    bytes newExecutionInfo;
    bytes32 redeliveryHash;
}

File 15 of 20 : WormholeRelayerSerde.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import {
    InvalidPayloadId,
    InvalidPayloadLength,
    InvalidVaaKeyType,
    TooManyMessageKeys,
    MessageKey,
    VAA_KEY_TYPE,
    VaaKey
} from "../../interfaces/relayer/IWormholeRelayerTyped.sol";
import {
    DeliveryOverride,
    DeliveryInstruction,
    RedeliveryInstruction
} from "../../relayer/libraries/RelayerInternalStructs.sol";
import {BytesParsing} from "../../relayer/libraries/BytesParsing.sol";
import "../../interfaces/relayer/TypedUnits.sol";

library WormholeRelayerSerde {
    using BytesParsing for bytes;
    using WeiLib for Wei;
    using GasLib for Gas;

    //The slightly subtle difference between `PAYLOAD_ID`s and `VERSION`s is that payload ids carry
    //  both type information _and_ version information, while `VERSION`s only carry the latter.
    //That is, when deserialing a "version struct" we already know the expected type, but since we
    //  publish both Delivery _and_ Redelivery instructions as serialized messages, we need a robust
    //  way to distinguish both their type and their version during deserialization.
    uint8 private constant VERSION_VAAKEY = 1;
    uint8 private constant VERSION_DELIVERY_OVERRIDE = 1;
    uint8 private constant PAYLOAD_ID_DELIVERY_INSTRUCTION = 1;
    uint8 private constant PAYLOAD_ID_REDELIVERY_INSTRUCTION = 2;

    uint256 constant VAA_KEY_TYPE_LENGTH = 2 + 32 + 8;

    // ---------------------- "public" (i.e implicitly internal) encode/decode -----------------------

    //TODO GAS OPTIMIZATION: All the recursive abi.encodePacked calls in here are _insanely_ gas
    //    inefficient (unless the optimizer is smart enough to just concatenate them tail-recursion
    //    style which seems highly unlikely)

    function encode(DeliveryInstruction memory strct)
        internal
        pure
        returns (bytes memory encoded)
    {
        encoded = abi.encodePacked(
            PAYLOAD_ID_DELIVERY_INSTRUCTION,
            strct.targetChain,
            strct.targetAddress,
            encodeBytes(strct.payload),
            strct.requestedReceiverValue,
            strct.extraReceiverValue
        );
        encoded = abi.encodePacked(
            encoded,
            encodeBytes(strct.encodedExecutionInfo),
            strct.refundChain,
            strct.refundAddress,
            strct.refundDeliveryProvider,
            strct.sourceDeliveryProvider,
            strct.senderAddress,
            encodeMessageKeyArray(strct.messageKeys)
        );
    }

    function decodeDeliveryInstruction(bytes memory encoded)
        internal
        pure
        returns (DeliveryInstruction memory strct)
    {
        uint256 offset = checkUint8(encoded, 0, PAYLOAD_ID_DELIVERY_INSTRUCTION);

        uint256 requestedReceiverValue;
        uint256 extraReceiverValue;

        (strct.targetChain, offset) = encoded.asUint16Unchecked(offset);
        (strct.targetAddress, offset) = encoded.asBytes32Unchecked(offset);
        (strct.payload, offset) = decodeBytes(encoded, offset);
        (requestedReceiverValue, offset) = encoded.asUint256Unchecked(offset);
        (extraReceiverValue, offset) = encoded.asUint256Unchecked(offset);
        (strct.encodedExecutionInfo, offset) = decodeBytes(encoded, offset);
        (strct.refundChain, offset) = encoded.asUint16Unchecked(offset);
        (strct.refundAddress, offset) = encoded.asBytes32Unchecked(offset);
        (strct.refundDeliveryProvider, offset) = encoded.asBytes32Unchecked(offset);
        (strct.sourceDeliveryProvider, offset) = encoded.asBytes32Unchecked(offset);
        (strct.senderAddress, offset) = encoded.asBytes32Unchecked(offset);
        (strct.messageKeys, offset) = decodeMessageKeyArray(encoded, offset);

        strct.requestedReceiverValue = TargetNative.wrap(requestedReceiverValue);
        strct.extraReceiverValue = TargetNative.wrap(extraReceiverValue);

        checkLength(encoded, offset);
    }

    function encode(RedeliveryInstruction memory strct)
        internal
        pure
        returns (bytes memory encoded)
    {
        bytes memory vaaKey = abi.encodePacked(VAA_KEY_TYPE, encodeVaaKey(strct.deliveryVaaKey));
        encoded = abi.encodePacked(
            PAYLOAD_ID_REDELIVERY_INSTRUCTION,
            vaaKey,
            strct.targetChain,
            strct.newRequestedReceiverValue,
            encodeBytes(strct.newEncodedExecutionInfo),
            strct.newSourceDeliveryProvider,
            strct.newSenderAddress
        );
    }

    function decodeRedeliveryInstruction(bytes memory encoded)
        internal
        pure
        returns (RedeliveryInstruction memory strct)
    {
        uint256 offset = checkUint8(encoded, 0, PAYLOAD_ID_REDELIVERY_INSTRUCTION);

        uint256 newRequestedReceiverValue;
        offset = checkUint8(encoded, offset, VAA_KEY_TYPE);
        (strct.deliveryVaaKey, offset) = decodeVaaKey(encoded, offset);
        (strct.targetChain, offset) = encoded.asUint16Unchecked(offset);
        (newRequestedReceiverValue, offset) = encoded.asUint256Unchecked(offset);
        (strct.newEncodedExecutionInfo, offset) = decodeBytes(encoded, offset);
        (strct.newSourceDeliveryProvider, offset) = encoded.asBytes32Unchecked(offset);
        (strct.newSenderAddress, offset) = encoded.asBytes32Unchecked(offset);

        strct.newRequestedReceiverValue = TargetNative.wrap(newRequestedReceiverValue);

        checkLength(encoded, offset);
    }

    function encode(DeliveryOverride memory strct) internal pure returns (bytes memory encoded) {
        encoded = abi.encodePacked(
            VERSION_DELIVERY_OVERRIDE,
            strct.newReceiverValue,
            encodeBytes(strct.newExecutionInfo),
            strct.redeliveryHash
        );
    }

    function decodeDeliveryOverride(bytes memory encoded)
        internal
        pure
        returns (DeliveryOverride memory strct)
    {
        uint256 offset = checkUint8(encoded, 0, VERSION_DELIVERY_OVERRIDE);

        uint256 receiverValue;

        (receiverValue, offset) = encoded.asUint256Unchecked(offset);
        (strct.newExecutionInfo, offset) = decodeBytes(encoded, offset);
        (strct.redeliveryHash, offset) = encoded.asBytes32Unchecked(offset);

        strct.newReceiverValue = TargetNative.wrap(receiverValue);

        checkLength(encoded, offset);
    }

    function vaaKeyArrayToMessageKeyArray(VaaKey[] memory vaaKeys)
        internal
        pure
        returns (MessageKey[] memory msgKeys)
    {
        msgKeys = new MessageKey[](vaaKeys.length);
        uint256 len = vaaKeys.length;
        for (uint256 i = 0; i < len;) {
            msgKeys[i] = MessageKey(VAA_KEY_TYPE, encodeVaaKey(vaaKeys[i]));
            unchecked {
                ++i;
            }
        }
    }

    function encodeMessageKey(
        MessageKey memory msgKey
    ) internal pure returns (bytes memory encoded) {
        if (msgKey.keyType == VAA_KEY_TYPE) {
            // known length
            encoded = abi.encodePacked(msgKey.keyType, msgKey.encodedKey);
        } else {
            encoded = abi.encodePacked(msgKey.keyType, encodeBytes(msgKey.encodedKey));
        }
    }

    function decodeMessageKey(
        bytes memory encoded,
        uint256 startOffset
    ) internal pure returns (MessageKey memory msgKey, uint256 offset) {
        (msgKey.keyType, offset) = encoded.asUint8Unchecked(startOffset);
        if (msgKey.keyType == VAA_KEY_TYPE) {
            (msgKey.encodedKey, offset) = encoded.sliceUnchecked(offset, VAA_KEY_TYPE_LENGTH);
        } else {
            (msgKey.encodedKey, offset) = decodeBytes(encoded, offset);
        }
    }

    function encodeVaaKey(VaaKey memory vaaKey) internal pure returns (bytes memory encoded) {
        encoded = abi.encodePacked(vaaKey.chainId, vaaKey.emitterAddress, vaaKey.sequence);
    }

    function decodeVaaKey(
        bytes memory encoded,
        uint256 startOffset
    ) internal pure returns (VaaKey memory vaaKey, uint256 offset) {
        offset = startOffset;
        (vaaKey.chainId, offset) = encoded.asUint16Unchecked(offset);
        (vaaKey.emitterAddress, offset) = encoded.asBytes32Unchecked(offset);
        (vaaKey.sequence, offset) = encoded.asUint64Unchecked(offset);
    }

    function encodeMessageKeyArray(MessageKey[] memory msgKeys)
        internal
        pure
        returns (bytes memory encoded)
    {
        uint256 len = msgKeys.length;
        if (len > type(uint8).max) {
            revert TooManyMessageKeys(len);
        }
        encoded = abi.encodePacked(uint8(msgKeys.length));
        for (uint256 i = 0; i < len;) {
            encoded = abi.encodePacked(encoded, encodeMessageKey(msgKeys[i]));
            unchecked {
                ++i;
            }
        }
    }

    function decodeMessageKeyArray(
        bytes memory encoded,
        uint256 startOffset
    ) internal pure returns (MessageKey[] memory msgKeys, uint256 offset) {
        uint8 msgKeysLength;
        (msgKeysLength, offset) = encoded.asUint8Unchecked(startOffset);
        msgKeys = new MessageKey[](msgKeysLength);
        for (uint256 i = 0; i < msgKeysLength;) {
            (msgKeys[i], offset) = decodeMessageKey(encoded, offset);
            unchecked {
                ++i;
            }
        }
    }

    // ------------------------------------------ private --------------------------------------------

    function encodeBytes(bytes memory payload) private pure returns (bytes memory encoded) {
        //casting payload.length to uint32 is safe because you'll be hard-pressed to allocate 4 GB of
        //  EVM memory in a single transaction
        encoded = abi.encodePacked(uint32(payload.length), payload);
    }

    function decodeBytes(
        bytes memory encoded,
        uint256 startOffset
    ) private pure returns (bytes memory payload, uint256 offset) {
        uint32 payloadLength;
        (payloadLength, offset) = encoded.asUint32Unchecked(startOffset);
        (payload, offset) = encoded.sliceUnchecked(offset, payloadLength);
    }

    function checkUint8(
        bytes memory encoded,
        uint256 startOffset,
        uint8 expectedPayloadId
    ) private pure returns (uint256 offset) {
        uint8 parsedPayloadId;
        (parsedPayloadId, offset) = encoded.asUint8Unchecked(startOffset);
        if (parsedPayloadId != expectedPayloadId) {
            revert InvalidPayloadId(parsedPayloadId, expectedPayloadId);
        }
    }

    function checkLength(bytes memory encoded, uint256 expected) private pure {
        if (encoded.length != expected) {
            revert InvalidPayloadLength(encoded.length, expected);
        }
    }
}

File 16 of 20 : ExecutionParameters.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.19;

import "../../interfaces/relayer/TypedUnits.sol";
import {BytesParsing} from "../../relayer/libraries/BytesParsing.sol";

error UnexpectedExecutionParamsVersion(uint8 version, uint8 expectedVersion);
error UnsupportedExecutionParamsVersion(uint8 version);
error TargetChainAndExecutionParamsVersionMismatch(uint16 targetChain, uint8 version);
error UnexpectedExecutionInfoVersion(uint8 version, uint8 expectedVersion);
error UnsupportedExecutionInfoVersion(uint8 version);
error TargetChainAndExecutionInfoVersionMismatch(uint16 targetChain, uint8 version);
error VersionMismatchOverride(uint8 instructionVersion, uint8 overrideVersion);

using BytesParsing for bytes;

enum ExecutionParamsVersion {EVM_V1}

struct EvmExecutionParamsV1 {
    Gas gasLimit;
}

enum ExecutionInfoVersion {EVM_V1}

struct EvmExecutionInfoV1 {
    Gas gasLimit;
    GasPrice targetChainRefundPerGasUnused;
}

function decodeExecutionParamsVersion(bytes memory data)
    pure
    returns (ExecutionParamsVersion version)
{
    (version) = abi.decode(data, (ExecutionParamsVersion));
}

function decodeExecutionInfoVersion(bytes memory data)
    pure
    returns (ExecutionInfoVersion version)
{
    (version) = abi.decode(data, (ExecutionInfoVersion));
}

function encodeEvmExecutionParamsV1(EvmExecutionParamsV1 memory executionParams)
    pure
    returns (bytes memory)
{
    return abi.encode(uint8(ExecutionParamsVersion.EVM_V1), executionParams.gasLimit);
}

function decodeEvmExecutionParamsV1(bytes memory data)
    pure
    returns (EvmExecutionParamsV1 memory executionParams)
{
    uint8 version;
    (version, executionParams.gasLimit) = abi.decode(data, (uint8, Gas));

    if (version != uint8(ExecutionParamsVersion.EVM_V1)) {
        revert UnexpectedExecutionParamsVersion(version, uint8(ExecutionParamsVersion.EVM_V1));
    }
}

function encodeEvmExecutionInfoV1(EvmExecutionInfoV1 memory executionInfo)
    pure
    returns (bytes memory)
{
    return abi.encode(
        uint8(ExecutionInfoVersion.EVM_V1),
        executionInfo.gasLimit,
        executionInfo.targetChainRefundPerGasUnused
    );
}

function decodeEvmExecutionInfoV1(bytes memory data)
    pure
    returns (EvmExecutionInfoV1 memory executionInfo)
{
    uint8 version;
    (version, executionInfo.gasLimit, executionInfo.targetChainRefundPerGasUnused) =
        abi.decode(data, (uint8, Gas, GasPrice));

    if (version != uint8(ExecutionInfoVersion.EVM_V1)) {
        revert UnexpectedExecutionInfoVersion(version, uint8(ExecutionInfoVersion.EVM_V1));
    }
}

function getEmptyEvmExecutionParamsV1()
    pure
    returns (EvmExecutionParamsV1 memory executionParams)
{
    executionParams.gasLimit = Gas.wrap(uint256(0));
}

File 17 of 20 : IWormholeReceiver.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

/**
 * @notice Interface for a contract which can receive Wormhole messages.
 */
interface IWormholeReceiver {
    /**
     * @notice When a `send` is performed with this contract as the target, this function will be
     *     invoked by the WormholeRelayer contract
     *
     * NOTE: This function should be restricted such that only the Wormhole Relayer contract can call it.
     *
     * We also recommend that this function:
     *   - Stores all received `deliveryHash`s in a mapping `(bytes32 => bool)`, and
     *       on every call, checks that deliveryHash has not already been stored in the
     *       map (This is to prevent other users maliciously trying to relay the same message)
     *   - Checks that `sourceChain` and `sourceAddress` are indeed who
     *       you expect to have requested the calling of `send` on the source chain
     *
     * The invocation of this function corresponding to the `send` request will have msg.value equal
     *   to the receiverValue specified in the send request.
     *
     * If the invocation of this function reverts or exceeds the gas limit 
     *   specified by the send requester, this delivery will result in a `ReceiverFailure`.
     *
     * @param payload - an arbitrary message which was included in the delivery by the
     *     requester.
     * @param additionalVaas - Additional VAAs which were requested to be included in this delivery.
     *   They are guaranteed to all be included and in the same order as was specified in the
     *     delivery request.
     * @param sourceAddress - the (wormhole format) address on the sending chain which requested
     *     this delivery.
     * @param sourceChain - the wormhole chain ID where this delivery was requested.
     * @param deliveryHash - the VAA hash of the deliveryVAA.
     *
     * NOTE: These signedVaas are NOT verified by the Wormhole core contract prior to being provided
     *     to this call. Always make sure `parseAndVerify()` is called on the Wormhole core contract
     *     before trusting the content of a raw VAA, otherwise the VAA may be invalid or malicious.
     */
    function receiveWormholeMessages(
        bytes memory payload,
        bytes[] memory additionalVaas,
        bytes32 sourceAddress,
        uint16 sourceChain,
        bytes32 deliveryHash
    ) external payable;
}

File 18 of 20 : IBeacon.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev This is the interface that {BeaconProxy} expects of its beacon.
 */
interface IBeacon {
    /**
     * @dev Must return an address that can be used as a delegate call target.
     *
     * {BeaconProxy} will check that this address is a contract.
     */
    function implementation() external view returns (address);
}

File 19 of 20 : Address.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @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
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize, which returns 0 for contracts in
        // construction, since the code is only stored at the end of the
        // constructor execution.

        uint256 size;
        assembly {
            size := extcodesize(account)
        }
        return size > 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 functionCall(target, data, "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");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(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) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason 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 {
            // 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

                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 20 of 20 : StorageSlot.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        assembly {
            r.slot := slot
        }
    }
}

Settings
{
  "remappings": [
    "@openzeppelin/=node_modules/@openzeppelin/",
    "@solidity-parser/=node_modules/@solidity-parser/",
    "ds-test/=lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/forge-std/src/",
    "truffle/=node_modules/truffle/",
    "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/",
    "openzeppelin-contracts/=lib/openzeppelin-contracts/",
    "openzeppelin/=lib/openzeppelin-contracts/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":"wormhole","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"registeredWormholeRelayerContract","type":"bytes32"}],"name":"ChainAlreadyRegistered","type":"error"},{"inputs":[{"internalType":"bytes","name":"failure","type":"bytes"}],"name":"ContractUpgradeFailed","type":"error"},{"inputs":[],"name":"DeliveryProviderCannotReceivePayment","type":"error"},{"inputs":[{"internalType":"uint8","name":"keyType","type":"uint8"}],"name":"DeliveryProviderDoesNotSupportMessageKeyType","type":"error"},{"inputs":[{"internalType":"address","name":"relayer","type":"address"},{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"DeliveryProviderDoesNotSupportTargetChain","type":"error"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"GovernanceActionAlreadyConsumed","type":"error"},{"inputs":[{"internalType":"LocalNative","name":"msgValue","type":"uint256"},{"internalType":"LocalNative","name":"minimum","type":"uint256"}],"name":"InsufficientRelayerFunds","type":"error"},{"inputs":[{"internalType":"bytes32","name":"defaultDeliveryProvider","type":"bytes32"}],"name":"InvalidDefaultDeliveryProvider","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"InvalidDeliveryVaa","type":"error"},{"inputs":[{"internalType":"bytes32","name":"emitter","type":"bytes32"},{"internalType":"bytes32","name":"registered","type":"bytes32"},{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"InvalidEmitter","type":"error"},{"inputs":[],"name":"InvalidFork","type":"error"},{"inputs":[{"internalType":"uint16","name":"parsed","type":"uint16"},{"internalType":"uint16","name":"expected","type":"uint16"}],"name":"InvalidGovernanceChainId","type":"error"},{"inputs":[{"internalType":"bytes32","name":"parsed","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidGovernanceContract","type":"error"},{"inputs":[{"internalType":"string","name":"reason","type":"string"}],"name":"InvalidGovernanceVM","type":"error"},{"inputs":[{"internalType":"LocalNative","name":"msgValue","type":"uint256"},{"internalType":"LocalNative","name":"totalFee","type":"uint256"}],"name":"InvalidMsgValue","type":"error"},{"inputs":[],"name":"InvalidOverrideGasLimit","type":"error"},{"inputs":[],"name":"InvalidOverrideReceiverValue","type":"error"},{"inputs":[{"internalType":"uint8","name":"parsed","type":"uint8"},{"internalType":"uint8","name":"expected","type":"uint8"}],"name":"InvalidPayloadAction","type":"error"},{"inputs":[{"internalType":"uint16","name":"parsed","type":"uint16"},{"internalType":"uint16","name":"expected","type":"uint16"}],"name":"InvalidPayloadChainId","type":"error"},{"inputs":[{"internalType":"uint8","name":"parsed","type":"uint8"},{"internalType":"uint8","name":"expected","type":"uint8"}],"name":"InvalidPayloadId","type":"error"},{"inputs":[{"internalType":"uint256","name":"received","type":"uint256"},{"internalType":"uint256","name":"expected","type":"uint256"}],"name":"InvalidPayloadLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"parsed","type":"bytes32"},{"internalType":"bytes32","name":"expected","type":"bytes32"}],"name":"InvalidPayloadModule","type":"error"},{"inputs":[{"internalType":"uint256","name":"keys","type":"uint256"},{"internalType":"uint256","name":"vaas","type":"uint256"}],"name":"MessageKeysLengthDoesNotMatchMessagesLength","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"NotAnEvmAddress","type":"error"},{"inputs":[{"internalType":"address","name":"msgSender","type":"address"},{"internalType":"address","name":"lockedBy","type":"address"}],"name":"ReentrantDelivery","type":"error"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"}],"name":"TargetChainIsNotThisChain","type":"error"},{"inputs":[{"internalType":"uint256","name":"numMessageKeys","type":"uint256"}],"name":"TooManyMessageKeys","type":"error"},{"inputs":[{"internalType":"uint8","name":"version","type":"uint8"},{"internalType":"uint8","name":"expectedVersion","type":"uint8"}],"name":"UnexpectedExecutionInfoVersion","type":"error"},{"inputs":[{"internalType":"uint8","name":"index","type":"uint8"}],"name":"VaaKeysDoNotMatchVaas","type":"error"},{"inputs":[{"internalType":"uint8","name":"instructionVersion","type":"uint8"},{"internalType":"uint8","name":"overrideVersion","type":"uint8"}],"name":"VersionMismatchOverride","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldContract","type":"address"},{"indexed":true,"internalType":"address","name":"newContract","type":"address"}],"name":"ContractUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"recipientContract","type":"address"},{"indexed":true,"internalType":"uint16","name":"sourceChain","type":"uint16"},{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"deliveryVaaHash","type":"bytes32"},{"indexed":false,"internalType":"enum IWormholeRelayerDelivery.DeliveryStatus","name":"status","type":"uint8"},{"indexed":false,"internalType":"Gas","name":"gasUsed","type":"uint256"},{"indexed":false,"internalType":"enum IWormholeRelayerDelivery.RefundStatus","name":"refundStatus","type":"uint8"},{"indexed":false,"internalType":"bytes","name":"additionalStatusInfo","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"overridesInfo","type":"bytes"}],"name":"Delivery","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"LocalNative","name":"deliveryQuote","type":"uint256"},{"indexed":false,"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"}],"name":"SendEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"checkAndExecuteUpgradeMigration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"encodedVMs","type":"bytes[]"},{"internalType":"bytes","name":"encodedDeliveryVAA","type":"bytes"},{"internalType":"address payable","name":"relayerRefundAddress","type":"address"},{"internalType":"bytes","name":"deliveryOverrides","type":"bytes"}],"name":"deliver","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"deliveryHash","type":"bytes32"}],"name":"deliveryAttempted","outputs":[{"internalType":"bool","name":"attempted","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"deliveryHash","type":"bytes32"}],"name":"deliveryFailureBlock","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"deliveryHash","type":"bytes32"}],"name":"deliverySuccessBlock","outputs":[{"internalType":"uint256","name":"blockNumber","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetAddress","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"","type":"uint256"},{"internalType":"bytes","name":"encodedExecutionParameters","type":"bytes"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"forward","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"}],"name":"forwardPayloadToEvm","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"address","name":"refundAddress","type":"address"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"forwardToEvm","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"}],"name":"forwardVaasToEvm","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"getDefaultDeliveryProvider","outputs":[{"internalType":"address","name":"deliveryProvider","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"getRegisteredWormholeRelayerContract","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"defaultDeliveryProvider","type":"address"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"bytes","name":"encodedExecutionParameters","type":"bytes"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"}],"name":"quoteDeliveryPrice","outputs":[{"internalType":"LocalNative","name":"nativePriceQuote","type":"uint256"},{"internalType":"bytes","name":"encodedExecutionInfo","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"}],"name":"quoteEVMDeliveryPrice","outputs":[{"internalType":"LocalNative","name":"nativePriceQuote","type":"uint256"},{"internalType":"GasPrice","name":"targetChainRefundPerGasUnused","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"}],"name":"quoteEVMDeliveryPrice","outputs":[{"internalType":"LocalNative","name":"nativePriceQuote","type":"uint256"},{"internalType":"GasPrice","name":"targetChainRefundPerGasUnused","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"LocalNative","name":"currentChainAmount","type":"uint256"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"}],"name":"quoteNativeForChain","outputs":[{"internalType":"TargetNative","name":"targetChainAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVm","type":"bytes"}],"name":"registerWormholeRelayerContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey","name":"deliveryVaaKey","type":"tuple"},{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"TargetNative","name":"newReceiverValue","type":"uint256"},{"internalType":"bytes","name":"newEncodedExecutionParameters","type":"bytes"},{"internalType":"address","name":"newDeliveryProviderAddress","type":"address"}],"name":"resend","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey","name":"deliveryVaaKey","type":"tuple"},{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"TargetNative","name":"newReceiverValue","type":"uint256"},{"internalType":"Gas","name":"newGasLimit","type":"uint256"},{"internalType":"address","name":"newDeliveryProviderAddress","type":"address"}],"name":"resendToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetAddress","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"},{"internalType":"bytes","name":"encodedExecutionParameters","type":"bytes"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"send","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"targetAddress","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"},{"internalType":"bytes","name":"encodedExecutionParameters","type":"bytes"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint8","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"encodedKey","type":"bytes"}],"internalType":"struct MessageKey[]","name":"messageKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"send","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"address","name":"refundAddress","type":"address"}],"name":"sendPayloadToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"}],"name":"sendPayloadToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"address","name":"refundAddress","type":"address"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"sendToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"LocalNative","name":"paymentForExtraReceiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"address","name":"refundAddress","type":"address"},{"internalType":"address","name":"deliveryProviderAddress","type":"address"},{"components":[{"internalType":"uint8","name":"keyType","type":"uint8"},{"internalType":"bytes","name":"encodedKey","type":"bytes"}],"internalType":"struct MessageKey[]","name":"messageKeys","type":"tuple[]"},{"internalType":"uint8","name":"consistencyLevel","type":"uint8"}],"name":"sendToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"}],"name":"sendVaasToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"targetAddress","type":"address"},{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"TargetNative","name":"receiverValue","type":"uint256"},{"internalType":"Gas","name":"gasLimit","type":"uint256"},{"components":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"emitterAddress","type":"bytes32"},{"internalType":"uint64","name":"sequence","type":"uint64"}],"internalType":"struct VaaKey[]","name":"vaaKeys","type":"tuple[]"},{"internalType":"uint16","name":"refundChain","type":"uint16"},{"internalType":"address","name":"refundAddress","type":"address"}],"name":"sendVaasToEvm","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVm","type":"bytes"}],"name":"setDefaultDeliveryProvider","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"encodedVm","type":"bytes"}],"name":"submitContractUpgrade","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60c080604052346200013f57602081620046d5803803809162000023828562000144565b8339810103126200013f57516001600160a01b038116908190036200013f5760208160049260805260405192838092634d4502c960e11b82525afa9081156200013357600091620000e9575b5060a05260405161455690816200017f82396080518181816106a401528181610aad015281816112040152818161162a0152818161198601528181612d750152818161300f01528181613a19015261400a015260a0518181816109ad0152818161123d0152818161166a015281816119c70152612b860152f35b6020813d82116200012a575b81620001046020938362000144565b810103126200012657519061ffff82168203620001235750386200006f565b80fd5b5080fd5b3d9150620000f5565b6040513d6000823e3d90fd5b600080fd5b601f909101601f19168101906001600160401b038211908210176200016857604052565b634e487b7160e01b600052604160045260246000fdfe60a080604052600436101561001357600080fd5b60003560e01c9081632385904a14611a885750806324320c9f14611a5257806328b1d852146118935780632c75470f14611877578063329a2be71461184557806332b2fc0e146117ab5780633a2c767d1461176c5780633e8267e7146117125780633ed334df146114f957806340984f08146114c05780634533e5ff1461143e5780634b5ca6f4146113aa5780634d48ec60146113535780635a3b92e81461131a5780635cb8cae21461100557806375ea8b5814610fd957806380ebabd014610fa55780638b0301b114610f615780638fecdd0214610f1e578063a60eb4c81461055e578063a79629d8146104ef578063b1eac87514610464578063b686d0891461040d578063c055120e14610354578063c23ee3c314610303578063c4d66de8146102a1578063c81fb7fe14610270578063cee4bda0146101c85763d0625a191461015e57600080fd5b346101c35760203660031901126101c3576004356000526000805160206144e1833981519152602052604060002054158015906101a3575b6020906040519015158152f35b506000805160206145018339815191526020526040600020541515610196565b600080fd5b6101603660031901126101c3576101dd611b29565b6001600160401b036044358181116101c3576101fd903690600401611ca6565b9160a4358281116101c357610216903690600401611ca6565b9261021f611b3a565b93610228611bb4565b61012435938585116101c35760209661024861026796369060040161206f565b93610251611e6c565b9560e435936084359160643591602435906135e6565b60405191168152f35b602061029061027e36611f87565b99989098979197969296959395613522565b6001600160401b0360405191168152f35b346101c35760203660031901126101c3576004356001600160a01b038116908190036101c35760016000546102d960ff82161561212c565b60ff19161760005560008051602061448183398151915280546001600160a01b0319169091179055005b346101c35760603660031901126101c3576040610348610321611b29565b600080516020614481833981519152546001600160a01b03169060443590602435906141f4565b82519182526020820152f35b6101603660031901126101c357610369611b29565b610371611b5c565b906001600160401b03906044358281116101c357610393903690600401611ca6565b9261039c611b3a565b916103a5611b72565b906103ae611bb4565b9061012435948686116101c3576020976103cf61026797369060040161206f565b946103d8611e6c565b966103f26040516103e881611bcb565b60a4358152612e02565b9260018060a01b0380931695608435936064359316906135e6565b60e03660031901126101c35761042236611d04565b61042a611b4b565b60a4356001600160401b03918282116101c357602093610451610267933690600401611ca6565b9061045a611b88565b9260843591613dfa565b6104ed61048d61047336611dfb565b9590604094929394519061048682611bcb565b8152612e02565b9061ffff6000805160206144a18339815191525416926000805160206144c1833981519152549460018060a01b0396876000805160206144818339815191525416976104e56104de8a888786614224565b5034612a00565b941690613469565b005b346101c35760803660031901126101c357610508611b29565b604435906001600160401b0382116101c35761052b61053d923690600401611ca6565b610533611b9e565b9160243590614224565b9061055a604051928392835260406020840152604083019061204a565b0390f35b60803660031901126101c3576004356001600160401b0381116101c357366023820112156101c357806004013561059481611ced565b916105a26040519384611c6a565b8183526024602084019260051b820101903682116101c35760248101925b828410610eef57846024356001600160401b0381116101c3576105e7903690600401611ca6565b906001600160a01b0360443581811681036101c3576064356001600160401b0381116101c35761061b903690600401611ca6565b7f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a675483811680610ed157506001600160a01b03191633177f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a675560405163607ec5ef60e11b81526020600482015293946000908590819061069f90602483019061204a565b0381867f0000000000000000000000000000000000000000000000000000000000000000165afa8015610bdb57600094600090600092610ea6575b5015610e815750606084015161ffff1660009081527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d6020526040902054608085015190808203610e5457505060e0840151836040519361073a85611bfc565b6000855260006020860152606060408601526000606086015260006080860152606060a0860152600060c0860152600060e086015260006101008601526000610120860152600061014086015260606101608601526107ba602261079d8561444d565b858101600281015161ffff1689528201516020890152018461442e565b93906040870152838101906107db604080602085015194015196018261442e565b959060a089015260838087840161ffff60028201511660c08c0152602281015160e08c015260428101516101008c015260628101516101208c015260828101516101408c0152015196019261083260ff88166142df565b6000975b60ff81168910610d9d575061085d959697506101608a015260608901526080880152613283565b61ffff60c08501511660e08501519061ffff196000805160206144a18339815191525416176000805160206144a1833981519152556000805160206144c18339815191525561ffff606087015116956101406001600160401b0360a08301511691015190604051976108ce89611c18565b8852602088015260408701521660608501528460808501528160a0850152600060c0850152600060e0850152600061010085015280610120850152600061014085015260009061092160a0840151612410565b61092a816123f0565b80610d64575061093d60a084015161242d565b908051610c50575b50602081519101519161096160608501516080860151906123e3565b906101408701526101008601528160e08601528060c0860152818102918183041490151715610c3a57610100840151610999916123e3565b803410610c1d575061ffff8151168061ffff7f00000000000000000000000000000000000000000000000000000000000000001603610c05575061016001519081518451808203610be757505081519360005b858110610a57576109fc856124c0565b6000805160206144a1833981519152805461ffff1916905560006000805160206144c1833981519152557f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a6780546001600160a01b0319169055005b600160ff610a658387612fdb565b51511614610a76575b6001016109ec565b610aa86000610a858385612fdb565b516040518093819263a9e1189360e01b835260206004840152602483019061204a565b0381877f0000000000000000000000000000000000000000000000000000000000000000165afa908115610bdb57600091610b9a575b506020610aeb8387612fdb565b51015160405191610afb83611c34565b600083526020830192600084526001600160401b03602a60408301946000865261ffff600282015116809452602281015180975201511680935261ffff6060830151161492831593610b8b575b508215610b73575b505015610a6e57604051633ad7858760e21b815260ff9091166004820152602490fd5b60a001516001600160401b0316141590508780610b50565b60808201511415925089610b48565b3d9150816000823e610bac8282611c6a565b60208183810103126101c35780516001600160401b0381116101c357610bd592820191016121dc565b87610ade565b6040513d6000823e3d90fd5b60449250604051916365c1f7cd60e01b835260048301526024820152fd5b6024906040519063d8215fc960e01b82526004820152fd5b60449060405190620885af60e61b82523460048301526024820152fd5b634e487b7160e01b600052601160045260246000fd5b604051919250610c5f82611c34565b60008252610cab602083019160608352600060408501526020610c818261444d565b610c938280838601015192018461442e565b91908652828285010151604088015286520190613283565b606084015160006020604051610cc081611c4f565b8281520152825110610d5257610cd68151612410565b610cdf816123f0565b80610d275750610cef905161242d565b908051928251905111610d15576040919260608501526000608085015201519086610945565b6040516315fc687d60e31b8152600490fd5b80610d336044926123f0565b60ff6040519163170cd96160e11b835260006004840152166024820152fd5b604051631c6e090160e31b8152600490fd5b80610d71610d99926123f0565b60405163c1f4bdd960e01b815260ff9091166004820152600060248201529081906044820190565b0390fd5b9193959796509193610dad6142c5565b96600191828082019189010151908360ff829316808c5214600014610e39575060405190600a90818301916034840190828c01015b818410610e29575050602a808452601f909201601f191660405260208b019290925260ff939291015b98610e168287612fdb565b5201918b97959391509795939197610836565b8051845260209384019301610de2565b60ff93929150610e49908961442e565b9060208b0152610e0b565b6064925061ffff6060870151169060405192633bb6036760e11b8452600484015260248301526044820152fd5b60405163b72c3b7f60e01b815260206004820152908190610d9990602483019061204a565b915050610ec79194503d806000833e610ebf8183611c6a565b810190612383565b90949194876106da565b604490604051906320b84ced60e01b82523360048301526024820152fd5b83356001600160401b0381116101c357602091610f13839260243691870101611ca6565b8152019301926105c0565b6020610290610f2c36611f2f565b9060018060a0969495961b0360008051602061448183398151915254169360405195610f5787611bcb565b60008752846132ae565b60e03660031901126101c3576020610290610f7b36611d04565b610f83611b4b565b610f8b611b88565b91610f9b6040516103e881611bcb565b9160843591613dfa565b346101c35760803660031901126101c3576040610348610fc3611b29565b610fcb611b9e565b9060443590602435906141f4565b6104ed610fe536611f87565b9993955097610fff6104de83878a889c969c9b979b614224565b93613522565b346101c3576020806003193601126101c3576004356001600160401b0381116101c357611036903690600401611ca6565b60018060a01b03917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9261106d8185541693613005565b828101516e576f726d686f6c6552656c617965728082036112fc57505060ff602182015116600281036112dd5750602381015161ffff908181168015806112d5575b156111f0575b5050506110ce6110c86043830151612a0d565b91613258565b803b15611195571692836bffffffffffffffffffffffff60a01b825416179055600080604051857fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2632c75470f60e01b818501908152600482529061113581611c4f565b519082305af190611144612e20565b91156111735750507f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a49600080a3005b610d9960405192839263135687c760e31b84526004840152602483019061204a565b60405162461bcd60e51b815260048101849052602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b60405163380e7c8960e21b815286816004817f00000000000000000000000000000000000000000000000000000000000000008a165afa908115610bdb576000916112a0575b5061128e577f00000000000000000000000000000000000000000000000000000000000000009283160361126a57806110b5565b60405163901f6ae360e01b815261ffff918216600482015291166024820152604490fd5b60405163ea03b6eb60e01b8152600490fd5b90508681813d83116112ce575b6112b78183611c6a565b810103126101c3576112c890612376565b89611236565b503d6112ad565b5060006110af565b60449060405190633460202560e21b8252600482015260026024820152fd5b6044925060405191633d254c6160e01b835260048301526024820152fd5b346101c35760203660031901126101c3576004356000526000805160206145018339815191526020526020604060002054604051908152f35b6104ed61137d61136236611e7d565b9a919894909995506040979297969396519061048682611bcb565b9361138a88868584614224565b506001600160a01b0397881697906113a29034612a00565b941690613522565b60e03660031901126101c3576113be611b29565b6113c6611b5c565b906001600160401b03906044358281116101c3576113e8903690600401611ca6565b60a4359161ffff831683036101c35760209461026793611406611b88565b9160018060a01b036000805160206144818339815191525416936040519561142d87611bcb565b60008752608435926064359261338d565b6104ed61145f61144d36611f2f565b60409591939295519061048682611bcb565b61ffff6000805160206144a18339815191525416916000805160206144c1833981519152549360018060a01b039687600080516020614481833981519152541696604051986114ad8a611bcb565b60008a526104e56104de8a888786614224565b346101c35760203660031901126101c3576004356000526000805160206144e18339815191526020526020604060002054604051908152f35b346101c3576020806003193601126101c3576004356001600160401b0381116101c35761152d611532913690600401611ca6565b613005565b90808201516e576f726d686f6c6552656c617965728082036112fc57505060ff602183015116600181036116f35750602382015161ffff90818116908115806116eb575b15611616575b5050602583015160458401519351604581036115f757501690816000527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d91828252604060002054806115d9575060005252604060002055600080f35b6044925060405191637b5672c560e11b835260048301526024820152fd5b6044906040519063061bc83560e51b8252600482015260456024820152fd5b60405163380e7c8960e21b815284816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bdb576000916116b6575b5061128e577f0000000000000000000000000000000000000000000000000000000000000000918383161461157c5760405163901f6ae360e01b815261ffff918216600482015291166024820152604490fd5b90508481813d83116116e4575b6116cd8183611c6a565b810103126101c3576116de90612376565b86611663565b503d6116c3565b506001611576565b60449060405190633460202560e21b8252600482015260016024820152fd5b346101c35760203660031901126101c3576020611764611730611b29565b61ffff166000527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d60205260406000205490565b604051908152f35b602061029061179661177d36611e7d565b9a90999198979295946040979497519061048682611bcb565b6001600160a01b039586169790951690613522565b6101003660031901126101c3576117c0611b29565b6117c8611b5c565b6001600160401b03906044358281116101c3576117e9903690600401611ca6565b9060a435918383116101c357602094611809610267943690600401611d50565b92611812611b3a565b9061181b611b72565b600080516020614481833981519152546001600160a01b031694909360843592606435929161338d565b602061029061185336611dfb565b949260018060a09493941b03600080516020614481833981519152541694846132ae565b346101c35760003660031901126101c3576104ed30331461212c565b346101c3576020806003193601126101c3576004356001600160401b0381116101c35761152d6118c7913690600401611ca6565b90808201516e576f726d686f6c6552656c617965728082036112fc57505060ff60218301511660038103611a335750602382015161ffff9182821690811580611a2b575b15611972575b505050506043810151906119276110c883612a0d565b6001600160a01b031690811561195a575060008051602061448183398151915280546001600160a01b0319169091179055005b60249060405190637a8ad12560e01b82526004820152fd5b60405163380e7c8960e21b815281816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa918215610bdb576000926119f5575b505061128e577f00000000000000000000000000000000000000000000000000000000000000009283160361126a578080611911565b90809250813d8311611a24575b611a0c8183611c6a565b810103126101c357611a1d90612376565b85806119bf565b503d611a02565b50600061190b565b60449060405190633460202560e21b8252600482015260036024820152fd5b346101c35760003660031901126101c357600080516020614481833981519152546040516001600160a01b039091168152602090f35b346101c35760603660031901126101c357611aa1611b29565b6044356001600160a01b03811691908290036101c357630cbcf9e160e21b835261ffff1660048301526024803590830152602090829060449082905afa8015610bdb57600090611af7575b602090604051908152f35b506020813d8211611b21575b81611b1060209383611c6a565b810103126101c35760209051611aec565b3d9150611b03565b6004359061ffff821682036101c357565b60c4359061ffff821682036101c357565b6064359061ffff821682036101c357565b602435906001600160a01b03821682036101c357565b60e435906001600160a01b03821682036101c357565b60c435906001600160a01b03821682036101c357565b606435906001600160a01b03821682036101c357565b61010435906001600160a01b03821682036101c357565b602081019081106001600160401b03821117611be657604052565b634e487b7160e01b600052604160045260246000fd5b61018081019081106001600160401b03821117611be657604052565b61016081019081106001600160401b03821117611be657604052565b606081019081106001600160401b03821117611be657604052565b604081019081106001600160401b03821117611be657604052565b90601f801991011681019081106001600160401b03821117611be657604052565b6001600160401b038111611be657601f01601f191660200190565b81601f820112156101c357803590611cbd82611c8b565b92611ccb6040519485611c6a565b828452602083830101116101c357816000926020809301838601378301015290565b6001600160401b038111611be65760051b60200190565b60609060031901126101c35760405190611d1d82611c34565b8160043561ffff811681036101c35781526024356020820152604435906001600160401b03821682036101c35760400152565b81601f820112156101c357803590611d6782611ced565b92604090611d7782519586611c6a565b83855260209182860191836060809702860101948186116101c3578401925b858410611da7575050505050505090565b86848303126101c357825190611dbc82611c34565b843561ffff811681036101c3578252858501358683015283850135906001600160401b03821682036101c357828792868b950152815201930192611d96565b60c06003198201126101c35760043561ffff811681036101c357916024356001600160a01b03811681036101c357916001600160401b03906044358281116101c35781611e4a91600401611ca6565b92606435926084359260a4359182116101c357611e6991600401611d50565b90565b610144359060ff821682036101c357565b906101606003198301126101c35761ffff9060043582811681036101c357926001600160a01b039160243583811681036101c357936001600160401b036044358181116101c35784611ed191600401611ca6565b94606435946084359460a4359460c43590811681036101c3579360e43584811681036101c357936101043590811681036101c35792610124359182116101c357611f1d91600401611d50565b906101443560ff811681036101c35790565b60a06003198201126101c35760043561ffff811681036101c357916024356001600160a01b03811681036101c35791604435906001600160401b0382116101c357611f7c91600401611ca6565b906064359060843590565b6101606003198201126101c35761ffff9160043583811681036101c35792602435926001600160401b03916044358381116101c35782611fc991600401611ca6565b93606435936084359360a4358281116101c35781611fe991600401611ca6565b9360c43590811681036101c3579260e43592610104356001600160a01b03811681036101c35792610124359182116101c357611f1d91600401611d50565b60005b83811061203a5750506000910152565b818101518382015260200161202a565b9060209161206381518092818552858086019101612027565b601f01601f1916010190565b81601f820112156101c35780359061208682611ced565b9260409261209684519586611c6a565b808552602093848087019260051b850101938385116101c357858101925b8584106120c5575050505050505090565b6001600160401b0384358181116101c35783019184601f1984890301126101c35784516120f181611c4f565b8984013560ff811681036101c3578152858401359283116101c35761211d888b80969581960101611ca6565b838201528152019301926120b4565b1561213357565b634e487b7160e01b600052600160045260246000fd5b519060ff821682036101c357565b519063ffffffff821682036101c357565b519061ffff821682036101c357565b51906001600160401b03821682036101c357565b9092919261219881611c8b565b916121a66040519384611c6a565b8294828452828201116101c35760206121c0930190612027565b565b9080601f830112156101c3578151611e699260200161218b565b9190610160838203126101c3576040928351916121f883611c18565b829461220383612149565b84526020612212818501612157565b81860152612221828501612157565b828601526060612232818601612168565b81870152608091828601518388015261224d60a08701612177565b60a088015261225e60c08701612149565b60c088015260e0860151936001600160401b03948581116101c357866122859189016121c2565b60e0890152610100612298818901612157565b9089015261012094858801518181116101c35788019387601f860112156101c3578451926122c584611ced565b986122d282519a8b611c6a565b848a5285808b019560071b880101968188116101c3578601945b87861061230b5750505050505050505083015261014080910151910152565b88868303126101c3578251908982019082821087831117612361578a9289928652885181528289015183820152612343868a01612149565b86820152612352878a01612149565b878201528152019501946122ec565b60246000634e487b7160e01b81526041600452fd5b519081151582036101c357565b90916060828403126101c3578151926001600160401b03938481116101c357816123ae9185016121dc565b936123bb60208501612376565b9360408101519182116101c357019080601f830112156101c3578151611e699260200161218b565b91908201809211610c3a57565b600111156123fa57565b634e487b7160e01b600052602160045260246000fd5b6020818051810103126101c3576020015160018110156101c35790565b906040519161243b83611c4f565b60008352602083019060008252836060828051810103126101c35761246260208301612149565b926060604084015193015190525260ff811661247b5750565b60405163c1f4bdd960e01b815260ff91909116600482015260006024820152604490fd5b604051906124ac82611c34565b606060408360008152600060208201520152565b60a0810151602081015115612927575060006124da61249f565b5060408281015182526000805160206144e183398151915260205281205415612688575060405161250a81611c4f565b601a81527f44656c697665727920616c726561647920706572666f726d656400000000000060208201526040519061254182611c34565b600082526001602083015260408201525b60a08201519060018060a01b036060840151169161257660c0850151835190612a00565b9260e085015193848102948186041490151715610c3a57602083015160028110156123fa5784600160009214612669575b6125b0916123e3565b9360e0830151801560001461264857506005945b9260068610156123fa576126159361260f928715801561263e575b612635575b6126056125ff846080606061260a96970151910151906123e3565b34612a00565b612a00565b6123e3565b90612b25565b15612623576121c092612a39565b6040516304aeb27d60e51b8152600490fd5b600091506125e4565b50600288146125df565b612663908661ffff60c0870151169161010087015192612b7a565b946125c4565b6125b0915061268160608501516080860151906123e3565b91506125a7565b61ffff8251169060a0830151602081015160408201519160c08601519061010087015161014060e08901519201519260408901519560808a015195604051998a6101208101106001600160401b036101208d01111761291357908a9594939291610120612781999c016040528652602086015260408501526060840152608083015260a082015260c0810191825260e08101938452610100810195865261272d61249f565b9560608201519260018060a01b036127486020850151612a0d565b16956040840151925191519061ffff85511690519160405197889563294ee51960e11b602088015260a0602488015260c487019061204a565b602319868203016044870152845180825260208201916020808360051b8301019701928d915b8383106128dc5750505050509260849285926020956064612823999801528484015260a483015203956127e2601f1997888101835282611c6a565b60805a940151978151906040519985808c0194019189f1943d806084106001146128d4575b80601f9189520116860101604052604087019485525a90612a00565b90808210156128cd57505b8452156128bf576040519061284282611bcb565b8282525260208201525b602081015160028110156123fa5760408301519061289e576000526000805160206144e18339815191526020524360406000205560008051602061450183398151915260205260006040812055612552565b60005260008051602061450183398151915260205243604060002055612552565b50506001602082015261284c565b905061282e565b506084612807565b9193985091939495966020806128fe600193601f198682030187528c5161204a565b9a019301930190928b989796959492936127a7565b634e487b7160e01b8a52604160045260248afd5b606082810151908201805160808401805190936001600160a01b0316929161294f91906123e3565b60e0850151909485826129e1575050506005935b60068510156123fa576129939361260f92861580156129d7575b6129ce575b61260a916125ff91519051906123e3565b15612623576040516121c0926129a882611bcb565b60008252604051916129b983611c34565b60008352600060208401526040830152612a39565b60009250612982565b506002871461297d565b6129fa9261010061ffff60c08501511693015192612b7a565b93612963565b91908203918211610c3a57565b8060a01c612a21576001600160a01b031690565b6024906040519063033b960d60e41b82526004820152fd5b90612a4b602060a08401510151612a0d565b61ffff835116926001600160401b036020820151169460408201519160208501519460028610156123fa578051604090910151610140830151909260009115612b0f5761012091500151955b6040519485526020850152604084015260068210156123fa577fbccc00b713f54173962e7de6098f643d8ebf53d488d71f4b2a5171496d038f9e93612af1612b0a928594606086015260c0608086015260c085019061204a565b83810360a08501526001600160a01b039091169561204a565b0390a4565b5060405190612b1d82611bcb565b815295612a97565b908015612b7357600060209181604051612b3e81611bcb565b5281805a926040519686880194f1913d801515600114612b6b575b808252601f01601f1916010160405290565b506000612b59565b5050600190565b90929161ffff808316907f0000000000000000000000000000000000000000000000000000000000000000168114612ce457612bb584612a0d565b6000918283612bd1604051612bc981611bcb565b828152612e02565b93612c0c6040519586926020978893849384830199635cf3af3360e11b8b52602484015287604484015260606064840152608483019061204a565b0393612c20601f1995868101835282611c6a565b51604051978389019a8b9360018060a01b0316620186a0f1913d808310600114612cdd575b808752601f011685010160405280612cd3575b15612cc85750508051810103126101c357519360015b158015612cbe575b8015612ca9575b612c9f57612c99611e6995612605612c93612d60565b85612a00565b92612e50565b5050505050600490565b50612cb68561260a612d60565b821115612c7d565b5084821115612c76565b925096925050612c6e565b5083835114612c58565b5081612c45565b50926001600160a01b039250612cfa9150612a0d565b168115612d5757600060209181604051612d1381611bcb565b5281806040519585870193620186a0f1913d801515600114612d4f575b808252601f01601f191601016040525b15612d4a57600090565b600190565b506000612d30565b50506001612d40565b604051631a90a21960e01b81526020816004817f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165afa908115610bdb57600091612db1575090565b906020823d8211612dda575b81612dca60209383611c6a565b81010312612dd757505190565b80fd5b3d9150612dbd565b611e69939261ffff6060931682526020820152816040820152019061204a565b516040519060006020830152604082015260408152611e6981611c34565b3d15612e4b573d90612e3182611c8b565b91612e3f6040519384611c6a565b82523d6000602084013e565b606090565b939192612ef193604092835193612e6685611bcb565b600095868652612e8b612e858351612e7d81611bcb565b898152612e02565b91612a0d565b825193612e9785611bcb565b8885528351998a9763640fdbff60e11b8952612ed261ffff809e169a8b60048c01528c60248c015261016060448c01526101648b019061204a565b908b60648b015260848a015260031994858a83030160a48b015261204a565b60c488019890985260e48701526001600160a01b0316610104860152848603016101248501528151808652602098899687019387019288915b838310612fa057505050505082809160c8610144830152039130620186a0f19283612f6a575b505050612f6557612f5f612e20565b50600390565b600290565b82813d8311612f99575b612f7e8183611c6a565b81010312612dd75750612f9090612177565b50388080612f50565b503d612f74565b8451805182168752898101518a8801528201516001600160401b0316828701528b988b98506060909601959094019360019290920191612f2a565b8051821015612fef5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b9060018060a01b037f00000000000000000000000000000000000000000000000000000000000000001691604061305e81519263607ec5ef60e11b8452602095600491878387015285806000958693602483019061204a565b0381845afa801561319c57839584908592613236575b50156132135750835163fbe3c2cd60e01b815287818481855afa9081156132095784916131d0575b5061ffff908160608801511691811682036131a65750508682918551928380926358b9591160e11b82525afa90811561319c57839161316b575b506080850151818103613150575050610140840195865183527f970ad24d4754c92e299cabb86552091f5df0a15abc0f1b71f37d3e30031585dc9182825260ff8585205416613139575060e095965183525220600160ff19825416179055015190565b875185516364cbf47160e01b815291820152602490fd5b84516342852f8d60e11b815292830152602482015260449150fd5b90508681813d8311613195575b6131828183611c6a565b810103126131915751386130d6565b8280fd5b503d613178565b84513d85823e3d90fd5b855163c97817ed60e01b815261ffff92831685820190815291909216602082015281900360400190fd5b90508781813d8311613202575b6131e78183611c6a565b810103126131fe576131f890612168565b3861309c565b8380fd5b503d6131dd565b85513d86823e3d90fd5b8451630169d68560e71b8152808401899052908190610d9990602483019061204a565b91505061324e9195503d8085833e610ebf8183611c6a565b9095919538613074565b51604381036132645750565b6044906040519063061bc83560e51b8252600482015260436024820152fd5b5190808203613290575050565b604492506040519163061bc83560e51b835260048301526024820152fd5b9194909395929796976132c960409788519061048682611bcb565b906132d48a516142df565b968a5160005b818110613347575050611e69999a508851986132f58a611c18565b61ffff8096168a5260018060a01b0380981660208b015289015260608801526000608088015260a08701521660c0850152600060e085015216610100830152610120820152600f61014082015261364f565b61335a613354828f612fdb565b5161432f565b908b5161336681611c4f565b600192838252602082015261337b828d612fdb565b52613386818c612fdb565b50016132da565b909295919693949897986133a960409687519061048682611bcb565b6133b38b516142df565b978b5160005b818110613427575050611e699a9b508751996133d48b611c18565b61ffff8095168b5260018060a01b03988980981660208d01528b015260608a0152600060808a015260a08901521660c08701521660e085015216610100830152610120820152600f61014082015261364f565b6134356133548f8390612fdb565b908b613457828d519261344784611c4f565b6001958685526020850152612fdb565b52613462818d612fdb565b50016133b9565b93909795929998999694919661347f8b516142df565b978b5160005b8181106134ef575050611e699a9b50604051996134a18b611c18565b61ffff9687168b5260208b015260408a01526060890152608088015260a08701521660c085015260e08401526001600160a01b0316610100830152610120820152600f61014082015261364f565b6134fd6133548f8390612fdb565b908b613510826040519261344784611c4f565b5261351b818d612fdb565b5001613485565b9390989a99979592969491966135388c516142df565b978c5160005b8181106135b3575050611e699b9c509060ff9998979695949392916040519b6135668d611c18565b61ffff9687168d5260208d015260408c015260608b015260808a015260a08901521660c087015260e08601526001600160a01b03166101008501526101208401521661014082015261364f565b6135c18f8261335491612fdb565b908b6135d4826040519261344784611c4f565b526135df818d612fdb565b500161353e565b9293611e699a979460ff9996929a97936040519b6135668d611c18565b9190916040818403126101c35780519260208201516001600160401b0381116101c357611e6992016121c2565b908160209103126101c357516001600160a01b03811681036101c35790565b60018060a01b03610100820151169161ffff825116604051906328f41de360e01b82526004820152602081602481875afa908115610bdb57600091613cf2575b5015613cbe5761ffff825116926000606084015160a0850151956136c76040519788938493635cf3af3360e11b855260048501612de2565b0381845afa938415610bdb576000908195613c98575b506136e6612d60565b60808501516136f98261260a83866123e3565b3403613c6d575061370f61012086015184613d2c565b845160208087015160408089015160608a015160808b01519251630cbcf9e160e21b815261ffff871660048201526024810193909352929a9093909190816044818b5afa908115610bdb5788928b91600093613c33575b5061ffff60c08301511690602061ffff60e0850151945116602460405180988193633d77cbfd60e01b835260048301525afa938415610bdb578e968e96600096613bed575b509260839895926138a59a989592613842989561012060018060a01b0361010089015116970151976137e260405180608052611bfc565b61ffff8c16608051526020608051015288604060805101526060608051015260808051015260a0608051015260c0608051015260e060805101526101006080510152610120608051015233610140608051015261016060805101526143ec565b6080519060806060830151920151906040519b8c94600160f81b602087015261ffff60f01b9060f01b166021860152602385015261388a815180926020604388019101612027565b83019160438301526063820152036063810189520187611c6a565b6138b460a060805101516143ec565b6080519660c088015160e0890151906101008a0151996101208101516101606101408301519201519b8c519460ff8611613bd4578d5160405160f89190911b6001600160f81b03191660208201526001815261390f81611c4f565b956000905b808210613b1b5750506004999a9b9c9d509160a29593916139a7979593604051998761394a8c995180926020808d019101612027565b880161395f8251809360208085019101612027565b019461ffff60f01b9060f01b16602086015260228501526042840152606283015260828201526139988251809360208785019101612027565b01036082810184520182611c6a565b602060ff61014060808a0151990151169560405194858092632fe4c87f60e21b82525afa928315610bdb57600093613ae3575b50602091613a0d916040518097819482936358cd21bf60e11b84526000600485015260606024850152606484019061204a565b604483019190915203917f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03165af1928315610bdb57600093613aa4575b50613a619061260f86846123e3565b9360405191825260208201527fda8540426b64ece7b164a9dce95448765f0a7263ef3ff85091c9c7361e48536460406001600160401b03841692a2911561262357565b90926020823d602011613adb575b81613abf60209383611c6a565b81010312612dd75750613ad4613a6191612177565b9290613a52565b3d9150613ab2565b613a0d91935091613b0b602093843d8611613b14575b613b038183611c6a565b810190613630565b939150916139da565b503d613af9565b90968f90613ba46020613b308b600195612fdb565b51805160ff16858103613bac5750613b6a8260ff83511692015191613b5c60405193849286840161429d565b03601f198101835282611c6a565b925b6040519381613b848693518092868087019101612027565b8201613b9882518093868085019101612027565b01038084520182611c6a565b970190613914565b90613bbc83613bce9201516143ec565b91613b5c60405193849286840161429d565b92613b6c565b6040516312d6a5c760e01b815260048101879052602490fd5b92949650965091936020823d602011613c2b575b81613c0e60209383611c6a565b81010312612dd75750518d958d95919491939192906138426137ab565b3d9150613c01565b92915092506020823d602011613c65575b81613c5160209383611c6a565b81010312612dd757505187918a9038613766565b3d9150613c44565b9061260a613c7d926044946123e3565b60405190631f89f67160e01b82523460048301526024820152fd5b90613cb69295503d8091833e613cae8183611c6a565b810190613603565b9390386136dd565b5061010081015190516040516366b69b9d60e01b81526001600160a01b03909216600483015261ffff166024820152604490fd5b906020823d602011613d24575b81613d0c60209383611c6a565b81010312612dd75750613d1e90612376565b3861368f565b3d9150613cff565b8151908115613df55760408051631284653d60e21b8152936004926020908690859082906001600160a01b03165afa948515613dea57600095613db7575b5060005b848110613d7d57505050505050565b60ff613d898284612fdb565b5151169060019182811b881615613da1575001613d6e565b8560249186519163041139f960e51b8352820152fd5b90946020823d8211613de2575b81613dd160209383611c6a565b81010312612dd75750519338613d6a565b3d9150613dc4565b82513d6000823e3d90fd5b505050565b604080516328f41de360e01b815261ffff841660048083018290526020999890979396956001600160a01b039485831693928c86602481885afa80156141e95760009687916141b0575b5015614180575093809392918a613e6f8a98978c519b8c948594635cf3af3360e11b86528501612de2565b0381855afa9586156141765783978497614154575b50613e8d612d60565b9395613e99858a6123e3565b340361412d5789519060c08201986001600160401b03998381108b82111761411957948f948d8f9b9a9895613fa895608395613f639c9a84528483528983019586528383019182526060830190815289613f44613f0360a060808701968d8852019733895261432f565b97613f3a60218851809b613f2a87830197600160f81b895282519283918686019101612027565b810103600181018c52018a611c6a565b51935192516143ec565b9351955194519d8e97600160f91b8d8a015251809260218a0190612027565b86019161ffff60f01b9060f01b1660218301526023820152613f8e825180938b604385019101612027565b019160438301526063820152036063810188520186611c6a565b8951632fe4c87f60e21b815296879182905afa94851561410f57918493918c93613fff9998976140ee575b5089516358cd21bf60e11b8152808c01869052606060248201529889938492918391606483019061204a565b60c8604483015203927f0000000000000000000000000000000000000000000000000000000000000000165af19485156140e25781956140a7575b508061409457507fda8540426b64ece7b164a9dce95448765f0a7263ef3ff85091c9c7361e485364916000614070858894612b25565b998351958652850152841692a29315614087575050565b516304aeb27d60e51b8152fd5b634e487b7160e01b815260118752602490fd5b9094508881813d83116140db575b6140bf8183611c6a565b810103126140d7576140d18591612177565b9461403a565b8480fd5b503d6140b5565b508551903d90823e3d90fd5b8591965061410890853d8711613b1457613b038183611c6a565b9590613fd3565b88513d86823e3d90fd5b50634e487b7160e01b895260418d52602489fd5b60448b8b61413b888d6123e3565b905191631f89f67160e01b835234908301526024820152fd5b90965061416c9197503d8085833e613cae8183611c6a565b9690969538613e84565b88513d85823e3d90fd5b89516366b69b9d60e01b81526001600160a01b03909116818c0190815261ffff8416602082015281906040010390fd5b90508d81813d83116141e2575b6141c78183611c6a565b810103126141de576141d890612376565b38613e44565b8680fd5b503d6141bd565b8a513d6000823e3d90fd5b9261421f9493614217926142116020956040519061048682611bcb565b91614224565b93909361242d565b015190565b926000929161424a9460405195869485938493635cf3af3360e11b855260048501612de2565b03916001600160a01b03165afa8015610bdb57600091829161427e575b5061427b9091614275612d60565b906123e3565b91565b614296915061427b923d8091833e613cae8183611c6a565b9091614267565b6001929160ff60f81b9060f81b1681526142c08251809360208685019101612027565b010190565b604051906142d282611c4f565b6060602083600081520152565b906142e982611ced565b6142f66040519182611c6a565b8281528092614307601f1991611ced565b019060005b82811061431857505050565b6020906143236142c5565b8282850101520161430c565b80519060406020820151910151906040519261ffff60f01b9060f01b16602084015260228301526001600160401b0360c01b9060c01b166042820152602a8152611e6981611c34565b929082156143cf578281019260405194601f82169283156143c6575b838701938385019201015b8184106143b65750508452601f01601f1916604052565b805184526020938401930161439f565b60209350614394565b925090506040516143df81611bcb565b6000815260003681379190565b611e696024825160405193849163ffffffff60e01b9060e01b16602083015261441e8151809260208686019101612027565b8101036004810184520182611c6a565b9061444991600463ffffffff81848401015116920190614378565b9091565b600101519060ff600192168281036144625750565b6044908360405191633ce5fedf60e11b835260048301526024820152fdfeebc28a1927f62765bfb7ada566eeab2d31a98c65dbd1e8cad64acae2a3ae45d41a2a8eb52f1d00a1242a3f8cc031e30a32870ff64f69009c4e06f75bd842fd221a2a8eb52f1d00a1242a3f8cc031e30a32870ff64f69009c4e06f75bd842fd231b988580e74603c035f5a7f71f2ae4647578af97cd0657db620836b9955fd8f56c615753402911c4de18a758def0565f37c41834d6eff72b16cb37cfb697f2a5a264697066735822122099073e38a4175732fdceb8d66f75e714a96fc9d50fe1ad3dd8914c358b5480be64736f6c63430008130033000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3

Deployed Bytecode

0x60a080604052600436101561001357600080fd5b60003560e01c9081632385904a14611a885750806324320c9f14611a5257806328b1d852146118935780632c75470f14611877578063329a2be71461184557806332b2fc0e146117ab5780633a2c767d1461176c5780633e8267e7146117125780633ed334df146114f957806340984f08146114c05780634533e5ff1461143e5780634b5ca6f4146113aa5780634d48ec60146113535780635a3b92e81461131a5780635cb8cae21461100557806375ea8b5814610fd957806380ebabd014610fa55780638b0301b114610f615780638fecdd0214610f1e578063a60eb4c81461055e578063a79629d8146104ef578063b1eac87514610464578063b686d0891461040d578063c055120e14610354578063c23ee3c314610303578063c4d66de8146102a1578063c81fb7fe14610270578063cee4bda0146101c85763d0625a191461015e57600080fd5b346101c35760203660031901126101c3576004356000526000805160206144e1833981519152602052604060002054158015906101a3575b6020906040519015158152f35b506000805160206145018339815191526020526040600020541515610196565b600080fd5b6101603660031901126101c3576101dd611b29565b6001600160401b036044358181116101c3576101fd903690600401611ca6565b9160a4358281116101c357610216903690600401611ca6565b9261021f611b3a565b93610228611bb4565b61012435938585116101c35760209661024861026796369060040161206f565b93610251611e6c565b9560e435936084359160643591602435906135e6565b60405191168152f35b602061029061027e36611f87565b99989098979197969296959395613522565b6001600160401b0360405191168152f35b346101c35760203660031901126101c3576004356001600160a01b038116908190036101c35760016000546102d960ff82161561212c565b60ff19161760005560008051602061448183398151915280546001600160a01b0319169091179055005b346101c35760603660031901126101c3576040610348610321611b29565b600080516020614481833981519152546001600160a01b03169060443590602435906141f4565b82519182526020820152f35b6101603660031901126101c357610369611b29565b610371611b5c565b906001600160401b03906044358281116101c357610393903690600401611ca6565b9261039c611b3a565b916103a5611b72565b906103ae611bb4565b9061012435948686116101c3576020976103cf61026797369060040161206f565b946103d8611e6c565b966103f26040516103e881611bcb565b60a4358152612e02565b9260018060a01b0380931695608435936064359316906135e6565b60e03660031901126101c35761042236611d04565b61042a611b4b565b60a4356001600160401b03918282116101c357602093610451610267933690600401611ca6565b9061045a611b88565b9260843591613dfa565b6104ed61048d61047336611dfb565b9590604094929394519061048682611bcb565b8152612e02565b9061ffff6000805160206144a18339815191525416926000805160206144c1833981519152549460018060a01b0396876000805160206144818339815191525416976104e56104de8a888786614224565b5034612a00565b941690613469565b005b346101c35760803660031901126101c357610508611b29565b604435906001600160401b0382116101c35761052b61053d923690600401611ca6565b610533611b9e565b9160243590614224565b9061055a604051928392835260406020840152604083019061204a565b0390f35b60803660031901126101c3576004356001600160401b0381116101c357366023820112156101c357806004013561059481611ced565b916105a26040519384611c6a565b8183526024602084019260051b820101903682116101c35760248101925b828410610eef57846024356001600160401b0381116101c3576105e7903690600401611ca6565b906001600160a01b0360443581811681036101c3576064356001600160401b0381116101c35761061b903690600401611ca6565b7f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a675483811680610ed157506001600160a01b03191633177f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a675560405163607ec5ef60e11b81526020600482015293946000908590819061069f90602483019061204a565b0381867f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3165afa8015610bdb57600094600090600092610ea6575b5015610e815750606084015161ffff1660009081527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d6020526040902054608085015190808203610e5457505060e0840151836040519361073a85611bfc565b6000855260006020860152606060408601526000606086015260006080860152606060a0860152600060c0860152600060e086015260006101008601526000610120860152600061014086015260606101608601526107ba602261079d8561444d565b858101600281015161ffff1689528201516020890152018461442e565b93906040870152838101906107db604080602085015194015196018261442e565b959060a089015260838087840161ffff60028201511660c08c0152602281015160e08c015260428101516101008c015260628101516101208c015260828101516101408c0152015196019261083260ff88166142df565b6000975b60ff81168910610d9d575061085d959697506101608a015260608901526080880152613283565b61ffff60c08501511660e08501519061ffff196000805160206144a18339815191525416176000805160206144a1833981519152556000805160206144c18339815191525561ffff606087015116956101406001600160401b0360a08301511691015190604051976108ce89611c18565b8852602088015260408701521660608501528460808501528160a0850152600060c0850152600060e0850152600061010085015280610120850152600061014085015260009061092160a0840151612410565b61092a816123f0565b80610d64575061093d60a084015161242d565b908051610c50575b50602081519101519161096160608501516080860151906123e3565b906101408701526101008601528160e08601528060c0860152818102918183041490151715610c3a57610100840151610999916123e3565b803410610c1d575061ffff8151168061ffff7f00000000000000000000000000000000000000000000000000000000000000101603610c05575061016001519081518451808203610be757505081519360005b858110610a57576109fc856124c0565b6000805160206144a1833981519152805461ffff1916905560006000805160206144c1833981519152557f44dc27ebd67a87ad2af1d98fc4a5f971d9492fe12498e4c413ab5a05b7807a6780546001600160a01b0319169055005b600160ff610a658387612fdb565b51511614610a76575b6001016109ec565b610aa86000610a858385612fdb565b516040518093819263a9e1189360e01b835260206004840152602483019061204a565b0381877f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3165afa908115610bdb57600091610b9a575b506020610aeb8387612fdb565b51015160405191610afb83611c34565b600083526020830192600084526001600160401b03602a60408301946000865261ffff600282015116809452602281015180975201511680935261ffff6060830151161492831593610b8b575b508215610b73575b505015610a6e57604051633ad7858760e21b815260ff9091166004820152602490fd5b60a001516001600160401b0316141590508780610b50565b60808201511415925089610b48565b3d9150816000823e610bac8282611c6a565b60208183810103126101c35780516001600160401b0381116101c357610bd592820191016121dc565b87610ade565b6040513d6000823e3d90fd5b60449250604051916365c1f7cd60e01b835260048301526024820152fd5b6024906040519063d8215fc960e01b82526004820152fd5b60449060405190620885af60e61b82523460048301526024820152fd5b634e487b7160e01b600052601160045260246000fd5b604051919250610c5f82611c34565b60008252610cab602083019160608352600060408501526020610c818261444d565b610c938280838601015192018461442e565b91908652828285010151604088015286520190613283565b606084015160006020604051610cc081611c4f565b8281520152825110610d5257610cd68151612410565b610cdf816123f0565b80610d275750610cef905161242d565b908051928251905111610d15576040919260608501526000608085015201519086610945565b6040516315fc687d60e31b8152600490fd5b80610d336044926123f0565b60ff6040519163170cd96160e11b835260006004840152166024820152fd5b604051631c6e090160e31b8152600490fd5b80610d71610d99926123f0565b60405163c1f4bdd960e01b815260ff9091166004820152600060248201529081906044820190565b0390fd5b9193959796509193610dad6142c5565b96600191828082019189010151908360ff829316808c5214600014610e39575060405190600a90818301916034840190828c01015b818410610e29575050602a808452601f909201601f191660405260208b019290925260ff939291015b98610e168287612fdb565b5201918b97959391509795939197610836565b8051845260209384019301610de2565b60ff93929150610e49908961442e565b9060208b0152610e0b565b6064925061ffff6060870151169060405192633bb6036760e11b8452600484015260248301526044820152fd5b60405163b72c3b7f60e01b815260206004820152908190610d9990602483019061204a565b915050610ec79194503d806000833e610ebf8183611c6a565b810190612383565b90949194876106da565b604490604051906320b84ced60e01b82523360048301526024820152fd5b83356001600160401b0381116101c357602091610f13839260243691870101611ca6565b8152019301926105c0565b6020610290610f2c36611f2f565b9060018060a0969495961b0360008051602061448183398151915254169360405195610f5787611bcb565b60008752846132ae565b60e03660031901126101c3576020610290610f7b36611d04565b610f83611b4b565b610f8b611b88565b91610f9b6040516103e881611bcb565b9160843591613dfa565b346101c35760803660031901126101c3576040610348610fc3611b29565b610fcb611b9e565b9060443590602435906141f4565b6104ed610fe536611f87565b9993955097610fff6104de83878a889c969c9b979b614224565b93613522565b346101c3576020806003193601126101c3576004356001600160401b0381116101c357611036903690600401611ca6565b60018060a01b03917f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc9261106d8185541693613005565b828101516e576f726d686f6c6552656c617965728082036112fc57505060ff602182015116600281036112dd5750602381015161ffff908181168015806112d5575b156111f0575b5050506110ce6110c86043830151612a0d565b91613258565b803b15611195571692836bffffffffffffffffffffffff60a01b825416179055600080604051857fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8380a2632c75470f60e01b818501908152600482529061113581611c4f565b519082305af190611144612e20565b91156111735750507f2e4cc16c100f0b55e2df82ab0b1a7e294aa9cbd01b48fbaf622683fbc0507a49600080a3005b610d9960405192839263135687c760e31b84526004840152602483019061204a565b60405162461bcd60e51b815260048101849052602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b60405163380e7c8960e21b815286816004817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f38a165afa908115610bdb576000916112a0575b5061128e577f00000000000000000000000000000000000000000000000000000000000000109283160361126a57806110b5565b60405163901f6ae360e01b815261ffff918216600482015291166024820152604490fd5b60405163ea03b6eb60e01b8152600490fd5b90508681813d83116112ce575b6112b78183611c6a565b810103126101c3576112c890612376565b89611236565b503d6112ad565b5060006110af565b60449060405190633460202560e21b8252600482015260026024820152fd5b6044925060405191633d254c6160e01b835260048301526024820152fd5b346101c35760203660031901126101c3576004356000526000805160206145018339815191526020526020604060002054604051908152f35b6104ed61137d61136236611e7d565b9a919894909995506040979297969396519061048682611bcb565b9361138a88868584614224565b506001600160a01b0397881697906113a29034612a00565b941690613522565b60e03660031901126101c3576113be611b29565b6113c6611b5c565b906001600160401b03906044358281116101c3576113e8903690600401611ca6565b60a4359161ffff831683036101c35760209461026793611406611b88565b9160018060a01b036000805160206144818339815191525416936040519561142d87611bcb565b60008752608435926064359261338d565b6104ed61145f61144d36611f2f565b60409591939295519061048682611bcb565b61ffff6000805160206144a18339815191525416916000805160206144c1833981519152549360018060a01b039687600080516020614481833981519152541696604051986114ad8a611bcb565b60008a526104e56104de8a888786614224565b346101c35760203660031901126101c3576004356000526000805160206144e18339815191526020526020604060002054604051908152f35b346101c3576020806003193601126101c3576004356001600160401b0381116101c35761152d611532913690600401611ca6565b613005565b90808201516e576f726d686f6c6552656c617965728082036112fc57505060ff602183015116600181036116f35750602382015161ffff90818116908115806116eb575b15611616575b5050602583015160458401519351604581036115f757501690816000527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d91828252604060002054806115d9575060005252604060002055600080f35b6044925060405191637b5672c560e11b835260048301526024820152fd5b6044906040519063061bc83560e51b8252600482015260456024820152fd5b60405163380e7c8960e21b815284816004817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03165afa908115610bdb576000916116b6575b5061128e577f0000000000000000000000000000000000000000000000000000000000000010918383161461157c5760405163901f6ae360e01b815261ffff918216600482015291166024820152604490fd5b90508481813d83116116e4575b6116cd8183611c6a565b810103126101c3576116de90612376565b86611663565b503d6116c3565b506001611576565b60449060405190633460202560e21b8252600482015260016024820152fd5b346101c35760203660031901126101c3576020611764611730611b29565b61ffff166000527f9e4e57806ba004485cfae8ca22fb13380f01c10b1b0ccf48c20464961643cf6d60205260406000205490565b604051908152f35b602061029061179661177d36611e7d565b9a90999198979295946040979497519061048682611bcb565b6001600160a01b039586169790951690613522565b6101003660031901126101c3576117c0611b29565b6117c8611b5c565b6001600160401b03906044358281116101c3576117e9903690600401611ca6565b9060a435918383116101c357602094611809610267943690600401611d50565b92611812611b3a565b9061181b611b72565b600080516020614481833981519152546001600160a01b031694909360843592606435929161338d565b602061029061185336611dfb565b949260018060a09493941b03600080516020614481833981519152541694846132ae565b346101c35760003660031901126101c3576104ed30331461212c565b346101c3576020806003193601126101c3576004356001600160401b0381116101c35761152d6118c7913690600401611ca6565b90808201516e576f726d686f6c6552656c617965728082036112fc57505060ff60218301511660038103611a335750602382015161ffff9182821690811580611a2b575b15611972575b505050506043810151906119276110c883612a0d565b6001600160a01b031690811561195a575060008051602061448183398151915280546001600160a01b0319169091179055005b60249060405190637a8ad12560e01b82526004820152fd5b60405163380e7c8960e21b815281816004817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03165afa918215610bdb576000926119f5575b505061128e577f00000000000000000000000000000000000000000000000000000000000000109283160361126a578080611911565b90809250813d8311611a24575b611a0c8183611c6a565b810103126101c357611a1d90612376565b85806119bf565b503d611a02565b50600061190b565b60449060405190633460202560e21b8252600482015260036024820152fd5b346101c35760003660031901126101c357600080516020614481833981519152546040516001600160a01b039091168152602090f35b346101c35760603660031901126101c357611aa1611b29565b6044356001600160a01b03811691908290036101c357630cbcf9e160e21b835261ffff1660048301526024803590830152602090829060449082905afa8015610bdb57600090611af7575b602090604051908152f35b506020813d8211611b21575b81611b1060209383611c6a565b810103126101c35760209051611aec565b3d9150611b03565b6004359061ffff821682036101c357565b60c4359061ffff821682036101c357565b6064359061ffff821682036101c357565b602435906001600160a01b03821682036101c357565b60e435906001600160a01b03821682036101c357565b60c435906001600160a01b03821682036101c357565b606435906001600160a01b03821682036101c357565b61010435906001600160a01b03821682036101c357565b602081019081106001600160401b03821117611be657604052565b634e487b7160e01b600052604160045260246000fd5b61018081019081106001600160401b03821117611be657604052565b61016081019081106001600160401b03821117611be657604052565b606081019081106001600160401b03821117611be657604052565b604081019081106001600160401b03821117611be657604052565b90601f801991011681019081106001600160401b03821117611be657604052565b6001600160401b038111611be657601f01601f191660200190565b81601f820112156101c357803590611cbd82611c8b565b92611ccb6040519485611c6a565b828452602083830101116101c357816000926020809301838601378301015290565b6001600160401b038111611be65760051b60200190565b60609060031901126101c35760405190611d1d82611c34565b8160043561ffff811681036101c35781526024356020820152604435906001600160401b03821682036101c35760400152565b81601f820112156101c357803590611d6782611ced565b92604090611d7782519586611c6a565b83855260209182860191836060809702860101948186116101c3578401925b858410611da7575050505050505090565b86848303126101c357825190611dbc82611c34565b843561ffff811681036101c3578252858501358683015283850135906001600160401b03821682036101c357828792868b950152815201930192611d96565b60c06003198201126101c35760043561ffff811681036101c357916024356001600160a01b03811681036101c357916001600160401b03906044358281116101c35781611e4a91600401611ca6565b92606435926084359260a4359182116101c357611e6991600401611d50565b90565b610144359060ff821682036101c357565b906101606003198301126101c35761ffff9060043582811681036101c357926001600160a01b039160243583811681036101c357936001600160401b036044358181116101c35784611ed191600401611ca6565b94606435946084359460a4359460c43590811681036101c3579360e43584811681036101c357936101043590811681036101c35792610124359182116101c357611f1d91600401611d50565b906101443560ff811681036101c35790565b60a06003198201126101c35760043561ffff811681036101c357916024356001600160a01b03811681036101c35791604435906001600160401b0382116101c357611f7c91600401611ca6565b906064359060843590565b6101606003198201126101c35761ffff9160043583811681036101c35792602435926001600160401b03916044358381116101c35782611fc991600401611ca6565b93606435936084359360a4358281116101c35781611fe991600401611ca6565b9360c43590811681036101c3579260e43592610104356001600160a01b03811681036101c35792610124359182116101c357611f1d91600401611d50565b60005b83811061203a5750506000910152565b818101518382015260200161202a565b9060209161206381518092818552858086019101612027565b601f01601f1916010190565b81601f820112156101c35780359061208682611ced565b9260409261209684519586611c6a565b808552602093848087019260051b850101938385116101c357858101925b8584106120c5575050505050505090565b6001600160401b0384358181116101c35783019184601f1984890301126101c35784516120f181611c4f565b8984013560ff811681036101c3578152858401359283116101c35761211d888b80969581960101611ca6565b838201528152019301926120b4565b1561213357565b634e487b7160e01b600052600160045260246000fd5b519060ff821682036101c357565b519063ffffffff821682036101c357565b519061ffff821682036101c357565b51906001600160401b03821682036101c357565b9092919261219881611c8b565b916121a66040519384611c6a565b8294828452828201116101c35760206121c0930190612027565b565b9080601f830112156101c3578151611e699260200161218b565b9190610160838203126101c3576040928351916121f883611c18565b829461220383612149565b84526020612212818501612157565b81860152612221828501612157565b828601526060612232818601612168565b81870152608091828601518388015261224d60a08701612177565b60a088015261225e60c08701612149565b60c088015260e0860151936001600160401b03948581116101c357866122859189016121c2565b60e0890152610100612298818901612157565b9089015261012094858801518181116101c35788019387601f860112156101c3578451926122c584611ced565b986122d282519a8b611c6a565b848a5285808b019560071b880101968188116101c3578601945b87861061230b5750505050505050505083015261014080910151910152565b88868303126101c3578251908982019082821087831117612361578a9289928652885181528289015183820152612343868a01612149565b86820152612352878a01612149565b878201528152019501946122ec565b60246000634e487b7160e01b81526041600452fd5b519081151582036101c357565b90916060828403126101c3578151926001600160401b03938481116101c357816123ae9185016121dc565b936123bb60208501612376565b9360408101519182116101c357019080601f830112156101c3578151611e699260200161218b565b91908201809211610c3a57565b600111156123fa57565b634e487b7160e01b600052602160045260246000fd5b6020818051810103126101c3576020015160018110156101c35790565b906040519161243b83611c4f565b60008352602083019060008252836060828051810103126101c35761246260208301612149565b926060604084015193015190525260ff811661247b5750565b60405163c1f4bdd960e01b815260ff91909116600482015260006024820152604490fd5b604051906124ac82611c34565b606060408360008152600060208201520152565b60a0810151602081015115612927575060006124da61249f565b5060408281015182526000805160206144e183398151915260205281205415612688575060405161250a81611c4f565b601a81527f44656c697665727920616c726561647920706572666f726d656400000000000060208201526040519061254182611c34565b600082526001602083015260408201525b60a08201519060018060a01b036060840151169161257660c0850151835190612a00565b9260e085015193848102948186041490151715610c3a57602083015160028110156123fa5784600160009214612669575b6125b0916123e3565b9360e0830151801560001461264857506005945b9260068610156123fa576126159361260f928715801561263e575b612635575b6126056125ff846080606061260a96970151910151906123e3565b34612a00565b612a00565b6123e3565b90612b25565b15612623576121c092612a39565b6040516304aeb27d60e51b8152600490fd5b600091506125e4565b50600288146125df565b612663908661ffff60c0870151169161010087015192612b7a565b946125c4565b6125b0915061268160608501516080860151906123e3565b91506125a7565b61ffff8251169060a0830151602081015160408201519160c08601519061010087015161014060e08901519201519260408901519560808a015195604051998a6101208101106001600160401b036101208d01111761291357908a9594939291610120612781999c016040528652602086015260408501526060840152608083015260a082015260c0810191825260e08101938452610100810195865261272d61249f565b9560608201519260018060a01b036127486020850151612a0d565b16956040840151925191519061ffff85511690519160405197889563294ee51960e11b602088015260a0602488015260c487019061204a565b602319868203016044870152845180825260208201916020808360051b8301019701928d915b8383106128dc5750505050509260849285926020956064612823999801528484015260a483015203956127e2601f1997888101835282611c6a565b60805a940151978151906040519985808c0194019189f1943d806084106001146128d4575b80601f9189520116860101604052604087019485525a90612a00565b90808210156128cd57505b8452156128bf576040519061284282611bcb565b8282525260208201525b602081015160028110156123fa5760408301519061289e576000526000805160206144e18339815191526020524360406000205560008051602061450183398151915260205260006040812055612552565b60005260008051602061450183398151915260205243604060002055612552565b50506001602082015261284c565b905061282e565b506084612807565b9193985091939495966020806128fe600193601f198682030187528c5161204a565b9a019301930190928b989796959492936127a7565b634e487b7160e01b8a52604160045260248afd5b606082810151908201805160808401805190936001600160a01b0316929161294f91906123e3565b60e0850151909485826129e1575050506005935b60068510156123fa576129939361260f92861580156129d7575b6129ce575b61260a916125ff91519051906123e3565b15612623576040516121c0926129a882611bcb565b60008252604051916129b983611c34565b60008352600060208401526040830152612a39565b60009250612982565b506002871461297d565b6129fa9261010061ffff60c08501511693015192612b7a565b93612963565b91908203918211610c3a57565b8060a01c612a21576001600160a01b031690565b6024906040519063033b960d60e41b82526004820152fd5b90612a4b602060a08401510151612a0d565b61ffff835116926001600160401b036020820151169460408201519160208501519460028610156123fa578051604090910151610140830151909260009115612b0f5761012091500151955b6040519485526020850152604084015260068210156123fa577fbccc00b713f54173962e7de6098f643d8ebf53d488d71f4b2a5171496d038f9e93612af1612b0a928594606086015260c0608086015260c085019061204a565b83810360a08501526001600160a01b039091169561204a565b0390a4565b5060405190612b1d82611bcb565b815295612a97565b908015612b7357600060209181604051612b3e81611bcb565b5281805a926040519686880194f1913d801515600114612b6b575b808252601f01601f1916010160405290565b506000612b59565b5050600190565b90929161ffff808316907f0000000000000000000000000000000000000000000000000000000000000010168114612ce457612bb584612a0d565b6000918283612bd1604051612bc981611bcb565b828152612e02565b93612c0c6040519586926020978893849384830199635cf3af3360e11b8b52602484015287604484015260606064840152608483019061204a565b0393612c20601f1995868101835282611c6a565b51604051978389019a8b9360018060a01b0316620186a0f1913d808310600114612cdd575b808752601f011685010160405280612cd3575b15612cc85750508051810103126101c357519360015b158015612cbe575b8015612ca9575b612c9f57612c99611e6995612605612c93612d60565b85612a00565b92612e50565b5050505050600490565b50612cb68561260a612d60565b821115612c7d565b5084821115612c76565b925096925050612c6e565b5083835114612c58565b5081612c45565b50926001600160a01b039250612cfa9150612a0d565b168115612d5757600060209181604051612d1381611bcb565b5281806040519585870193620186a0f1913d801515600114612d4f575b808252601f01601f191601016040525b15612d4a57600090565b600190565b506000612d30565b50506001612d40565b604051631a90a21960e01b81526020816004817f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03165afa908115610bdb57600091612db1575090565b906020823d8211612dda575b81612dca60209383611c6a565b81010312612dd757505190565b80fd5b3d9150612dbd565b611e69939261ffff6060931682526020820152816040820152019061204a565b516040519060006020830152604082015260408152611e6981611c34565b3d15612e4b573d90612e3182611c8b565b91612e3f6040519384611c6a565b82523d6000602084013e565b606090565b939192612ef193604092835193612e6685611bcb565b600095868652612e8b612e858351612e7d81611bcb565b898152612e02565b91612a0d565b825193612e9785611bcb565b8885528351998a9763640fdbff60e11b8952612ed261ffff809e169a8b60048c01528c60248c015261016060448c01526101648b019061204a565b908b60648b015260848a015260031994858a83030160a48b015261204a565b60c488019890985260e48701526001600160a01b0316610104860152848603016101248501528151808652602098899687019387019288915b838310612fa057505050505082809160c8610144830152039130620186a0f19283612f6a575b505050612f6557612f5f612e20565b50600390565b600290565b82813d8311612f99575b612f7e8183611c6a565b81010312612dd75750612f9090612177565b50388080612f50565b503d612f74565b8451805182168752898101518a8801528201516001600160401b0316828701528b988b98506060909601959094019360019290920191612f2a565b8051821015612fef5760209160051b010190565b634e487b7160e01b600052603260045260246000fd5b9060018060a01b037f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f31691604061305e81519263607ec5ef60e11b8452602095600491878387015285806000958693602483019061204a565b0381845afa801561319c57839584908592613236575b50156132135750835163fbe3c2cd60e01b815287818481855afa9081156132095784916131d0575b5061ffff908160608801511691811682036131a65750508682918551928380926358b9591160e11b82525afa90811561319c57839161316b575b506080850151818103613150575050610140840195865183527f970ad24d4754c92e299cabb86552091f5df0a15abc0f1b71f37d3e30031585dc9182825260ff8585205416613139575060e095965183525220600160ff19825416179055015190565b875185516364cbf47160e01b815291820152602490fd5b84516342852f8d60e11b815292830152602482015260449150fd5b90508681813d8311613195575b6131828183611c6a565b810103126131915751386130d6565b8280fd5b503d613178565b84513d85823e3d90fd5b855163c97817ed60e01b815261ffff92831685820190815291909216602082015281900360400190fd5b90508781813d8311613202575b6131e78183611c6a565b810103126131fe576131f890612168565b3861309c565b8380fd5b503d6131dd565b85513d86823e3d90fd5b8451630169d68560e71b8152808401899052908190610d9990602483019061204a565b91505061324e9195503d8085833e610ebf8183611c6a565b9095919538613074565b51604381036132645750565b6044906040519063061bc83560e51b8252600482015260436024820152fd5b5190808203613290575050565b604492506040519163061bc83560e51b835260048301526024820152fd5b9194909395929796976132c960409788519061048682611bcb565b906132d48a516142df565b968a5160005b818110613347575050611e69999a508851986132f58a611c18565b61ffff8096168a5260018060a01b0380981660208b015289015260608801526000608088015260a08701521660c0850152600060e085015216610100830152610120820152600f61014082015261364f565b61335a613354828f612fdb565b5161432f565b908b5161336681611c4f565b600192838252602082015261337b828d612fdb565b52613386818c612fdb565b50016132da565b909295919693949897986133a960409687519061048682611bcb565b6133b38b516142df565b978b5160005b818110613427575050611e699a9b508751996133d48b611c18565b61ffff8095168b5260018060a01b03988980981660208d01528b015260608a0152600060808a015260a08901521660c08701521660e085015216610100830152610120820152600f61014082015261364f565b6134356133548f8390612fdb565b908b613457828d519261344784611c4f565b6001958685526020850152612fdb565b52613462818d612fdb565b50016133b9565b93909795929998999694919661347f8b516142df565b978b5160005b8181106134ef575050611e699a9b50604051996134a18b611c18565b61ffff9687168b5260208b015260408a01526060890152608088015260a08701521660c085015260e08401526001600160a01b0316610100830152610120820152600f61014082015261364f565b6134fd6133548f8390612fdb565b908b613510826040519261344784611c4f565b5261351b818d612fdb565b5001613485565b9390989a99979592969491966135388c516142df565b978c5160005b8181106135b3575050611e699b9c509060ff9998979695949392916040519b6135668d611c18565b61ffff9687168d5260208d015260408c015260608b015260808a015260a08901521660c087015260e08601526001600160a01b03166101008501526101208401521661014082015261364f565b6135c18f8261335491612fdb565b908b6135d4826040519261344784611c4f565b526135df818d612fdb565b500161353e565b9293611e699a979460ff9996929a97936040519b6135668d611c18565b9190916040818403126101c35780519260208201516001600160401b0381116101c357611e6992016121c2565b908160209103126101c357516001600160a01b03811681036101c35790565b60018060a01b03610100820151169161ffff825116604051906328f41de360e01b82526004820152602081602481875afa908115610bdb57600091613cf2575b5015613cbe5761ffff825116926000606084015160a0850151956136c76040519788938493635cf3af3360e11b855260048501612de2565b0381845afa938415610bdb576000908195613c98575b506136e6612d60565b60808501516136f98261260a83866123e3565b3403613c6d575061370f61012086015184613d2c565b845160208087015160408089015160608a015160808b01519251630cbcf9e160e21b815261ffff871660048201526024810193909352929a9093909190816044818b5afa908115610bdb5788928b91600093613c33575b5061ffff60c08301511690602061ffff60e0850151945116602460405180988193633d77cbfd60e01b835260048301525afa938415610bdb578e968e96600096613bed575b509260839895926138a59a989592613842989561012060018060a01b0361010089015116970151976137e260405180608052611bfc565b61ffff8c16608051526020608051015288604060805101526060608051015260808051015260a0608051015260c0608051015260e060805101526101006080510152610120608051015233610140608051015261016060805101526143ec565b6080519060806060830151920151906040519b8c94600160f81b602087015261ffff60f01b9060f01b166021860152602385015261388a815180926020604388019101612027565b83019160438301526063820152036063810189520187611c6a565b6138b460a060805101516143ec565b6080519660c088015160e0890151906101008a0151996101208101516101606101408301519201519b8c519460ff8611613bd4578d5160405160f89190911b6001600160f81b03191660208201526001815261390f81611c4f565b956000905b808210613b1b5750506004999a9b9c9d509160a29593916139a7979593604051998761394a8c995180926020808d019101612027565b880161395f8251809360208085019101612027565b019461ffff60f01b9060f01b16602086015260228501526042840152606283015260828201526139988251809360208785019101612027565b01036082810184520182611c6a565b602060ff61014060808a0151990151169560405194858092632fe4c87f60e21b82525afa928315610bdb57600093613ae3575b50602091613a0d916040518097819482936358cd21bf60e11b84526000600485015260606024850152606484019061204a565b604483019190915203917f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f36001600160a01b03165af1928315610bdb57600093613aa4575b50613a619061260f86846123e3565b9360405191825260208201527fda8540426b64ece7b164a9dce95448765f0a7263ef3ff85091c9c7361e48536460406001600160401b03841692a2911561262357565b90926020823d602011613adb575b81613abf60209383611c6a565b81010312612dd75750613ad4613a6191612177565b9290613a52565b3d9150613ab2565b613a0d91935091613b0b602093843d8611613b14575b613b038183611c6a565b810190613630565b939150916139da565b503d613af9565b90968f90613ba46020613b308b600195612fdb565b51805160ff16858103613bac5750613b6a8260ff83511692015191613b5c60405193849286840161429d565b03601f198101835282611c6a565b925b6040519381613b848693518092868087019101612027565b8201613b9882518093868085019101612027565b01038084520182611c6a565b970190613914565b90613bbc83613bce9201516143ec565b91613b5c60405193849286840161429d565b92613b6c565b6040516312d6a5c760e01b815260048101879052602490fd5b92949650965091936020823d602011613c2b575b81613c0e60209383611c6a565b81010312612dd75750518d958d95919491939192906138426137ab565b3d9150613c01565b92915092506020823d602011613c65575b81613c5160209383611c6a565b81010312612dd757505187918a9038613766565b3d9150613c44565b9061260a613c7d926044946123e3565b60405190631f89f67160e01b82523460048301526024820152fd5b90613cb69295503d8091833e613cae8183611c6a565b810190613603565b9390386136dd565b5061010081015190516040516366b69b9d60e01b81526001600160a01b03909216600483015261ffff166024820152604490fd5b906020823d602011613d24575b81613d0c60209383611c6a565b81010312612dd75750613d1e90612376565b3861368f565b3d9150613cff565b8151908115613df55760408051631284653d60e21b8152936004926020908690859082906001600160a01b03165afa948515613dea57600095613db7575b5060005b848110613d7d57505050505050565b60ff613d898284612fdb565b5151169060019182811b881615613da1575001613d6e565b8560249186519163041139f960e51b8352820152fd5b90946020823d8211613de2575b81613dd160209383611c6a565b81010312612dd75750519338613d6a565b3d9150613dc4565b82513d6000823e3d90fd5b505050565b604080516328f41de360e01b815261ffff841660048083018290526020999890979396956001600160a01b039485831693928c86602481885afa80156141e95760009687916141b0575b5015614180575093809392918a613e6f8a98978c519b8c948594635cf3af3360e11b86528501612de2565b0381855afa9586156141765783978497614154575b50613e8d612d60565b9395613e99858a6123e3565b340361412d5789519060c08201986001600160401b03998381108b82111761411957948f948d8f9b9a9895613fa895608395613f639c9a84528483528983019586528383019182526060830190815289613f44613f0360a060808701968d8852019733895261432f565b97613f3a60218851809b613f2a87830197600160f81b895282519283918686019101612027565b810103600181018c52018a611c6a565b51935192516143ec565b9351955194519d8e97600160f91b8d8a015251809260218a0190612027565b86019161ffff60f01b9060f01b1660218301526023820152613f8e825180938b604385019101612027565b019160438301526063820152036063810188520186611c6a565b8951632fe4c87f60e21b815296879182905afa94851561410f57918493918c93613fff9998976140ee575b5089516358cd21bf60e11b8152808c01869052606060248201529889938492918391606483019061204a565b60c8604483015203927f000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3165af19485156140e25781956140a7575b508061409457507fda8540426b64ece7b164a9dce95448765f0a7263ef3ff85091c9c7361e485364916000614070858894612b25565b998351958652850152841692a29315614087575050565b516304aeb27d60e51b8152fd5b634e487b7160e01b815260118752602490fd5b9094508881813d83116140db575b6140bf8183611c6a565b810103126140d7576140d18591612177565b9461403a565b8480fd5b503d6140b5565b508551903d90823e3d90fd5b8591965061410890853d8711613b1457613b038183611c6a565b9590613fd3565b88513d86823e3d90fd5b50634e487b7160e01b895260418d52602489fd5b60448b8b61413b888d6123e3565b905191631f89f67160e01b835234908301526024820152fd5b90965061416c9197503d8085833e613cae8183611c6a565b9690969538613e84565b88513d85823e3d90fd5b89516366b69b9d60e01b81526001600160a01b03909116818c0190815261ffff8416602082015281906040010390fd5b90508d81813d83116141e2575b6141c78183611c6a565b810103126141de576141d890612376565b38613e44565b8680fd5b503d6141bd565b8a513d6000823e3d90fd5b9261421f9493614217926142116020956040519061048682611bcb565b91614224565b93909361242d565b015190565b926000929161424a9460405195869485938493635cf3af3360e11b855260048501612de2565b03916001600160a01b03165afa8015610bdb57600091829161427e575b5061427b9091614275612d60565b906123e3565b91565b614296915061427b923d8091833e613cae8183611c6a565b9091614267565b6001929160ff60f81b9060f81b1681526142c08251809360208685019101612027565b010190565b604051906142d282611c4f565b6060602083600081520152565b906142e982611ced565b6142f66040519182611c6a565b8281528092614307601f1991611ced565b019060005b82811061431857505050565b6020906143236142c5565b8282850101520161430c565b80519060406020820151910151906040519261ffff60f01b9060f01b16602084015260228301526001600160401b0360c01b9060c01b166042820152602a8152611e6981611c34565b929082156143cf578281019260405194601f82169283156143c6575b838701938385019201015b8184106143b65750508452601f01601f1916604052565b805184526020938401930161439f565b60209350614394565b925090506040516143df81611bcb565b6000815260003681379190565b611e696024825160405193849163ffffffff60e01b9060e01b16602083015261441e8151809260208686019101612027565b8101036004810184520182611c6a565b9061444991600463ffffffff81848401015116920190614378565b9091565b600101519060ff600192168281036144625750565b6044908360405191633ce5fedf60e11b835260048301526024820152fdfeebc28a1927f62765bfb7ada566eeab2d31a98c65dbd1e8cad64acae2a3ae45d41a2a8eb52f1d00a1242a3f8cc031e30a32870ff64f69009c4e06f75bd842fd221a2a8eb52f1d00a1242a3f8cc031e30a32870ff64f69009c4e06f75bd842fd231b988580e74603c035f5a7f71f2ae4647578af97cd0657db620836b9955fd8f56c615753402911c4de18a758def0565f37c41834d6eff72b16cb37cfb697f2a5a264697066735822122099073e38a4175732fdceb8d66f75e714a96fc9d50fe1ad3dd8914c358b5480be64736f6c63430008130033

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

000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3

-----Decoded View---------------
Arg [0] : wormhole (address): 0xC8e2b0cD52Cf01b0Ce87d389Daa3d414d4cE29f3

-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000c8e2b0cd52cf01b0ce87d389daa3d414d4ce29f3


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
[ 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.