Source Code
Overview
GLMR Balance
GLMR Value
$0.00| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
Latest 25 internal transactions (View All)
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 14211473 | 5 mins ago | 0.00875454 GLMR | ||||
| 14209709 | 3 hrs ago | 0.00875454 GLMR | ||||
| 14209542 | 3 hrs ago | 0.00875454 GLMR | ||||
| 14207292 | 7 hrs ago | 0.00875454 GLMR | ||||
| 14207113 | 8 hrs ago | 0.00875454 GLMR | ||||
| 14207009 | 8 hrs ago | 0.00875454 GLMR | ||||
| 14206673 | 9 hrs ago | 0.00875454 GLMR | ||||
| 14206507 | 9 hrs ago | 0.00875454 GLMR | ||||
| 14206276 | 9 hrs ago | 0.00875454 GLMR | ||||
| 14206106 | 10 hrs ago | 0.00875454 GLMR | ||||
| 14206044 | 10 hrs ago | 0.00875454 GLMR | ||||
| 14205920 | 10 hrs ago | 0.00875454 GLMR | ||||
| 14205651 | 11 hrs ago | 0.00875454 GLMR | ||||
| 14205591 | 11 hrs ago | 0.00875454 GLMR | ||||
| 14205488 | 11 hrs ago | 0.00875454 GLMR | ||||
| 14205420 | 11 hrs ago | 0.00875454 GLMR | ||||
| 14205009 | 12 hrs ago | 0.00875454 GLMR | ||||
| 14204948 | 12 hrs ago | 0.00875454 GLMR | ||||
| 14204796 | 12 hrs ago | 0.00875454 GLMR | ||||
| 14204618 | 13 hrs ago | 0.00875454 GLMR | ||||
| 14204498 | 13 hrs ago | 0.00875454 GLMR | ||||
| 14204340 | 13 hrs ago | 0.00875454 GLMR | ||||
| 14204109 | 13 hrs ago | 0.00875454 GLMR | ||||
| 14203990 | 14 hrs ago | 0.00875454 GLMR | ||||
| 14203873 | 14 hrs ago | 0.00875454 GLMR |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
WormholeRelayer
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// 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;
}
}// 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);// 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
}
}// 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);
}
}
}// 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
);
}
}// 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;
}
}
}// 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;
}
}// 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));
}
}// 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);
}
}
}// 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;
}// 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)
}
}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);
}
}// 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);
}// 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;
}// 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);
}
}
}// 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));
}// 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;
}// 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);
}// 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);
}
}
}
}// 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
}
}
}{
"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
- No Contract Security Audit Submitted- Submit Audit Here
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"}]Contract Creation Code
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
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in GLMR
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.