Source Code
Overview
ETH Balance
0 ETH
More Info
ContractCreator
Multichain Info
N/A
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
Loading...
Loading
Contract Name:
GmpManager
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 200 runs
Other Settings:
london EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "../interfaces/IGmpManager.sol";
import "../libraries/GmpStructs.sol";
import "./GmpIntegration.sol";
import {ManagerBase} from "../NttManager/ManagerBase.sol";
import "wormhole-solidity-sdk/Utils.sol";
contract GmpManager is IGmpManager, ManagerBase {
string public constant GMP_MANAGER_VERSION = "1.0.0";
constructor(
uint16 _chainId
) ManagerBase(_chainId) {}
struct GmpPeer {
bytes32 peerAddress;
}
function __GmpManager_init() internal onlyInitializing {
// check if the owner is the deployer of this contract
if (msg.sender != deployer) {
revert UnexpectedDeployer(deployer, msg.sender);
}
if (msg.value != 0) {
revert UnexpectedMsgValue();
}
__PausedOwnable_init(msg.sender, msg.sender);
__ReentrancyGuard_init();
// NOTE: we bump the message counter to start from 1
// this is so we can use '0' as a sentinel value for unreserved sequences
_useMessageSequence();
}
function _initialize() internal virtual override {
super._initialize();
__GmpManager_init();
// Note: _checkThresholdInvariants() removed since we don't maintain global thresholds
_checkTransceiversInvariants();
}
// =============== Storage ==============================================================
bytes32 private constant PEERS_SLOT = bytes32(uint256(keccak256("gmp.peers")) - 1);
bytes32 private constant RESERVED_SEQUENCES_SLOT =
bytes32(uint256(keccak256("gmp.reservedSequences")) - 1);
// =============== Storage Getters/Setters ==============================================
function _getPeersStorage() internal pure returns (mapping(uint16 => GmpPeer) storage $) {
uint256 slot = uint256(PEERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getReservedSequencesStorage()
internal
pure
returns (mapping(address => mapping(uint64 => bool)) storage $)
{
uint256 slot = uint256(RESERVED_SEQUENCES_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
// =============== Public Getters ========================================================
function getPeer(
uint16 chainId_
) external view returns (GmpPeer memory) {
return _getPeersStorage()[chainId_];
}
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view override {
if (_getPeersStorage()[sourceChainId].peerAddress != peerAddress) {
revert InvalidPeer(sourceChainId, peerAddress);
}
}
// =============== External Interface =========================================================
/**
* @notice Reserve a message sequence number for later use
* @dev This function allows users to reserve sequence numbers ahead of time,
* which can be useful for applications that need deterministic sequence numbers
* or want to guarantee a specific ordering of messages.
*
* @dev Sequence numbers start at 1 (not 0) to allow 0 to be used as a sentinel value
* to indicate "no reserved sequence" in sendMessage calls.
*
* @dev Reserved sequences are per-sender, meaning only the address that reserved
* a sequence can use it in a subsequent sendMessage call.
*
* @dev Reserved sequences are single-use - once consumed in a sendMessage call,
* they cannot be reused.
*
* @return sequence The reserved sequence number
*/
function reserveMessageSequence() external override returns (uint64 sequence) {
sequence = _useMessageSequence();
_getReservedSequencesStorage()[msg.sender][sequence] = true;
}
function _verifyAndConsumeReservedMessageSequence(
uint64 sequence
) internal {
if (!_getReservedSequencesStorage()[msg.sender][sequence]) {
revert SequenceNotReservedBySender(sequence, msg.sender);
}
_getReservedSequencesStorage()[msg.sender][sequence] = false;
}
// this exists just to minimise the number of local variable assignments :(
struct PreparedTransfer {
address[] enabledTransceivers;
TransceiverStructs.TransceiverInstruction[] instructions;
uint256[] priceQuotes;
uint256 totalPriceQuote;
}
/**
* @notice Send a cross-chain message to a target contract
* @dev This function supports both immediate sequence allocation and pre-reserved sequences.
*
* ## Sequence Reservation Flow:
*
* ### Option 1: Immediate Sequence Allocation
* - Pass `reservedSequence = 0` to allocate a new sequence immediately
* - The function will automatically assign the next available sequence number
* - This is the default behavior for most use cases
*
* ### Option 2: Pre-Reserved Sequence Usage
* - First call `reserveMessageSequence()` to obtain a reserved sequence number
* - Then pass that sequence number as `reservedSequence` parameter
* - The function will validate that the sequence was reserved by the caller
* - Once used, the reserved sequence is consumed and cannot be reused
*
* @param targetChain The Wormhole chain ID of the target chain
* @param callee The address of the contract to call on the target chain (32-byte format)
* @param refundAddress The address to refund excess fees to on the target chain (32-byte format)
* @param reservedSequence The pre-reserved sequence to use, or 0 for immediate allocation
* @param data The calldata to execute on the target chain
* @param transceiverInstructions Instructions for transceivers (e.g., gas limits, relayer settings)
*
* @return actualSequence The sequence number assigned to this message
*
*/
function sendMessage(
uint16 targetChain,
bytes32 callee,
bytes32 refundAddress,
uint64 reservedSequence,
bytes calldata data,
bytes calldata transceiverInstructions
) external payable override nonReentrant whenNotPaused returns (uint64 actualSequence) {
return _sendMessage(
targetChain, callee, refundAddress, reservedSequence, data, transceiverInstructions
);
}
function _sendMessage(
uint16 targetChain,
bytes32 callee,
bytes32 refundAddress,
uint64 reservedSequence,
bytes calldata data,
bytes calldata transceiverInstructions
) internal returns (uint64 sequence) {
if (callee == bytes32(0)) {
revert InvalidCallee();
}
if (refundAddress == bytes32(0)) {
revert InvalidRefundAddress();
}
// Handle sequence allocation/reservation
if (reservedSequence == 0) {
// No sequence provided, allocate a new one
sequence = _useMessageSequence();
} else {
_verifyAndConsumeReservedMessageSequence(reservedSequence);
sequence = reservedSequence;
}
bytes memory encodedGmpManagerPayload;
{
GmpStructs.GenericMessage memory message = GmpStructs.GenericMessage({
toChain: targetChain,
callee: callee,
sender: toWormholeFormat(msg.sender),
data: data
});
encodedGmpManagerPayload = TransceiverStructs.encodeNttManagerMessage(
TransceiverStructs.NttManagerMessage(
bytes32(uint256(sequence)),
toWormholeFormat(msg.sender),
GmpStructs.encodeGenericMessage(message)
)
);
}
PreparedTransfer memory preparedTransfer;
{
(
address[] memory enabledTransceivers,
TransceiverStructs.TransceiverInstruction[] memory instructions,
uint256[] memory priceQuotes,
uint256 totalPriceQuote
) = _prepareForTransfer(targetChain, transceiverInstructions);
preparedTransfer = PreparedTransfer({
enabledTransceivers: enabledTransceivers,
instructions: instructions,
priceQuotes: priceQuotes,
totalPriceQuote: totalPriceQuote
});
}
bytes32 peerAddress = _getPeersStorage()[targetChain].peerAddress;
if (peerAddress == bytes32(0)) {
revert InvalidPeer(targetChain, peerAddress);
}
_sendMessageToTransceivers(
targetChain,
refundAddress,
peerAddress,
preparedTransfer.priceQuotes,
preparedTransfer.instructions,
preparedTransfer.enabledTransceivers,
encodedGmpManagerPayload
);
emit MessageSent(
sequence, msg.sender, targetChain, callee, data, preparedTransfer.totalPriceQuote
);
}
function executeMsg(
uint16 sourceChainId,
bytes32 sourceGmpManagerAddress,
TransceiverStructs.NttManagerMessage memory message
) public override nonReentrant whenNotPaused {
(bytes32 digest, bool alreadyExecuted) =
_isMessageExecuted(sourceChainId, sourceGmpManagerAddress, message);
if (alreadyExecuted) {
return;
}
GmpStructs.GenericMessage memory gmp = GmpStructs.parseGenericMessage(message.payload);
if (gmp.toChain != chainId) {
revert InvalidTargetChain(gmp.toChain, chainId);
}
address callee = fromWormholeFormat(gmp.callee);
GmpIntegration(callee).receiveMessage(sourceChainId, gmp.sender, gmp.data);
emit MessageExecuted(
digest, sourceChainId, fromWormholeFormat(message.sender), callee, gmp.data
);
}
// =============== Admin ==============================================================
function setPeer(uint16 peerChainId, bytes32 peerAddress) public onlyOwner {
if (peerChainId == 0) {
revert InvalidPeerChainIdZero();
}
if (peerAddress == bytes32(0)) {
revert InvalidPeerZeroAddress();
}
if (peerChainId == chainId) {
revert InvalidPeerSameChainId();
}
GmpPeer memory oldPeer = _getPeersStorage()[peerChainId];
_getPeersStorage()[peerChainId].peerAddress = peerAddress;
_addToKnownChains(peerChainId);
emit PeerUpdated(peerChainId, oldPeer.peerAddress, peerAddress);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "./IManagerBase.sol";
interface IGmpManager is IManagerBase {
/// @notice The caller is not the deployer.
error UnexpectedDeployer(address expectedOwner, address owner);
/// @notice An unexpected msg.value was passed with the call
/// @dev Selector 0xbd28e889.
error UnexpectedMsgValue();
error InvalidTargetChain(uint16 targetChain, uint16 chainId);
error CallFailed(bytes returnData);
error InvalidCallee();
error InvalidEvmAddress();
error SequenceNotReserved(uint64 sequence);
error SequenceNotReservedBySender(uint64 sequence, address sender);
/// @notice Emitted when a message is sent to another chain
/// @param sequence The sequence number of the message
/// @param sender The address of the message sender
/// @param targetChain The chain ID of the target chain
/// @param callee The address of the contract to call on the target chain
/// @param data The calldata to be executed on the target chain
/// @param fee The total fee paid for sending the message
event MessageSent(
uint64 indexed sequence,
address indexed sender,
uint16 targetChain,
bytes32 callee,
bytes data,
uint256 fee
);
/// @notice Emitted when a message is executed on this chain
/// @param messageHash The hash of the executed message
/// @param sourceChain The chain ID of the source chain
/// @param sender The address of the message sender on the source chain
/// @param callee The address of the contract called on this chain
/// @param data The calldata executed on this chain
event MessageExecuted(
bytes32 indexed messageHash,
uint16 indexed sourceChain,
address indexed sender,
address callee,
bytes data
);
/// @notice Emitted when a peer is updated
/// @param chainId The chain ID of the updated peer
/// @param oldPeerAddress The previous address of the peer
/// @param newPeerAddress The new address of the peer
event PeerUpdated(uint16 indexed chainId, bytes32 oldPeerAddress, bytes32 newPeerAddress);
/**
* @notice Reserve a message sequence number for later use
* @dev Sequence numbers start at 1 to allow 0 as sentinel value for "no reserved sequence"
* @dev Reserved sequences are per-sender and single-use
* @return sequence The reserved sequence number
*/
function reserveMessageSequence() external returns (uint64 sequence);
/**
* @notice Send a cross-chain message with optional sequence reservation
* @dev Pass reservedSequence = 0 for immediate allocation, or a pre-reserved sequence number
* @param targetChain The Wormhole chain ID of the target chain
* @param callee The target contract address (32-byte format)
* @param refundAddress The refund address (32-byte format)
* @param reservedSequence Pre-reserved sequence (0 for immediate allocation)
* @param data The calldata to execute on target chain
* @param transceiverInstructions Instructions for transceivers
* @return sequence The sequence number assigned to this message
*/
function sendMessage(
uint16 targetChain,
bytes32 callee,
bytes32 refundAddress,
uint64 reservedSequence,
bytes calldata data,
bytes calldata transceiverInstructions
) external payable returns (uint64 sequence);
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
library GmpStructs {
using BytesParsing for bytes;
error PayloadTooLong(uint256 length);
error InvalidPrefix();
/// @dev Prefix for all GenericMesage payloads
/// This is 0x99'G''M''P'
bytes4 constant GMP_PREFIX = 0x99474D50;
struct GenericMessage {
/// @notice target chain
uint16 toChain;
/// @notice contract to deliver the payload to
bytes32 callee;
/// @notice sender of the message
bytes32 sender;
/// @notice calldata to pass to the recipient contract
bytes data;
}
function encodeGenericMessage(
GenericMessage memory message
) internal pure returns (bytes memory) {
if (message.data.length > type(uint16).max) {
revert PayloadTooLong(message.data.length);
}
return abi.encodePacked(
GMP_PREFIX,
message.toChain,
message.callee,
message.sender,
uint16(message.data.length),
message.data
);
}
function parseGenericMessage(
bytes memory encoded
) internal pure returns (GenericMessage memory message) {
uint256 offset = 0;
bytes4 prefix;
(prefix, offset) = encoded.asBytes4Unchecked(offset);
if (prefix != GMP_PREFIX) revert InvalidPrefix();
(message.toChain, offset) = encoded.asUint16Unchecked(offset);
(message.callee, offset) = encoded.asBytes32Unchecked(offset);
(message.sender, offset) = encoded.asBytes32Unchecked(offset);
uint16 dataLength;
(dataLength, offset) = encoded.asUint16Unchecked(offset);
(message.data, offset) = encoded.sliceUnchecked(offset, dataLength);
encoded.checkLength(offset);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "../interfaces/IGmpManager.sol";
abstract contract GmpIntegration {
IGmpManager public immutable gmpManager;
error OnlyGmpManagerAllowed();
constructor(
IGmpManager _gmpManager
) {
gmpManager = _gmpManager;
}
modifier onlyGmpManager() {
if (msg.sender != address(gmpManager)) revert OnlyGmpManagerAllowed();
_;
}
function receiveMessage(
uint16 sourceChainId,
bytes32 sender,
bytes calldata data
) external onlyGmpManager {
_receiveMessage(sourceChainId, sender, data);
}
function _receiveMessage(
uint16 sourceChainId,
bytes32 sender,
bytes calldata data
) internal virtual;
function _sendMessage(
uint256 msgValue,
uint16 targetChain,
bytes32 callee,
bytes32 refundAddress,
uint64 reservedSequence,
bytes memory data,
bytes memory transceiverInstructions
) internal returns (uint64 sequence) {
return gmpManager.sendMessage{value: msgValue}(
targetChain, callee, refundAddress, reservedSequence, data, transceiverInstructions
);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/Utils.sol";
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "../libraries/external/OwnableUpgradeable.sol";
import "../libraries/external/ReentrancyGuardUpgradeable.sol";
import "../libraries/TransceiverStructs.sol";
import "../libraries/TransceiverHelpers.sol";
import "../libraries/PausableOwnable.sol";
import "../libraries/Implementation.sol";
import "../interfaces/ITransceiver.sol";
import "../interfaces/IManagerBase.sol";
import "./TransceiverRegistry.sol";
abstract contract ManagerBase is
IManagerBase,
TransceiverRegistry,
PausableOwnable,
ReentrancyGuardUpgradeable,
Implementation
{
// =============== Immutables ============================================================
/// @dev Contract deployer address
address immutable deployer;
/// @dev Wormhole chain ID that the NTT Manager is deployed on.
/// This chain ID is formatted Wormhole Chain IDs -- https://docs.wormhole.com/wormhole/reference/constants
uint16 public immutable chainId;
/// @dev EVM chain ID that the NTT Manager is deployed on.
/// This chain ID is formatted based on standardized chain IDs, e.g. Ethereum mainnet is 1, Sepolia is 11155111, etc.
uint256 immutable evmChainId;
// =============== Setup =================================================================
constructor(
uint16 _chainId
) {
chainId = _chainId;
evmChainId = block.chainid;
// save the deployer (check this on initialization)
deployer = msg.sender;
}
function _migrate() internal virtual override {
// Note: _checkThresholdInvariants() removed since we don't maintain global thresholds
_checkTransceiversInvariants();
}
// =============== Storage ==============================================================
bytes32 private constant MESSAGE_ATTESTATIONS_SLOT =
bytes32(uint256(keccak256("ntt.messageAttestations")) - 1);
bytes32 private constant MESSAGE_SEQUENCE_SLOT =
bytes32(uint256(keccak256("ntt.messageSequence")) - 1);
// Note: THRESHOLD_SLOT removed - we now use per-chain thresholds only
// TODO: come up with a backwards compatible way so this contract can be
// merged upstream (probably some simple abstract class hierarchy)
// =============== Storage Getters/Setters ==============================================
// Note: _getThresholdStorage() removed - we now use per-chain thresholds only
function _getMessageAttestationsStorage()
internal
pure
returns (mapping(bytes32 => AttestationInfo) storage $)
{
uint256 slot = uint256(MESSAGE_ATTESTATIONS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getMessageSequenceStorage() internal pure returns (_Sequence storage $) {
uint256 slot = uint256(MESSAGE_SEQUENCE_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
// =============== External Logic =============================================================
function attestationReceived(
uint16 sourceChainId,
bytes32 sourceNttManagerAddress,
TransceiverStructs.NttManagerMessage memory payload
) external onlyTransceiver whenNotPaused {
_verifyPeer(sourceChainId, sourceNttManagerAddress);
// Compute manager message digest and record transceiver attestation.
bytes32 nttManagerMessageHash = _recordTransceiverAttestation(sourceChainId, payload);
if (isMessageApprovedForChain(sourceChainId, nttManagerMessageHash)) {
this.executeMsg(sourceChainId, sourceNttManagerAddress, payload);
}
}
/// @inheritdoc IManagerBase
function quoteDeliveryPrice(
uint16 recipientChain,
bytes memory transceiverInstructions
) public view returns (uint256[] memory, uint256) {
uint256 numRegisteredTransceivers = _getRegisteredTransceiversStorage().length;
address[] memory enabledTransceivers = getSendTransceiversForChain(recipientChain);
TransceiverStructs.TransceiverInstruction[] memory instructions = TransceiverStructs
.parseTransceiverInstructions(transceiverInstructions, numRegisteredTransceivers);
return _quoteDeliveryPrice(recipientChain, instructions, enabledTransceivers);
}
// =============== Internal Logic ===========================================================
function _quoteDeliveryPrice(
uint16 recipientChain,
TransceiverStructs.TransceiverInstruction[] memory transceiverInstructions,
address[] memory enabledTransceivers
) internal view returns (uint256[] memory, uint256) {
uint256 numEnabledTransceivers = enabledTransceivers.length;
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
uint256[] memory priceQuotes = new uint256[](numEnabledTransceivers);
uint256 totalPriceQuote = 0;
for (uint256 i = 0; i < numEnabledTransceivers; i++) {
address transceiverAddr = enabledTransceivers[i];
uint8 registeredTransceiverIndex = transceiverInfos[transceiverAddr].index;
uint256 transceiverPriceQuote = ITransceiver(transceiverAddr).quoteDeliveryPrice(
recipientChain, transceiverInstructions[registeredTransceiverIndex]
);
priceQuotes[i] = transceiverPriceQuote;
totalPriceQuote += transceiverPriceQuote;
}
return (priceQuotes, totalPriceQuote);
}
function _recordTransceiverAttestation(
uint16 sourceChainId,
TransceiverStructs.NttManagerMessage memory payload
) internal returns (bytes32) {
bytes32 nttManagerMessageHash =
TransceiverStructs.nttManagerMessageDigest(sourceChainId, payload);
// set the attested flag for this transceiver.
// NOTE: Attestation is idempotent (bitwise or 1), but we revert
// anyway to ensure that the client does not continue to initiate calls
// to receive the same message through the same transceiver.
if (
transceiverAttestedToMessage(
nttManagerMessageHash, _getTransceiverInfosStorage()[msg.sender].index
)
) {
revert TransceiverAlreadyAttestedToMessage(nttManagerMessageHash);
}
_setTransceiverAttestedToMessage(nttManagerMessageHash, msg.sender);
return nttManagerMessageHash;
}
function _isMessageExecuted(
uint16 sourceChainId,
bytes32 sourceNttManagerAddress,
TransceiverStructs.NttManagerMessage memory message
) internal returns (bytes32, bool) {
bytes32 digest = TransceiverStructs.nttManagerMessageDigest(sourceChainId, message);
if (!isMessageApprovedForChain(sourceChainId, digest)) {
revert MessageNotApproved(digest);
}
bool msgAlreadyExecuted = _replayProtect(digest);
if (msgAlreadyExecuted) {
// end execution early to mitigate the possibility of race conditions from transceivers
// attempting to deliver the same message when (threshold < number of transceiver messages)
// notify client (off-chain process) so they don't attempt redundant msg delivery
emit MessageAlreadyExecuted(sourceNttManagerAddress, digest);
return (bytes32(0), msgAlreadyExecuted);
}
return (digest, msgAlreadyExecuted);
}
function _sendMessageToTransceivers(
uint16 recipientChain,
bytes32 refundAddress,
bytes32 peerAddress,
uint256[] memory priceQuotes,
TransceiverStructs.TransceiverInstruction[] memory transceiverInstructions,
address[] memory enabledTransceivers,
bytes memory nttManagerMessage
) internal {
uint256 numEnabledTransceivers = enabledTransceivers.length;
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
if (peerAddress == bytes32(0)) {
revert PeerNotRegistered(recipientChain);
}
// push onto the stack again to avoid stack too deep error
bytes32 refundRecipient = refundAddress;
// call into transceiver contracts to send the message
for (uint256 i = 0; i < numEnabledTransceivers; i++) {
address transceiverAddr = enabledTransceivers[i];
// send it to the recipient nttManager based on the chain
ITransceiver(transceiverAddr).sendMessage{value: priceQuotes[i]}(
recipientChain,
transceiverInstructions[transceiverInfos[transceiverAddr].index],
nttManagerMessage,
peerAddress,
refundRecipient
);
}
}
function _prepareForTransfer(
uint16 recipientChain,
bytes memory transceiverInstructions
)
internal
returns (
address[] memory,
TransceiverStructs.TransceiverInstruction[] memory,
uint256[] memory,
uint256
)
{
address[] memory enabledTransceivers = getSendTransceiversForChain(recipientChain);
TransceiverStructs.TransceiverInstruction[] memory instructions;
{
uint256 numRegisteredTransceivers = _getRegisteredTransceiversStorage().length;
uint256 numEnabledTransceivers = enabledTransceivers.length;
if (numEnabledTransceivers == 0) {
revert NoEnabledTransceivers();
}
instructions = TransceiverStructs.parseTransceiverInstructions(
transceiverInstructions, numRegisteredTransceivers
);
}
(uint256[] memory priceQuotes, uint256 totalPriceQuote) =
_quoteDeliveryPrice(recipientChain, instructions, enabledTransceivers);
{
// check up front that msg.value will cover the delivery price
if (msg.value < totalPriceQuote) {
revert DeliveryPaymentTooLow(totalPriceQuote, msg.value);
}
// refund user extra excess value from msg.value
uint256 excessValue = msg.value - totalPriceQuote;
if (excessValue > 0) {
_refundToSender(excessValue);
}
}
return (enabledTransceivers, instructions, priceQuotes, totalPriceQuote);
}
function _refundToSender(
uint256 refundAmount
) internal {
// refund the price quote back to sender
(bool refundSuccessful,) = payable(msg.sender).call{value: refundAmount}("");
// check success
if (!refundSuccessful) {
revert RefundFailed(refundAmount);
}
}
// =============== Public Getters ========================================================
/// @notice Check if a message has enough attestations for a specific source chain
function isMessageApprovedForChain(
uint16 sourceChain,
bytes32 digest
) public view returns (bool) {
uint8 threshold = _getThresholdForChain(sourceChain);
uint8 attestations = messageAttestationsForChain(sourceChain, digest);
return attestations >= threshold && threshold > 0;
}
/// @inheritdoc IManagerBase
function getThreshold(
uint16 sourceChain
) external view returns (uint8) {
return _getThresholdForChain(sourceChain);
}
/// @inheritdoc IManagerBase
function nextMessageSequence() external view returns (uint64) {
return _getMessageSequenceStorage().num;
}
/// @inheritdoc IManagerBase
function isMessageExecuted(
bytes32 digest
) public view returns (bool) {
return _getMessageAttestationsStorage()[digest].executed;
}
/// @inheritdoc IManagerBase
function transceiverAttestedToMessage(bytes32 digest, uint8 index) public view returns (bool) {
return
_getMessageAttestationsStorage()[digest].attestedTransceivers & uint64(1 << index) > 0;
}
/// @inheritdoc IManagerBase
function messageAttestations(
bytes32 digest
) public view returns (uint8 count) {
return countSetBits(_getMessageAttestations(digest));
}
/// @notice Get the number of attestations for a message from a specific source chain
function messageAttestationsForChain(
uint16 sourceChain,
bytes32 digest
) public view returns (uint8 count) {
return countSetBits(_getMessageAttestationsForChain(sourceChain, digest));
}
// =============== Admin ==============================================================
/// @inheritdoc IManagerBase
function upgrade(
address newImplementation
) external onlyOwner {
_upgrade(newImplementation);
}
/// @inheritdoc IManagerBase
function pause() public onlyOwnerOrPauser {
_pause();
}
function unpause() public onlyOwner {
_unpause();
}
/// @notice Transfer ownership of the Manager contract and all Transceiver contracts to a new owner.
function transferOwnership(
address newOwner
) public override onlyOwner {
super.transferOwnership(newOwner);
// loop through all the registered transceivers and set the new owner of each transceiver to the newOwner
address[] storage _registeredTransceivers = _getRegisteredTransceiversStorage();
_checkRegisteredTransceiversInvariants();
for (uint256 i = 0; i < _registeredTransceivers.length; i++) {
ITransceiver(_registeredTransceivers[i]).transferTransceiverOwnership(newOwner);
}
}
/// @inheritdoc IManagerBase
function setTransceiver(
address transceiver
) external onlyOwner {
_setTransceiver(transceiver);
// Note: Global threshold is no longer maintained since we use per-chain thresholds.
// Per-chain thresholds must be configured separately using setThreshold(uint16, uint8).
emit TransceiverAdded(transceiver, _getNumTransceiversStorage().enabled, 0);
// Note: _checkThresholdInvariants() removed since we don't maintain global thresholds
}
/// @inheritdoc IManagerBase
function removeTransceiver(
address transceiver
) external onlyOwner {
uint8 numEnabledTransceivers = _getNumTransceiversStorage().enabled;
// Prevent removing the last transceiver - you need at least one for the system to work
if (numEnabledTransceivers <= 1) {
revert ZeroThreshold(); // Reusing this error since it's about threshold requirements
}
// remove from all per-chain configurations first
_removeTransceiverFromAllChains(transceiver);
// then remove globally
_removeTransceiver(transceiver);
// Note: Global threshold is no longer maintained since we use per-chain thresholds.
// Per-chain thresholds are automatically adjusted in _removeReceiveTransceiverForChain().
emit TransceiverRemoved(transceiver, 0);
}
/// @notice Add a transceiver for sending to a specific chain
/// @param targetChain The chain ID to send to
/// @param transceiver The transceiver to enable for sending to this chain
function setSendTransceiverForChain(
uint16 targetChain,
address transceiver
) external onlyOwner {
_setSendTransceiverForChain(targetChain, transceiver);
emit SendTransceiverUpdatedForChain(targetChain, transceiver, true);
}
/// @notice Remove a transceiver for sending to a specific chain
/// @param targetChain The chain ID
/// @param transceiver The transceiver to disable for sending to this chain
function removeSendTransceiverForChain(
uint16 targetChain,
address transceiver
) external onlyOwner {
_removeSendTransceiverForChain(targetChain, transceiver);
emit SendTransceiverUpdatedForChain(targetChain, transceiver, false);
}
/// @notice Add a transceiver for receiving from a specific chain
/// @param sourceChain The chain ID to receive from
/// @param transceiver The transceiver to enable for receiving from this chain
function setReceiveTransceiverForChain(
uint16 sourceChain,
address transceiver
) external onlyOwner {
_setReceiveTransceiverForChain(sourceChain, transceiver);
emit ReceiveTransceiverUpdatedForChain(sourceChain, transceiver, true);
}
/// @notice Remove a transceiver for receiving from a specific chain
/// @param sourceChain The chain ID
/// @param transceiver The transceiver to disable for receiving from this chain
function removeReceiveTransceiverForChain(
uint16 sourceChain,
address transceiver
) external onlyOwner {
_removeReceiveTransceiverForChain(sourceChain, transceiver);
emit ReceiveTransceiverUpdatedForChain(sourceChain, transceiver, false);
}
/// @notice Set the threshold for receiving from a specific chain
/// @param sourceChain The chain ID
/// @param threshold The threshold for receiving from this chain
function setThreshold(uint16 sourceChain, uint8 threshold) external onlyOwner {
_setThresholdForChain(sourceChain, threshold);
emit ThresholdUpdatedForChain(sourceChain, threshold);
}
/// @notice Register a known chain for migration purposes
/// @dev This function is used to populate the known chains list for existing deployments
/// that were created before the chain registry was introduced. It verifies the peer
/// relationship before adding the chain to ensure only valid chains are registered.
/// This function can be called by anyone since it only adds valid peer chains.
/// @param peerChainId The chain ID to register
/// @param peerAddress The peer address on that chain (used for verification)
function registerKnownChain(uint16 peerChainId, bytes32 peerAddress) external {
// Verify this is a valid peer relationship
_verifyPeer(peerChainId, peerAddress);
// If verification passes, add to known chains
_addToKnownChains(peerChainId);
}
// =============== Internal ==============================================================
function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal virtual;
function _setTransceiverAttestedToMessage(bytes32 digest, uint8 index) internal {
_getMessageAttestationsStorage()[digest].attestedTransceivers |= uint64(1 << index);
}
function _setTransceiverAttestedToMessage(bytes32 digest, address transceiver) internal {
_setTransceiverAttestedToMessage(digest, _getTransceiverInfosStorage()[transceiver].index);
emit MessageAttestedTo(
digest, transceiver, _getTransceiverInfosStorage()[transceiver].index
);
}
/// @dev Returns the bitmap of attestations from enabled transceivers for a given message.
function _getMessageAttestations(
bytes32 digest
) internal view returns (uint64) {
uint64 enabledTransceiverBitmap = _getEnabledTransceiversBitmap();
return
_getMessageAttestationsStorage()[digest].attestedTransceivers & enabledTransceiverBitmap;
}
/// @dev Returns the bitmap of attestations from enabled transceivers for a given message and source chain.
function _getMessageAttestationsForChain(
uint16 sourceChain,
bytes32 digest
) internal view returns (uint64) {
uint64 enabledTransceiverBitmap = _getReceiveTransceiversBitmapForChain(sourceChain);
return
_getMessageAttestationsStorage()[digest].attestedTransceivers & enabledTransceiverBitmap;
}
function _getEnabledTransceiverAttestedToMessage(
bytes32 digest,
uint8 index
) internal view returns (bool) {
return _getMessageAttestations(digest) & uint64(1 << index) != 0;
}
// @dev Mark a message as executed.
// This function will retuns `true` if the message has already been executed.
function _replayProtect(
bytes32 digest
) internal returns (bool) {
// check if this message has already been executed
if (isMessageExecuted(digest)) {
return true;
}
// mark this message as executed
_getMessageAttestationsStorage()[digest].executed = true;
return false;
}
function _useMessageSequence() internal returns (uint64 currentSequence) {
currentSequence = _getMessageSequenceStorage().num;
_getMessageSequenceStorage().num++;
}
/// ============== Invariants =============================================
/// @dev When we add new immutables, this function should be updated
function _checkImmutables() internal view virtual override {
super._checkImmutables();
assert(this.chainId() == chainId);
}
function _checkRegisteredTransceiversInvariants() internal view {
if (_getRegisteredTransceiversStorage().length != _getNumTransceiversStorage().registered) {
revert RetrievedIncorrectRegisteredTransceivers(
_getRegisteredTransceiversStorage().length, _getNumTransceiversStorage().registered
);
}
}
// Note: _checkThresholdInvariants() function removed since we don't maintain global thresholds
// Per-chain threshold validation is handled in _setThresholdForChain()
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
import "./interfaces/IWormholeRelayer.sol";
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)));
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "../libraries/TransceiverStructs.sol";
interface IManagerBase {
/// @notice Information about attestations for a given message.
/// @dev The fields are as follows:
/// - executed: whether the message has been executed.
/// - attested: bitmap of transceivers that have attested to this message.
/// (NOTE: might contain disabled transceivers)
struct AttestationInfo {
bool executed;
uint64 attestedTransceivers;
}
struct _Sequence {
uint64 num;
}
struct _Threshold {
uint8 num;
}
/// @notice Emitted when a message has been attested to.
/// @dev Topic0
/// 0x35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e5.
/// @param digest The digest of the message.
/// @param transceiver The address of the transceiver.
/// @param index The index of the transceiver in the bitmap.
event MessageAttestedTo(bytes32 digest, address transceiver, uint8 index);
/// @notice Emmitted when the threshold required transceivers is changed.
/// @dev Topic0
/// 0x2a855b929b9a53c6fb5b5ed248b27e502b709c088e036a5aa17620c8fc5085a9.
/// @param oldThreshold The old threshold.
/// @param threshold The new threshold.
event ThresholdChanged(uint8 oldThreshold, uint8 threshold);
/// @notice Emitted when an transceiver is removed from the nttManager.
/// @dev Topic0
/// 0xf05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5.
/// @param transceiver The address of the transceiver.
/// @param transceiversNum The current number of transceivers.
/// @param threshold The current threshold of transceivers.
event TransceiverAdded(address transceiver, uint256 transceiversNum, uint8 threshold);
/// @notice Emitted when an transceiver is removed from the nttManager.
/// @dev Topic0
/// 0x697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f.
/// @param transceiver The address of the transceiver.
/// @param threshold The current threshold of transceivers.
event TransceiverRemoved(address transceiver, uint8 threshold);
/// @notice Emitted when a send transceiver is updated for a specific chain.
/// @param targetChain The chain ID.
/// @param transceiver The transceiver address.
/// @param enabled Whether the transceiver is enabled or disabled.
event SendTransceiverUpdatedForChain(uint16 targetChain, address transceiver, bool enabled);
/// @notice Emitted when a receive transceiver is updated for a specific chain.
/// @param sourceChain The chain ID.
/// @param transceiver The transceiver address.
/// @param enabled Whether the transceiver is enabled or disabled.
event ReceiveTransceiverUpdatedForChain(uint16 sourceChain, address transceiver, bool enabled);
/// @notice Emitted when the threshold is updated for a specific chain.
/// @param sourceChain The chain ID.
/// @param threshold The new threshold.
event ThresholdUpdatedForChain(uint16 sourceChain, uint8 threshold);
/// @notice payment for a transfer is too low.
/// @param requiredPayment The required payment.
/// @param providedPayment The provided payment.
error DeliveryPaymentTooLow(uint256 requiredPayment, uint256 providedPayment);
/// @notice Error when the refund to the sender fails.
/// @dev Selector 0x2ca23714.
/// @param refundAmount The refund amount.
error RefundFailed(uint256 refundAmount);
/// @notice The number of thresholds should not be zero.
error ZeroThreshold();
error RetrievedIncorrectRegisteredTransceivers(uint256 retrieved, uint256 registered);
/// @notice The threshold for transceiver attestations is too high.
/// @param threshold The threshold.
/// @param transceivers The number of transceivers.
error ThresholdTooHigh(uint256 threshold, uint256 transceivers);
/// @notice Error when the tranceiver already attested to the message.
/// To ensure the client does not continue to initiate calls to the attestationReceived function.
/// @dev Selector 0x2113894.
/// @param nttManagerMessageHash The hash of the message.
error TransceiverAlreadyAttestedToMessage(bytes32 nttManagerMessageHash);
/// @notice Error when the message is not approved.
/// @dev Selector 0x451c4fb0.
/// @param msgHash The hash of the message.
error MessageNotApproved(bytes32 msgHash);
/// @notice Emitted when a message has already been executed to
/// notify client of against retries.
/// @dev Topic0
/// 0x4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2.
/// @param sourceNttManager The address of the source nttManager.
/// @param msgHash The keccak-256 hash of the message.
event MessageAlreadyExecuted(bytes32 indexed sourceNttManager, bytes32 indexed msgHash);
/// @notice There are no transceivers enabled with the Manager
/// @dev Selector 0x69cf632a
error NoEnabledTransceivers();
/// @notice Error when the recipient is invalid.
/// @dev Selector 0xe2fe2726.
error InvalidRefundAddress();
/// @notice Peer chain ID cannot be zero.
error InvalidPeerChainIdZero();
/// @notice Peer cannot be the zero address.
error InvalidPeerZeroAddress();
/// @notice Peer cannot be on the same chain
/// @dev Selector 0x20371f2a.
error InvalidPeerSameChainId();
/// @notice Peer for the chain does not match the configuration.
/// @param chainId ChainId of the source chain.
/// @param peerAddress Address of the peer nttManager contract.
error InvalidPeer(uint16 chainId, bytes32 peerAddress);
/// @notice Error when the manager doesn't have a peer registered for the destination chain
/// @dev Selector 0x3af256bc.
/// @param chainId The target Wormhole chain id
error PeerNotRegistered(uint16 chainId);
/// @notice Called by a Transceiver contract to deliver a verified attestation.
/// @dev This function enforces attestation threshold and replay logic for messages. Once all
/// validations are complete, this function calls `executeMsg` to execute the command specified
/// by the message.
/// @param sourceChainId The Wormhole chain id of the sender.
/// @param sourceNttManagerAddress The address of the sender's NTT Manager contract.
/// @param payload The VAA payload.
function attestationReceived(
uint16 sourceChainId,
bytes32 sourceNttManagerAddress,
TransceiverStructs.NttManagerMessage memory payload
) external;
/// @notice Called after a message has been sufficiently verified to execute
/// the command in the message.
/// @dev This function is exposed as a fallback for when an `Transceiver` is deregistered
/// when a message is in flight.
/// @param sourceChainId The Wormhole chain id of the sender.
/// @param sourceNttManagerAddress The address of the sender's nttManager contract.
/// @param message The message to execute.
function executeMsg(
uint16 sourceChainId,
bytes32 sourceNttManagerAddress,
TransceiverStructs.NttManagerMessage memory message
) external;
/// @notice Fetch the delivery price for a given recipient chain transfer.
/// @param recipientChain The Wormhole chain ID of the transfer destination.
/// @param transceiverInstructions The transceiver specific instructions for quoting and sending
/// @return - The delivery prices associated with each enabled endpoint and the total price.
function quoteDeliveryPrice(
uint16 recipientChain,
bytes memory transceiverInstructions
) external view returns (uint256[] memory, uint256);
/// @notice Sets the threshold for the number of attestations required for a message
/// from a specific source chain to be considered valid.
/// @param sourceChain The chain ID to set the threshold for.
/// @param threshold The new threshold (number of attestations).
/// @dev This method can only be executed by the `owner`.
function setThreshold(uint16 sourceChain, uint8 threshold) external;
/// @notice Sets the transceiver for the given chain.
/// @param transceiver The address of the transceiver.
/// @dev This method can only be executed by the `owner`.
function setTransceiver(
address transceiver
) external;
/// @notice Removes the transceiver for the given chain.
/// @param transceiver The address of the transceiver.
/// @dev This method can only be executed by the `owner`.
function removeTransceiver(
address transceiver
) external;
/// @param sourceChain The chain ID of the message source.
/// @param digest The digest of the message.
/// @return approved Boolean indicating if the message is approved for execution.
function isMessageApprovedForChain(
uint16 sourceChain,
bytes32 digest
) external view returns (bool approved);
/// @notice Checks if a message has been executed.
/// @param digest The digest of the message.
/// @return - Boolean indicating if message has been executed.
function isMessageExecuted(
bytes32 digest
) external view returns (bool);
/// @notice Returns the next message sequence.
function nextMessageSequence() external view returns (uint64);
/// @notice Upgrades to a new manager implementation.
/// @dev This is upgraded via a proxy, and can only be executed
/// by the `owner`.
/// @param newImplementation The address of the new implementation.
function upgrade(
address newImplementation
) external;
/// @notice Pauses the manager.
function pause() external;
/// @notice Returns the number of Transceivers that must attest to a msgId for
/// it to be considered valid and acted upon from a particular source chain.
/// @param sourceChain The chain ID.
/// @return threshold The threshold for this chain.
function getThreshold(
uint16 sourceChain
) external view returns (uint8 threshold);
/// @notice Returns a boolean indicating if the transceiver has attested to the message.
/// @param digest The digest of the message.
/// @param index The index of the transceiver
/// @return - Boolean indicating whether the transceiver at index `index` attested to a message digest
function transceiverAttestedToMessage(
bytes32 digest,
uint8 index
) external view returns (bool);
/// @notice Returns the number of attestations for a given message.
/// @param digest The digest of the message.
/// @return count The number of attestations received for the given message digest
function messageAttestations(
bytes32 digest
) external view returns (uint8 count);
/// @notice Returns the chain ID.
function chainId() external view returns (uint16);
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.13;
library BytesParsing {
uint256 private constant freeMemoryPtr = 0x40;
uint256 private constant wordSize = 32;
error OutOfBounds(uint256 offset, uint256 length);
error LengthMismatch(uint256 encodedLength, uint256 expectedLength);
error InvalidBoolVal(uint8 val);
function checkBound(uint offset, uint length) internal pure {
if (offset > length)
revert OutOfBounds(offset, length);
}
function checkLength(bytes memory encoded, uint256 expected) internal pure {
if (encoded.length != expected)
revert LengthMismatch(encoded.length, expected);
}
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) = asUint160Unchecked(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 asBoolUnchecked(
bytes memory encoded,
uint offset
) internal pure returns (bool, uint) {
(uint8 val, uint nextOffset) = asUint8Unchecked(encoded, offset);
if (val & 0xfe != 0)
revert InvalidBoolVal(val);
uint cleanedVal = uint(val);
bool ret;
//skip 2x iszero opcode
assembly ("memory-safe") {
ret := cleanedVal
}
return (ret, nextOffset);
}
function asBool(
bytes memory encoded,
uint offset
) internal pure returns (bool ret, uint nextOffset) {
(ret, nextOffset) = asBoolUnchecked(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: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
// COPIED FROM OPENZEPPELIN v5.0.1
// COPIED TO CHANGE SOLC FROM ^0.8.20 TO ^0.8.19
pragma solidity ^0.8.19;
import {ContextUpgradeable} from "./ContextUpgradeable.sol";
import {Initializable} from "./Initializable.sol";
import "../../interfaces/IOwnableUpgradeable.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract OwnableUpgradeable is Initializable, ContextUpgradeable, IOwnableUpgradeable {
/// @custom:storage-location erc7201:openzeppelin.storage.Ownable
struct OwnableStorage {
address _owner;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Ownable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant OwnableStorageLocation =
0x9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300;
function _getOwnableStorage() private pure returns (OwnableStorage storage $) {
assembly {
$.slot := OwnableStorageLocation
}
}
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
function __Ownable_init(
address initialOwner
) internal onlyInitializing {
__Ownable_init_unchained(initialOwner);
}
function __Ownable_init_unchained(
address initialOwner
) internal onlyInitializing {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
OwnableStorage storage $ = _getOwnableStorage();
return $._owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(
address newOwner
) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(
address newOwner
) internal virtual {
OwnableStorage storage $ = _getOwnableStorage();
address oldOwner = $._owner;
$._owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.19;
import {Initializable} from "./Initializable.sol";
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuardUpgradeable is Initializable {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
/// @custom:storage-location erc7201:openzeppelin.storage.ReentrancyGuard
struct ReentrancyGuardStorage {
uint256 _status;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.ReentrancyGuard")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant ReentrancyGuardStorageLocation =
0x9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00;
function _getReentrancyGuardStorage() private pure returns (ReentrancyGuardStorage storage $) {
assembly {
$.slot := ReentrancyGuardStorageLocation
}
}
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
function __ReentrancyGuard_init() internal onlyInitializing {
__ReentrancyGuard_init_unchained();
}
function __ReentrancyGuard_init_unchained() internal onlyInitializing {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
$._status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// On the first call to nonReentrant, _status will be NOT_ENTERED
if ($._status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
$._status = ENTERED;
}
function _nonReentrantAfter() private {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
$._status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
ReentrancyGuardStorage storage $ = _getReentrancyGuardStorage();
return $._status == ENTERED;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "wormhole-solidity-sdk/libraries/BytesParsing.sol";
import "./TrimmedAmount.sol";
library TransceiverStructs {
using BytesParsing for bytes;
using TrimmedAmountLib for TrimmedAmount;
/// @notice Error thrown when the payload length exceeds the allowed maximum.
/// @dev Selector 0xa3419691.
/// @param size The size of the payload.
error PayloadTooLong(uint256 size);
/// @notice Error thrown when the prefix of an encoded message
/// does not match the expected value.
/// @dev Selector 0x56d2569d.
/// @param prefix The prefix that was found in the encoded message.
error IncorrectPrefix(bytes4 prefix);
/// @notice Error thrown when the transceiver instructions aren't
/// encoded with strictly increasing indices
/// @dev Selector 0x0555a4b9.
/// @param lastIndex Last parsed instruction index
/// @param instructionIndex The instruction index that was unordered
error UnorderedInstructions(uint256 lastIndex, uint256 instructionIndex);
/// @notice Error thrown when a transceiver instruction index
/// is greater than the number of registered transceivers
/// @dev We index from 0 so if providedIndex == numTransceivers then we're out-of-bounds too
/// @dev Selector 0x689f5016.
/// @param providedIndex The index specified in the instruction
/// @param numTransceivers The number of registered transceivers
error InvalidInstructionIndex(uint256 providedIndex, uint256 numTransceivers);
/// @dev Prefix for all NativeTokenTransfer payloads
/// This is 0x99'N''T''T'
bytes4 constant NTT_PREFIX = 0x994E5454;
/// @dev Message emitted and received by the nttManager contract.
/// The wire format is as follows:
/// - id - 32 bytes
/// - sender - 32 bytes
/// - payloadLength - 2 bytes
/// - payload - `payloadLength` bytes
struct NttManagerMessage {
/// @notice unique message identifier
/// @dev This is incrementally assigned on EVM chains, but this is not
/// guaranteed on other runtimes.
bytes32 id;
/// @notice original message sender address.
bytes32 sender;
/// @notice payload that corresponds to the type.
bytes payload;
}
function nttManagerMessageDigest(
uint16 sourceChainId,
NttManagerMessage memory m
) internal pure returns (bytes32) {
return _nttManagerMessageDigest(sourceChainId, encodeNttManagerMessage(m));
}
function _nttManagerMessageDigest(
uint16 sourceChainId,
bytes memory encodedNttManagerMessage
) internal pure returns (bytes32) {
return keccak256(abi.encodePacked(sourceChainId, encodedNttManagerMessage));
}
function encodeNttManagerMessage(
NttManagerMessage memory m
) internal pure returns (bytes memory encoded) {
if (m.payload.length > type(uint16).max) {
revert PayloadTooLong(m.payload.length);
}
uint16 payloadLength = uint16(m.payload.length);
return abi.encodePacked(m.id, m.sender, payloadLength, m.payload);
}
/// @notice Parse a NttManagerMessage.
/// @param encoded The byte array corresponding to the encoded message
/// @return nttManagerMessage The parsed NttManagerMessage struct.
function parseNttManagerMessage(
bytes memory encoded
) internal pure returns (NttManagerMessage memory nttManagerMessage) {
uint256 offset = 0;
(nttManagerMessage.id, offset) = encoded.asBytes32Unchecked(offset);
(nttManagerMessage.sender, offset) = encoded.asBytes32Unchecked(offset);
uint256 payloadLength;
(payloadLength, offset) = encoded.asUint16Unchecked(offset);
(nttManagerMessage.payload, offset) = encoded.sliceUnchecked(offset, payloadLength);
encoded.checkLength(offset);
}
/// @dev Native Token Transfer payload.
/// The wire format is as follows:
/// - NTT_PREFIX - 4 bytes
/// - numDecimals - 1 byte
/// - amount - 8 bytes
/// - sourceToken - 32 bytes
/// - to - 32 bytes
/// - toChain - 2 bytes
/// - additionalPayloadLength - 2 bytes, optional
/// - additionalPayload - `additionalPayloadLength` bytes
struct NativeTokenTransfer {
/// @notice Amount being transferred (big-endian u64 and u8 for decimals)
TrimmedAmount amount;
/// @notice Source chain token address.
bytes32 sourceToken;
/// @notice Address of the recipient.
bytes32 to;
/// @notice Chain ID of the recipient
uint16 toChain;
/// @notice Custom payload
/// @dev Recommended that the first 4 bytes are a unique prefix
bytes additionalPayload;
}
function encodeNativeTokenTransfer(
NativeTokenTransfer memory m
) internal pure returns (bytes memory encoded) {
// The `amount` and `decimals` fields are encoded in reverse order compared to how they are declared in the
// `TrimmedAmount` type. This is consistent with the Rust NTT implementation.
TrimmedAmount transferAmount = m.amount;
if (m.additionalPayload.length > 0) {
if (m.additionalPayload.length > type(uint16).max) {
revert PayloadTooLong(m.additionalPayload.length);
}
uint16 additionalPayloadLength = uint16(m.additionalPayload.length);
return abi.encodePacked(
NTT_PREFIX,
transferAmount.getDecimals(),
transferAmount.getAmount(),
m.sourceToken,
m.to,
m.toChain,
additionalPayloadLength,
m.additionalPayload
);
}
return abi.encodePacked(
NTT_PREFIX,
transferAmount.getDecimals(),
transferAmount.getAmount(),
m.sourceToken,
m.to,
m.toChain
);
}
/// @dev Parse a NativeTokenTransfer.
/// @param encoded The byte array corresponding to the encoded message
/// @return nativeTokenTransfer The parsed NativeTokenTransfer struct.
function parseNativeTokenTransfer(
bytes memory encoded
) internal pure returns (NativeTokenTransfer memory nativeTokenTransfer) {
uint256 offset = 0;
bytes4 prefix;
(prefix, offset) = encoded.asBytes4Unchecked(offset);
if (prefix != NTT_PREFIX) {
revert IncorrectPrefix(prefix);
}
// The `amount` and `decimals` fields are parsed in reverse order compared to how they are declared in the
// `TrimmedAmount` struct. This is consistent with the Rust NTT implementation.
uint8 numDecimals;
(numDecimals, offset) = encoded.asUint8Unchecked(offset);
uint64 amount;
(amount, offset) = encoded.asUint64Unchecked(offset);
nativeTokenTransfer.amount = packTrimmedAmount(amount, numDecimals);
(nativeTokenTransfer.sourceToken, offset) = encoded.asBytes32Unchecked(offset);
(nativeTokenTransfer.to, offset) = encoded.asBytes32Unchecked(offset);
(nativeTokenTransfer.toChain, offset) = encoded.asUint16Unchecked(offset);
// The additional payload may be omitted, but if it is included, it is prefixed by a u16 for its length.
// If there are at least 2 bytes remaining, attempt to parse the additional payload.
if (encoded.length >= offset + 2) {
uint256 payloadLength;
(payloadLength, offset) = encoded.asUint16Unchecked(offset);
(nativeTokenTransfer.additionalPayload, offset) =
encoded.sliceUnchecked(offset, payloadLength);
}
encoded.checkLength(offset);
}
/// @dev Message emitted by Transceiver implementations.
/// Each message includes an Transceiver-specified 4-byte prefix.
/// The wire format is as follows:
/// - prefix - 4 bytes
/// - sourceNttManagerAddress - 32 bytes
/// - recipientNttManagerAddress - 32 bytes
/// - nttManagerPayloadLength - 2 bytes
/// - nttManagerPayload - `nttManagerPayloadLength` bytes
/// - transceiverPayloadLength - 2 bytes
/// - transceiverPayload - `transceiverPayloadLength` bytes
struct TransceiverMessage {
/// @notice Address of the NttManager contract that emitted this message.
bytes32 sourceNttManagerAddress;
/// @notice Address of the NttManager contract that receives this message.
bytes32 recipientNttManagerAddress;
/// @notice Payload provided to the Transceiver contract by the NttManager contract.
bytes nttManagerPayload;
/// @notice Optional payload that the transceiver can encode and use for its own message passing purposes.
bytes transceiverPayload;
}
// @notice Encodes an Transceiver message for communication between the
// NttManager and the Transceiver.
// @param m The TransceiverMessage struct containing the message details.
// @return encoded The byte array corresponding to the encoded message.
// @custom:throw PayloadTooLong if the length of transceiverId, nttManagerPayload,
// or transceiverPayload exceeds the allowed maximum.
function encodeTransceiverMessage(
bytes4 prefix,
TransceiverMessage memory m
) internal pure returns (bytes memory encoded) {
if (m.nttManagerPayload.length > type(uint16).max) {
revert PayloadTooLong(m.nttManagerPayload.length);
}
uint16 nttManagerPayloadLength = uint16(m.nttManagerPayload.length);
if (m.transceiverPayload.length > type(uint16).max) {
revert PayloadTooLong(m.transceiverPayload.length);
}
uint16 transceiverPayloadLength = uint16(m.transceiverPayload.length);
return abi.encodePacked(
prefix,
m.sourceNttManagerAddress,
m.recipientNttManagerAddress,
nttManagerPayloadLength,
m.nttManagerPayload,
transceiverPayloadLength,
m.transceiverPayload
);
}
function buildAndEncodeTransceiverMessage(
bytes4 prefix,
bytes32 sourceNttManagerAddress,
bytes32 recipientNttManagerAddress,
bytes memory nttManagerMessage,
bytes memory transceiverPayload
) internal pure returns (TransceiverMessage memory, bytes memory) {
TransceiverMessage memory transceiverMessage = TransceiverMessage({
sourceNttManagerAddress: sourceNttManagerAddress,
recipientNttManagerAddress: recipientNttManagerAddress,
nttManagerPayload: nttManagerMessage,
transceiverPayload: transceiverPayload
});
bytes memory encoded = encodeTransceiverMessage(prefix, transceiverMessage);
return (transceiverMessage, encoded);
}
/// @dev Parses an encoded message and extracts information into an TransceiverMessage struct.
/// @param encoded The encoded bytes containing information about the TransceiverMessage.
/// @return transceiverMessage The parsed TransceiverMessage struct.
/// @custom:throw IncorrectPrefix if the prefix of the encoded message does not
/// match the expected prefix.
function parseTransceiverMessage(
bytes4 expectedPrefix,
bytes memory encoded
) internal pure returns (TransceiverMessage memory transceiverMessage) {
uint256 offset = 0;
bytes4 prefix;
(prefix, offset) = encoded.asBytes4Unchecked(offset);
if (prefix != expectedPrefix) {
revert IncorrectPrefix(prefix);
}
(transceiverMessage.sourceNttManagerAddress, offset) = encoded.asBytes32Unchecked(offset);
(transceiverMessage.recipientNttManagerAddress, offset) = encoded.asBytes32Unchecked(offset);
uint16 nttManagerPayloadLength;
(nttManagerPayloadLength, offset) = encoded.asUint16Unchecked(offset);
(transceiverMessage.nttManagerPayload, offset) =
encoded.sliceUnchecked(offset, nttManagerPayloadLength);
uint16 transceiverPayloadLength;
(transceiverPayloadLength, offset) = encoded.asUint16Unchecked(offset);
(transceiverMessage.transceiverPayload, offset) =
encoded.sliceUnchecked(offset, transceiverPayloadLength);
// Check if the entire byte array has been processed
encoded.checkLength(offset);
}
/// @dev Parses the payload of an Transceiver message and returns
/// the parsed NttManagerMessage struct.
/// @param expectedPrefix The prefix that should be encoded in the nttManager message.
/// @param payload The payload sent across the wire.
function parseTransceiverAndNttManagerMessage(
bytes4 expectedPrefix,
bytes memory payload
) internal pure returns (TransceiverMessage memory, NttManagerMessage memory) {
// parse the encoded message payload from the Transceiver
TransceiverMessage memory parsedTransceiverMessage =
parseTransceiverMessage(expectedPrefix, payload);
// parse the encoded message payload from the NttManager
NttManagerMessage memory parsedNttManagerMessage =
parseNttManagerMessage(parsedTransceiverMessage.nttManagerPayload);
return (parsedTransceiverMessage, parsedNttManagerMessage);
}
/// @dev Variable-length transceiver-specific instruction that can be passed by the caller to the nttManager.
/// The index field refers to the index of the registeredTransceiver that this instruction should be passed to.
/// The serialization format is:
/// - index - 1 byte
/// - payloadLength - 1 byte
/// - payload - `payloadLength` bytes
struct TransceiverInstruction {
uint8 index;
bytes payload;
}
function encodeTransceiverInstruction(
TransceiverInstruction memory instruction
) internal pure returns (bytes memory) {
if (instruction.payload.length > type(uint8).max) {
revert PayloadTooLong(instruction.payload.length);
}
uint8 payloadLength = uint8(instruction.payload.length);
return abi.encodePacked(instruction.index, payloadLength, instruction.payload);
}
function parseTransceiverInstructionUnchecked(
bytes memory encoded,
uint256 offset
) internal pure returns (TransceiverInstruction memory instruction, uint256 nextOffset) {
(instruction.index, nextOffset) = encoded.asUint8Unchecked(offset);
uint8 instructionLength;
(instructionLength, nextOffset) = encoded.asUint8Unchecked(nextOffset);
(instruction.payload, nextOffset) = encoded.sliceUnchecked(nextOffset, instructionLength);
}
function parseTransceiverInstructionChecked(
bytes memory encoded
) internal pure returns (TransceiverInstruction memory instruction) {
uint256 offset = 0;
(instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset);
encoded.checkLength(offset);
}
/// @dev Encode an array of multiple variable-length transceiver-specific instructions.
/// The serialization format is:
/// - instructionsLength - 1 byte
/// - `instructionsLength` number of serialized `TransceiverInstruction` types.
function encodeTransceiverInstructions(
TransceiverInstruction[] memory instructions
) internal pure returns (bytes memory) {
if (instructions.length > type(uint8).max) {
revert PayloadTooLong(instructions.length);
}
uint256 instructionsLength = instructions.length;
bytes memory encoded;
for (uint256 i = 0; i < instructionsLength; i++) {
bytes memory innerEncoded = encodeTransceiverInstruction(instructions[i]);
encoded = bytes.concat(encoded, innerEncoded);
}
return abi.encodePacked(uint8(instructionsLength), encoded);
}
function parseTransceiverInstructions(
bytes memory encoded,
uint256 numRegisteredTransceivers
) internal pure returns (TransceiverInstruction[] memory) {
uint256 offset = 0;
uint256 instructionsLength;
(instructionsLength, offset) = encoded.asUint8Unchecked(offset);
// We allocate an array with the length of the number of registered transceivers
// This gives us the flexibility to not have to pass instructions for transceivers that
// don't need them
TransceiverInstruction[] memory instructions =
new TransceiverInstruction[](numRegisteredTransceivers);
uint256 lastIndex = 0;
for (uint256 i = 0; i < instructionsLength; i++) {
TransceiverInstruction memory instruction;
(instruction, offset) = parseTransceiverInstructionUnchecked(encoded, offset);
uint8 instructionIndex = instruction.index;
// The instructions passed in have to be strictly increasing in terms of transceiver index
if (i != 0 && instructionIndex <= lastIndex) {
revert UnorderedInstructions(lastIndex, instructionIndex);
}
// Instruction index is out of bounds
if (instructionIndex >= numRegisteredTransceivers) {
revert InvalidInstructionIndex(instructionIndex, numRegisteredTransceivers);
}
lastIndex = instructionIndex;
instructions[instructionIndex] = instruction;
}
encoded.checkLength(offset);
return instructions;
}
struct TransceiverInit {
bytes4 transceiverIdentifier;
bytes32 nttManagerAddress;
uint8 nttManagerMode;
bytes32 tokenAddress;
uint8 tokenDecimals;
}
function encodeTransceiverInit(
TransceiverInit memory init
) internal pure returns (bytes memory) {
return abi.encodePacked(
init.transceiverIdentifier,
init.nttManagerAddress,
init.nttManagerMode,
init.tokenAddress,
init.tokenDecimals
);
}
function decodeTransceiverInit(
bytes memory encoded
) internal pure returns (TransceiverInit memory init) {
uint256 offset = 0;
(init.transceiverIdentifier, offset) = encoded.asBytes4Unchecked(offset);
(init.nttManagerAddress, offset) = encoded.asBytes32Unchecked(offset);
(init.nttManagerMode, offset) = encoded.asUint8Unchecked(offset);
(init.tokenAddress, offset) = encoded.asBytes32Unchecked(offset);
(init.tokenDecimals, offset) = encoded.asUint8Unchecked(offset);
encoded.checkLength(offset);
}
struct TransceiverRegistration {
bytes4 transceiverIdentifier;
uint16 transceiverChainId;
bytes32 transceiverAddress;
}
function encodeTransceiverRegistration(
TransceiverRegistration memory registration
) internal pure returns (bytes memory) {
return abi.encodePacked(
registration.transceiverIdentifier,
registration.transceiverChainId,
registration.transceiverAddress
);
}
function decodeTransceiverRegistration(
bytes memory encoded
) internal pure returns (TransceiverRegistration memory registration) {
uint256 offset = 0;
(registration.transceiverIdentifier, offset) = encoded.asBytes4Unchecked(offset);
(registration.transceiverChainId, offset) = encoded.asUint16Unchecked(offset);
(registration.transceiverAddress, offset) = encoded.asBytes32Unchecked(offset);
encoded.checkLength(offset);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
error InvalidFork(uint256 evmChainId, uint256 blockChainId);
function checkFork(
uint256 evmChainId
) view {
if (isFork(evmChainId)) {
revert InvalidFork(evmChainId, block.chainid);
}
}
function isFork(
uint256 evmChainId
) view returns (bool) {
return evmChainId != block.chainid;
}
function min(uint256 a, uint256 b) pure returns (uint256) {
return a < b ? a : b;
}
// @dev Count the number of set bits in a uint64
function countSetBits(
uint64 x
) pure returns (uint8 count) {
while (x != 0) {
x &= x - 1;
count++;
}
return count;
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "./PausableUpgradeable.sol";
import "./external/OwnableUpgradeable.sol";
abstract contract PausableOwnable is PausableUpgradeable, OwnableUpgradeable {
/*
* @dev Modifier to allow only the Pauser and the Owner to access pausing functionality
*/
modifier onlyOwnerOrPauser() {
_checkOwnerOrPauser(owner());
_;
}
/*
* @dev Modifier to allow only the Pauser to access some functionality
*/
function _checkOwnerOrPauser(
address owner
) internal view {
if (pauser() != msg.sender && owner != msg.sender) {
revert InvalidPauser(msg.sender);
}
}
function __PausedOwnable_init(address initialPauser, address owner) internal onlyInitializing {
__Paused_init(initialPauser);
__Ownable_init(owner);
}
/**
* @dev Transfers the ability to pause to a new account (`newPauser`).
*/
function transferPauserCapability(
address newPauser
) public virtual onlyOwnerOrPauser {
PauserStorage storage $ = _getPauserStorage();
address oldPauser = $._pauser;
$._pauser = newPauser;
emit PauserTransferred(oldPauser, newPauser);
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "./external/Initializable.sol";
import "openzeppelin-contracts/contracts/proxy/ERC1967/ERC1967Upgrade.sol";
/// @dev This contract should be used as a base contract for implementation contracts
/// that are used with ERC1967Proxy.
/// It ensures that the contract cannot be initialized directly, only through
/// the proxy (by disabling initializers in the constructor).
/// It also exposes a migrate function that is called during upgrades.
abstract contract Implementation is Initializable, ERC1967Upgrade {
address immutable _this;
error OnlyDelegateCall();
error NotMigrating();
constructor() {
_disableInitializers();
_this = address(this);
}
modifier onlyDelegateCall() {
_checkDelegateCall();
_;
}
struct _Migrating {
bool isMigrating;
}
struct _Bool {
bool value;
}
bytes32 private constant MIGRATING_SLOT = bytes32(uint256(keccak256("ntt.migrating")) - 1);
bytes32 private constant MIGRATES_IMMUTABLES_SLOT =
bytes32(uint256(keccak256("ntt.migratesImmutables")) - 1);
function _getMigratingStorage() private pure returns (_Migrating storage $) {
uint256 slot = uint256(MIGRATING_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getMigratesImmutablesStorage() internal pure returns (_Bool storage $) {
uint256 slot = uint256(MIGRATES_IMMUTABLES_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _checkDelegateCall() internal view {
if (address(this) == _this) {
revert OnlyDelegateCall();
}
}
function initialize() external payable onlyDelegateCall initializer {
_initialize();
}
function migrate() external onlyDelegateCall reinitializer(_getInitializedVersion() + 1) {
// NOTE: we add the reinitializer() modifier so that onlyInitializing
// functions can be called inside
if (!_getMigratingStorage().isMigrating) {
revert NotMigrating();
}
_migrate();
}
function _migrate() internal virtual;
function _initialize() internal virtual {}
function _checkImmutables() internal view virtual {}
function _upgrade(
address newImplementation
) internal {
_checkDelegateCall();
_upgradeTo(newImplementation);
_Migrating storage _migrating = _getMigratingStorage();
assert(!_migrating.isMigrating);
_migrating.isMigrating = true;
this.migrate();
if (!this.getMigratesImmutables()) {
_checkImmutables();
}
_setMigratesImmutables(false);
_migrating.isMigrating = false;
}
function getMigratesImmutables() public view returns (bool) {
return _getMigratesImmutablesStorage().value;
}
function _setMigratesImmutables(
bool value
) internal {
_getMigratesImmutablesStorage().value = value;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "../libraries/TransceiverStructs.sol";
interface ITransceiver {
/// @notice The caller is not the deployer.
/// @dev Selector: 0xc68a0e42.
/// @param deployer The address of the deployer.
/// @param caller The address of the caller.
error UnexpectedDeployer(address deployer, address caller);
/// @notice The caller is not the NttManager.
/// @dev Selector: 0xc5aa6153.
/// @param caller The address of the caller.
error CallerNotNttManager(address caller);
/// @notice Error when trying renounce transceiver ownership.
/// Ensures the owner of the transceiver is in sync with
/// the owner of the NttManager.
/// @dev Selector: 0x66791dd6.
/// @param currentOwner he current owner of the transceiver.
error CannotRenounceTransceiverOwnership(address currentOwner);
/// @notice Error when trying to transfer transceiver ownership.
/// @dev Selector: 0x306239eb.
/// @param currentOwner The current owner of the transceiver.
/// @param newOwner The new owner of the transceiver.
error CannotTransferTransceiverOwnership(address currentOwner, address newOwner);
/// @notice Error when the recipient NttManager address is not the
/// corresponding manager of the transceiver.
/// @dev Selector: 0x73bdd322.
/// @param recipientNttManagerAddress The address of the recipient NttManager.
/// @param expectedRecipientNttManagerAddress The expected address of the recipient NttManager.
error UnexpectedRecipientNttManagerAddress(
bytes32 recipientNttManagerAddress, bytes32 expectedRecipientNttManagerAddress
);
/// @notice Returns the owner address of the NTT Manager that this transceiver is related to.
function getNttManagerOwner() external view returns (address);
/// @notice Returns the string type of the transceiver. E.g. "wormhole", "axelar", etc.
function getTransceiverType() external view returns (string memory);
/// @notice Fetch the delivery price for a given recipient chain transfer.
/// @param recipientChain The Wormhole chain ID of the target chain.
/// @param instruction An additional Instruction provided by the Transceiver to be
/// executed on the recipient chain.
/// @return deliveryPrice The cost of delivering a message to the recipient chain,
/// in this chain's native token.
function quoteDeliveryPrice(
uint16 recipientChain,
TransceiverStructs.TransceiverInstruction memory instruction
) external view returns (uint256);
/// @dev Send a message to another chain.
/// @param recipientChain The Wormhole chain ID of the recipient.
/// @param instruction An additional Instruction provided by the Transceiver to be
/// executed on the recipient chain.
/// @param nttManagerMessage A message to be sent to the nttManager on the recipient chain.
/// @param recipientNttManagerAddress The Wormhole formatted address of the peer NTT Manager on the recipient chain.
/// @param refundAddress The Wormhole formatted address of the refund recipient
function sendMessage(
uint16 recipientChain,
TransceiverStructs.TransceiverInstruction memory instruction,
bytes memory nttManagerMessage,
bytes32 recipientNttManagerAddress,
bytes32 refundAddress
) external payable;
/// @notice Upgrades the transceiver to a new implementation.
/// @param newImplementation The address of the new implementation contract
function upgrade(
address newImplementation
) external;
/// @notice Transfers the ownership of the transceiver to a new address.
/// @param newOwner The address of the new owner
function transferTransceiverOwnership(
address newOwner
) external;
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
import "../interfaces/IManagerBase.sol";
import "./ChainRegistry.sol";
/// @title TransceiverRegistry
/// @author Wormhole Project Contributors.
/// @notice This contract is responsible for handling the registration of Transceivers.
/// @dev This contract checks that a few critical invariants hold when transceivers are added or removed,
/// including:
/// 1. If a transceiver is not registered, it should be enabled.
/// 2. The value set in the bitmap of trannsceivers
/// should directly correspond to the whether the transceiver is enabled
abstract contract TransceiverRegistry is ChainRegistry {
constructor() {
// Per-chain configuration is now required, so no global invariants to check
}
/// @dev Information about registered transceivers.
struct TransceiverInfo {
// whether this transceiver is registered
bool registered;
// whether this transceiver is enabled
bool enabled;
uint8 index;
}
/// @dev Struct representing a transceiver address with its index
struct TransceiverWithIndex {
address transceiver;
uint8 index;
}
/// @dev Bitmap encoding the enabled transceivers.
/// invariant: forall (i: uint8), enabledTransceiverBitmap & i == 1 <=> transceiverInfos[i].enabled
struct _EnabledTransceiverBitmap {
uint64 bitmap;
}
/// @dev Total number of registered transceivers. This number can only increase.
/// invariant: numRegisteredTransceivers <= MAX_TRANSCEIVERS
/// invariant: forall (i: uint8),
/// i < numRegisteredTransceivers <=> exists (a: address), transceiverInfos[a].index == i
struct _NumTransceivers {
uint8 registered;
uint8 enabled;
}
/// @dev Common fields shared by both send and receive transceiver configs
struct TransceiverConfig {
uint64 bitmap; // Bitmap of enabled transceivers
address[] transceivers; // Array of enabled transceivers
}
/// @dev Per-chain configuration for sending transceivers
struct PerChainSendTransceiverConfig {
TransceiverConfig config; // Common transceiver configuration
}
/// @dev Per-chain configuration for receiving transceivers
struct PerChainReceiveTransceiverConfig {
TransceiverConfig config; // Common transceiver configuration
uint8 threshold; // Threshold for receiving from this chain
}
uint8 constant MAX_TRANSCEIVERS = 64;
/// @notice Error when the caller is not the transceiver.
/// @dev Selector 0xa0ae911d.
/// @param caller The address of the caller.
error CallerNotTransceiver(address caller);
/// @notice Error when the transceiver is the zero address.
/// @dev Selector 0x2f44bd77.
error InvalidTransceiverZeroAddress();
/// @notice Error when the transceiver is disabled.
/// @dev Selector 0x1f61ba44.
error DisabledTransceiver(address transceiver);
/// @notice Error when the number of registered transceivers
/// exceeeds (MAX_TRANSCEIVERS = 64).
/// @dev Selector 0x891684c3.
error TooManyTransceivers();
/// @notice Error when attempting to remove a transceiver
/// that is not registered.
/// @dev Selector 0xd583f470.
/// @param transceiver The address of the transceiver.
error NonRegisteredTransceiver(address transceiver);
/// @notice Error when attempting to enable a transceiver that is already enabled.
/// @dev Selector 0x8d68f84d.
/// @param transceiver The address of the transceiver.
error TransceiverAlreadyEnabled(address transceiver);
error NoTransceiversConfiguredForChain(uint16 chainId);
error NoThresholdConfiguredForChain(uint16 chainId);
error InvalidChainId();
modifier onlyTransceiver() {
/// NOTE: this modifier is quite coarse-grained, and is only used on the
/// `attestationReceived` function, to check that the caller is a *known* transceiver.
///
/// This is important because later on, the transceiver's index is used
/// to record its vote, and if the address is not known, it would return
/// 0 from the mapping.
/// We could even change this to check `.registered` instead of `.enabled`,
/// because the when counting the votes, we consult the enabled bitmap
/// anyway, so letting disabled transceivers vote is not a problem.
if (!_getTransceiverInfosStorage()[msg.sender].enabled) {
revert CallerNotTransceiver(msg.sender);
}
_;
}
// =============== Storage ===============================================
bytes32 private constant TRANSCEIVER_INFOS_SLOT =
bytes32(uint256(keccak256("ntt.transceiverInfos")) - 1);
bytes32 private constant TRANSCEIVER_BITMAP_SLOT =
bytes32(uint256(keccak256("ntt.transceiverBitmap")) - 1);
bytes32 private constant ENABLED_TRANSCEIVERS_SLOT =
bytes32(uint256(keccak256("ntt.enabledTransceivers")) - 1);
bytes32 private constant REGISTERED_TRANSCEIVERS_SLOT =
bytes32(uint256(keccak256("ntt.registeredTransceivers")) - 1);
bytes32 private constant NUM_REGISTERED_TRANSCEIVERS_SLOT =
bytes32(uint256(keccak256("ntt.numRegisteredTransceivers")) - 1);
bytes32 private constant PER_CHAIN_SEND_TRANSCEIVERS_SLOT =
bytes32(uint256(keccak256("ntt.perChainSendTransceivers")) - 1);
bytes32 private constant PER_CHAIN_RECEIVE_TRANSCEIVERS_SLOT =
bytes32(uint256(keccak256("ntt.perChainReceiveTransceivers")) - 1);
function _getTransceiverInfosStorage()
internal
pure
returns (mapping(address => TransceiverInfo) storage $)
{
uint256 slot = uint256(TRANSCEIVER_INFOS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getEnabledTransceiversStorage() internal pure returns (address[] storage $) {
uint256 slot = uint256(ENABLED_TRANSCEIVERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getTransceiverBitmapStorage()
private
pure
returns (_EnabledTransceiverBitmap storage $)
{
uint256 slot = uint256(TRANSCEIVER_BITMAP_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getRegisteredTransceiversStorage() internal pure returns (address[] storage $) {
uint256 slot = uint256(REGISTERED_TRANSCEIVERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getNumTransceiversStorage() internal pure returns (_NumTransceivers storage $) {
uint256 slot = uint256(NUM_REGISTERED_TRANSCEIVERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getPerChainSendTransceiversStorage()
internal
pure
returns (mapping(uint16 => PerChainSendTransceiverConfig) storage $)
{
uint256 slot = uint256(PER_CHAIN_SEND_TRANSCEIVERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _getPerChainReceiveTransceiversStorage()
internal
pure
returns (mapping(uint16 => PerChainReceiveTransceiverConfig) storage $)
{
uint256 slot = uint256(PER_CHAIN_RECEIVE_TRANSCEIVERS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
// =============== Storage Getters/Setters ========================================
function _setTransceiver(
address transceiver
) internal returns (uint8 index) {
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();
if (transceiver == address(0)) {
revert InvalidTransceiverZeroAddress();
}
if (transceiverInfos[transceiver].registered) {
transceiverInfos[transceiver].enabled = true;
} else {
if (_numTransceivers.registered >= MAX_TRANSCEIVERS) {
revert TooManyTransceivers();
}
transceiverInfos[transceiver] = TransceiverInfo({
registered: true,
enabled: true,
index: _numTransceivers.registered
});
_numTransceivers.registered++;
_getRegisteredTransceiversStorage().push(transceiver);
}
_enabledTransceivers.push(transceiver);
_numTransceivers.enabled++;
uint64 updatedEnabledTransceiverBitmap =
_enabledTransceiverBitmap.bitmap | uint64(1 << transceiverInfos[transceiver].index);
// ensure that this actually changed the bitmap
if (updatedEnabledTransceiverBitmap == _enabledTransceiverBitmap.bitmap) {
revert TransceiverAlreadyEnabled(transceiver);
}
_enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap;
_checkTransceiversInvariants();
return transceiverInfos[transceiver].index;
}
function _removeTransceiver(
address transceiver
) internal {
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
if (transceiver == address(0)) {
revert InvalidTransceiverZeroAddress();
}
if (!transceiverInfos[transceiver].registered) {
revert NonRegisteredTransceiver(transceiver);
}
if (!transceiverInfos[transceiver].enabled) {
revert DisabledTransceiver(transceiver);
}
transceiverInfos[transceiver].enabled = false;
_getNumTransceiversStorage().enabled--;
uint64 updatedEnabledTransceiverBitmap =
_enabledTransceiverBitmap.bitmap & uint64(~(1 << transceiverInfos[transceiver].index));
// ensure that this actually changed the bitmap
assert(updatedEnabledTransceiverBitmap < _enabledTransceiverBitmap.bitmap);
_enabledTransceiverBitmap.bitmap = updatedEnabledTransceiverBitmap;
bool removed = false;
uint256 numEnabledTransceivers = _enabledTransceivers.length;
for (uint256 i = 0; i < numEnabledTransceivers; i++) {
if (_enabledTransceivers[i] == transceiver) {
_enabledTransceivers[i] = _enabledTransceivers[numEnabledTransceivers - 1];
_enabledTransceivers.pop();
removed = true;
break;
}
}
assert(removed);
_checkTransceiversInvariants();
// we call the invariant check on the transceiver here as well, since
// the above check only iterates through the enabled transceivers.
_checkTransceiverInvariants(transceiver);
}
function _getEnabledTransceiversBitmap() internal view virtual returns (uint64 bitmap) {
return _getTransceiverBitmapStorage().bitmap;
}
/// @notice Returns the Transceiver contracts that have been enabled via governance.
function getTransceivers() external pure returns (address[] memory result) {
result = _getEnabledTransceiversStorage();
}
/// @notice Returns the info for all enabled transceivers
function getTransceiverInfo() external view returns (TransceiverInfo[] memory) {
address[] memory enabledTransceivers = _getEnabledTransceiversStorage();
uint256 numEnabledTransceivers = enabledTransceivers.length;
TransceiverInfo[] memory result = new TransceiverInfo[](numEnabledTransceivers);
for (uint256 i = 0; i < numEnabledTransceivers; ++i) {
result[i] = _getTransceiverInfosStorage()[enabledTransceivers[i]];
}
return result;
}
// =============== Generic Helper Functions =========================================
/// @dev Generic function to add transceiver to any config
/// @param chainId The chain ID for validation
/// @param transceiver The transceiver address to add
/// @param config The transceiver config to modify
function _addTransceiverToConfig(
uint16 chainId,
address transceiver,
TransceiverConfig storage config
) internal {
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
if (transceiver == address(0)) {
revert InvalidTransceiverZeroAddress();
}
if (chainId == 0) {
revert InvalidChainId();
}
// Transceiver must be enabled
if (!transceiverInfos[transceiver].enabled) {
revert DisabledTransceiver(transceiver);
}
uint8 index = transceiverInfos[transceiver].index;
uint64 transceiverBit = uint64(1 << index);
// Check if already enabled for this chain
if ((config.bitmap & transceiverBit) != 0) {
revert TransceiverAlreadyEnabled(transceiver);
}
// Add to configuration
config.bitmap |= transceiverBit;
config.transceivers.push(transceiver);
}
/// @dev Generic function to remove transceiver from any config
/// @param transceiver The transceiver address to remove
/// @param config The transceiver config to modify
/// @return remainingCount The number of transceivers remaining after removal
function _removeTransceiverFromConfig(
address transceiver,
TransceiverConfig storage config
) internal returns (uint8 remainingCount) {
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
if (transceiver == address(0)) {
revert InvalidTransceiverZeroAddress();
}
if (!transceiverInfos[transceiver].registered) {
revert NonRegisteredTransceiver(transceiver);
}
uint8 index = transceiverInfos[transceiver].index;
uint64 transceiverBit = uint64(1 << index);
// Check if enabled for this chain
if ((config.bitmap & transceiverBit) == 0) {
revert DisabledTransceiver(transceiver);
}
// Remove from configuration
config.bitmap &= ~transceiverBit;
// Remove from array
bool removed = false;
uint256 numEnabled = config.transceivers.length;
for (uint256 i = 0; i < numEnabled; i++) {
if (config.transceivers[i] == transceiver) {
config.transceivers[i] = config.transceivers[numEnabled - 1];
config.transceivers.pop();
removed = true;
break;
}
}
assert(removed);
return uint8(config.transceivers.length);
}
// =============== Per-Chain Configuration Functions ===============================
/// @notice Add a transceiver for sending to a specific chain
/// @param targetChain The chain ID to send to
/// @param transceiver The transceiver to enable for sending to this chain
function _setSendTransceiverForChain(uint16 targetChain, address transceiver) internal {
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[targetChain];
_addTransceiverToConfig(targetChain, transceiver, sendConfig.config);
_addToKnownChains(targetChain);
}
/// @notice Remove a transceiver for sending to a specific chain
/// @param targetChain The chain ID
/// @param transceiver The transceiver to disable for sending to this chain
function _removeSendTransceiverForChain(uint16 targetChain, address transceiver) internal {
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[targetChain];
_removeTransceiverFromConfig(transceiver, sendConfig.config);
}
/// @notice Add a transceiver for receiving from a specific chain
/// @param sourceChain The chain ID to receive from
/// @param transceiver The transceiver to enable for receiving from this chain
function _setReceiveTransceiverForChain(uint16 sourceChain, address transceiver) internal {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
_addTransceiverToConfig(sourceChain, transceiver, receiveConfig.config);
// Set default threshold to 1 if not set
if (receiveConfig.threshold == 0) {
receiveConfig.threshold = 1;
}
_addToKnownChains(sourceChain);
}
/// @notice Remove a transceiver for receiving from a specific chain
/// @param sourceChain The chain ID
/// @param transceiver The transceiver to disable for receiving from this chain
function _removeReceiveTransceiverForChain(uint16 sourceChain, address transceiver) internal {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
uint8 remainingCount = _removeTransceiverFromConfig(transceiver, receiveConfig.config);
// Adjust threshold if necessary
if (receiveConfig.threshold > remainingCount) {
receiveConfig.threshold = remainingCount;
}
}
/// @notice Set the threshold for receiving from a specific chain
/// @param sourceChain The chain ID
/// @param threshold The threshold for receiving from this chain
function _setThresholdForChain(uint16 sourceChain, uint8 threshold) internal {
if (sourceChain == 0) {
revert InvalidChainId();
}
if (threshold == 0) {
revert IManagerBase.ZeroThreshold();
}
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
uint8 numEnabled = uint8(receiveConfig.config.transceivers.length);
if (threshold > numEnabled) {
revert IManagerBase.ThresholdTooHigh(uint256(threshold), uint256(numEnabled));
}
receiveConfig.threshold = threshold;
}
/// @notice Get the transceivers enabled for sending to a specific chain
/// @param targetChain The chain ID
/// @return transceivers The list of enabled transceivers for sending
function getSendTransceiversForChain(
uint16 targetChain
) public view returns (address[] memory transceivers) {
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[targetChain];
if (sendConfig.config.transceivers.length == 0) {
revert NoTransceiversConfiguredForChain(targetChain);
}
return sendConfig.config.transceivers;
}
/// @notice Get the transceivers enabled for receiving from a specific chain
/// @param sourceChain The chain ID
/// @return transceivers The list of enabled transceivers for receiving
/// @return threshold The threshold for this chain
function getReceiveTransceiversForChain(
uint16 sourceChain
) public view returns (address[] memory transceivers, uint8 threshold) {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
if (receiveConfig.config.transceivers.length == 0 || receiveConfig.threshold == 0) {
revert NoTransceiversConfiguredForChain(sourceChain);
}
return (receiveConfig.config.transceivers, receiveConfig.threshold);
}
/// @notice Get the bitmap of transceivers enabled for sending to a specific chain
/// @param targetChain The chain ID
/// @return bitmap The bitmap of enabled transceivers
function _getSendTransceiversBitmapForChain(
uint16 targetChain
) internal view returns (uint64 bitmap) {
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[targetChain];
if (sendConfig.config.transceivers.length == 0) {
revert NoTransceiversConfiguredForChain(targetChain);
}
return sendConfig.config.bitmap;
}
/// @notice Get the bitmap of transceivers enabled for receiving from a specific chain
/// @param sourceChain The chain ID
/// @return bitmap The bitmap of enabled transceivers
function _getReceiveTransceiversBitmapForChain(
uint16 sourceChain
) internal view returns (uint64 bitmap) {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
if (receiveConfig.config.transceivers.length == 0 || receiveConfig.threshold == 0) {
revert NoTransceiversConfiguredForChain(sourceChain);
}
return receiveConfig.config.bitmap;
}
/// @notice Get the threshold for receiving from a specific chain
/// @param sourceChain The chain ID
/// @return threshold The threshold for this chain
function _getThresholdForChain(
uint16 sourceChain
) internal view returns (uint8 threshold) {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
if (receiveConfig.threshold == 0) {
revert NoThresholdConfiguredForChain(sourceChain);
}
return receiveConfig.threshold;
}
/// @dev Internal helper to get transceivers with indices from a TransceiverConfig
/// @param config The transceiver config storage pointer
/// @return transceivers Array of (address, index) pairs for enabled transceivers
function _getTransceiversWithIndicesFromConfig(
TransceiverConfig storage config
) internal view returns (TransceiverWithIndex[] memory transceivers) {
address[] memory transceiverAddresses = config.transceivers;
transceivers = new TransceiverWithIndex[](transceiverAddresses.length);
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
for (uint256 i = 0; i < transceiverAddresses.length; i++) {
transceivers[i] = TransceiverWithIndex({
transceiver: transceiverAddresses[i],
index: transceiverInfos[transceiverAddresses[i]].index
});
}
return transceivers;
}
/// @notice Get the transceivers with their indices enabled for sending to a specific chain
/// @param targetChain The chain ID
/// @return transceivers Array of (address, index) pairs for enabled send transceivers
function getSendTransceiversWithIndicesForChain(
uint16 targetChain
) public view returns (TransceiverWithIndex[] memory transceivers) {
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[targetChain];
return _getTransceiversWithIndicesFromConfig(sendConfig.config);
}
/// @notice Get the transceivers with their indices enabled for receiving from a specific chain
/// @param sourceChain The chain ID
/// @return transceivers Array of (address, index) pairs for enabled receive transceivers
function getReceiveTransceiversWithIndicesForChain(
uint16 sourceChain
) public view returns (TransceiverWithIndex[] memory transceivers) {
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[sourceChain];
return _getTransceiversWithIndicesFromConfig(receiveConfig.config);
}
// ============== Invariants =============================================
/// @dev Check that the transceiver nttManager is in a valid state.
/// Checking these invariants is somewhat costly, but we only need to do it
/// when modifying the transceivers, which happens infrequently.
function _checkTransceiversInvariants() internal view {
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
uint256 numTransceiversEnabled = _numTransceivers.enabled;
assert(numTransceiversEnabled == _enabledTransceivers.length);
for (uint256 i = 0; i < numTransceiversEnabled; i++) {
_checkTransceiverInvariants(_enabledTransceivers[i]);
}
// invariant: each transceiver is only enabled once
for (uint256 i = 0; i < numTransceiversEnabled; i++) {
for (uint256 j = i + 1; j < numTransceiversEnabled; j++) {
assert(_enabledTransceivers[i] != _enabledTransceivers[j]);
}
}
// invariant: numRegisteredTransceivers <= MAX_TRANSCEIVERS
assert(_numTransceivers.registered <= MAX_TRANSCEIVERS);
}
// @dev Check that the transceiver is in a valid state.
function _checkTransceiverInvariants(
address transceiver
) private view {
mapping(address => TransceiverInfo) storage transceiverInfos = _getTransceiverInfosStorage();
_EnabledTransceiverBitmap storage _enabledTransceiverBitmap = _getTransceiverBitmapStorage();
_NumTransceivers storage _numTransceivers = _getNumTransceiversStorage();
address[] storage _enabledTransceivers = _getEnabledTransceiversStorage();
TransceiverInfo memory transceiverInfo = transceiverInfos[transceiver];
// if an transceiver is not registered, it should not be enabled
assert(
transceiverInfo.registered || (!transceiverInfo.enabled && transceiverInfo.index == 0)
);
bool transceiverInEnabledBitmap =
(_enabledTransceiverBitmap.bitmap & uint64(1 << transceiverInfo.index)) != 0;
bool transceiverEnabled = transceiverInfo.enabled;
bool transceiverInEnabledTransceivers = false;
for (uint256 i = 0; i < _numTransceivers.enabled; i++) {
if (_enabledTransceivers[i] == transceiver) {
transceiverInEnabledTransceivers = true;
break;
}
}
// invariant: transceiverInfos[transceiver].enabled
// <=> enabledTransceiverBitmap & (1 << transceiverInfos[transceiver].index) != 0
assert(transceiverInEnabledBitmap == transceiverEnabled);
// invariant: transceiverInfos[transceiver].enabled <=> transceiver in _enabledTransceivers
assert(transceiverInEnabledTransceivers == transceiverEnabled);
assert(transceiverInfo.index < _numTransceivers.registered);
}
/// @dev Remove a transceiver from all per-chain configurations
function _removeTransceiverFromAllChains(
address transceiver
) internal {
uint16[] storage knownChains = _getKnownChainsStorage();
uint8 transceiverIndex = _getTransceiverInfosStorage()[transceiver].index;
uint64 transceiverBit = uint64(1 << transceiverIndex);
for (uint256 i = 0; i < knownChains.length; i++) {
uint16 chainId = knownChains[i];
PerChainSendTransceiverConfig storage sendConfig =
_getPerChainSendTransceiversStorage()[chainId];
if ((sendConfig.config.bitmap & transceiverBit) != 0) {
_removeSendTransceiverForChain(chainId, transceiver);
}
PerChainReceiveTransceiverConfig storage receiveConfig =
_getPerChainReceiveTransceiversStorage()[chainId];
if ((receiveConfig.config.bitmap & transceiverBit) != 0) {
_removeReceiveTransceiverForChain(chainId, transceiver);
}
}
}
}// SPDX-License-Identifier: Apache 2
pragma solidity ^0.8.0;
/**
* @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,
uint256 deliveryQuote,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 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,
uint256 receiverValue,
uint256 paymentForExtraReceiverValue,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 receiverValue,
uint256 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,
uint256 newReceiverValue,
uint256 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,
uint256 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,
uint256 receiverValue,
uint256 gasLimit
)
external
view
returns (
uint256 nativePriceQuote,
uint256 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,
uint256 receiverValue,
uint256 gasLimit,
address deliveryProviderAddress
)
external
view
returns (
uint256 nativePriceQuote,
uint256 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,
uint256 receiverValue,
bytes memory encodedExecutionParameters,
address deliveryProviderAddress
)
external
view
returns (uint256 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,
uint256 currentChainAmount,
address deliveryProviderAddress
) external view returns (uint256 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,
uint256 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(uint256 msgValue, uint256 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(uint256 msgValue, uint256 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: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
// COPIED FROM OPENZEPPELIN v5.0.1
// COPIED TO CHANGE SOLC FROM ^0.8.20 TO ^0.8.19
pragma solidity ^0.8.19;
import {Initializable} from "./Initializable.sol";
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract ContextUpgradeable is Initializable {
function __Context_init() internal onlyInitializing {}
function __Context_init_unchained() internal onlyInitializing {}
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (proxy/utils/Initializable.sol)
// COPIED FROM OPENZEPPELIN v5.0.1
// COPIED TO CHANGE SOLC FROM ^0.8.20 TO ^0.8.19
pragma solidity ^0.8.19;
/**
* @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
* behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
* external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
* function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
*
* The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
* reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
* case an upgrade adds a module that needs to be initialized.
*
* For example:
*
* [.hljs-theme-light.nopadding]
* ```solidity
* contract MyToken is ERC20Upgradeable {
* function initialize() initializer public {
* __ERC20_init("MyToken", "MTK");
* }
* }
*
* contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
* function initializeV2() reinitializer(2) public {
* __ERC20Permit_init("MyToken");
* }
* }
* ```
*
* TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
* possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
*
* CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
* that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
*
* [CAUTION]
* ====
* Avoid leaving a contract uninitialized.
*
* An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
* contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
* the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
*
* [.hljs-theme-light.nopadding]
* ```
* /// @custom:oz-upgrades-unsafe-allow constructor
* constructor() {
* _disableInitializers();
* }
* ```
* ====
*/
abstract contract Initializable {
/**
* @dev Storage of the initializable contract.
*
* It's implemented on a custom ERC-7201 namespace to reduce the risk of storage collisions
* when using with upgradeable contracts.
*
* @custom:storage-location erc7201:openzeppelin.storage.Initializable
*/
struct InitializableStorage {
/**
* @dev Indicates that the contract has been initialized.
*/
uint64 _initialized;
/**
* @dev Indicates that the contract is in the process of being initialized.
*/
bool _initializing;
}
// keccak256(abi.encode(uint256(keccak256("openzeppelin.storage.Initializable")) - 1)) & ~bytes32(uint256(0xff))
bytes32 private constant INITIALIZABLE_STORAGE =
0xf0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00;
/**
* @dev The contract is already initialized.
*/
error InvalidInitialization();
/**
* @dev The contract is not initializing.
*/
error NotInitializing();
/**
* @dev Triggered when the contract has been initialized or reinitialized.
*/
event Initialized(uint64 version);
/**
* @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
* `onlyInitializing` functions can be used to initialize parent contracts.
*
* Similar to `reinitializer(1)`, except that in the context of a constructor an `initializer` may be invoked any
* number of times. This behavior in the constructor can be useful during testing and is not expected to be used in
* production.
*
* Emits an {Initialized} event.
*/
modifier initializer() {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
// Cache values to avoid duplicated sloads
bool isTopLevelCall = !$._initializing;
uint64 initialized = $._initialized;
// Allowed calls:
// - initialSetup: the contract is not in the initializing state and no previous version was
// initialized
// - construction: the contract is initialized at version 1 (no reininitialization) and the
// current contract is just being deployed
bool initialSetup = initialized == 0 && isTopLevelCall;
bool construction = initialized == 1 && address(this).code.length == 0;
if (!initialSetup && !construction) {
revert InvalidInitialization();
}
$._initialized = 1;
if (isTopLevelCall) {
$._initializing = true;
}
_;
if (isTopLevelCall) {
$._initializing = false;
emit Initialized(1);
}
}
/**
* @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
* contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
* used to initialize parent contracts.
*
* A reinitializer may be used after the original initialization step. This is essential to configure modules that
* are added through upgrades and that require initialization.
*
* When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
* cannot be nested. If one is invoked in the context of another, execution will revert.
*
* Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
* a contract, executing them in the right order is up to the developer or operator.
*
* WARNING: Setting the version to 2**64 - 1 will prevent any future reinitialization.
*
* Emits an {Initialized} event.
*/
modifier reinitializer(
uint64 version
) {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing || $._initialized >= version) {
revert InvalidInitialization();
}
$._initialized = version;
$._initializing = true;
_;
$._initializing = false;
emit Initialized(version);
}
/**
* @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
* {initializer} and {reinitializer} modifiers, directly or indirectly.
*/
modifier onlyInitializing() {
_checkInitializing();
_;
}
/**
* @dev Reverts if the contract is not in an initializing state. See {onlyInitializing}.
*/
function _checkInitializing() internal view virtual {
if (!_isInitializing()) {
revert NotInitializing();
}
}
/**
* @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
* Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
* to any version. It is recommended to use this to lock implementation contracts that are designed to be called
* through proxies.
*
* Emits an {Initialized} event the first time it is successfully executed.
*/
function _disableInitializers() internal virtual {
// solhint-disable-next-line var-name-mixedcase
InitializableStorage storage $ = _getInitializableStorage();
if ($._initializing) {
revert InvalidInitialization();
}
if ($._initialized != type(uint64).max) {
$._initialized = type(uint64).max;
emit Initialized(type(uint64).max);
}
}
/**
* @dev Returns the highest version that has been initialized. See {reinitializer}.
*/
function _getInitializedVersion() internal view returns (uint64) {
return _getInitializableStorage()._initialized;
}
/**
* @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
*/
function _isInitializing() internal view returns (bool) {
return _getInitializableStorage()._initializing;
}
/**
* @dev Returns a pointer to the storage namespace.
*/
// solhint-disable-next-line var-name-mixedcase
function _getInitializableStorage() private pure returns (InitializableStorage storage $) {
assembly {
$.slot := INITIALIZABLE_STORAGE
}
}
}// SPDX-License-Identifier: Apache 2
//
pragma solidity >=0.8.8 <0.9.0;
interface IOwnableUpgradeable {
function owner() external view returns (address);
}// SPDX-License-Identifier: Apache 2
/// @dev TrimmedAmount is a utility library to handle token amounts with different decimals
pragma solidity >=0.8.8 <0.9.0;
import "openzeppelin-contracts/contracts/utils/math/SafeCast.sol";
/// @dev TrimmedAmount is a bit-packed representation of a token amount and its decimals.
/// @dev 64 bits: [0 - 64] amount
/// @dev 8 bits: [64 - 72] decimals
type TrimmedAmount is uint72;
using {gt as >, lt as <, sub as -, add as +, eq as ==, min, unwrap} for TrimmedAmount global;
function minUint8(uint8 a, uint8 b) pure returns (uint8) {
return a < b ? a : b;
}
/// @notice Error when the decimals of two TrimmedAmounts are not equal
/// @dev Selector. b9cdb6c2
/// @param decimals the decimals of the first TrimmedAmount
/// @param decimalsOther the decimals of the second TrimmedAmount
error NumberOfDecimalsNotEqual(uint8 decimals, uint8 decimalsOther);
uint8 constant TRIMMED_DECIMALS = 8;
function unwrap(
TrimmedAmount a
) pure returns (uint72) {
return TrimmedAmount.unwrap(a);
}
function packTrimmedAmount(uint64 amt, uint8 decimals) pure returns (TrimmedAmount) {
// cast to u72 first to prevent overflow
uint72 amount = uint72(amt);
uint72 dec = uint72(decimals);
// shift the amount to the left 8 bits
amount <<= 8;
return TrimmedAmount.wrap(amount | dec);
}
function eq(TrimmedAmount a, TrimmedAmount b) pure returns (bool) {
return TrimmedAmountLib.getAmount(a) == TrimmedAmountLib.getAmount(b)
&& TrimmedAmountLib.getDecimals(a) == TrimmedAmountLib.getDecimals(b);
}
function checkDecimals(TrimmedAmount a, TrimmedAmount b) pure {
uint8 aDecimals = TrimmedAmountLib.getDecimals(a);
uint8 bDecimals = TrimmedAmountLib.getDecimals(b);
if (aDecimals != bDecimals) {
revert NumberOfDecimalsNotEqual(aDecimals, bDecimals);
}
}
function gt(TrimmedAmount a, TrimmedAmount b) pure returns (bool) {
checkDecimals(a, b);
return TrimmedAmountLib.getAmount(a) > TrimmedAmountLib.getAmount(b);
}
function lt(TrimmedAmount a, TrimmedAmount b) pure returns (bool) {
checkDecimals(a, b);
return TrimmedAmountLib.getAmount(a) < TrimmedAmountLib.getAmount(b);
}
function sub(TrimmedAmount a, TrimmedAmount b) pure returns (TrimmedAmount) {
checkDecimals(a, b);
return packTrimmedAmount(
TrimmedAmountLib.getAmount(a) - TrimmedAmountLib.getAmount(b),
TrimmedAmountLib.getDecimals(a)
);
}
function add(TrimmedAmount a, TrimmedAmount b) pure returns (TrimmedAmount) {
checkDecimals(a, b);
return packTrimmedAmount(
TrimmedAmountLib.getAmount(a) + TrimmedAmountLib.getAmount(b),
TrimmedAmountLib.getDecimals(b)
);
}
function min(TrimmedAmount a, TrimmedAmount b) pure returns (TrimmedAmount) {
checkDecimals(a, b);
return TrimmedAmountLib.getAmount(a) < TrimmedAmountLib.getAmount(b) ? a : b;
}
library TrimmedAmountLib {
/// @notice Error when the amount to be trimmed is greater than u64MAX.
/// @dev Selector 0x08083b2a.
/// @param amount The amount to be trimmed.
error AmountTooLarge(uint256 amount);
function getAmount(
TrimmedAmount a
) internal pure returns (uint64) {
// Extract the raw integer value from TrimmedAmount
uint72 rawValue = TrimmedAmount.unwrap(a);
// Right shift to keep only the higher 64 bits
uint64 result = uint64(rawValue >> 8);
return result;
}
function getDecimals(
TrimmedAmount a
) internal pure returns (uint8) {
return uint8(TrimmedAmount.unwrap(a) & 0xFF);
}
/// @dev Set the decimals of the TrimmedAmount.
/// This function should only be used for testing purposes, as it
/// should not be necessary to change the decimals of a TrimmedAmount
/// under normal circumstances.
function setDecimals(TrimmedAmount a, uint8 decimals) internal pure returns (TrimmedAmount) {
return TrimmedAmount.wrap((TrimmedAmount.unwrap(a) & ~uint72(0xFF)) | decimals);
}
function isNull(
TrimmedAmount a
) internal pure returns (bool) {
return (getAmount(a) == 0 && getDecimals(a) == 0);
}
function saturatingAdd(
TrimmedAmount a,
TrimmedAmount b
) internal pure returns (TrimmedAmount) {
checkDecimals(a, b);
uint256 saturatedSum;
uint64 aAmount = getAmount(a);
uint64 bAmount = getAmount(b);
unchecked {
saturatedSum = uint256(aAmount) + uint256(bAmount);
saturatedSum = saturatedSum > type(uint64).max ? type(uint64).max : saturatedSum;
}
return packTrimmedAmount(SafeCast.toUint64(saturatedSum), getDecimals(a));
}
/// @dev scale the amount from original decimals to target decimals (base 10)
function scale(
uint256 amount,
uint8 fromDecimals,
uint8 toDecimals
) internal pure returns (uint256) {
if (fromDecimals == toDecimals) {
return amount;
}
if (fromDecimals > toDecimals) {
return amount / (10 ** (fromDecimals - toDecimals));
} else {
return amount * (10 ** (toDecimals - fromDecimals));
}
}
function shift(TrimmedAmount amount, uint8 toDecimals) internal pure returns (TrimmedAmount) {
uint8 actualToDecimals = minUint8(TRIMMED_DECIMALS, toDecimals);
return packTrimmedAmount(
SafeCast.toUint64(scale(getAmount(amount), getDecimals(amount), actualToDecimals)),
actualToDecimals
);
}
function max(
uint8 decimals
) internal pure returns (TrimmedAmount) {
uint8 actualDecimals = minUint8(TRIMMED_DECIMALS, decimals);
return packTrimmedAmount(type(uint64).max, actualDecimals);
}
/// @dev trim the amount to target decimals.
/// The actual resulting decimals is the minimum of TRIMMED_DECIMALS,
/// fromDecimals, and toDecimals. This ensures that no dust is
/// destroyed on either side of the transfer.
/// @param amt the amount to be trimmed
/// @param fromDecimals the original decimals of the amount
/// @param toDecimals the target decimals of the amount
/// @return TrimmedAmount uint72 value type bit-packed with decimals
function trim(
uint256 amt,
uint8 fromDecimals,
uint8 toDecimals
) internal pure returns (TrimmedAmount) {
uint8 actualToDecimals = minUint8(minUint8(TRIMMED_DECIMALS, fromDecimals), toDecimals);
uint256 amountScaled = scale(amt, fromDecimals, actualToDecimals);
// NOTE: amt after trimming must fit into uint64 (that's the point of
// trimming, as Solana only supports uint64 for token amts)
return packTrimmedAmount(SafeCast.toUint64(amountScaled), actualToDecimals);
}
function untrim(TrimmedAmount amt, uint8 toDecimals) internal pure returns (uint256) {
uint256 deNorm = uint256(getAmount(amt));
uint8 fromDecimals = getDecimals(amt);
uint256 amountScaled = scale(deNorm, fromDecimals, toDecimals);
return amountScaled;
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
/**
* @dev Contact Module that allows children to implement logic to pause and unpause the contract.
* This is based on the OpenZeppelin Pausable contract but makes use of deterministic storage slots
* and the EVM native word size to optimize gas costs.
*
* The `whenPaused` and `whenNotPaused` modifiers are used to
* execute code based on the current state of the contract.
*
*/
import {Initializable} from "./external/Initializable.sol";
abstract contract PausableUpgradeable is Initializable {
/*
* @custom:storage-location erc7201:openzeppelin.storage.Pausable.
* @dev Storage slot with the pauser account, this is managed by the `PauserStorage` struct
*/
struct PauserStorage {
address _pauser;
}
// @dev Storage slot with the pause flag, this is managed by the `PauseStorage` struct
struct PauseStorage {
uint256 _pauseFlag;
}
/// NOTE: use uint256 to save on gas because it is the native word size of the EVM
/// it is cheaper than using a bool because modifying a boolean value requires an extra SLOAD
uint256 private constant NOT_PAUSED = 1;
uint256 private constant PAUSED = 2;
event PauserTransferred(address indexed oldPauser, address indexed newPauser);
/**
* @dev Contract is not paused, functionality is unblocked
*/
error RequireContractIsNotPaused();
/**
* @dev Contract state is paused, blocking
*/
error RequireContractIsPaused();
/**
* @dev the pauser is not a valid pauser account (e.g. `address(0)`)
*/
error InvalidPauser(address account);
// @dev Emitted when the contract is paused
event Paused(bool paused);
event NotPaused(bool notPaused);
bytes32 private constant PAUSE_SLOT = bytes32(uint256(keccak256("Pause.pauseFlag")) - 1);
bytes32 private constant PAUSER_ROLE_SLOT = bytes32(uint256(keccak256("Pause.pauseRole")) - 1);
function _getPauserStorage() internal pure returns (PauserStorage storage $) {
uint256 slot = uint256(PAUSER_ROLE_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
/**
* @dev Returns the current pauser account address.
*/
function pauser() public view returns (address) {
return _getPauserStorage()._pauser;
}
function _getPauseStorage() private pure returns (PauseStorage storage $) {
uint256 slot = uint256(PAUSE_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
function _setPauseStorage(
uint256 pauseFlag
) internal {
_getPauseStorage()._pauseFlag = pauseFlag;
}
function __Paused_init(
address initialPauser
) internal onlyInitializing {
__Paused_init_unchained(initialPauser);
}
function __Paused_init_unchained(
address initialPauser
) internal onlyInitializing {
// set pause flag to false initially
PauseStorage storage $ = _getPauseStorage();
$._pauseFlag = NOT_PAUSED;
// set the initial pauser
PauserStorage storage $_role = _getPauserStorage();
$_role._pauser = initialPauser;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
* Calling a function when this flag is set to `PAUSED` will cause the transaction to revert.
*/
modifier whenNotPaused() {
if (isPaused()) {
revert RequireContractIsNotPaused();
}
_;
}
/**
* @dev Modifier to make a function callable only when the contract is not paused.
* Calling a function when this flag is set to `PAUSED` will cause the transaction to revert.
*/
modifier whenPaused() {
if (!isPaused()) {
revert RequireContractIsPaused();
}
_;
}
/*
* @dev Modifier to allow only the Pauser to access pausing functionality
*/
modifier onlyPauser() {
_checkPauser();
_;
}
/*
* @dev Modifier to allow only the Pauser to access some functionality
*/
function _checkPauser() internal view {
if (pauser() != msg.sender) {
revert InvalidPauser(msg.sender);
}
}
/**
* @dev pauses the function and emits the `Paused` event
*/
function _pause() internal virtual whenNotPaused {
// this can only be set to PAUSED when the state is NOTPAUSED
_setPauseStorage(PAUSED);
emit Paused(true);
}
/**
* @dev unpauses the function
*/
function _unpause() internal virtual whenPaused {
// this can only be set to NOTPAUSED when the state is PAUSED
_setPauseStorage(NOT_PAUSED);
emit NotPaused(false);
}
/**
* @dev Returns true if the method is paused, and false otherwise.
*/
function isPaused() public view returns (bool) {
PauseStorage storage $ = _getPauseStorage();
return $._pauseFlag == PAUSED;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (proxy/ERC1967/ERC1967Upgrade.sol)
pragma solidity ^0.8.2;
import "../beacon/IBeacon.sol";
import "../../interfaces/draft-IERC1822.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 _upgradeToAndCallUUPS(
address newImplementation,
bytes memory data,
bool forceCall
) internal {
// Upgrades from old implementations will perform a rollback test. This test requires the new
// implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing
// this special case will break upgrade paths from old UUPS implementation to new ones.
if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) {
_setImplementation(newImplementation);
} else {
try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) {
require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID");
} catch {
revert("ERC1967Upgrade: new implementation is not UUPS");
}
_upgradeToAndCall(newImplementation, data, forceCall);
}
}
/**
* @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);
}
}
}// SPDX-License-Identifier: Apache 2
pragma solidity >=0.8.8 <0.9.0;
/// @dev This contract manages a registry of known blockchain networks (chains).
abstract contract ChainRegistry {
bytes32 private constant KNOWN_CHAINS_SLOT = bytes32(uint256(keccak256("ntt.knownChains")) - 1);
function _getKnownChainsStorage() internal pure returns (uint16[] storage $) {
uint256 slot = uint256(KNOWN_CHAINS_SLOT);
assembly ("memory-safe") {
$.slot := slot
}
}
/// @notice Add a chain to the known chains list if not already present
function _addToKnownChains(
uint16 chainId
) internal {
uint16[] storage knownChains = _getKnownChainsStorage();
for (uint256 i = 0; i < knownChains.length; i++) {
if (knownChains[i] == chainId) return;
}
knownChains.push(chainId);
}
/// @notice Get all known chains
/// @return The array of known chain IDs
function getKnownChains() public pure returns (uint16[] memory) {
return _getKnownChainsStorage();
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SafeCast.sol)
// This file was procedurally generated from scripts/generate/templates/SafeCast.js.
pragma solidity ^0.8.0;
/**
* @dev Wrappers over Solidity's uintXX/intXX casting operators with added overflow
* checks.
*
* Downcasting from uint256/int256 in Solidity does not revert on overflow. This can
* easily result in undesired exploitation or bugs, since developers usually
* assume that overflows raise errors. `SafeCast` restores this intuition by
* reverting the transaction when such an operation overflows.
*
* Using this library instead of the unchecked operations eliminates an entire
* class of bugs, so it's recommended to use it always.
*
* Can be combined with {SafeMath} and {SignedSafeMath} to extend it to smaller types, by performing
* all math on `uint256` and `int256` and then downcasting.
*/
library SafeCast {
/**
* @dev Returns the downcasted uint248 from uint256, reverting on
* overflow (when the input is greater than largest uint248).
*
* Counterpart to Solidity's `uint248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toUint248(uint256 value) internal pure returns (uint248) {
require(value <= type(uint248).max, "SafeCast: value doesn't fit in 248 bits");
return uint248(value);
}
/**
* @dev Returns the downcasted uint240 from uint256, reverting on
* overflow (when the input is greater than largest uint240).
*
* Counterpart to Solidity's `uint240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toUint240(uint256 value) internal pure returns (uint240) {
require(value <= type(uint240).max, "SafeCast: value doesn't fit in 240 bits");
return uint240(value);
}
/**
* @dev Returns the downcasted uint232 from uint256, reverting on
* overflow (when the input is greater than largest uint232).
*
* Counterpart to Solidity's `uint232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toUint232(uint256 value) internal pure returns (uint232) {
require(value <= type(uint232).max, "SafeCast: value doesn't fit in 232 bits");
return uint232(value);
}
/**
* @dev Returns the downcasted uint224 from uint256, reverting on
* overflow (when the input is greater than largest uint224).
*
* Counterpart to Solidity's `uint224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.2._
*/
function toUint224(uint256 value) internal pure returns (uint224) {
require(value <= type(uint224).max, "SafeCast: value doesn't fit in 224 bits");
return uint224(value);
}
/**
* @dev Returns the downcasted uint216 from uint256, reverting on
* overflow (when the input is greater than largest uint216).
*
* Counterpart to Solidity's `uint216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toUint216(uint256 value) internal pure returns (uint216) {
require(value <= type(uint216).max, "SafeCast: value doesn't fit in 216 bits");
return uint216(value);
}
/**
* @dev Returns the downcasted uint208 from uint256, reverting on
* overflow (when the input is greater than largest uint208).
*
* Counterpart to Solidity's `uint208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toUint208(uint256 value) internal pure returns (uint208) {
require(value <= type(uint208).max, "SafeCast: value doesn't fit in 208 bits");
return uint208(value);
}
/**
* @dev Returns the downcasted uint200 from uint256, reverting on
* overflow (when the input is greater than largest uint200).
*
* Counterpart to Solidity's `uint200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toUint200(uint256 value) internal pure returns (uint200) {
require(value <= type(uint200).max, "SafeCast: value doesn't fit in 200 bits");
return uint200(value);
}
/**
* @dev Returns the downcasted uint192 from uint256, reverting on
* overflow (when the input is greater than largest uint192).
*
* Counterpart to Solidity's `uint192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toUint192(uint256 value) internal pure returns (uint192) {
require(value <= type(uint192).max, "SafeCast: value doesn't fit in 192 bits");
return uint192(value);
}
/**
* @dev Returns the downcasted uint184 from uint256, reverting on
* overflow (when the input is greater than largest uint184).
*
* Counterpart to Solidity's `uint184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toUint184(uint256 value) internal pure returns (uint184) {
require(value <= type(uint184).max, "SafeCast: value doesn't fit in 184 bits");
return uint184(value);
}
/**
* @dev Returns the downcasted uint176 from uint256, reverting on
* overflow (when the input is greater than largest uint176).
*
* Counterpart to Solidity's `uint176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toUint176(uint256 value) internal pure returns (uint176) {
require(value <= type(uint176).max, "SafeCast: value doesn't fit in 176 bits");
return uint176(value);
}
/**
* @dev Returns the downcasted uint168 from uint256, reverting on
* overflow (when the input is greater than largest uint168).
*
* Counterpart to Solidity's `uint168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toUint168(uint256 value) internal pure returns (uint168) {
require(value <= type(uint168).max, "SafeCast: value doesn't fit in 168 bits");
return uint168(value);
}
/**
* @dev Returns the downcasted uint160 from uint256, reverting on
* overflow (when the input is greater than largest uint160).
*
* Counterpart to Solidity's `uint160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toUint160(uint256 value) internal pure returns (uint160) {
require(value <= type(uint160).max, "SafeCast: value doesn't fit in 160 bits");
return uint160(value);
}
/**
* @dev Returns the downcasted uint152 from uint256, reverting on
* overflow (when the input is greater than largest uint152).
*
* Counterpart to Solidity's `uint152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toUint152(uint256 value) internal pure returns (uint152) {
require(value <= type(uint152).max, "SafeCast: value doesn't fit in 152 bits");
return uint152(value);
}
/**
* @dev Returns the downcasted uint144 from uint256, reverting on
* overflow (when the input is greater than largest uint144).
*
* Counterpart to Solidity's `uint144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toUint144(uint256 value) internal pure returns (uint144) {
require(value <= type(uint144).max, "SafeCast: value doesn't fit in 144 bits");
return uint144(value);
}
/**
* @dev Returns the downcasted uint136 from uint256, reverting on
* overflow (when the input is greater than largest uint136).
*
* Counterpart to Solidity's `uint136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toUint136(uint256 value) internal pure returns (uint136) {
require(value <= type(uint136).max, "SafeCast: value doesn't fit in 136 bits");
return uint136(value);
}
/**
* @dev Returns the downcasted uint128 from uint256, reverting on
* overflow (when the input is greater than largest uint128).
*
* Counterpart to Solidity's `uint128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v2.5._
*/
function toUint128(uint256 value) internal pure returns (uint128) {
require(value <= type(uint128).max, "SafeCast: value doesn't fit in 128 bits");
return uint128(value);
}
/**
* @dev Returns the downcasted uint120 from uint256, reverting on
* overflow (when the input is greater than largest uint120).
*
* Counterpart to Solidity's `uint120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toUint120(uint256 value) internal pure returns (uint120) {
require(value <= type(uint120).max, "SafeCast: value doesn't fit in 120 bits");
return uint120(value);
}
/**
* @dev Returns the downcasted uint112 from uint256, reverting on
* overflow (when the input is greater than largest uint112).
*
* Counterpart to Solidity's `uint112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toUint112(uint256 value) internal pure returns (uint112) {
require(value <= type(uint112).max, "SafeCast: value doesn't fit in 112 bits");
return uint112(value);
}
/**
* @dev Returns the downcasted uint104 from uint256, reverting on
* overflow (when the input is greater than largest uint104).
*
* Counterpart to Solidity's `uint104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toUint104(uint256 value) internal pure returns (uint104) {
require(value <= type(uint104).max, "SafeCast: value doesn't fit in 104 bits");
return uint104(value);
}
/**
* @dev Returns the downcasted uint96 from uint256, reverting on
* overflow (when the input is greater than largest uint96).
*
* Counterpart to Solidity's `uint96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.2._
*/
function toUint96(uint256 value) internal pure returns (uint96) {
require(value <= type(uint96).max, "SafeCast: value doesn't fit in 96 bits");
return uint96(value);
}
/**
* @dev Returns the downcasted uint88 from uint256, reverting on
* overflow (when the input is greater than largest uint88).
*
* Counterpart to Solidity's `uint88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toUint88(uint256 value) internal pure returns (uint88) {
require(value <= type(uint88).max, "SafeCast: value doesn't fit in 88 bits");
return uint88(value);
}
/**
* @dev Returns the downcasted uint80 from uint256, reverting on
* overflow (when the input is greater than largest uint80).
*
* Counterpart to Solidity's `uint80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toUint80(uint256 value) internal pure returns (uint80) {
require(value <= type(uint80).max, "SafeCast: value doesn't fit in 80 bits");
return uint80(value);
}
/**
* @dev Returns the downcasted uint72 from uint256, reverting on
* overflow (when the input is greater than largest uint72).
*
* Counterpart to Solidity's `uint72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toUint72(uint256 value) internal pure returns (uint72) {
require(value <= type(uint72).max, "SafeCast: value doesn't fit in 72 bits");
return uint72(value);
}
/**
* @dev Returns the downcasted uint64 from uint256, reverting on
* overflow (when the input is greater than largest uint64).
*
* Counterpart to Solidity's `uint64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v2.5._
*/
function toUint64(uint256 value) internal pure returns (uint64) {
require(value <= type(uint64).max, "SafeCast: value doesn't fit in 64 bits");
return uint64(value);
}
/**
* @dev Returns the downcasted uint56 from uint256, reverting on
* overflow (when the input is greater than largest uint56).
*
* Counterpart to Solidity's `uint56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toUint56(uint256 value) internal pure returns (uint56) {
require(value <= type(uint56).max, "SafeCast: value doesn't fit in 56 bits");
return uint56(value);
}
/**
* @dev Returns the downcasted uint48 from uint256, reverting on
* overflow (when the input is greater than largest uint48).
*
* Counterpart to Solidity's `uint48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toUint48(uint256 value) internal pure returns (uint48) {
require(value <= type(uint48).max, "SafeCast: value doesn't fit in 48 bits");
return uint48(value);
}
/**
* @dev Returns the downcasted uint40 from uint256, reverting on
* overflow (when the input is greater than largest uint40).
*
* Counterpart to Solidity's `uint40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toUint40(uint256 value) internal pure returns (uint40) {
require(value <= type(uint40).max, "SafeCast: value doesn't fit in 40 bits");
return uint40(value);
}
/**
* @dev Returns the downcasted uint32 from uint256, reverting on
* overflow (when the input is greater than largest uint32).
*
* Counterpart to Solidity's `uint32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v2.5._
*/
function toUint32(uint256 value) internal pure returns (uint32) {
require(value <= type(uint32).max, "SafeCast: value doesn't fit in 32 bits");
return uint32(value);
}
/**
* @dev Returns the downcasted uint24 from uint256, reverting on
* overflow (when the input is greater than largest uint24).
*
* Counterpart to Solidity's `uint24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toUint24(uint256 value) internal pure returns (uint24) {
require(value <= type(uint24).max, "SafeCast: value doesn't fit in 24 bits");
return uint24(value);
}
/**
* @dev Returns the downcasted uint16 from uint256, reverting on
* overflow (when the input is greater than largest uint16).
*
* Counterpart to Solidity's `uint16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v2.5._
*/
function toUint16(uint256 value) internal pure returns (uint16) {
require(value <= type(uint16).max, "SafeCast: value doesn't fit in 16 bits");
return uint16(value);
}
/**
* @dev Returns the downcasted uint8 from uint256, reverting on
* overflow (when the input is greater than largest uint8).
*
* Counterpart to Solidity's `uint8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v2.5._
*/
function toUint8(uint256 value) internal pure returns (uint8) {
require(value <= type(uint8).max, "SafeCast: value doesn't fit in 8 bits");
return uint8(value);
}
/**
* @dev Converts a signed int256 into an unsigned uint256.
*
* Requirements:
*
* - input must be greater than or equal to 0.
*
* _Available since v3.0._
*/
function toUint256(int256 value) internal pure returns (uint256) {
require(value >= 0, "SafeCast: value must be positive");
return uint256(value);
}
/**
* @dev Returns the downcasted int248 from int256, reverting on
* overflow (when the input is less than smallest int248 or
* greater than largest int248).
*
* Counterpart to Solidity's `int248` operator.
*
* Requirements:
*
* - input must fit into 248 bits
*
* _Available since v4.7._
*/
function toInt248(int256 value) internal pure returns (int248 downcasted) {
downcasted = int248(value);
require(downcasted == value, "SafeCast: value doesn't fit in 248 bits");
}
/**
* @dev Returns the downcasted int240 from int256, reverting on
* overflow (when the input is less than smallest int240 or
* greater than largest int240).
*
* Counterpart to Solidity's `int240` operator.
*
* Requirements:
*
* - input must fit into 240 bits
*
* _Available since v4.7._
*/
function toInt240(int256 value) internal pure returns (int240 downcasted) {
downcasted = int240(value);
require(downcasted == value, "SafeCast: value doesn't fit in 240 bits");
}
/**
* @dev Returns the downcasted int232 from int256, reverting on
* overflow (when the input is less than smallest int232 or
* greater than largest int232).
*
* Counterpart to Solidity's `int232` operator.
*
* Requirements:
*
* - input must fit into 232 bits
*
* _Available since v4.7._
*/
function toInt232(int256 value) internal pure returns (int232 downcasted) {
downcasted = int232(value);
require(downcasted == value, "SafeCast: value doesn't fit in 232 bits");
}
/**
* @dev Returns the downcasted int224 from int256, reverting on
* overflow (when the input is less than smallest int224 or
* greater than largest int224).
*
* Counterpart to Solidity's `int224` operator.
*
* Requirements:
*
* - input must fit into 224 bits
*
* _Available since v4.7._
*/
function toInt224(int256 value) internal pure returns (int224 downcasted) {
downcasted = int224(value);
require(downcasted == value, "SafeCast: value doesn't fit in 224 bits");
}
/**
* @dev Returns the downcasted int216 from int256, reverting on
* overflow (when the input is less than smallest int216 or
* greater than largest int216).
*
* Counterpart to Solidity's `int216` operator.
*
* Requirements:
*
* - input must fit into 216 bits
*
* _Available since v4.7._
*/
function toInt216(int256 value) internal pure returns (int216 downcasted) {
downcasted = int216(value);
require(downcasted == value, "SafeCast: value doesn't fit in 216 bits");
}
/**
* @dev Returns the downcasted int208 from int256, reverting on
* overflow (when the input is less than smallest int208 or
* greater than largest int208).
*
* Counterpart to Solidity's `int208` operator.
*
* Requirements:
*
* - input must fit into 208 bits
*
* _Available since v4.7._
*/
function toInt208(int256 value) internal pure returns (int208 downcasted) {
downcasted = int208(value);
require(downcasted == value, "SafeCast: value doesn't fit in 208 bits");
}
/**
* @dev Returns the downcasted int200 from int256, reverting on
* overflow (when the input is less than smallest int200 or
* greater than largest int200).
*
* Counterpart to Solidity's `int200` operator.
*
* Requirements:
*
* - input must fit into 200 bits
*
* _Available since v4.7._
*/
function toInt200(int256 value) internal pure returns (int200 downcasted) {
downcasted = int200(value);
require(downcasted == value, "SafeCast: value doesn't fit in 200 bits");
}
/**
* @dev Returns the downcasted int192 from int256, reverting on
* overflow (when the input is less than smallest int192 or
* greater than largest int192).
*
* Counterpart to Solidity's `int192` operator.
*
* Requirements:
*
* - input must fit into 192 bits
*
* _Available since v4.7._
*/
function toInt192(int256 value) internal pure returns (int192 downcasted) {
downcasted = int192(value);
require(downcasted == value, "SafeCast: value doesn't fit in 192 bits");
}
/**
* @dev Returns the downcasted int184 from int256, reverting on
* overflow (when the input is less than smallest int184 or
* greater than largest int184).
*
* Counterpart to Solidity's `int184` operator.
*
* Requirements:
*
* - input must fit into 184 bits
*
* _Available since v4.7._
*/
function toInt184(int256 value) internal pure returns (int184 downcasted) {
downcasted = int184(value);
require(downcasted == value, "SafeCast: value doesn't fit in 184 bits");
}
/**
* @dev Returns the downcasted int176 from int256, reverting on
* overflow (when the input is less than smallest int176 or
* greater than largest int176).
*
* Counterpart to Solidity's `int176` operator.
*
* Requirements:
*
* - input must fit into 176 bits
*
* _Available since v4.7._
*/
function toInt176(int256 value) internal pure returns (int176 downcasted) {
downcasted = int176(value);
require(downcasted == value, "SafeCast: value doesn't fit in 176 bits");
}
/**
* @dev Returns the downcasted int168 from int256, reverting on
* overflow (when the input is less than smallest int168 or
* greater than largest int168).
*
* Counterpart to Solidity's `int168` operator.
*
* Requirements:
*
* - input must fit into 168 bits
*
* _Available since v4.7._
*/
function toInt168(int256 value) internal pure returns (int168 downcasted) {
downcasted = int168(value);
require(downcasted == value, "SafeCast: value doesn't fit in 168 bits");
}
/**
* @dev Returns the downcasted int160 from int256, reverting on
* overflow (when the input is less than smallest int160 or
* greater than largest int160).
*
* Counterpart to Solidity's `int160` operator.
*
* Requirements:
*
* - input must fit into 160 bits
*
* _Available since v4.7._
*/
function toInt160(int256 value) internal pure returns (int160 downcasted) {
downcasted = int160(value);
require(downcasted == value, "SafeCast: value doesn't fit in 160 bits");
}
/**
* @dev Returns the downcasted int152 from int256, reverting on
* overflow (when the input is less than smallest int152 or
* greater than largest int152).
*
* Counterpart to Solidity's `int152` operator.
*
* Requirements:
*
* - input must fit into 152 bits
*
* _Available since v4.7._
*/
function toInt152(int256 value) internal pure returns (int152 downcasted) {
downcasted = int152(value);
require(downcasted == value, "SafeCast: value doesn't fit in 152 bits");
}
/**
* @dev Returns the downcasted int144 from int256, reverting on
* overflow (when the input is less than smallest int144 or
* greater than largest int144).
*
* Counterpart to Solidity's `int144` operator.
*
* Requirements:
*
* - input must fit into 144 bits
*
* _Available since v4.7._
*/
function toInt144(int256 value) internal pure returns (int144 downcasted) {
downcasted = int144(value);
require(downcasted == value, "SafeCast: value doesn't fit in 144 bits");
}
/**
* @dev Returns the downcasted int136 from int256, reverting on
* overflow (when the input is less than smallest int136 or
* greater than largest int136).
*
* Counterpart to Solidity's `int136` operator.
*
* Requirements:
*
* - input must fit into 136 bits
*
* _Available since v4.7._
*/
function toInt136(int256 value) internal pure returns (int136 downcasted) {
downcasted = int136(value);
require(downcasted == value, "SafeCast: value doesn't fit in 136 bits");
}
/**
* @dev Returns the downcasted int128 from int256, reverting on
* overflow (when the input is less than smallest int128 or
* greater than largest int128).
*
* Counterpart to Solidity's `int128` operator.
*
* Requirements:
*
* - input must fit into 128 bits
*
* _Available since v3.1._
*/
function toInt128(int256 value) internal pure returns (int128 downcasted) {
downcasted = int128(value);
require(downcasted == value, "SafeCast: value doesn't fit in 128 bits");
}
/**
* @dev Returns the downcasted int120 from int256, reverting on
* overflow (when the input is less than smallest int120 or
* greater than largest int120).
*
* Counterpart to Solidity's `int120` operator.
*
* Requirements:
*
* - input must fit into 120 bits
*
* _Available since v4.7._
*/
function toInt120(int256 value) internal pure returns (int120 downcasted) {
downcasted = int120(value);
require(downcasted == value, "SafeCast: value doesn't fit in 120 bits");
}
/**
* @dev Returns the downcasted int112 from int256, reverting on
* overflow (when the input is less than smallest int112 or
* greater than largest int112).
*
* Counterpart to Solidity's `int112` operator.
*
* Requirements:
*
* - input must fit into 112 bits
*
* _Available since v4.7._
*/
function toInt112(int256 value) internal pure returns (int112 downcasted) {
downcasted = int112(value);
require(downcasted == value, "SafeCast: value doesn't fit in 112 bits");
}
/**
* @dev Returns the downcasted int104 from int256, reverting on
* overflow (when the input is less than smallest int104 or
* greater than largest int104).
*
* Counterpart to Solidity's `int104` operator.
*
* Requirements:
*
* - input must fit into 104 bits
*
* _Available since v4.7._
*/
function toInt104(int256 value) internal pure returns (int104 downcasted) {
downcasted = int104(value);
require(downcasted == value, "SafeCast: value doesn't fit in 104 bits");
}
/**
* @dev Returns the downcasted int96 from int256, reverting on
* overflow (when the input is less than smallest int96 or
* greater than largest int96).
*
* Counterpart to Solidity's `int96` operator.
*
* Requirements:
*
* - input must fit into 96 bits
*
* _Available since v4.7._
*/
function toInt96(int256 value) internal pure returns (int96 downcasted) {
downcasted = int96(value);
require(downcasted == value, "SafeCast: value doesn't fit in 96 bits");
}
/**
* @dev Returns the downcasted int88 from int256, reverting on
* overflow (when the input is less than smallest int88 or
* greater than largest int88).
*
* Counterpart to Solidity's `int88` operator.
*
* Requirements:
*
* - input must fit into 88 bits
*
* _Available since v4.7._
*/
function toInt88(int256 value) internal pure returns (int88 downcasted) {
downcasted = int88(value);
require(downcasted == value, "SafeCast: value doesn't fit in 88 bits");
}
/**
* @dev Returns the downcasted int80 from int256, reverting on
* overflow (when the input is less than smallest int80 or
* greater than largest int80).
*
* Counterpart to Solidity's `int80` operator.
*
* Requirements:
*
* - input must fit into 80 bits
*
* _Available since v4.7._
*/
function toInt80(int256 value) internal pure returns (int80 downcasted) {
downcasted = int80(value);
require(downcasted == value, "SafeCast: value doesn't fit in 80 bits");
}
/**
* @dev Returns the downcasted int72 from int256, reverting on
* overflow (when the input is less than smallest int72 or
* greater than largest int72).
*
* Counterpart to Solidity's `int72` operator.
*
* Requirements:
*
* - input must fit into 72 bits
*
* _Available since v4.7._
*/
function toInt72(int256 value) internal pure returns (int72 downcasted) {
downcasted = int72(value);
require(downcasted == value, "SafeCast: value doesn't fit in 72 bits");
}
/**
* @dev Returns the downcasted int64 from int256, reverting on
* overflow (when the input is less than smallest int64 or
* greater than largest int64).
*
* Counterpart to Solidity's `int64` operator.
*
* Requirements:
*
* - input must fit into 64 bits
*
* _Available since v3.1._
*/
function toInt64(int256 value) internal pure returns (int64 downcasted) {
downcasted = int64(value);
require(downcasted == value, "SafeCast: value doesn't fit in 64 bits");
}
/**
* @dev Returns the downcasted int56 from int256, reverting on
* overflow (when the input is less than smallest int56 or
* greater than largest int56).
*
* Counterpart to Solidity's `int56` operator.
*
* Requirements:
*
* - input must fit into 56 bits
*
* _Available since v4.7._
*/
function toInt56(int256 value) internal pure returns (int56 downcasted) {
downcasted = int56(value);
require(downcasted == value, "SafeCast: value doesn't fit in 56 bits");
}
/**
* @dev Returns the downcasted int48 from int256, reverting on
* overflow (when the input is less than smallest int48 or
* greater than largest int48).
*
* Counterpart to Solidity's `int48` operator.
*
* Requirements:
*
* - input must fit into 48 bits
*
* _Available since v4.7._
*/
function toInt48(int256 value) internal pure returns (int48 downcasted) {
downcasted = int48(value);
require(downcasted == value, "SafeCast: value doesn't fit in 48 bits");
}
/**
* @dev Returns the downcasted int40 from int256, reverting on
* overflow (when the input is less than smallest int40 or
* greater than largest int40).
*
* Counterpart to Solidity's `int40` operator.
*
* Requirements:
*
* - input must fit into 40 bits
*
* _Available since v4.7._
*/
function toInt40(int256 value) internal pure returns (int40 downcasted) {
downcasted = int40(value);
require(downcasted == value, "SafeCast: value doesn't fit in 40 bits");
}
/**
* @dev Returns the downcasted int32 from int256, reverting on
* overflow (when the input is less than smallest int32 or
* greater than largest int32).
*
* Counterpart to Solidity's `int32` operator.
*
* Requirements:
*
* - input must fit into 32 bits
*
* _Available since v3.1._
*/
function toInt32(int256 value) internal pure returns (int32 downcasted) {
downcasted = int32(value);
require(downcasted == value, "SafeCast: value doesn't fit in 32 bits");
}
/**
* @dev Returns the downcasted int24 from int256, reverting on
* overflow (when the input is less than smallest int24 or
* greater than largest int24).
*
* Counterpart to Solidity's `int24` operator.
*
* Requirements:
*
* - input must fit into 24 bits
*
* _Available since v4.7._
*/
function toInt24(int256 value) internal pure returns (int24 downcasted) {
downcasted = int24(value);
require(downcasted == value, "SafeCast: value doesn't fit in 24 bits");
}
/**
* @dev Returns the downcasted int16 from int256, reverting on
* overflow (when the input is less than smallest int16 or
* greater than largest int16).
*
* Counterpart to Solidity's `int16` operator.
*
* Requirements:
*
* - input must fit into 16 bits
*
* _Available since v3.1._
*/
function toInt16(int256 value) internal pure returns (int16 downcasted) {
downcasted = int16(value);
require(downcasted == value, "SafeCast: value doesn't fit in 16 bits");
}
/**
* @dev Returns the downcasted int8 from int256, reverting on
* overflow (when the input is less than smallest int8 or
* greater than largest int8).
*
* Counterpart to Solidity's `int8` operator.
*
* Requirements:
*
* - input must fit into 8 bits
*
* _Available since v3.1._
*/
function toInt8(int256 value) internal pure returns (int8 downcasted) {
downcasted = int8(value);
require(downcasted == value, "SafeCast: value doesn't fit in 8 bits");
}
/**
* @dev Converts an unsigned uint256 into a signed int256.
*
* Requirements:
*
* - input must be less than or equal to maxInt256.
*
* _Available since v3.0._
*/
function toInt256(uint256 value) internal pure returns (int256) {
// Note: Unsafe cast below is okay because `type(int256).max` is guaranteed to be positive
require(value <= uint256(type(int256).max), "SafeCast: value doesn't fit in an int256");
return int256(value);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol)
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
// OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol)
pragma solidity ^0.8.0;
/**
* @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified
* proxy whose upgrades are fully controlled by the current implementation.
*/
interface IERC1822Proxiable {
/**
* @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation
* address.
*
* IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks
* bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this
* function revert if invoked through a proxy.
*/
function proxiableUUID() external view returns (bytes32);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
pragma solidity ^0.8.1;
/**
* @dev Collection of functions related to the address type
*/
library Address {
/**
* @dev Returns true if `account` is a contract.
*
* [IMPORTANT]
* ====
* It is unsafe to assume that an address for which this function returns
* false is an externally-owned account (EOA) and not a contract.
*
* Among others, `isContract` will return false for the following
* types of addresses:
*
* - an externally-owned account
* - a contract in construction
* - an address where a contract will be created
* - an address where a contract lived, but was destroyed
* ====
*
* [IMPORTANT]
* ====
* You shouldn't rely on `isContract` to protect against flash loan attacks!
*
* Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
* like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
* constructor.
* ====
*/
function isContract(address account) internal view returns (bool) {
// This method relies on extcodesize/address.code.length, which returns 0
// for contracts in construction, since the code is only stored at the end
// of the constructor execution.
return account.code.length > 0;
}
/**
* @dev Replacement for Solidity's `transfer`: sends `amount` wei to
* `recipient`, forwarding all available gas and reverting on errors.
*
* https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
* of certain opcodes, possibly making contracts go over the 2300 gas limit
* imposed by `transfer`, making them unable to receive funds via
* `transfer`. {sendValue} removes this limitation.
*
* https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
*
* IMPORTANT: because control is transferred to `recipient`, care must be
* taken to not create reentrancy vulnerabilities. Consider using
* {ReentrancyGuard} or the
* https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
*/
function sendValue(address payable recipient, uint256 amount) internal {
require(address(this).balance >= amount, "Address: insufficient balance");
(bool success, ) = recipient.call{value: amount}("");
require(success, "Address: unable to send value, recipient may have reverted");
}
/**
* @dev Performs a Solidity function call using a low level `call`. A
* plain `call` is an unsafe replacement for a function call: use this
* function instead.
*
* If `target` reverts with a revert reason, it is bubbled up by this
* function (like regular Solidity function calls).
*
* Returns the raw returned data. To convert to the expected return value,
* use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
*
* Requirements:
*
* - `target` must be a contract.
* - calling `target` with `data` must not revert.
*
* _Available since v3.1._
*/
function functionCall(address target, bytes memory data) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, "Address: low-level call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
* `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
return functionCallWithValue(target, data, 0, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but also transferring `value` wei to `target`.
*
* Requirements:
*
* - the calling contract must have an ETH balance of at least `value`.
* - the called Solidity function must be `payable`.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value
) internal returns (bytes memory) {
return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
}
/**
* @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
* with `errorMessage` as a fallback revert reason when `target` reverts.
*
* _Available since v3.1._
*/
function functionCallWithValue(
address target,
bytes memory data,
uint256 value,
string memory errorMessage
) internal returns (bytes memory) {
require(address(this).balance >= value, "Address: insufficient balance for call");
(bool success, bytes memory returndata) = target.call{value: value}(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
return functionStaticCall(target, data, "Address: low-level static call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a static call.
*
* _Available since v3.3._
*/
function functionStaticCall(
address target,
bytes memory data,
string memory errorMessage
) internal view returns (bytes memory) {
(bool success, bytes memory returndata) = target.staticcall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
return functionDelegateCall(target, data, "Address: low-level delegate call failed");
}
/**
* @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
* but performing a delegate call.
*
* _Available since v3.4._
*/
function functionDelegateCall(
address target,
bytes memory data,
string memory errorMessage
) internal returns (bytes memory) {
(bool success, bytes memory returndata) = target.delegatecall(data);
return verifyCallResultFromTarget(target, success, returndata, errorMessage);
}
/**
* @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
* the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
*
* _Available since v4.8._
*/
function verifyCallResultFromTarget(
address target,
bool success,
bytes memory returndata,
string memory errorMessage
) internal view returns (bytes memory) {
if (success) {
if (returndata.length == 0) {
// only check isContract if the call was successful and the return data is empty
// otherwise we already know that it was a contract
require(isContract(target), "Address: call to non-contract");
}
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
/**
* @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
* revert reason or using the provided one.
*
* _Available since v4.3._
*/
function verifyCallResult(
bool success,
bytes memory returndata,
string memory errorMessage
) internal pure returns (bytes memory) {
if (success) {
return returndata;
} else {
_revert(returndata, errorMessage);
}
}
function _revert(bytes memory returndata, string memory errorMessage) private pure {
// Look for revert reason and bubble it up if present
if (returndata.length > 0) {
// The easiest way to bubble the revert reason is using memory via assembly
/// @solidity memory-safe-assembly
assembly {
let returndata_size := mload(returndata)
revert(add(32, returndata), returndata_size)
}
} else {
revert(errorMessage);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol)
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) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `BooleanSlot` with member `value` located at `slot`.
*/
function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
*/
function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
/**
* @dev Returns an `Uint256Slot` with member `value` located at `slot`.
*/
function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
/// @solidity memory-safe-assembly
assembly {
r.slot := slot
}
}
}{
"remappings": [
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"openzeppelin-contracts-upgradeable/=lib/openzeppelin-contracts-upgradeable/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"solidity-bytes-utils/=lib/solidity-bytes-utils/contracts/",
"wormhole-solidity-sdk/=lib/wormhole-solidity-sdk/src/"
],
"optimizer": {
"enabled": true,
"runs": 200
},
"metadata": {
"useLiteralContent": false,
"bytecodeHash": "ipfs",
"appendCBOR": true
},
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "london",
"viaIR": false
}Contract ABI
API[{"inputs":[{"internalType":"uint16","name":"_chainId","type":"uint16"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"CallFailed","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerNotTransceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"requiredPayment","type":"uint256"},{"internalType":"uint256","name":"providedPayment","type":"uint256"}],"name":"DeliveryPaymentTooLow","type":"error"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"DisabledTransceiver","type":"error"},{"inputs":[],"name":"InvalidCallee","type":"error"},{"inputs":[],"name":"InvalidChainId","type":"error"},{"inputs":[],"name":"InvalidEvmAddress","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint256","name":"providedIndex","type":"uint256"},{"internalType":"uint256","name":"numTransceivers","type":"uint256"}],"name":"InvalidInstructionIndex","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"InvalidPauser","type":"error"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"peerAddress","type":"bytes32"}],"name":"InvalidPeer","type":"error"},{"inputs":[],"name":"InvalidPeerChainIdZero","type":"error"},{"inputs":[],"name":"InvalidPeerSameChainId","type":"error"},{"inputs":[],"name":"InvalidPeerZeroAddress","type":"error"},{"inputs":[],"name":"InvalidPrefix","type":"error"},{"inputs":[],"name":"InvalidRefundAddress","type":"error"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"InvalidTargetChain","type":"error"},{"inputs":[],"name":"InvalidTransceiverZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"encodedLength","type":"uint256"},{"internalType":"uint256","name":"expectedLength","type":"uint256"}],"name":"LengthMismatch","type":"error"},{"inputs":[{"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"MessageNotApproved","type":"error"},{"inputs":[],"name":"NoEnabledTransceivers","type":"error"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"NoThresholdConfiguredForChain","type":"error"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"NoTransceiversConfiguredForChain","type":"error"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"NonRegisteredTransceiver","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"NotAnEvmAddress","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotMigrating","type":"error"},{"inputs":[],"name":"OnlyDelegateCall","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[{"internalType":"uint256","name":"length","type":"uint256"}],"name":"PayloadTooLong","type":"error"},{"inputs":[{"internalType":"uint256","name":"size","type":"uint256"}],"name":"PayloadTooLong","type":"error"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"}],"name":"PeerNotRegistered","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[{"internalType":"uint256","name":"refundAmount","type":"uint256"}],"name":"RefundFailed","type":"error"},{"inputs":[],"name":"RequireContractIsNotPaused","type":"error"},{"inputs":[],"name":"RequireContractIsPaused","type":"error"},{"inputs":[{"internalType":"uint256","name":"retrieved","type":"uint256"},{"internalType":"uint256","name":"registered","type":"uint256"}],"name":"RetrievedIncorrectRegisteredTransceivers","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"name":"SequenceNotReserved","type":"error"},{"inputs":[{"internalType":"uint64","name":"sequence","type":"uint64"},{"internalType":"address","name":"sender","type":"address"}],"name":"SequenceNotReservedBySender","type":"error"},{"inputs":[{"internalType":"uint256","name":"threshold","type":"uint256"},{"internalType":"uint256","name":"transceivers","type":"uint256"}],"name":"ThresholdTooHigh","type":"error"},{"inputs":[],"name":"TooManyTransceivers","type":"error"},{"inputs":[{"internalType":"bytes32","name":"nttManagerMessageHash","type":"bytes32"}],"name":"TransceiverAlreadyAttestedToMessage","type":"error"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"TransceiverAlreadyEnabled","type":"error"},{"inputs":[{"internalType":"address","name":"expectedOwner","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"UnexpectedDeployer","type":"error"},{"inputs":[],"name":"UnexpectedMsgValue","type":"error"},{"inputs":[{"internalType":"uint256","name":"lastIndex","type":"uint256"},{"internalType":"uint256","name":"instructionIndex","type":"uint256"}],"name":"UnorderedInstructions","type":"error"},{"inputs":[],"name":"ZeroThreshold","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":false,"internalType":"uint64","name":"version","type":"uint64"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"sourceNttManager","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"MessageAlreadyExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"digest","type":"bytes32"},{"indexed":false,"internalType":"address","name":"transceiver","type":"address"},{"indexed":false,"internalType":"uint8","name":"index","type":"uint8"}],"name":"MessageAttestedTo","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"indexed":true,"internalType":"uint16","name":"sourceChain","type":"uint16"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"callee","type":"address"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"}],"name":"MessageExecuted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint16","name":"targetChain","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"callee","type":"bytes32"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"}],"name":"MessageSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"notPaused","type":"bool"}],"name":"NotPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldPauser","type":"address"},{"indexed":true,"internalType":"address","name":"newPauser","type":"address"}],"name":"PauserTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint16","name":"chainId","type":"uint16"},{"indexed":false,"internalType":"bytes32","name":"oldPeerAddress","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"newPeerAddress","type":"bytes32"}],"name":"PeerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"sourceChain","type":"uint16"},{"indexed":false,"internalType":"address","name":"transceiver","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"ReceiveTransceiverUpdatedForChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"targetChain","type":"uint16"},{"indexed":false,"internalType":"address","name":"transceiver","type":"address"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SendTransceiverUpdatedForChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint8","name":"oldThreshold","type":"uint8"},{"indexed":false,"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"ThresholdChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"sourceChain","type":"uint16"},{"indexed":false,"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"ThresholdUpdatedForChain","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"transceiver","type":"address"},{"indexed":false,"internalType":"uint256","name":"transceiversNum","type":"uint256"},{"indexed":false,"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"TransceiverAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"transceiver","type":"address"},{"indexed":false,"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"TransceiverRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"GMP_MANAGER_VERSION","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChainId","type":"uint16"},{"internalType":"bytes32","name":"sourceNttManagerAddress","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct TransceiverStructs.NttManagerMessage","name":"payload","type":"tuple"}],"name":"attestationReceived","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChainId","type":"uint16"},{"internalType":"bytes32","name":"sourceGmpManagerAddress","type":"bytes32"},{"components":[{"internalType":"bytes32","name":"id","type":"bytes32"},{"internalType":"bytes32","name":"sender","type":"bytes32"},{"internalType":"bytes","name":"payload","type":"bytes"}],"internalType":"struct TransceiverStructs.NttManagerMessage","name":"message","type":"tuple"}],"name":"executeMsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"getKnownChains","outputs":[{"internalType":"uint16[]","name":"","type":"uint16[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getMigratesImmutables","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"getPeer","outputs":[{"components":[{"internalType":"bytes32","name":"peerAddress","type":"bytes32"}],"internalType":"struct GmpManager.GmpPeer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"}],"name":"getReceiveTransceiversForChain","outputs":[{"internalType":"address[]","name":"transceivers","type":"address[]"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"}],"name":"getReceiveTransceiversWithIndicesForChain","outputs":[{"components":[{"internalType":"address","name":"transceiver","type":"address"},{"internalType":"uint8","name":"index","type":"uint8"}],"internalType":"struct TransceiverRegistry.TransceiverWithIndex[]","name":"transceivers","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"}],"name":"getSendTransceiversForChain","outputs":[{"internalType":"address[]","name":"transceivers","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"}],"name":"getSendTransceiversWithIndicesForChain","outputs":[{"components":[{"internalType":"address","name":"transceiver","type":"address"},{"internalType":"uint8","name":"index","type":"uint8"}],"internalType":"struct TransceiverRegistry.TransceiverWithIndex[]","name":"transceivers","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"}],"name":"getThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransceiverInfo","outputs":[{"components":[{"internalType":"bool","name":"registered","type":"bool"},{"internalType":"bool","name":"enabled","type":"bool"},{"internalType":"uint8","name":"index","type":"uint8"}],"internalType":"struct TransceiverRegistry.TransceiverInfo[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransceivers","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"isMessageApprovedForChain","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"isMessageExecuted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"messageAttestations","outputs":[{"internalType":"uint8","name":"count","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"messageAttestationsForChain","outputs":[{"internalType":"uint8","name":"count","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"nextMessageSequence","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"pauser","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes","name":"transceiverInstructions","type":"bytes"}],"name":"quoteDeliveryPrice","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"peerChainId","type":"uint16"},{"internalType":"bytes32","name":"peerAddress","type":"bytes32"}],"name":"registerKnownChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"address","name":"transceiver","type":"address"}],"name":"removeReceiveTransceiverForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"transceiver","type":"address"}],"name":"removeSendTransceiverForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"removeTransceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"reserveMessageSequence","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"bytes32","name":"callee","type":"bytes32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"uint64","name":"reservedSequence","type":"uint64"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"bytes","name":"transceiverInstructions","type":"bytes"}],"name":"sendMessage","outputs":[{"internalType":"uint64","name":"actualSequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"peerChainId","type":"uint16"},{"internalType":"bytes32","name":"peerAddress","type":"bytes32"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"address","name":"transceiver","type":"address"}],"name":"setReceiveTransceiverForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"address","name":"transceiver","type":"address"}],"name":"setSendTransceiverForChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"sourceChain","type":"uint16"},{"internalType":"uint8","name":"threshold","type":"uint8"}],"name":"setThreshold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"setTransceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"uint8","name":"index","type":"uint8"}],"name":"transceiverAttestedToMessage","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newPauser","type":"address"}],"name":"transferPauserCapability","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgrade","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
6101006040523480156200001257600080fd5b5060405162004f9b38038062004f9b83398101604081905262000035916200010e565b80620000406200005a565b3060805261ffff1660c052504660e0523360a0526200013b565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805468010000000000000000900460ff1615620000ab5760405163f92ee8a960e01b815260040160405180910390fd5b80546001600160401b03908116146200010b5780546001600160401b0319166001600160401b0390811782556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b50565b6000602082840312156200012157600080fd5b815161ffff811681146200013457600080fd5b9392505050565b60805160a05160c05160e051614e066200019560003960005050600081816105c6015281816109a601528181611567015281816115b4015261329101526000818161369b01526136d7015260006121a00152614e066000f3fe6080604052600436106102515760003560e01c80638da5cb5b11610139578063b13c82ea116100b6578063da4856a11161007a578063da4856a114610739578063db5fdb9114610759578063e54ff04014610786578063ee0bdb1c146107a6578063f2fde38b146107b9578063ff428f09146107d957600080fd5b8063b13c82ea1461069e578063b150fc55146106be578063b187bd26146106e0578063b4d591bb146106f5578063c128d1701461070a57600080fd5b80639ab730d7116100fd5780639ab730d7146105fb5780639d7824541461061b5780639f86029c1461063b5780639fd0506d1461065b578063adaf575f1461067057600080fd5b80638da5cb5b146105245780638e3ba8c9146105515780638fd3ab80146105715780639057412d146105865780639a8a0592146105b457600080fd5b8063396c16b7116101d2578063689f90c311610196578063689f90c3146104925780636a4db160146104a75780637c9d2708146104c75780638129fc1c146104e75780638456cb59146104ef57806389c619dd1461050457600080fd5b8063396c16b7146103f05780633a495e0b146104105780633f4ba83a14610430578063451d5332146104455780634f4bb3e51461047257600080fd5b80632310dd3c116102195780632310dd3c1461032f57806323d75e3114610361578063295d819e1461038e57806332cf4cd5146103ae5780633951cbe6146103ce57600080fd5b80630271510814610256578063036de8af1461029d57806307299652146102bf5780630900f010146102ef578063203e4a9b1461030f575b600080fd5b34801561026257600080fd5b50610287604051806040016040528060058152602001640312e302e360dc1b81525081565b60405161029491906143fb565b60405180910390f35b3480156102a957600080fd5b506102bd6102b8366004614425565b6107ee565b005b3480156102cb57600080fd5b506102df6102da366004614450565b61085a565b6040519015158152602001610294565b3480156102fb57600080fd5b506102bd61030a366004614425565b61089a565b34801561031b57600080fd5b506102bd61032a366004614425565b6108ae565b34801561033b57600080fd5b5061034f61034a36600461447c565b61091e565b60405160ff9091168152602001610294565b34801561036d57600080fd5b50610376610929565b6040516001600160401b039091168152602001610294565b34801561039a57600080fd5b506102bd6103a9366004614450565b610942565b3480156103ba57600080fd5b506102bd6103c9366004614450565b610959565b3480156103da57600080fd5b506103e3610a85565b6040516102949190614499565b3480156103fc57600080fd5b506102df61040b3660046144e1565b610b0b565b34801561041c57600080fd5b506102bd61042b3660046144fa565b610b29565b34801561043c57600080fd5b506102bd610b7b565b34801561045157600080fd5b5061046561046036600461447c565b610b8d565b6040516102949190614573565b34801561047e57600080fd5b5061034f61048d366004614450565b610c41565b34801561049e57600080fd5b506102df610c5c565b3480156104b357600080fd5b506102bd6104c2366004614597565b610c6f565b3480156104d357600080fd5b506102bd6104e23660046144fa565b610cbd565b6102bd610d03565b3480156104fb57600080fd5b506102bd610e05565b34801561051057600080fd5b5061034f61051f3660046144e1565b610e18565b34801561053057600080fd5b50610539610e26565b6040516001600160a01b039091168152602001610294565b34801561055d57600080fd5b506102df61056c3660046145c3565b610e54565b34801561057d57600080fd5b506102bd610e8e565b34801561059257600080fd5b506105a66105a1366004614688565b610f90565b6040516102949291906146d7565b3480156105c057600080fd5b506105e87f000000000000000000000000000000000000000000000000000000000000000081565b60405161ffff9091168152602001610294565b34801561060757600080fd5b506102bd6106163660046144fa565b610fd5565b34801561062757600080fd5b506102bd61063636600461471f565b61101b565b34801561064757600080fd5b506102bd610656366004614425565b611108565b34801561066757600080fd5b50610539611197565b34801561067c57600080fd5b5061069061068b36600461447c565b6111b0565b6040516102949291906147d5565b3480156106aa57600080fd5b506102bd6106b93660046144fa565b61127f565b3480156106ca57600080fd5b506106d36112c5565b60405161029491906147fa565b3480156106ec57600080fd5b506102df61144f565b34801561070157600080fd5b50610465611464565b34801561071657600080fd5b5061072a61072536600461447c565b6114cb565b60405190518152602001610294565b34801561074557600080fd5b506102bd61075436600461471f565b611507565b34801561076557600080fd5b5061077961077436600461447c565b6116d8565b604051610294919061485a565b34801561079257600080fd5b506107796107a136600461447c565b611703565b6103766107b43660046148e9565b61170f565b3480156107c557600080fd5b506102bd6107d4366004614425565b611774565b3480156107e557600080fd5b50610376611832565b6107fe6107f9610e26565b61187a565b60006108086118c3565b80546001600160a01b038481166001600160a01b031983168117845560405193945091169182907f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef690600090a3505050565b600080610866846118f1565b905060006108748585610c41565b90508160ff168160ff161015801561088f575060008260ff16115b925050505b92915050565b6108a261194d565b6108ab8161197f565b50565b6108b661194d565b6108bf81611a8d565b507ff05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5816108ea611d3f565b54604080516001600160a01b03909316835261010090910460ff16602083015260009082015260600160405180910390a150565b6000610894826118f1565b6000610933611d6d565b546001600160401b0316919050565b61094c8282611d9b565b61095582611de4565b5050565b61096161194d565b8161ffff166000036109865760405163100b0f2760e11b815260040160405180910390fd5b806109a45760405163f839a0cb60e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000000061ffff168261ffff16036109ec5760405163101b8f9560e11b815260040160405180910390fd5b60006109f6611e91565b61ffff8416600090815260209182526040908190208151928301909152548152905081610a21611e91565b61ffff851660009081526020919091526040902055610a3f83611de4565b8051604080519182526020820184905261ffff8516917f6b8e3e5d5cb35ca559551a3a468913b588421f8eeb87fabc088aa03638ce1369910160405180910390a2505050565b6060610a8f611ebf565b805480602002602001604051908101604052809291908181526020018280548015610b0157602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610ac85790505b5050505050905090565b6000610b15611eed565b600092835260205250604090205460ff1690565b610b3161194d565b610b3b8282611f1b565b7f6b9b1f20ce684fc1c23217395b766f44fb36a93fb907e41e4243fe2f9c101c2d82826001604051610b6f93929190614997565b60405180910390a15050565b610b8361194d565b610b8b611f4f565b565b60606000610b99611fb5565b61ffff841660009081526020919091526040812060018101549092509003610bdf5760405163186b202960e11b815261ffff841660048201526024015b60405180910390fd5b60018101805460408051602080840282018101909252828152929190830182828015610c3457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c16575b5050505050915050919050565b6000610c55610c508484611fe3565b612022565b9392505050565b6000610c6661205a565b5460ff16919050565b610c7761194d565b610c818282612088565b6040805161ffff8416815260ff831660208201527f463734bd482c3b124a4f4ee8cbda3b9beb1aa70b7346ca456fec770efc446c7b9101610b6f565b610cc561194d565b610ccf8282612144565b7f9a8d72d56c46cf95458ced32b1aa082ed04dd70c7119b6779521bb1893ee0b7382826001604051610b6f93929190614997565b610d0b612196565b600080516020614db18339815191528054600160401b810460ff1615906001600160401b0316600081158015610d3e5750825b90506000826001600160401b03166001148015610d5a5750303b155b905081158015610d68575080155b15610d865760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610db057845460ff60401b1916600160401b1785555b610db86121df565b8315610dfe57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b610e106107f9610e26565b610b8b6121ef565b6000610894610c5083612250565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b600080600160ff84161b610e66611eed565b600086815260209190915260409020546101009004166001600160401b031611905092915050565b610e96612196565b610e9e61228c565b610ea99060016149d4565b600080516020614db18339815191528054600160401b900460ff1680610edc575080546001600160401b03808416911610155b15610efa5760405163f92ee8a960e01b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155610f236122a2565b5460ff16610f4457604051632866815360e11b815260040160405180910390fd5b610f4c6121e7565b805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602001610b6f565b6060600080610f9d6122d0565b5490506000610fab86610b8d565b90506000610fb986846122fe565b9050610fc687828461245d565b945094505050505b9250929050565b610fdd61194d565b610fe782826125dd565b7f9a8d72d56c46cf95458ced32b1aa082ed04dd70c7119b6779521bb1893ee0b7382826000604051610b6f93929190614997565b611023612635565b3360009081526020919091526040902054610100900460ff1661105b5760405163a0ae911d60e01b8152336004820152602401610bd6565b61106361144f565b15611081576040516309e3d0f360e11b815260040160405180910390fd5b61108b8383611d9b565b60006110978483612663565b90506110a3848261085a565b156111025760405163da4856a160e01b8152309063da4856a1906110cf908790879087906004016149fb565b600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b505050505b50505050565b61111061194d565b600061111a611d3f565b54610100900460ff169050600181116111465760405163831761d760e01b815260040160405180910390fd5b61114f826126c8565b611158826127d7565b604080516001600160a01b0384168152600060208201527f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f9101610b6f565b60006111a16118c3565b546001600160a01b0316919050565b60606000806111bd612a9f565b61ffff8516600090815260209190915260409020600181015490915015806111ea5750600281015460ff16155b1561120e5760405163186b202960e11b815261ffff85166004820152602401610bd6565b600281015460018201805460408051602080840282018101909252828152929360ff169291849183018282801561126e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611250575b505050505091509250925050915091565b61128761194d565b6112918282612acd565b7f6b9b1f20ce684fc1c23217395b766f44fb36a93fb907e41e4243fe2f9c101c2d82826000604051610b6f93929190614997565b606060006112d1612af7565b80548060200260200160405190810160405280929190818152602001828054801561132557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611307575b505050505090506000815190506000816001600160401b0381111561134c5761134c6145e6565b60405190808252806020026020018201604052801561139757816020015b604080516060810182526000808252602080830182905292820152825260001990920191018161136a5790505b50905060005b82811015611447576113ad612635565b60008583815181106113c1576113c1614a45565b6020908102919091018101516001600160a01b031682528181019290925260409081016000208151606081018352905460ff808216151583526101008204811615159483019490945262010000900490921690820152825183908390811061142b5761142b614a45565b60200260200101819052508061144090614a5b565b905061139d565b509392505050565b60008061145a612b24565b5460021492915050565b606061146e612af7565b805480602002602001604051908101604052809291908181526020018280548015610b0157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114a4575050505050905090565b6040805160208101909152600081526114e2611e91565b61ffff9092166000908152602092835260409081902081519384019091525482525090565b61150f612b52565b61151761144f565b15611535576040516309e3d0f360e11b815260040160405180910390fd5b600080611543858585612b8a565b9150915080156115545750506116bc565b60006115638460400151612c1e565b90507f000000000000000000000000000000000000000000000000000000000000000061ffff16816000015161ffff16146115e3578051604051631ee5902560e11b815261ffff91821660048201527f00000000000000000000000000000000000000000000000000000000000000009091166024820152604401610bd6565b60006115f28260200151612cff565b9050806001600160a01b031663e7fa3a5a88846040015185606001516040518463ffffffff1660e01b815260040161162c93929190614a74565b600060405180830381600087803b15801561164657600080fd5b505af115801561165a573d6000803e3d6000fd5b5050505061166b8560200151612cff565b6001600160a01b03168761ffff16857f1000a14cded4271da033293964b8a9ce647c150f445bb766d7d8219acefb665e8486606001516040516116af929190614aa0565b60405180910390a4505050505b6116d36001600080516020614d9183398151915255565b505050565b606060006116e4612a9f565b61ffff84166000908152602091909152604090209050610c5581612d3f565b606060006116e4611fb5565b6000611719612b52565b61172161144f565b1561173f576040516309e3d0f360e11b815260040160405180910390fd5b61174f8989898989898989612ec4565b90506117686001600080516020614d9183398151915255565b98975050505050505050565b61177c61194d565b61178581613138565b600061178f6122d0565b9050611799613173565b60005b81548110156116d3578181815481106117b7576117b7614a45565b600091825260209091200154604051632c7b84dd60e11b81526001600160a01b038581166004830152909116906358f709ba90602401600060405180830381600087803b15801561180757600080fd5b505af115801561181b573d6000803e3d6000fd5b50505050808061182a90614a5b565b91505061179c565b600061183c6131c4565b90506001611848613221565b336000908152602091825260408082206001600160401b038616835290925220805460ff191691151591909117905590565b33611883611197565b6001600160a01b0316141580156118a357506001600160a01b0381163314155b156108ab5760405163e2a08e5d60e01b8152336004820152602401610bd6565b60008061089460017fbfa91572ce1e5fe8776a160d3b1f862e83f5ee2c080a7423b4761602a3ad124a614acc565b6000806118fc612a9f565b61ffff8416600090815260209190915260408120600281015490925060ff16900361194057604051631fc0a48b60e01b815261ffff84166004820152602401610bd6565b6002015460ff1692915050565b33611956610e26565b6001600160a01b031614610b8b5760405163118cdaa760e01b8152336004820152602401610bd6565b611987612196565b6119908161324f565b600061199a6122a2565b805490915060ff16156119af576119af614adf565b805460ff191660011781556040805163011fa75760e71b815290513091638fd3ab8091600480830192600092919082900301818387803b1580156119f257600080fd5b505af1158015611a06573d6000803e3d6000fd5b50505050306001600160a01b031663689f90c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6c9190614af5565b611a7857611a7861328f565b611a826000613327565b805460ff1916905550565b600080611a98612635565b90506000611aa4613342565b90506000611ab0612af7565b90506000611abc611d3f565b90506001600160a01b038616611ae557604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03861660009081526020859052604090205460ff1615611b30576001600160a01b0386166000908152602085905260409020805461ff001916610100179055611c2d565b8054604060ff90911610611b575760405163891684c360e01b815260040160405180910390fd5b6040805160608101825260018082526020808301918252845460ff9081168486019081526001600160a01b038c166000908152928a905294822093518454935195518216620100000262ff0000199615156101000261ff00199215159290921661ffff19909516949094171794909416919091179091558254909116908290611bdf83614b17565b91906101000a81548160ff021916908360ff16021790555050611c006122d0565b8054600181018255600091825260209091200180546001600160a01b0319166001600160a01b0388161790555b81546001808201845560008481526020902090910180546001600160a01b0319166001600160a01b0389161790558154610100900460ff16908290611c7183614b17565b82546101009290920a60ff8181021990931691831602179091556001600160a01b03881660009081526020879052604090205485546001620100009092049092161b6001600160401b0391821681811793509116811703611cf057604051638d68f84d60e01b81526001600160a01b0388166004820152602401610bd6565b835467ffffffffffffffff19166001600160401b038216178455611d12613370565b505050506001600160a01b0392909216600090815260209290925250604090205462010000900460ff1690565b60008061089460017f8561949d1c6242cee5c5a5aeb6b9c190ee611d7742fcec65d9e5b1341ea04d8a614acc565b60008061089460017fad78307a8b51804c575f26039dcb87c58925afb3b7c08732f3b21b942aed7a77614acc565b80611da4611e91565b61ffff8416600090815260209190915260409020541461095557604051635788c0fd60e11b815261ffff8316600482015260248101829052604401610bd6565b6000611dee611ebf565b905060005b8154811015611e51578261ffff16828281548110611e1357611e13614a45565b60009182526020909120601082040154600f9091166002026101000a900461ffff1603611e3f57505050565b80611e4981614a5b565b915050611df3565b5080546001810182556000918252602090912060108204018054600f9092166002026101000a61ffff818102199093169390921691909102919091179055565b60008061089460017f4c5e3a4bc66f163a233a21bf8ef776e10842bce70809a1c964eb9acdc3d5cd4b614acc565b60008061089460017f8571232e6643c3c4913142bb252555aaa29e5ecb8975f1d3b7aa29ede8f2ed1e614acc565b60008061089460017f68dfeeddfa5e4e9adceec01a3aba274bdcbab3f6ac9956417a4332f2b08abddb614acc565b6000611f25611fb5565b61ffff84166000908152602091909152604090209050611f468383836134b1565b6116d383611de4565b611f5761144f565b611f7457604051637e38d1d360e11b815260040160405180910390fd5b611f7e600161360f565b604051600081527fe11c2112add17fb763d3bd59f63b10429c3e11373da4fb8ef6725107a2fdc4b0906020015b60405180910390a1565b60008061089460017faf3e857a2ae24065b1bd005f8a72dea35481e3cf2e40353c4c7dac4b0051e8fc614acc565b600080611fef8461361c565b905080611ffa611eed565b600085815260209190915260409020546101009004166001600160401b031691505092915050565b60005b6001600160401b038216156120555761203f600183614b36565b909116908061204d81614b17565b915050612025565b919050565b60008061089460017f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cc614acc565b8161ffff166000036120ad57604051633d23e4d160e11b815260040160405180910390fd5b8060ff166000036120d15760405163831761d760e01b815260040160405180910390fd5b60006120db612a9f565b61ffff8416600090815260209190915260409020600181015490915060ff808216908416111561212b576040516313c3d1b160e01b815260ff808516600483015282166024820152604401610bd6565b50600201805460ff191660ff9290921691909117905550565b600061214e612a9f565b61ffff8416600090815260209190915260409020905061216f8383836134b1565b600281015460ff16600003611f465760028101805460ff191660011790556116d383611de4565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163003610b8b57604051633c64f99360e21b815260040160405180910390fd5b6121e7613688565b610b8b613370565b6121f761144f565b15612215576040516309e3d0f360e11b815260040160405180910390fd5b61221f600261360f565b604051600181527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd290602001611fab565b60008061225b613743565b905080612266611eed565b60009485526020526040909320546101009004929092166001600160401b031692915050565b6000600080516020614db1833981519152610933565b60008061089460017f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4f614acc565b60008061089460017f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed979614acc565b6001828101516060919060ff166000846001600160401b03811115612325576123256145e6565b60405190808252806020026020018201604052801561236b57816020015b6040805180820190915260008152606060208201528152602001906001900390816123435790505b5090506000805b8381101561244857604080518082019091526000815260606020820152612399898761374d565b815190975090915082158015906123b35750838160ff1611155b156123dd57604051630555a4b960e01b81526004810185905260ff82166024820152604401610bd6565b888160ff161061240c5760405163344fa80b60e11b815260ff82166004820152602481018a9052604401610bd6565b8060ff16935081858260ff168151811061242857612428614a45565b60200260200101819052505050808061244090614a5b565b915050612372565b50612453878561379f565b5095945050505050565b80516060906000908161246e612635565b90506000826001600160401b0381111561248a5761248a6145e6565b6040519080825280602002602001820160405280156124b3578160200160208202803683370190505b5090506000805b848110156125cc5760008882815181106124d6576124d6614a45565b6020908102919091018101516001600160a01b03811660008181529288905260408320548d5192945062010000900460ff16929163b5634c73908f908f908690811061252457612524614a45565b60200260200101516040518363ffffffff1660e01b8152600401612549929190614b78565b602060405180830381865afa158015612566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061258a9190614b95565b90508086858151811061259f5761259f614a45565b60209081029190910101526125b48186614bae565b945050505080806125c490614a5b565b9150506124ba565b50909450925050505b935093915050565b60006125e7612a9f565b61ffff8416600090815260209190915260408120915061260783836137cd565b600283015490915060ff808316911611156111025760028201805460ff831660ff1990911617905550505050565b60008061089460017f49bca747e973430e858f2f5de357b8dba36ea6d375b81bdb5d53dfaabf0b3a80614acc565b60008061267084846139fd565b905061269d8161267e612635565b336000908152602091909152604090205462010000900460ff16610e54565b156126be57604051631089c4a160e11b815260048101829052602401610bd6565b610c558133613a11565b60006126d2611ebf565b905060006126de612635565b6001600160a01b0384166000908152602091909152604081205462010000900460ff1691506001821b905b8354811015610dfe57600084828154811061272657612726614a45565b600091825260208220601082040154600f9091166002026101000a900461ffff169150612751611fb5565b61ffff8316600090815260209190915260409020805490915084166001600160401b031615612784576127848288612acd565b600061278e612a9f565b61ffff8416600090815260209190915260409020805490915085166001600160401b0316156127c1576127c183896125dd565b50505080806127cf90614a5b565b915050612709565b60006127e1612635565b905060006127ed613342565b905060006127f9612af7565b90506001600160a01b03841661282257604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03841660009081526020849052604090205460ff1661286657604051630d583f4760e41b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b038416600090815260208490526040902054610100900460ff166128af576040516307d86e9160e21b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b0384166000908152602084905260409020805461ff00191690556128d8611d3f565b8054610100900460ff169060016128ee83614bc1565b82546101009290920a60ff8181021990931691831602179091556001600160a01b03861660009081526020869052604090205484546001600160401b036001620100009093049093169190911b1981168216925016811061295157612951614adf565b825467ffffffffffffffff19166001600160401b0382161783558154600090815b81811015612a7757876001600160a01b031685828154811061299657612996614a45565b6000918252602090912001546001600160a01b031603612a6557846129bc600184614acc565b815481106129cc576129cc614a45565b9060005260206000200160009054906101000a90046001600160a01b03168582815481106129fc576129fc614a45565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555084805480612a3a57612a3a614bde565b600082815260209020810160001990810180546001600160a01b031916905501905560019250612a77565b80612a6f81614a5b565b915050612972565b5081612a8557612a85614adf565b612a8d613370565b612a9687613ab2565b50505050505050565b60008061089460017faf0a382368c2faefe3458a9184c278f02a5091cca99095e9051eb2cf76449aff614acc565b6000612ad7611fb5565b61ffff8416600090815260209190915260409020905061110282826137cd565b60008061089460017e758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e2614acc565b60008061089460017f64bacf405c5d7f563d3ba5252584a52c37e4fee380fd825b10666c27b8258023614acc565b600080516020614d91833981519152805460011901612b8457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6000806000612b9986856139fd565b9050612ba5868261085a565b612bc557604051630451c4fb60e41b815260048101829052602401610bd6565b6000612bd082613c31565b90508015612c1257604051829087907f4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef290600090a36000935091506125d59050565b90969095509350505050565b604080516080810182526000808252602082018190529181018290526060808201529080612c4c8482613c72565b925090506001600160e01b0319811663099474d560e41b14612c8157604051635aaa8f5160e01b815260040160405180910390fd5b600284830181015161ffff16845290910190612c9d8483613c9d565b60208501919091529150612cb18483613c9d565b604085019190915291506000612cd08584600291810182015192910190565b93509050612ce3858461ffff8416613cc3565b60608601919091529250612cf7858461379f565b505050919050565b600060a082901c15612d275760405163033b960d60e41b815260048101839052602401610bd6565b5090565b6001600080516020614d9183398151915255565b6060600082600101805480602002602001604051908101604052809291908181526020018280548015612d9b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612d7d575b5050505050905080516001600160401b03811115612dbb57612dbb6145e6565b604051908082528060200260200182016040528015612e0057816020015b6040805180820190915260008082526020820152815260200190600190039081612dd95790505b5091506000612e0d612635565b905060005b8251811015612cf7576040518060400160405280848381518110612e3857612e38614a45565b60200260200101516001600160a01b03168152602001836000868581518110612e6357612e63614a45565b6020908102919091018101516001600160a01b031682528101919091526040016000205462010000900460ff1690528451859083908110612ea657612ea6614a45565b60200260200101819052508080612ebc90614a5b565b915050612e12565b600087612ee4576040516351d7656b60e01b815260040160405180910390fd5b86612f025760405163717f139360e11b815260040160405180910390fd5b856001600160401b0316600003612f2257612f1b6131c4565b9050612f2e565b612f2b86613d37565b50845b6060600060405180608001604052808c61ffff1681526020018b8152602001612f5d336001600160a01b031690565b815260200188888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050915250604080516060810182526001600160401b0386168152336020820152919250612fd091908101612fc984613dd2565b9052613e49565b915050612ffe6040518060800160405280606081526020016060815260200160608152602001600081525090565b6000806000806130448f8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613ebb92505050565b6040805160808101825294855260208501939093529183015260608201529450600093506130759250611e91915050565b61ffff8d16600090815260209190915260409020549050806130b757604051635788c0fd60e11b815261ffff8d16600482015260248101829052604401610bd6565b6130d28c8b8385604001518660200151876000015189613f7a565b336001600160a01b0316846001600160401b03167f63eefc6a01dedd195b6bca015db99eb7905ad05547b48c92500987395f78ae7b8e8e8c8c8860600151604051613121959493929190614bf4565b60405180910390a350505098975050505050505050565b61314061194d565b6001600160a01b03811661316a57604051631e4fbdf760e01b815260006004820152602401610bd6565b6108ab816140c7565b61317b611d3f565b5460ff166131876122d0565b5414610b8b576131956122d0565b5461319e611d3f565b5460405163d2a13a2960e01b8152600481019290925260ff166024820152604401610bd6565b60006131ce611d6d565b546001600160401b031690506131e2611d6d565b80546001600160401b03169060006131f983614c3f565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505090565b60008061089460017f36408a71599ca6e68632104165d777346e57bee9acd9f469d182a52bc8170e22614acc565b61325881614138565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b7f000000000000000000000000000000000000000000000000000000000000000061ffff16306001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133169190614c65565b61ffff1614610b8b57610b8b614adf565b8061333061205a565b805460ff191691151591909117905550565b60008061089460017ffd6568c039679b3b7cc93c26c41d9379b7b1bec1677120493b467688302cb120614acc565b600061337a611d3f565b90506000613386612af7565b82548154919250610100900460ff169081146133a4576133a4614adf565b60005b818110156133f0576133de8382815481106133c4576133c4614a45565b6000918252602090912001546001600160a01b0316613ab2565b806133e881614a5b565b9150506133a7565b5060005b81811015613499576000613409826001614bae565b90505b828110156134865783818154811061342657613426614a45565b60009182526020909120015484546001600160a01b039091169085908490811061345257613452614a45565b6000918252602090912001546001600160a01b03160361347457613474614adf565b8061347e81614a5b565b91505061340c565b508061349181614a5b565b9150506133f4565b508254604060ff90911611156116d3576116d3614adf565b60006134bb612635565b90506001600160a01b0383166134e457604051632f44bd7760e01b815260040160405180910390fd5b8361ffff1660000361350957604051633d23e4d160e11b815260040160405180910390fd5b6001600160a01b038316600090815260208290526040902054610100900460ff16613552576040516307d86e9160e21b81526001600160a01b0384166004820152602401610bd6565b6001600160a01b03831660009081526020829052604090205482546201000090910460ff16906001821b906001600160401b0390821616156135b257604051638d68f84d60e01b81526001600160a01b0386166004820152602401610bd6565b835467ffffffffffffffff1981166001600160401b03918216929091169190911717835550506001908101805491820181556000908152602090200180546001600160a01b0319166001600160a01b039290921691909117905550565b80613618612b24565b5550565b600080613627612a9f565b61ffff8416600090815260209190915260409020600181015490915015806136545750600281015460ff16155b156136785760405163186b202960e11b815261ffff84166004820152602401610bd6565b546001600160401b031692915050565b6136906141e6565b336001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000161461370a57604051636345072160e11b81526001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000166004820152336024820152604401610bd6565b34156137295760405163bd28e88960e01b815260040160405180910390fd5b613733333361421d565b61373b614237565b6108ab6131c4565b6000610933613342565b604080518082019091526000815260606020820152818301600181015160ff9081168352600291820151918401919061378b90869084908416613cc3565b846020018194508290525050509250929050565b808251146109555781516040516355c5b3e360e11b8152600481019190915260248101829052604401610bd6565b6000806137d8612635565b90506001600160a01b03841661380157604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03841660009081526020829052604090205460ff1661384557604051630d583f4760e41b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b03841660009081526020829052604081205484546201000090910460ff16916001831b916001600160401b039083161690036138a6576040516307d86e9160e21b81526001600160a01b0387166004820152602401610bd6565b84546001600160401b03821982161667ffffffffffffffff199091161785556001850154600090815b818110156139dd57886001600160a01b03168860010182815481106138f6576138f6614a45565b6000918252602090912001546001600160a01b0316036139cb57876001016001836139219190614acc565b8154811061393157613931614a45565b6000918252602090912001546001890180546001600160a01b03909216918390811061395f5761395f614a45565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550876001018054806139a0576139a0614bde565b600082815260209020810160001990810180546001600160a01b0319169055019055600192506139dd565b806139d581614a5b565b9150506138cf565b50816139eb576139eb614adf565b50505060018401549250505092915050565b6000610c5583613a0c84613e49565b614247565b613a4582613a1d612635565b6001600160a01b0384166000908152602091909152604090205462010000900460ff1661427a565b7f35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e58282613a70612635565b6001600160a01b038581166000908152602092835260409081902054815195865293909116918401919091526201000090910460ff1690820152606001610b6f565b6000613abc612635565b90506000613ac8613342565b90506000613ad4611d3f565b90506000613ae0612af7565b6001600160a01b038616600090815260208681526040918290208251606081018452905460ff8082161515808452610100830482161515948401949094526201000090910416928101929092529192509080613b4e57508060200151158015613b4e5750604081015160ff16155b613b5a57613b5a614adf565b604081015184546020830151600160ff9093169290921b166001600160401b03161515906000805b8654610100900460ff16811015613be457896001600160a01b0316868281548110613baf57613baf614a45565b6000918252602090912001546001600160a01b031603613bd25760019150613be4565b80613bdc81614a5b565b915050613b82565b5081151583151514613bf857613bf8614adf565b81151581151514613c0b57613c0b614adf565b8554604085015160ff918216911610613c2657613c26614adf565b505050505050505050565b6000613c3c82610b0b565b15613c4957506001919050565b6001613c53611eed565b600093845260205260408320805460ff19169115159190911790555090565b600080600080613c8b8686600491810182015192910190565b60e09190911b97909650945050505050565b600080600080613cb68686602091810182015192910190565b9097909650945050505050565b6060600082600003613ce6575050604080516000815260208101909152826125d5565b5050604051828201601f831680613cfb575060205b80830184810186838901015b81831015613d1f578051835260209283019201613d07565b5050848452601f01601f191660405250935093915050565b613d3f613221565b336000908152602091825260408082206001600160401b0385168352909252205460ff16613d9157604051637bef2ac760e01b81526001600160401b0382166004820152336024820152604401610bd6565b6000613d9b613221565b336000908152602091825260408082206001600160401b039590951682529390915291909120805460ff1916911515919091179055565b6060818101515161ffff1015613e045781606001515160405163a341969160e01b8152600401610bd691815260200190565b8151602080840151604080860151606087015180519251613e339663099474d560e41b96909594929101614c82565b6040516020818303038152906040529050919050565b606061ffff80168260400151511115613e7e5781604001515160405163a341969160e01b8152600401610bd691815260200190565b6040808301518051845160208087015194519294613ea494929390928692909101614cde565b604051602081830303815290604052915050919050565b6060806060600080613ecc87610b8d565b905060606000613eda6122d0565b5483519091506000819003613f02576040516334e7b19560e11b815260040160405180910390fd5b613f0c89836122fe565b92505050600080613f1e8a848661245d565b9150915080341015613f4c576040516306a91e3760e51b815260048101829052346024820152604401610bd6565b6000613f588234614acc565b90508015613f6957613f69816142c8565b509299919850965090945092505050565b81516000613f86612635565b905086613fac57604051630ebc95af60e21b815261ffff8a166004820152602401610bd6565b8760005b838110156140ba576000868281518110613fcc57613fcc614a45565b60200260200101519050806001600160a01b0316634b5b05058a8481518110613ff757613ff7614a45565b60200260200101518e8b886000876001600160a01b03166001600160a01b0316815260200190815260200160002060000160029054906101000a900460ff1660ff168151811061404957614049614a45565b60200260200101518a8f896040518763ffffffff1660e01b8152600401614074959493929190614d1c565b6000604051808303818588803b15801561408d57600080fd5b505af11580156140a1573d6000803e3d6000fd5b50505050505080806140b290614a5b565b915050613fb0565b5050505050505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6001600160a01b0381163b6141a55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610bd6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020614db183398151915254600160401b900460ff16610b8b57604051631afcd79f60e31b815260040160405180910390fd5b6142256141e6565b61422e82614334565b61095581614345565b61423f6141e6565b610b8b614356565b6000828260405160200161425c929190614d60565b60405160208183030381529060405280519060200120905092915050565b600160ff82161b614289611eed565b60009384526020526040909220805468ffffffffffffffff00198116610100918290046001600160401b03908116951694909417029290921790915550565b604051600090339083908381818185875af1925050503d806000811461430a576040519150601f19603f3d011682016040523d82523d6000602084013e61430f565b606091505b505090508061095557604051630b288dc560e21b815260048101839052602401610bd6565b61433c6141e6565b6108ab8161435e565b61434d6141e6565b6108ab816143a3565b612d2b6141e6565b6143666141e6565b6000614370612b24565b60018155905060006143806118c3565b80546001600160a01b0319166001600160a01b0394909416939093179092555050565b6131406141e6565b60005b838110156143c65781810151838201526020016143ae565b50506000910152565b600081518084526143e78160208601602086016143ab565b601f01601f19169290920160200192915050565b602081526000610c5560208301846143cf565b80356001600160a01b038116811461205557600080fd5b60006020828403121561443757600080fd5b610c558261440e565b61ffff811681146108ab57600080fd5b6000806040838503121561446357600080fd5b823561446e81614440565b946020939093013593505050565b60006020828403121561448e57600080fd5b8135610c5581614440565b6020808252825182820181905260009190848201906040850190845b818110156144d557835161ffff16835292840192918401916001016144b5565b50909695505050505050565b6000602082840312156144f357600080fd5b5035919050565b6000806040838503121561450d57600080fd5b823561451881614440565b91506145266020840161440e565b90509250929050565b600081518084526020808501945080840160005b838110156145685781516001600160a01b031687529582019590820190600101614543565b509495945050505050565b602081526000610c55602083018461452f565b803560ff8116811461205557600080fd5b600080604083850312156145aa57600080fd5b82356145b581614440565b915061452660208401614586565b600080604083850312156145d657600080fd5b8235915061452660208401614586565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261460d57600080fd5b81356001600160401b0380821115614627576146276145e6565b604051601f8301601f19908116603f0116810190828211818310171561464f5761464f6145e6565b8160405283815286602085880101111561466857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561469b57600080fd5b82356146a681614440565b915060208301356001600160401b038111156146c157600080fd5b6146cd858286016145fc565b9150509250929050565b604080825283519082018190526000906020906060840190828701845b82811015614710578151845292840192908401906001016146f4565b50505092019290925292915050565b60008060006060848603121561473457600080fd5b833561473f81614440565b92506020840135915060408401356001600160401b038082111561476257600080fd5b908501906060828803121561477657600080fd5b604051606081018181108382111715614791576147916145e6565b806040525082358152602083013560208201526040830135828111156147b657600080fd5b6147c2898286016145fc565b6040830152508093505050509250925092565b6040815260006147e8604083018561452f565b905060ff831660208301529392505050565b602080825282518282018190526000919060409081850190868401855b8281101561484d5781518051151585528681015115158786015285015160ff168585015260609093019290850190600101614817565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101561484d57815180516001600160a01b0316855286015160ff16868501529284019290850190600101614877565b60008083601f8401126148ba57600080fd5b5081356001600160401b038111156148d157600080fd5b602083019150836020828501011115610fce57600080fd5b60008060008060008060008060c0898b03121561490557600080fd5b883561491081614440565b9750602089013596506040890135955060608901356001600160401b03808216821461493b57600080fd5b90955060808a0135908082111561495157600080fd5b61495d8c838d016148a8565b909650945060a08b013591508082111561497657600080fd5b506149838b828c016148a8565b999c989b5096995094979396929594505050565b61ffff9390931683526001600160a01b039190911660208301521515604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b038181168382160190808211156149f4576149f46149be565b5092915050565b61ffff8416815282602082015260606040820152815160608201526020820151608082015260006040830151606060a0840152614a3b60c08401826143cf565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201614a6d57614a6d6149be565b5060010190565b61ffff84168152826020820152606060408201526000614a9760608301846143cf565b95945050505050565b6001600160a01b0383168152604060208201819052600090614ac4908301846143cf565b949350505050565b81810381811115610894576108946149be565b634e487b7160e01b600052600160045260246000fd5b600060208284031215614b0757600080fd5b81518015158114610c5557600080fd5b600060ff821660ff8103614b2d57614b2d6149be565b60010192915050565b6001600160401b038281168282160390808211156149f4576149f46149be565b60ff81511682526000602082015160406020850152614ac460408501826143cf565b61ffff83168152604060208201526000614ac46040830184614b56565b600060208284031215614ba757600080fd5b5051919050565b80820180821115610894576108946149be565b600060ff821680614bd457614bd46149be565b6000190192915050565b634e487b7160e01b600052603160045260246000fd5b61ffff8616815284602082015260806040820152826080820152828460a0830137600060a08483010152600060a0601f19601f86011683010190508260608301529695505050505050565b60006001600160401b03808316818103614c5b57614c5b6149be565b6001019392505050565b600060208284031215614c7757600080fd5b8151610c5581614440565b63ffffffff60e01b87168152600061ffff60f01b808860f01b166004840152866006840152856026840152808560f01b166046840152508251614ccc8160488501602087016143ab565b91909101604801979650505050505050565b84815283602082015261ffff60f01b8360f01b16604082015260008251614d0c8160428501602087016143ab565b9190910160420195945050505050565b61ffff8616815260a060208201526000614d3960a0830187614b56565b8281036040840152614d4b81876143cf565b60608401959095525050608001529392505050565b61ffff60f01b8360f01b16815260008251614d828160028501602087016143ab565b91909101600201939250505056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122073aab26df1c80ff78ff6b64e88465ba3238f92133d0c3571b1aa2dd145b35b3c64736f6c634300081300330000000000000000000000000000000000000000000000000000000000002712
Deployed Bytecode
0x6080604052600436106102515760003560e01c80638da5cb5b11610139578063b13c82ea116100b6578063da4856a11161007a578063da4856a114610739578063db5fdb9114610759578063e54ff04014610786578063ee0bdb1c146107a6578063f2fde38b146107b9578063ff428f09146107d957600080fd5b8063b13c82ea1461069e578063b150fc55146106be578063b187bd26146106e0578063b4d591bb146106f5578063c128d1701461070a57600080fd5b80639ab730d7116100fd5780639ab730d7146105fb5780639d7824541461061b5780639f86029c1461063b5780639fd0506d1461065b578063adaf575f1461067057600080fd5b80638da5cb5b146105245780638e3ba8c9146105515780638fd3ab80146105715780639057412d146105865780639a8a0592146105b457600080fd5b8063396c16b7116101d2578063689f90c311610196578063689f90c3146104925780636a4db160146104a75780637c9d2708146104c75780638129fc1c146104e75780638456cb59146104ef57806389c619dd1461050457600080fd5b8063396c16b7146103f05780633a495e0b146104105780633f4ba83a14610430578063451d5332146104455780634f4bb3e51461047257600080fd5b80632310dd3c116102195780632310dd3c1461032f57806323d75e3114610361578063295d819e1461038e57806332cf4cd5146103ae5780633951cbe6146103ce57600080fd5b80630271510814610256578063036de8af1461029d57806307299652146102bf5780630900f010146102ef578063203e4a9b1461030f575b600080fd5b34801561026257600080fd5b50610287604051806040016040528060058152602001640312e302e360dc1b81525081565b60405161029491906143fb565b60405180910390f35b3480156102a957600080fd5b506102bd6102b8366004614425565b6107ee565b005b3480156102cb57600080fd5b506102df6102da366004614450565b61085a565b6040519015158152602001610294565b3480156102fb57600080fd5b506102bd61030a366004614425565b61089a565b34801561031b57600080fd5b506102bd61032a366004614425565b6108ae565b34801561033b57600080fd5b5061034f61034a36600461447c565b61091e565b60405160ff9091168152602001610294565b34801561036d57600080fd5b50610376610929565b6040516001600160401b039091168152602001610294565b34801561039a57600080fd5b506102bd6103a9366004614450565b610942565b3480156103ba57600080fd5b506102bd6103c9366004614450565b610959565b3480156103da57600080fd5b506103e3610a85565b6040516102949190614499565b3480156103fc57600080fd5b506102df61040b3660046144e1565b610b0b565b34801561041c57600080fd5b506102bd61042b3660046144fa565b610b29565b34801561043c57600080fd5b506102bd610b7b565b34801561045157600080fd5b5061046561046036600461447c565b610b8d565b6040516102949190614573565b34801561047e57600080fd5b5061034f61048d366004614450565b610c41565b34801561049e57600080fd5b506102df610c5c565b3480156104b357600080fd5b506102bd6104c2366004614597565b610c6f565b3480156104d357600080fd5b506102bd6104e23660046144fa565b610cbd565b6102bd610d03565b3480156104fb57600080fd5b506102bd610e05565b34801561051057600080fd5b5061034f61051f3660046144e1565b610e18565b34801561053057600080fd5b50610539610e26565b6040516001600160a01b039091168152602001610294565b34801561055d57600080fd5b506102df61056c3660046145c3565b610e54565b34801561057d57600080fd5b506102bd610e8e565b34801561059257600080fd5b506105a66105a1366004614688565b610f90565b6040516102949291906146d7565b3480156105c057600080fd5b506105e87f000000000000000000000000000000000000000000000000000000000000271281565b60405161ffff9091168152602001610294565b34801561060757600080fd5b506102bd6106163660046144fa565b610fd5565b34801561062757600080fd5b506102bd61063636600461471f565b61101b565b34801561064757600080fd5b506102bd610656366004614425565b611108565b34801561066757600080fd5b50610539611197565b34801561067c57600080fd5b5061069061068b36600461447c565b6111b0565b6040516102949291906147d5565b3480156106aa57600080fd5b506102bd6106b93660046144fa565b61127f565b3480156106ca57600080fd5b506106d36112c5565b60405161029491906147fa565b3480156106ec57600080fd5b506102df61144f565b34801561070157600080fd5b50610465611464565b34801561071657600080fd5b5061072a61072536600461447c565b6114cb565b60405190518152602001610294565b34801561074557600080fd5b506102bd61075436600461471f565b611507565b34801561076557600080fd5b5061077961077436600461447c565b6116d8565b604051610294919061485a565b34801561079257600080fd5b506107796107a136600461447c565b611703565b6103766107b43660046148e9565b61170f565b3480156107c557600080fd5b506102bd6107d4366004614425565b611774565b3480156107e557600080fd5b50610376611832565b6107fe6107f9610e26565b61187a565b60006108086118c3565b80546001600160a01b038481166001600160a01b031983168117845560405193945091169182907f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef690600090a3505050565b600080610866846118f1565b905060006108748585610c41565b90508160ff168160ff161015801561088f575060008260ff16115b925050505b92915050565b6108a261194d565b6108ab8161197f565b50565b6108b661194d565b6108bf81611a8d565b507ff05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda5816108ea611d3f565b54604080516001600160a01b03909316835261010090910460ff16602083015260009082015260600160405180910390a150565b6000610894826118f1565b6000610933611d6d565b546001600160401b0316919050565b61094c8282611d9b565b61095582611de4565b5050565b61096161194d565b8161ffff166000036109865760405163100b0f2760e11b815260040160405180910390fd5b806109a45760405163f839a0cb60e01b815260040160405180910390fd5b7f000000000000000000000000000000000000000000000000000000000000271261ffff168261ffff16036109ec5760405163101b8f9560e11b815260040160405180910390fd5b60006109f6611e91565b61ffff8416600090815260209182526040908190208151928301909152548152905081610a21611e91565b61ffff851660009081526020919091526040902055610a3f83611de4565b8051604080519182526020820184905261ffff8516917f6b8e3e5d5cb35ca559551a3a468913b588421f8eeb87fabc088aa03638ce1369910160405180910390a2505050565b6060610a8f611ebf565b805480602002602001604051908101604052809291908181526020018280548015610b0157602002820191906000526020600020906000905b82829054906101000a900461ffff1661ffff1681526020019060020190602082600101049283019260010382029150808411610ac85790505b5050505050905090565b6000610b15611eed565b600092835260205250604090205460ff1690565b610b3161194d565b610b3b8282611f1b565b7f6b9b1f20ce684fc1c23217395b766f44fb36a93fb907e41e4243fe2f9c101c2d82826001604051610b6f93929190614997565b60405180910390a15050565b610b8361194d565b610b8b611f4f565b565b60606000610b99611fb5565b61ffff841660009081526020919091526040812060018101549092509003610bdf5760405163186b202960e11b815261ffff841660048201526024015b60405180910390fd5b60018101805460408051602080840282018101909252828152929190830182828015610c3457602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610c16575b5050505050915050919050565b6000610c55610c508484611fe3565b612022565b9392505050565b6000610c6661205a565b5460ff16919050565b610c7761194d565b610c818282612088565b6040805161ffff8416815260ff831660208201527f463734bd482c3b124a4f4ee8cbda3b9beb1aa70b7346ca456fec770efc446c7b9101610b6f565b610cc561194d565b610ccf8282612144565b7f9a8d72d56c46cf95458ced32b1aa082ed04dd70c7119b6779521bb1893ee0b7382826001604051610b6f93929190614997565b610d0b612196565b600080516020614db18339815191528054600160401b810460ff1615906001600160401b0316600081158015610d3e5750825b90506000826001600160401b03166001148015610d5a5750303b155b905081158015610d68575080155b15610d865760405163f92ee8a960e01b815260040160405180910390fd5b845467ffffffffffffffff191660011785558315610db057845460ff60401b1916600160401b1785555b610db86121df565b8315610dfe57845460ff60401b19168555604051600181527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d29060200160405180910390a15b5050505050565b610e106107f9610e26565b610b8b6121ef565b6000610894610c5083612250565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c199300546001600160a01b031690565b600080600160ff84161b610e66611eed565b600086815260209190915260409020546101009004166001600160401b031611905092915050565b610e96612196565b610e9e61228c565b610ea99060016149d4565b600080516020614db18339815191528054600160401b900460ff1680610edc575080546001600160401b03808416911610155b15610efa5760405163f92ee8a960e01b815260040160405180910390fd5b805468ffffffffffffffffff19166001600160401b03831617600160401b178155610f236122a2565b5460ff16610f4457604051632866815360e11b815260040160405180910390fd5b610f4c6121e7565b805460ff60401b191681556040516001600160401b03831681527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602001610b6f565b6060600080610f9d6122d0565b5490506000610fab86610b8d565b90506000610fb986846122fe565b9050610fc687828461245d565b945094505050505b9250929050565b610fdd61194d565b610fe782826125dd565b7f9a8d72d56c46cf95458ced32b1aa082ed04dd70c7119b6779521bb1893ee0b7382826000604051610b6f93929190614997565b611023612635565b3360009081526020919091526040902054610100900460ff1661105b5760405163a0ae911d60e01b8152336004820152602401610bd6565b61106361144f565b15611081576040516309e3d0f360e11b815260040160405180910390fd5b61108b8383611d9b565b60006110978483612663565b90506110a3848261085a565b156111025760405163da4856a160e01b8152309063da4856a1906110cf908790879087906004016149fb565b600060405180830381600087803b1580156110e957600080fd5b505af11580156110fd573d6000803e3d6000fd5b505050505b50505050565b61111061194d565b600061111a611d3f565b54610100900460ff169050600181116111465760405163831761d760e01b815260040160405180910390fd5b61114f826126c8565b611158826127d7565b604080516001600160a01b0384168152600060208201527f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f9101610b6f565b60006111a16118c3565b546001600160a01b0316919050565b60606000806111bd612a9f565b61ffff8516600090815260209190915260409020600181015490915015806111ea5750600281015460ff16155b1561120e5760405163186b202960e11b815261ffff85166004820152602401610bd6565b600281015460018201805460408051602080840282018101909252828152929360ff169291849183018282801561126e57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611250575b505050505091509250925050915091565b61128761194d565b6112918282612acd565b7f6b9b1f20ce684fc1c23217395b766f44fb36a93fb907e41e4243fe2f9c101c2d82826000604051610b6f93929190614997565b606060006112d1612af7565b80548060200260200160405190810160405280929190818152602001828054801561132557602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311611307575b505050505090506000815190506000816001600160401b0381111561134c5761134c6145e6565b60405190808252806020026020018201604052801561139757816020015b604080516060810182526000808252602080830182905292820152825260001990920191018161136a5790505b50905060005b82811015611447576113ad612635565b60008583815181106113c1576113c1614a45565b6020908102919091018101516001600160a01b031682528181019290925260409081016000208151606081018352905460ff808216151583526101008204811615159483019490945262010000900490921690820152825183908390811061142b5761142b614a45565b60200260200101819052508061144090614a5b565b905061139d565b509392505050565b60008061145a612b24565b5460021492915050565b606061146e612af7565b805480602002602001604051908101604052809291908181526020018280548015610b0157602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116114a4575050505050905090565b6040805160208101909152600081526114e2611e91565b61ffff9092166000908152602092835260409081902081519384019091525482525090565b61150f612b52565b61151761144f565b15611535576040516309e3d0f360e11b815260040160405180910390fd5b600080611543858585612b8a565b9150915080156115545750506116bc565b60006115638460400151612c1e565b90507f000000000000000000000000000000000000000000000000000000000000271261ffff16816000015161ffff16146115e3578051604051631ee5902560e11b815261ffff91821660048201527f00000000000000000000000000000000000000000000000000000000000027129091166024820152604401610bd6565b60006115f28260200151612cff565b9050806001600160a01b031663e7fa3a5a88846040015185606001516040518463ffffffff1660e01b815260040161162c93929190614a74565b600060405180830381600087803b15801561164657600080fd5b505af115801561165a573d6000803e3d6000fd5b5050505061166b8560200151612cff565b6001600160a01b03168761ffff16857f1000a14cded4271da033293964b8a9ce647c150f445bb766d7d8219acefb665e8486606001516040516116af929190614aa0565b60405180910390a4505050505b6116d36001600080516020614d9183398151915255565b505050565b606060006116e4612a9f565b61ffff84166000908152602091909152604090209050610c5581612d3f565b606060006116e4611fb5565b6000611719612b52565b61172161144f565b1561173f576040516309e3d0f360e11b815260040160405180910390fd5b61174f8989898989898989612ec4565b90506117686001600080516020614d9183398151915255565b98975050505050505050565b61177c61194d565b61178581613138565b600061178f6122d0565b9050611799613173565b60005b81548110156116d3578181815481106117b7576117b7614a45565b600091825260209091200154604051632c7b84dd60e11b81526001600160a01b038581166004830152909116906358f709ba90602401600060405180830381600087803b15801561180757600080fd5b505af115801561181b573d6000803e3d6000fd5b50505050808061182a90614a5b565b91505061179c565b600061183c6131c4565b90506001611848613221565b336000908152602091825260408082206001600160401b038616835290925220805460ff191691151591909117905590565b33611883611197565b6001600160a01b0316141580156118a357506001600160a01b0381163314155b156108ab5760405163e2a08e5d60e01b8152336004820152602401610bd6565b60008061089460017fbfa91572ce1e5fe8776a160d3b1f862e83f5ee2c080a7423b4761602a3ad124a614acc565b6000806118fc612a9f565b61ffff8416600090815260209190915260408120600281015490925060ff16900361194057604051631fc0a48b60e01b815261ffff84166004820152602401610bd6565b6002015460ff1692915050565b33611956610e26565b6001600160a01b031614610b8b5760405163118cdaa760e01b8152336004820152602401610bd6565b611987612196565b6119908161324f565b600061199a6122a2565b805490915060ff16156119af576119af614adf565b805460ff191660011781556040805163011fa75760e71b815290513091638fd3ab8091600480830192600092919082900301818387803b1580156119f257600080fd5b505af1158015611a06573d6000803e3d6000fd5b50505050306001600160a01b031663689f90c36040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a48573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a6c9190614af5565b611a7857611a7861328f565b611a826000613327565b805460ff1916905550565b600080611a98612635565b90506000611aa4613342565b90506000611ab0612af7565b90506000611abc611d3f565b90506001600160a01b038616611ae557604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03861660009081526020859052604090205460ff1615611b30576001600160a01b0386166000908152602085905260409020805461ff001916610100179055611c2d565b8054604060ff90911610611b575760405163891684c360e01b815260040160405180910390fd5b6040805160608101825260018082526020808301918252845460ff9081168486019081526001600160a01b038c166000908152928a905294822093518454935195518216620100000262ff0000199615156101000261ff00199215159290921661ffff19909516949094171794909416919091179091558254909116908290611bdf83614b17565b91906101000a81548160ff021916908360ff16021790555050611c006122d0565b8054600181018255600091825260209091200180546001600160a01b0319166001600160a01b0388161790555b81546001808201845560008481526020902090910180546001600160a01b0319166001600160a01b0389161790558154610100900460ff16908290611c7183614b17565b82546101009290920a60ff8181021990931691831602179091556001600160a01b03881660009081526020879052604090205485546001620100009092049092161b6001600160401b0391821681811793509116811703611cf057604051638d68f84d60e01b81526001600160a01b0388166004820152602401610bd6565b835467ffffffffffffffff19166001600160401b038216178455611d12613370565b505050506001600160a01b0392909216600090815260209290925250604090205462010000900460ff1690565b60008061089460017f8561949d1c6242cee5c5a5aeb6b9c190ee611d7742fcec65d9e5b1341ea04d8a614acc565b60008061089460017fad78307a8b51804c575f26039dcb87c58925afb3b7c08732f3b21b942aed7a77614acc565b80611da4611e91565b61ffff8416600090815260209190915260409020541461095557604051635788c0fd60e11b815261ffff8316600482015260248101829052604401610bd6565b6000611dee611ebf565b905060005b8154811015611e51578261ffff16828281548110611e1357611e13614a45565b60009182526020909120601082040154600f9091166002026101000a900461ffff1603611e3f57505050565b80611e4981614a5b565b915050611df3565b5080546001810182556000918252602090912060108204018054600f9092166002026101000a61ffff818102199093169390921691909102919091179055565b60008061089460017f4c5e3a4bc66f163a233a21bf8ef776e10842bce70809a1c964eb9acdc3d5cd4b614acc565b60008061089460017f8571232e6643c3c4913142bb252555aaa29e5ecb8975f1d3b7aa29ede8f2ed1e614acc565b60008061089460017f68dfeeddfa5e4e9adceec01a3aba274bdcbab3f6ac9956417a4332f2b08abddb614acc565b6000611f25611fb5565b61ffff84166000908152602091909152604090209050611f468383836134b1565b6116d383611de4565b611f5761144f565b611f7457604051637e38d1d360e11b815260040160405180910390fd5b611f7e600161360f565b604051600081527fe11c2112add17fb763d3bd59f63b10429c3e11373da4fb8ef6725107a2fdc4b0906020015b60405180910390a1565b60008061089460017faf3e857a2ae24065b1bd005f8a72dea35481e3cf2e40353c4c7dac4b0051e8fc614acc565b600080611fef8461361c565b905080611ffa611eed565b600085815260209190915260409020546101009004166001600160401b031691505092915050565b60005b6001600160401b038216156120555761203f600183614b36565b909116908061204d81614b17565b915050612025565b919050565b60008061089460017f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cc614acc565b8161ffff166000036120ad57604051633d23e4d160e11b815260040160405180910390fd5b8060ff166000036120d15760405163831761d760e01b815260040160405180910390fd5b60006120db612a9f565b61ffff8416600090815260209190915260409020600181015490915060ff808216908416111561212b576040516313c3d1b160e01b815260ff808516600483015282166024820152604401610bd6565b50600201805460ff191660ff9290921691909117905550565b600061214e612a9f565b61ffff8416600090815260209190915260409020905061216f8383836134b1565b600281015460ff16600003611f465760028101805460ff191660011790556116d383611de4565b6001600160a01b037f00000000000000000000000046c6058a62583a7767d9be4094cda080b36b229d163003610b8b57604051633c64f99360e21b815260040160405180910390fd5b6121e7613688565b610b8b613370565b6121f761144f565b15612215576040516309e3d0f360e11b815260040160405180910390fd5b61221f600261360f565b604051600181527f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd290602001611fab565b60008061225b613743565b905080612266611eed565b60009485526020526040909320546101009004929092166001600160401b031692915050565b6000600080516020614db1833981519152610933565b60008061089460017f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4f614acc565b60008061089460017f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed979614acc565b6001828101516060919060ff166000846001600160401b03811115612325576123256145e6565b60405190808252806020026020018201604052801561236b57816020015b6040805180820190915260008152606060208201528152602001906001900390816123435790505b5090506000805b8381101561244857604080518082019091526000815260606020820152612399898761374d565b815190975090915082158015906123b35750838160ff1611155b156123dd57604051630555a4b960e01b81526004810185905260ff82166024820152604401610bd6565b888160ff161061240c5760405163344fa80b60e11b815260ff82166004820152602481018a9052604401610bd6565b8060ff16935081858260ff168151811061242857612428614a45565b60200260200101819052505050808061244090614a5b565b915050612372565b50612453878561379f565b5095945050505050565b80516060906000908161246e612635565b90506000826001600160401b0381111561248a5761248a6145e6565b6040519080825280602002602001820160405280156124b3578160200160208202803683370190505b5090506000805b848110156125cc5760008882815181106124d6576124d6614a45565b6020908102919091018101516001600160a01b03811660008181529288905260408320548d5192945062010000900460ff16929163b5634c73908f908f908690811061252457612524614a45565b60200260200101516040518363ffffffff1660e01b8152600401612549929190614b78565b602060405180830381865afa158015612566573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061258a9190614b95565b90508086858151811061259f5761259f614a45565b60209081029190910101526125b48186614bae565b945050505080806125c490614a5b565b9150506124ba565b50909450925050505b935093915050565b60006125e7612a9f565b61ffff8416600090815260209190915260408120915061260783836137cd565b600283015490915060ff808316911611156111025760028201805460ff831660ff1990911617905550505050565b60008061089460017f49bca747e973430e858f2f5de357b8dba36ea6d375b81bdb5d53dfaabf0b3a80614acc565b60008061267084846139fd565b905061269d8161267e612635565b336000908152602091909152604090205462010000900460ff16610e54565b156126be57604051631089c4a160e11b815260048101829052602401610bd6565b610c558133613a11565b60006126d2611ebf565b905060006126de612635565b6001600160a01b0384166000908152602091909152604081205462010000900460ff1691506001821b905b8354811015610dfe57600084828154811061272657612726614a45565b600091825260208220601082040154600f9091166002026101000a900461ffff169150612751611fb5565b61ffff8316600090815260209190915260409020805490915084166001600160401b031615612784576127848288612acd565b600061278e612a9f565b61ffff8416600090815260209190915260409020805490915085166001600160401b0316156127c1576127c183896125dd565b50505080806127cf90614a5b565b915050612709565b60006127e1612635565b905060006127ed613342565b905060006127f9612af7565b90506001600160a01b03841661282257604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03841660009081526020849052604090205460ff1661286657604051630d583f4760e41b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b038416600090815260208490526040902054610100900460ff166128af576040516307d86e9160e21b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b0384166000908152602084905260409020805461ff00191690556128d8611d3f565b8054610100900460ff169060016128ee83614bc1565b82546101009290920a60ff8181021990931691831602179091556001600160a01b03861660009081526020869052604090205484546001600160401b036001620100009093049093169190911b1981168216925016811061295157612951614adf565b825467ffffffffffffffff19166001600160401b0382161783558154600090815b81811015612a7757876001600160a01b031685828154811061299657612996614a45565b6000918252602090912001546001600160a01b031603612a6557846129bc600184614acc565b815481106129cc576129cc614a45565b9060005260206000200160009054906101000a90046001600160a01b03168582815481106129fc576129fc614a45565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555084805480612a3a57612a3a614bde565b600082815260209020810160001990810180546001600160a01b031916905501905560019250612a77565b80612a6f81614a5b565b915050612972565b5081612a8557612a85614adf565b612a8d613370565b612a9687613ab2565b50505050505050565b60008061089460017faf0a382368c2faefe3458a9184c278f02a5091cca99095e9051eb2cf76449aff614acc565b6000612ad7611fb5565b61ffff8416600090815260209190915260409020905061110282826137cd565b60008061089460017e758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e2614acc565b60008061089460017f64bacf405c5d7f563d3ba5252584a52c37e4fee380fd825b10666c27b8258023614acc565b600080516020614d91833981519152805460011901612b8457604051633ee5aeb560e01b815260040160405180910390fd5b60029055565b6000806000612b9986856139fd565b9050612ba5868261085a565b612bc557604051630451c4fb60e41b815260048101829052602401610bd6565b6000612bd082613c31565b90508015612c1257604051829087907f4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef290600090a36000935091506125d59050565b90969095509350505050565b604080516080810182526000808252602082018190529181018290526060808201529080612c4c8482613c72565b925090506001600160e01b0319811663099474d560e41b14612c8157604051635aaa8f5160e01b815260040160405180910390fd5b600284830181015161ffff16845290910190612c9d8483613c9d565b60208501919091529150612cb18483613c9d565b604085019190915291506000612cd08584600291810182015192910190565b93509050612ce3858461ffff8416613cc3565b60608601919091529250612cf7858461379f565b505050919050565b600060a082901c15612d275760405163033b960d60e41b815260048101839052602401610bd6565b5090565b6001600080516020614d9183398151915255565b6060600082600101805480602002602001604051908101604052809291908181526020018280548015612d9b57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311612d7d575b5050505050905080516001600160401b03811115612dbb57612dbb6145e6565b604051908082528060200260200182016040528015612e0057816020015b6040805180820190915260008082526020820152815260200190600190039081612dd95790505b5091506000612e0d612635565b905060005b8251811015612cf7576040518060400160405280848381518110612e3857612e38614a45565b60200260200101516001600160a01b03168152602001836000868581518110612e6357612e63614a45565b6020908102919091018101516001600160a01b031682528101919091526040016000205462010000900460ff1690528451859083908110612ea657612ea6614a45565b60200260200101819052508080612ebc90614a5b565b915050612e12565b600087612ee4576040516351d7656b60e01b815260040160405180910390fd5b86612f025760405163717f139360e11b815260040160405180910390fd5b856001600160401b0316600003612f2257612f1b6131c4565b9050612f2e565b612f2b86613d37565b50845b6060600060405180608001604052808c61ffff1681526020018b8152602001612f5d336001600160a01b031690565b815260200188888080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152505050915250604080516060810182526001600160401b0386168152336020820152919250612fd091908101612fc984613dd2565b9052613e49565b915050612ffe6040518060800160405280606081526020016060815260200160608152602001600081525090565b6000806000806130448f8a8a8080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250613ebb92505050565b6040805160808101825294855260208501939093529183015260608201529450600093506130759250611e91915050565b61ffff8d16600090815260209190915260409020549050806130b757604051635788c0fd60e11b815261ffff8d16600482015260248101829052604401610bd6565b6130d28c8b8385604001518660200151876000015189613f7a565b336001600160a01b0316846001600160401b03167f63eefc6a01dedd195b6bca015db99eb7905ad05547b48c92500987395f78ae7b8e8e8c8c8860600151604051613121959493929190614bf4565b60405180910390a350505098975050505050505050565b61314061194d565b6001600160a01b03811661316a57604051631e4fbdf760e01b815260006004820152602401610bd6565b6108ab816140c7565b61317b611d3f565b5460ff166131876122d0565b5414610b8b576131956122d0565b5461319e611d3f565b5460405163d2a13a2960e01b8152600481019290925260ff166024820152604401610bd6565b60006131ce611d6d565b546001600160401b031690506131e2611d6d565b80546001600160401b03169060006131f983614c3f565b91906101000a8154816001600160401b0302191690836001600160401b031602179055505090565b60008061089460017f36408a71599ca6e68632104165d777346e57bee9acd9f469d182a52bc8170e22614acc565b61325881614138565b6040516001600160a01b038216907fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b90600090a250565b7f000000000000000000000000000000000000000000000000000000000000271261ffff16306001600160a01b0316639a8a05926040518163ffffffff1660e01b8152600401602060405180830381865afa1580156132f2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906133169190614c65565b61ffff1614610b8b57610b8b614adf565b8061333061205a565b805460ff191691151591909117905550565b60008061089460017ffd6568c039679b3b7cc93c26c41d9379b7b1bec1677120493b467688302cb120614acc565b600061337a611d3f565b90506000613386612af7565b82548154919250610100900460ff169081146133a4576133a4614adf565b60005b818110156133f0576133de8382815481106133c4576133c4614a45565b6000918252602090912001546001600160a01b0316613ab2565b806133e881614a5b565b9150506133a7565b5060005b81811015613499576000613409826001614bae565b90505b828110156134865783818154811061342657613426614a45565b60009182526020909120015484546001600160a01b039091169085908490811061345257613452614a45565b6000918252602090912001546001600160a01b03160361347457613474614adf565b8061347e81614a5b565b91505061340c565b508061349181614a5b565b9150506133f4565b508254604060ff90911611156116d3576116d3614adf565b60006134bb612635565b90506001600160a01b0383166134e457604051632f44bd7760e01b815260040160405180910390fd5b8361ffff1660000361350957604051633d23e4d160e11b815260040160405180910390fd5b6001600160a01b038316600090815260208290526040902054610100900460ff16613552576040516307d86e9160e21b81526001600160a01b0384166004820152602401610bd6565b6001600160a01b03831660009081526020829052604090205482546201000090910460ff16906001821b906001600160401b0390821616156135b257604051638d68f84d60e01b81526001600160a01b0386166004820152602401610bd6565b835467ffffffffffffffff1981166001600160401b03918216929091169190911717835550506001908101805491820181556000908152602090200180546001600160a01b0319166001600160a01b039290921691909117905550565b80613618612b24565b5550565b600080613627612a9f565b61ffff8416600090815260209190915260409020600181015490915015806136545750600281015460ff16155b156136785760405163186b202960e11b815261ffff84166004820152602401610bd6565b546001600160401b031692915050565b6136906141e6565b336001600160a01b037f0000000000000000000000003d6cb9d16fd5ff33511d630fc1e98a8f5f93dd85161461370a57604051636345072160e11b81526001600160a01b037f0000000000000000000000003d6cb9d16fd5ff33511d630fc1e98a8f5f93dd85166004820152336024820152604401610bd6565b34156137295760405163bd28e88960e01b815260040160405180910390fd5b613733333361421d565b61373b614237565b6108ab6131c4565b6000610933613342565b604080518082019091526000815260606020820152818301600181015160ff9081168352600291820151918401919061378b90869084908416613cc3565b846020018194508290525050509250929050565b808251146109555781516040516355c5b3e360e11b8152600481019190915260248101829052604401610bd6565b6000806137d8612635565b90506001600160a01b03841661380157604051632f44bd7760e01b815260040160405180910390fd5b6001600160a01b03841660009081526020829052604090205460ff1661384557604051630d583f4760e41b81526001600160a01b0385166004820152602401610bd6565b6001600160a01b03841660009081526020829052604081205484546201000090910460ff16916001831b916001600160401b039083161690036138a6576040516307d86e9160e21b81526001600160a01b0387166004820152602401610bd6565b84546001600160401b03821982161667ffffffffffffffff199091161785556001850154600090815b818110156139dd57886001600160a01b03168860010182815481106138f6576138f6614a45565b6000918252602090912001546001600160a01b0316036139cb57876001016001836139219190614acc565b8154811061393157613931614a45565b6000918252602090912001546001890180546001600160a01b03909216918390811061395f5761395f614a45565b9060005260206000200160006101000a8154816001600160a01b0302191690836001600160a01b03160217905550876001018054806139a0576139a0614bde565b600082815260209020810160001990810180546001600160a01b0319169055019055600192506139dd565b806139d581614a5b565b9150506138cf565b50816139eb576139eb614adf565b50505060018401549250505092915050565b6000610c5583613a0c84613e49565b614247565b613a4582613a1d612635565b6001600160a01b0384166000908152602091909152604090205462010000900460ff1661427a565b7f35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e58282613a70612635565b6001600160a01b038581166000908152602092835260409081902054815195865293909116918401919091526201000090910460ff1690820152606001610b6f565b6000613abc612635565b90506000613ac8613342565b90506000613ad4611d3f565b90506000613ae0612af7565b6001600160a01b038616600090815260208681526040918290208251606081018452905460ff8082161515808452610100830482161515948401949094526201000090910416928101929092529192509080613b4e57508060200151158015613b4e5750604081015160ff16155b613b5a57613b5a614adf565b604081015184546020830151600160ff9093169290921b166001600160401b03161515906000805b8654610100900460ff16811015613be457896001600160a01b0316868281548110613baf57613baf614a45565b6000918252602090912001546001600160a01b031603613bd25760019150613be4565b80613bdc81614a5b565b915050613b82565b5081151583151514613bf857613bf8614adf565b81151581151514613c0b57613c0b614adf565b8554604085015160ff918216911610613c2657613c26614adf565b505050505050505050565b6000613c3c82610b0b565b15613c4957506001919050565b6001613c53611eed565b600093845260205260408320805460ff19169115159190911790555090565b600080600080613c8b8686600491810182015192910190565b60e09190911b97909650945050505050565b600080600080613cb68686602091810182015192910190565b9097909650945050505050565b6060600082600003613ce6575050604080516000815260208101909152826125d5565b5050604051828201601f831680613cfb575060205b80830184810186838901015b81831015613d1f578051835260209283019201613d07565b5050848452601f01601f191660405250935093915050565b613d3f613221565b336000908152602091825260408082206001600160401b0385168352909252205460ff16613d9157604051637bef2ac760e01b81526001600160401b0382166004820152336024820152604401610bd6565b6000613d9b613221565b336000908152602091825260408082206001600160401b039590951682529390915291909120805460ff1916911515919091179055565b6060818101515161ffff1015613e045781606001515160405163a341969160e01b8152600401610bd691815260200190565b8151602080840151604080860151606087015180519251613e339663099474d560e41b96909594929101614c82565b6040516020818303038152906040529050919050565b606061ffff80168260400151511115613e7e5781604001515160405163a341969160e01b8152600401610bd691815260200190565b6040808301518051845160208087015194519294613ea494929390928692909101614cde565b604051602081830303815290604052915050919050565b6060806060600080613ecc87610b8d565b905060606000613eda6122d0565b5483519091506000819003613f02576040516334e7b19560e11b815260040160405180910390fd5b613f0c89836122fe565b92505050600080613f1e8a848661245d565b9150915080341015613f4c576040516306a91e3760e51b815260048101829052346024820152604401610bd6565b6000613f588234614acc565b90508015613f6957613f69816142c8565b509299919850965090945092505050565b81516000613f86612635565b905086613fac57604051630ebc95af60e21b815261ffff8a166004820152602401610bd6565b8760005b838110156140ba576000868281518110613fcc57613fcc614a45565b60200260200101519050806001600160a01b0316634b5b05058a8481518110613ff757613ff7614a45565b60200260200101518e8b886000876001600160a01b03166001600160a01b0316815260200190815260200160002060000160029054906101000a900460ff1660ff168151811061404957614049614a45565b60200260200101518a8f896040518763ffffffff1660e01b8152600401614074959493929190614d1c565b6000604051808303818588803b15801561408d57600080fd5b505af11580156140a1573d6000803e3d6000fd5b50505050505080806140b290614a5b565b915050613fb0565b5050505050505050505050565b7f9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930080546001600160a01b031981166001600160a01b03848116918217845560405192169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a3505050565b6001600160a01b0381163b6141a55760405162461bcd60e51b815260206004820152602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608401610bd6565b7f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b0319166001600160a01b0392909216919091179055565b600080516020614db183398151915254600160401b900460ff16610b8b57604051631afcd79f60e31b815260040160405180910390fd5b6142256141e6565b61422e82614334565b61095581614345565b61423f6141e6565b610b8b614356565b6000828260405160200161425c929190614d60565b60405160208183030381529060405280519060200120905092915050565b600160ff82161b614289611eed565b60009384526020526040909220805468ffffffffffffffff00198116610100918290046001600160401b03908116951694909417029290921790915550565b604051600090339083908381818185875af1925050503d806000811461430a576040519150601f19603f3d011682016040523d82523d6000602084013e61430f565b606091505b505090508061095557604051630b288dc560e21b815260048101839052602401610bd6565b61433c6141e6565b6108ab8161435e565b61434d6141e6565b6108ab816143a3565b612d2b6141e6565b6143666141e6565b6000614370612b24565b60018155905060006143806118c3565b80546001600160a01b0319166001600160a01b0394909416939093179092555050565b6131406141e6565b60005b838110156143c65781810151838201526020016143ae565b50506000910152565b600081518084526143e78160208601602086016143ab565b601f01601f19169290920160200192915050565b602081526000610c5560208301846143cf565b80356001600160a01b038116811461205557600080fd5b60006020828403121561443757600080fd5b610c558261440e565b61ffff811681146108ab57600080fd5b6000806040838503121561446357600080fd5b823561446e81614440565b946020939093013593505050565b60006020828403121561448e57600080fd5b8135610c5581614440565b6020808252825182820181905260009190848201906040850190845b818110156144d557835161ffff16835292840192918401916001016144b5565b50909695505050505050565b6000602082840312156144f357600080fd5b5035919050565b6000806040838503121561450d57600080fd5b823561451881614440565b91506145266020840161440e565b90509250929050565b600081518084526020808501945080840160005b838110156145685781516001600160a01b031687529582019590820190600101614543565b509495945050505050565b602081526000610c55602083018461452f565b803560ff8116811461205557600080fd5b600080604083850312156145aa57600080fd5b82356145b581614440565b915061452660208401614586565b600080604083850312156145d657600080fd5b8235915061452660208401614586565b634e487b7160e01b600052604160045260246000fd5b600082601f83011261460d57600080fd5b81356001600160401b0380821115614627576146276145e6565b604051601f8301601f19908116603f0116810190828211818310171561464f5761464f6145e6565b8160405283815286602085880101111561466857600080fd5b836020870160208301376000602085830101528094505050505092915050565b6000806040838503121561469b57600080fd5b82356146a681614440565b915060208301356001600160401b038111156146c157600080fd5b6146cd858286016145fc565b9150509250929050565b604080825283519082018190526000906020906060840190828701845b82811015614710578151845292840192908401906001016146f4565b50505092019290925292915050565b60008060006060848603121561473457600080fd5b833561473f81614440565b92506020840135915060408401356001600160401b038082111561476257600080fd5b908501906060828803121561477657600080fd5b604051606081018181108382111715614791576147916145e6565b806040525082358152602083013560208201526040830135828111156147b657600080fd5b6147c2898286016145fc565b6040830152508093505050509250925092565b6040815260006147e8604083018561452f565b905060ff831660208301529392505050565b602080825282518282018190526000919060409081850190868401855b8281101561484d5781518051151585528681015115158786015285015160ff168585015260609093019290850190600101614817565b5091979650505050505050565b602080825282518282018190526000919060409081850190868401855b8281101561484d57815180516001600160a01b0316855286015160ff16868501529284019290850190600101614877565b60008083601f8401126148ba57600080fd5b5081356001600160401b038111156148d157600080fd5b602083019150836020828501011115610fce57600080fd5b60008060008060008060008060c0898b03121561490557600080fd5b883561491081614440565b9750602089013596506040890135955060608901356001600160401b03808216821461493b57600080fd5b90955060808a0135908082111561495157600080fd5b61495d8c838d016148a8565b909650945060a08b013591508082111561497657600080fd5b506149838b828c016148a8565b999c989b5096995094979396929594505050565b61ffff9390931683526001600160a01b039190911660208301521515604082015260600190565b634e487b7160e01b600052601160045260246000fd5b6001600160401b038181168382160190808211156149f4576149f46149be565b5092915050565b61ffff8416815282602082015260606040820152815160608201526020820151608082015260006040830151606060a0840152614a3b60c08401826143cf565b9695505050505050565b634e487b7160e01b600052603260045260246000fd5b600060018201614a6d57614a6d6149be565b5060010190565b61ffff84168152826020820152606060408201526000614a9760608301846143cf565b95945050505050565b6001600160a01b0383168152604060208201819052600090614ac4908301846143cf565b949350505050565b81810381811115610894576108946149be565b634e487b7160e01b600052600160045260246000fd5b600060208284031215614b0757600080fd5b81518015158114610c5557600080fd5b600060ff821660ff8103614b2d57614b2d6149be565b60010192915050565b6001600160401b038281168282160390808211156149f4576149f46149be565b60ff81511682526000602082015160406020850152614ac460408501826143cf565b61ffff83168152604060208201526000614ac46040830184614b56565b600060208284031215614ba757600080fd5b5051919050565b80820180821115610894576108946149be565b600060ff821680614bd457614bd46149be565b6000190192915050565b634e487b7160e01b600052603160045260246000fd5b61ffff8616815284602082015260806040820152826080820152828460a0830137600060a08483010152600060a0601f19601f86011683010190508260608301529695505050505050565b60006001600160401b03808316818103614c5b57614c5b6149be565b6001019392505050565b600060208284031215614c7757600080fd5b8151610c5581614440565b63ffffffff60e01b87168152600061ffff60f01b808860f01b166004840152866006840152856026840152808560f01b166046840152508251614ccc8160488501602087016143ab565b91909101604801979650505050505050565b84815283602082015261ffff60f01b8360f01b16604082015260008251614d0c8160428501602087016143ab565b9190910160420195945050505050565b61ffff8616815260a060208201526000614d3960a0830187614b56565b8281036040840152614d4b81876143cf565b60608401959095525050608001529392505050565b61ffff60f01b8360f01b16815260008251614d828160028501602087016143ab565b91909101600201939250505056fe9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00f0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00a264697066735822122073aab26df1c80ff78ff6b64e88465ba3238f92133d0c3571b1aa2dd145b35b3c64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000000000000000000000000000000000000000002712
-----Decoded View---------------
Arg [0] : _chainId (uint16): 10002
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000002712
Loading...
Loading
Loading...
Loading
Loading...
Loading
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.