Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
Latest 1 from a total of 1 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
Value | ||||
---|---|---|---|---|---|---|---|---|---|
0x61016034 | 19583505 | 92 days ago | IN | Create: NttManager | 0 ETH | 0.42952937 |
View more zero value Internal Transactions in Advanced View mode
Advanced mode:
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Name:
NttManager
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 "openzeppelin-contracts/contracts/token/ERC20/IERC20.sol"; import "openzeppelin-contracts/contracts/token/ERC20/utils/SafeERC20.sol"; import "openzeppelin-contracts/contracts/token/ERC20/extensions/ERC20Burnable.sol"; import "wormhole-solidity-sdk/Utils.sol"; import "wormhole-solidity-sdk/libraries/BytesParsing.sol"; import "../libraries/RateLimiter.sol"; import "../interfaces/INttManager.sol"; import "../interfaces/INttToken.sol"; import "../interfaces/ITransceiver.sol"; import {ManagerBase} from "./ManagerBase.sol"; /// @title NttManager /// @author Wormhole Project Contributors. /// @notice The NttManager contract is responsible for managing the token /// and associated transceivers. /// /// @dev Each NttManager contract is associated with a single token but /// can be responsible for multiple transceivers. /// /// @dev When transferring tokens, the NttManager contract will either /// lock the tokens or burn them, depending on the mode. /// /// @dev To initiate a transfer, the user calls the transfer function with: /// - the amount /// - the recipient chain /// - the recipient address /// - the refund address: the address to which refunds are issued for any unused gas /// for attestations on a given transfer. If the gas limit is configured /// to be too high, users will be refunded the difference. /// - (optional) a flag to indicate whether the transfer should be queued /// if the rate limit is exceeded contract NttManager is INttManager, RateLimiter, ManagerBase { using BytesParsing for bytes; using SafeERC20 for IERC20; using TrimmedAmountLib for uint256; using TrimmedAmountLib for TrimmedAmount; string public constant NTT_MANAGER_VERSION = "0.1.0"; // =============== Setup ================================================================= constructor( address _token, Mode _mode, uint16 _chainId, uint64 _rateLimitDuration, bool _skipRateLimiting ) RateLimiter(_rateLimitDuration, _skipRateLimiting) ManagerBase(_token, _mode, _chainId) {} function __NttManager_init() internal onlyInitializing { // check if the owner is the deployer of this contract if (msg.sender != deployer) { revert UnexpectedDeployer(deployer, msg.sender); } __PausedOwnable_init(msg.sender, msg.sender); __ReentrancyGuard_init(); _setOutboundLimit(TrimmedAmountLib.max(tokenDecimals())); } function _initialize() internal virtual override { __NttManager_init(); _checkThresholdInvariants(); _checkTransceiversInvariants(); } // =============== Storage ============================================================== bytes32 private constant PEERS_SLOT = bytes32(uint256(keccak256("ntt.peers")) - 1); // =============== Storage Getters/Setters ============================================== function _getPeersStorage() internal pure returns (mapping(uint16 => NttManagerPeer) storage $) { uint256 slot = uint256(PEERS_SLOT); assembly ("memory-safe") { $.slot := slot } } // =============== Public Getters ======================================================== /// @inheritdoc INttManager function getPeer(uint16 chainId_) external view returns (NttManagerPeer memory) { return _getPeersStorage()[chainId_]; } // =============== Admin ============================================================== /// @inheritdoc INttManager function setPeer( uint16 peerChainId, bytes32 peerContract, uint8 decimals, uint256 inboundLimit ) public onlyOwner { if (peerChainId == 0) { revert InvalidPeerChainIdZero(); } if (peerContract == bytes32(0)) { revert InvalidPeerZeroAddress(); } if (decimals == 0) { revert InvalidPeerDecimals(); } NttManagerPeer memory oldPeer = _getPeersStorage()[peerChainId]; _getPeersStorage()[peerChainId].peerAddress = peerContract; _getPeersStorage()[peerChainId].tokenDecimals = decimals; uint8 toDecimals = tokenDecimals(); _setInboundLimit(inboundLimit.trim(toDecimals, toDecimals), peerChainId); emit PeerUpdated( peerChainId, oldPeer.peerAddress, oldPeer.tokenDecimals, peerContract, decimals ); } /// @inheritdoc INttManager function setOutboundLimit(uint256 limit) external onlyOwner { uint8 toDecimals = tokenDecimals(); _setOutboundLimit(limit.trim(toDecimals, toDecimals)); } /// @inheritdoc INttManager function setInboundLimit(uint256 limit, uint16 chainId_) external onlyOwner { uint8 toDecimals = tokenDecimals(); _setInboundLimit(limit.trim(toDecimals, toDecimals), chainId_); } /// ============== Invariants ============================================= /// @dev When we add new immutables, this function should be updated function _checkImmutables() internal view override { super._checkImmutables(); assert(this.rateLimitDuration() == rateLimitDuration); } // ==================== External Interface =============================================== /// @inheritdoc INttManager function transfer( uint256 amount, uint16 recipientChain, bytes32 recipient ) external payable nonReentrant whenNotPaused returns (uint64) { return _transferEntryPoint(amount, recipientChain, recipient, recipient, false, new bytes(1)); } /// @inheritdoc INttManager function transfer( uint256 amount, uint16 recipientChain, bytes32 recipient, bytes32 refundAddress, bool shouldQueue, bytes memory transceiverInstructions ) external payable nonReentrant whenNotPaused returns (uint64) { return _transferEntryPoint( amount, recipientChain, recipient, refundAddress, shouldQueue, transceiverInstructions ); } /// @inheritdoc INttManager 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 (isMessageApproved(nttManagerMessageHash)) { executeMsg(sourceChainId, sourceNttManagerAddress, payload); } } /// @inheritdoc INttManager function executeMsg( uint16 sourceChainId, bytes32 sourceNttManagerAddress, TransceiverStructs.NttManagerMessage memory message ) public whenNotPaused { // verify chain has not forked checkFork(evmChainId); (bytes32 digest, bool alreadyExecuted) = _isMessageExecuted(sourceChainId, sourceNttManagerAddress, message); if (alreadyExecuted) { return; } TransceiverStructs.NativeTokenTransfer memory nativeTokenTransfer = TransceiverStructs.parseNativeTokenTransfer(message.payload); // verify that the destination chain is valid if (nativeTokenTransfer.toChain != chainId) { revert InvalidTargetChain(nativeTokenTransfer.toChain, chainId); } uint8 toDecimals = tokenDecimals(); TrimmedAmount nativeTransferAmount = (nativeTokenTransfer.amount.untrim(toDecimals)).trim(toDecimals, toDecimals); address transferRecipient = fromWormholeFormat(nativeTokenTransfer.to); { // Check inbound rate limits bool isRateLimited = _isInboundAmountRateLimited(nativeTransferAmount, sourceChainId); if (isRateLimited) { // queue up the transfer _enqueueInboundTransfer(digest, nativeTransferAmount, transferRecipient); // end execution early return; } } // consume the amount for the inbound rate limit _consumeInboundAmount(nativeTransferAmount, sourceChainId); // When receiving a transfer, we refill the outbound rate limit // by the same amount (we call this "backflow") _backfillOutboundAmount(nativeTransferAmount); _mintOrUnlockToRecipient(digest, transferRecipient, nativeTransferAmount, false); } /// @inheritdoc INttManager function completeInboundQueuedTransfer(bytes32 digest) external nonReentrant whenNotPaused { // find the message in the queue InboundQueuedTransfer memory queuedTransfer = getInboundQueuedTransfer(digest); if (queuedTransfer.txTimestamp == 0) { revert InboundQueuedTransferNotFound(digest); } // check that > RATE_LIMIT_DURATION has elapsed if (block.timestamp - queuedTransfer.txTimestamp < rateLimitDuration) { revert InboundQueuedTransferStillQueued(digest, queuedTransfer.txTimestamp); } // remove transfer from the queue delete _getInboundQueueStorage()[digest]; // run it through the mint/unlock logic _mintOrUnlockToRecipient(digest, queuedTransfer.recipient, queuedTransfer.amount, false); } /// @inheritdoc INttManager function completeOutboundQueuedTransfer(uint64 messageSequence) external payable nonReentrant whenNotPaused returns (uint64) { // find the message in the queue OutboundQueuedTransfer memory queuedTransfer = _getOutboundQueueStorage()[messageSequence]; if (queuedTransfer.txTimestamp == 0) { revert OutboundQueuedTransferNotFound(messageSequence); } // check that > RATE_LIMIT_DURATION has elapsed if (block.timestamp - queuedTransfer.txTimestamp < rateLimitDuration) { revert OutboundQueuedTransferStillQueued(messageSequence, queuedTransfer.txTimestamp); } // remove transfer from the queue delete _getOutboundQueueStorage()[messageSequence]; // run it through the transfer logic and skip the rate limit return _transfer( messageSequence, queuedTransfer.amount, queuedTransfer.recipientChain, queuedTransfer.recipient, queuedTransfer.refundAddress, queuedTransfer.sender, queuedTransfer.transceiverInstructions ); } /// @inheritdoc INttManager function cancelOutboundQueuedTransfer(uint64 messageSequence) external nonReentrant whenNotPaused { // find the message in the queue OutboundQueuedTransfer memory queuedTransfer = _getOutboundQueueStorage()[messageSequence]; if (queuedTransfer.txTimestamp == 0) { revert OutboundQueuedTransferNotFound(messageSequence); } // check msg.sender initiated the transfer if (queuedTransfer.sender != msg.sender) { revert CancellerNotSender(msg.sender, queuedTransfer.sender); } // remove transfer from the queue delete _getOutboundQueueStorage()[messageSequence]; // return the queued funds to the sender _mintOrUnlockToRecipient( bytes32(uint256(messageSequence)), msg.sender, queuedTransfer.amount, true ); } // ==================== Internal Business Logic ========================================= function _transferEntryPoint( uint256 amount, uint16 recipientChain, bytes32 recipient, bytes32 refundAddress, bool shouldQueue, bytes memory transceiverInstructions ) internal returns (uint64) { if (amount == 0) { revert ZeroAmount(); } if (recipient == bytes32(0)) { revert InvalidRecipient(); } if (refundAddress == bytes32(0)) { revert InvalidRefundAddress(); } { // Lock/burn tokens before checking rate limits // use transferFrom to pull tokens from the user and lock them // query own token balance before transfer uint256 balanceBefore = _getTokenBalanceOf(token, address(this)); // transfer tokens IERC20(token).safeTransferFrom(msg.sender, address(this), amount); // query own token balance after transfer uint256 balanceAfter = _getTokenBalanceOf(token, address(this)); // correct amount for potential transfer fees amount = balanceAfter - balanceBefore; if (mode == Mode.BURNING) { { // NOTE: We don't account for burn fees in this code path. // We verify that the user's change in balance is equal to the amount that's burned. // Accounting for burn fees can be non-trivial, since there // is no standard way to account for the fee if the fee amount // is taken out of the burn amount. // For example, if there's a fee of 1 which is taken out of the // amount, then burning 20 tokens would result in a transfer of only 19 tokens. // However, the difference in the user's balance would only show 20. // Since there is no standard way to query for burn fee amounts with burnable tokens, // and NTT would be used on a per-token basis, implementing this functionality // is left to integrating projects who may need to account for burn fees on their tokens. ERC20Burnable(token).burn(amount); // tokens held by the contract after the operation should be the same as before uint256 balanceAfterBurn = _getTokenBalanceOf(token, address(this)); if (balanceBefore != balanceAfterBurn) { revert BurnAmountDifferentThanBalanceDiff(balanceBefore, balanceAfterBurn); } } } } // trim amount after burning to ensure transfer amount matches (amount - fee) TrimmedAmount trimmedAmount = _trimTransferAmount(amount, recipientChain); TrimmedAmount internalAmount = trimmedAmount.shift(tokenDecimals()); // get the sequence for this transfer uint64 sequence = _useMessageSequence(); { // now check rate limits bool isAmountRateLimited = _isOutboundAmountRateLimited(internalAmount); if (!shouldQueue && isAmountRateLimited) { revert NotEnoughCapacity(getCurrentOutboundCapacity(), amount); } if (shouldQueue && isAmountRateLimited) { // emit an event to notify the user that the transfer is rate limited emit OutboundTransferRateLimited( msg.sender, sequence, amount, getCurrentOutboundCapacity() ); // queue up and return _enqueueOutboundTransfer( sequence, trimmedAmount, recipientChain, recipient, refundAddress, msg.sender, transceiverInstructions ); // refund price quote back to sender _refundToSender(msg.value); // return the sequence in the queue return sequence; } } // otherwise, consume the outbound amount _consumeOutboundAmount(internalAmount); // When sending a transfer, we refill the inbound rate limit for // that chain by the same amount (we call this "backflow") _backfillInboundAmount(internalAmount, recipientChain); return _transfer( sequence, trimmedAmount, recipientChain, recipient, refundAddress, msg.sender, transceiverInstructions ); } function _transfer( uint64 sequence, TrimmedAmount amount, uint16 recipientChain, bytes32 recipient, bytes32 refundAddress, address sender, bytes memory transceiverInstructions ) internal returns (uint64 msgSequence) { ( address[] memory enabledTransceivers, TransceiverStructs.TransceiverInstruction[] memory instructions, uint256[] memory priceQuotes, uint256 totalPriceQuote ) = _prepareForTransfer(recipientChain, transceiverInstructions); // push it on the stack again to avoid a stack too deep error uint64 seq = sequence; TransceiverStructs.NativeTokenTransfer memory ntt = TransceiverStructs.NativeTokenTransfer( amount, toWormholeFormat(token), recipient, recipientChain ); // construct the NttManagerMessage payload bytes memory encodedNttManagerPayload = TransceiverStructs.encodeNttManagerMessage( TransceiverStructs.NttManagerMessage( bytes32(uint256(seq)), toWormholeFormat(sender), TransceiverStructs.encodeNativeTokenTransfer(ntt) ) ); // push onto the stack again to avoid stack too deep error uint16 destinationChain = recipientChain; // send the message _sendMessageToTransceivers( recipientChain, refundAddress, _getPeersStorage()[destinationChain].peerAddress, priceQuotes, instructions, enabledTransceivers, encodedNttManagerPayload ); // push it on the stack again to avoid a stack too deep error TrimmedAmount amt = amount; emit TransferSent( recipient, refundAddress, amt.untrim(tokenDecimals()), totalPriceQuote, destinationChain, seq ); // return the sequence number return seq; } function _mintOrUnlockToRecipient( bytes32 digest, address recipient, TrimmedAmount amount, bool cancelled ) internal { // calculate proper amount of tokens to unlock/mint to recipient // untrim the amount uint256 untrimmedAmount = amount.untrim(tokenDecimals()); if (cancelled) { emit OutboundTransferCancelled(uint256(digest), recipient, untrimmedAmount); } else { emit TransferRedeemed(digest); } if (mode == Mode.LOCKING) { // unlock tokens to the specified recipient IERC20(token).safeTransfer(recipient, untrimmedAmount); } else if (mode == Mode.BURNING) { // mint tokens to the specified recipient INttToken(token).mint(recipient, untrimmedAmount); } else { revert InvalidMode(uint8(mode)); } } function tokenDecimals() public view override(INttManager, RateLimiter) returns (uint8) { (, bytes memory queriedDecimals) = token.staticcall(abi.encodeWithSignature("decimals()")); return abi.decode(queriedDecimals, (uint8)); } // ==================== Internal Helpers =============================================== /// @dev Verify that the peer address saved for `sourceChainId` matches the `peerAddress`. function _verifyPeer(uint16 sourceChainId, bytes32 peerAddress) internal view { if (_getPeersStorage()[sourceChainId].peerAddress != peerAddress) { revert InvalidPeer(sourceChainId, peerAddress); } } function _trimTransferAmount( uint256 amount, uint16 toChain ) internal view returns (TrimmedAmount) { uint8 toDecimals = _getPeersStorage()[toChain].tokenDecimals; if (toDecimals == 0) { revert InvalidPeerDecimals(); } TrimmedAmount trimmedAmount; { uint8 fromDecimals = tokenDecimals(); trimmedAmount = amount.trim(fromDecimals, toDecimals); // don't deposit dust that can not be bridged due to the decimal shift uint256 newAmount = trimmedAmount.untrim(fromDecimals); if (amount != newAmount) { revert TransferAmountHasDust(amount, amount - newAmount); } } return trimmedAmount; } function _getTokenBalanceOf( address tokenAddr, address accountAddr ) internal view returns (uint256) { (, bytes memory queriedBalance) = tokenAddr.staticcall(abi.encodeWithSelector(IERC20.balanceOf.selector, accountAddr)); return abi.decode(queriedBalance, (uint256)); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/utils/SafeERC20.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; import "../extensions/draft-IERC20Permit.sol"; import "../../../utils/Address.sol"; /** * @title SafeERC20 * @dev Wrappers around ERC20 operations that throw on failure (when the token * contract returns false). Tokens that return no value (and instead revert or * throw on failure) are also supported, non-reverting calls are assumed to be * successful. * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract, * which allows you to call the safe operations as `token.safeTransfer(...)`, etc. */ library SafeERC20 { using Address for address; function safeTransfer( IERC20 token, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value)); } function safeTransferFrom( IERC20 token, address from, address to, uint256 value ) internal { _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value)); } /** * @dev Deprecated. This function has issues similar to the ones found in * {IERC20-approve}, and its usage is discouraged. * * Whenever possible, use {safeIncreaseAllowance} and * {safeDecreaseAllowance} instead. */ function safeApprove( IERC20 token, address spender, uint256 value ) internal { // safeApprove should only be called when setting an initial allowance, // or when resetting it to zero. To increase and decrease it, use // 'safeIncreaseAllowance' and 'safeDecreaseAllowance' require( (value == 0) || (token.allowance(address(this), spender) == 0), "SafeERC20: approve from non-zero to non-zero allowance" ); _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value)); } function safeIncreaseAllowance( IERC20 token, address spender, uint256 value ) internal { uint256 newAllowance = token.allowance(address(this), spender) + value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } function safeDecreaseAllowance( IERC20 token, address spender, uint256 value ) internal { unchecked { uint256 oldAllowance = token.allowance(address(this), spender); require(oldAllowance >= value, "SafeERC20: decreased allowance below zero"); uint256 newAllowance = oldAllowance - value; _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance)); } } function safePermit( IERC20Permit token, address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) internal { uint256 nonceBefore = token.nonces(owner); token.permit(owner, spender, value, deadline, v, r, s); uint256 nonceAfter = token.nonces(owner); require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed"); } /** * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement * on the return value: the return value is optional (but if data is returned, it must not be false). * @param token The token targeted by the call. * @param data The call data (encoded using abi.encode or one of its variants). */ function _callOptionalReturn(IERC20 token, bytes memory data) private { // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that // the target address contains contract code and also asserts for success in the low-level call. bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed"); if (returndata.length > 0) { // Return data is optional require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed"); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (token/ERC20/extensions/ERC20Burnable.sol) pragma solidity ^0.8.0; import "../ERC20.sol"; import "../../../utils/Context.sol"; /** * @dev Extension of {ERC20} that allows token holders to destroy both their own * tokens and those that they have an allowance for, in a way that can be * recognized off-chain (via event analysis). */ abstract contract ERC20Burnable is Context, ERC20 { /** * @dev Destroys `amount` tokens from the caller. * * See {ERC20-_burn}. */ function burn(uint256 amount) public virtual { _burn(_msgSender(), amount); } /** * @dev Destroys `amount` tokens from `account`, deducting from the caller's * allowance. * * See {ERC20-_burn} and {ERC20-allowance}. * * Requirements: * * - the caller must have allowance for ``accounts``'s tokens of at least * `amount`. */ function burnFrom(address account, uint256 amount) public virtual { _spendAllowance(account, _msgSender(), amount); _burn(account, amount); } }
// 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.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) = asUint160(encoded, offset); return (address(ret), nextOffset); } function asAddress( bytes memory encoded, uint offset ) internal pure returns (address ret, uint nextOffset) { (ret, nextOffset) = asAddressUnchecked(encoded, offset); checkBound(nextOffset, encoded.length); } function 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: Apache 2 pragma solidity >=0.8.8 <0.9.0; import "../interfaces/IRateLimiter.sol"; import "../interfaces/IRateLimiterEvents.sol"; import "./TransceiverHelpers.sol"; import "./TransceiverStructs.sol"; import "../libraries/TrimmedAmount.sol"; import "openzeppelin-contracts/contracts/utils/math/SafeCast.sol"; abstract contract RateLimiter is IRateLimiter, IRateLimiterEvents { using TrimmedAmountLib for TrimmedAmount; /// @dev The duration (in seconds) it takes for the limits to fully replenish. uint64 public immutable rateLimitDuration; /// =============== STORAGE =============================================== bytes32 private constant OUTBOUND_LIMIT_PARAMS_SLOT = bytes32(uint256(keccak256("ntt.outboundLimitParams")) - 1); bytes32 private constant OUTBOUND_QUEUE_SLOT = bytes32(uint256(keccak256("ntt.outboundQueue")) - 1); bytes32 private constant INBOUND_LIMIT_PARAMS_SLOT = bytes32(uint256(keccak256("ntt.inboundLimitParams")) - 1); bytes32 private constant INBOUND_QUEUE_SLOT = bytes32(uint256(keccak256("ntt.inboundQueue")) - 1); function _getOutboundLimitParamsStorage() internal pure returns (RateLimitParams storage $) { uint256 slot = uint256(OUTBOUND_LIMIT_PARAMS_SLOT); assembly ("memory-safe") { $.slot := slot } } function _getOutboundQueueStorage() internal pure returns (mapping(uint64 => OutboundQueuedTransfer) storage $) { uint256 slot = uint256(OUTBOUND_QUEUE_SLOT); assembly ("memory-safe") { $.slot := slot } } function _getInboundLimitParamsStorage() internal pure returns (mapping(uint16 => RateLimitParams) storage $) { uint256 slot = uint256(INBOUND_LIMIT_PARAMS_SLOT); assembly ("memory-safe") { $.slot := slot } } function _getInboundQueueStorage() internal pure returns (mapping(bytes32 => InboundQueuedTransfer) storage $) { uint256 slot = uint256(INBOUND_QUEUE_SLOT); assembly ("memory-safe") { $.slot := slot } } constructor(uint64 _rateLimitDuration, bool _skipRateLimiting) { if ( _rateLimitDuration == 0 && !_skipRateLimiting || _rateLimitDuration != 0 && _skipRateLimiting ) { revert UndefinedRateLimiting(); } rateLimitDuration = _rateLimitDuration; } function _setLimit(TrimmedAmount limit, RateLimitParams storage rateLimitParams) internal { TrimmedAmount oldLimit = rateLimitParams.limit; if (oldLimit.isNull()) { rateLimitParams.currentCapacity = limit; } else { TrimmedAmount currentCapacity = _getCurrentCapacity(rateLimitParams); rateLimitParams.currentCapacity = _calculateNewCurrentCapacity(limit, oldLimit, currentCapacity); } rateLimitParams.limit = limit; rateLimitParams.lastTxTimestamp = uint64(block.timestamp); } function _setOutboundLimit(TrimmedAmount limit) internal { _setLimit(limit, _getOutboundLimitParamsStorage()); } function getOutboundLimitParams() public pure returns (RateLimitParams memory) { return _getOutboundLimitParamsStorage(); } function getCurrentOutboundCapacity() public view returns (uint256) { TrimmedAmount trimmedCapacity = _getCurrentCapacity(getOutboundLimitParams()); uint8 decimals = tokenDecimals(); return trimmedCapacity.untrim(decimals); } function getOutboundQueuedTransfer(uint64 queueSequence) public view returns (OutboundQueuedTransfer memory) { return _getOutboundQueueStorage()[queueSequence]; } function _setInboundLimit(TrimmedAmount limit, uint16 chainId_) internal { _setLimit(limit, _getInboundLimitParamsStorage()[chainId_]); } function getInboundLimitParams(uint16 chainId_) public view returns (RateLimitParams memory) { return _getInboundLimitParamsStorage()[chainId_]; } function getCurrentInboundCapacity(uint16 chainId_) public view returns (uint256) { TrimmedAmount trimmedCapacity = _getCurrentCapacity(getInboundLimitParams(chainId_)); uint8 decimals = tokenDecimals(); return trimmedCapacity.untrim(decimals); } function getInboundQueuedTransfer(bytes32 digest) public view returns (InboundQueuedTransfer memory) { return _getInboundQueueStorage()[digest]; } /** * @dev Gets the current capacity for a parameterized rate limits struct */ function _getCurrentCapacity(RateLimitParams memory rateLimitParams) internal view returns (TrimmedAmount capacity) { // If the rate limit duration is 0 then the rate limiter is skipped if (rateLimitDuration == 0) { return packTrimmedAmount(type(uint64).max, rateLimitParams.currentCapacity.getDecimals()); } // The capacity and rate limit are expressed as trimmed amounts, i.e. // 64-bit unsigned integers. The following operations upcast the 64-bit // unsigned integers to 256-bit unsigned integers to avoid overflow. // Specifically, the calculatedCapacity can overflow the u64 max. // For example, if the limit is uint64.max, then the multiplication in calculatedCapacity // will overflow when timePassed is greater than rateLimitDuration. // Operating on uint256 avoids this issue. The overflow is cancelled out by the min operation, // whose second argument is a uint64, so the result can safely be downcast to a uint64. unchecked { uint256 timePassed = block.timestamp - rateLimitParams.lastTxTimestamp; // Multiply (limit * timePassed), then divide by the duration. // Dividing first has terrible numerical stability -- // when rateLimitDuration is close to the limit, there is significant rounding error. // We are safe to multiply first, since these numbers are u64 TrimmedAmount types // and we're performing arithmetic on u256 words. uint256 calculatedCapacity = rateLimitParams.currentCapacity.getAmount() + (rateLimitParams.limit.getAmount() * timePassed) / rateLimitDuration; uint256 result = min(calculatedCapacity, rateLimitParams.limit.getAmount()); return packTrimmedAmount( SafeCast.toUint64(result), rateLimitParams.currentCapacity.getDecimals() ); } } /** * @dev Updates the current capacity * * @param newLimit The new limit * @param oldLimit The old limit * @param currentCapacity The current capacity */ function _calculateNewCurrentCapacity( TrimmedAmount newLimit, TrimmedAmount oldLimit, TrimmedAmount currentCapacity ) internal pure returns (TrimmedAmount newCurrentCapacity) { TrimmedAmount difference; if (oldLimit > newLimit) { difference = oldLimit - newLimit; newCurrentCapacity = currentCapacity > difference ? currentCapacity - difference : packTrimmedAmount(0, currentCapacity.getDecimals()); } else { difference = newLimit - oldLimit; newCurrentCapacity = currentCapacity + difference; } if (newCurrentCapacity > newLimit) { revert CapacityCannotExceedLimit(newCurrentCapacity, newLimit); } } function _consumeOutboundAmount(TrimmedAmount amount) internal { if (rateLimitDuration == 0) return; _consumeRateLimitAmount( amount, _getCurrentCapacity(getOutboundLimitParams()), _getOutboundLimitParamsStorage() ); } function _backfillOutboundAmount(TrimmedAmount amount) internal { if (rateLimitDuration == 0) return; _backfillRateLimitAmount( amount, _getCurrentCapacity(getOutboundLimitParams()), _getOutboundLimitParamsStorage() ); } function _consumeInboundAmount(TrimmedAmount amount, uint16 chainId_) internal { if (rateLimitDuration == 0) return; _consumeRateLimitAmount( amount, _getCurrentCapacity(getInboundLimitParams(chainId_)), _getInboundLimitParamsStorage()[chainId_] ); } function _backfillInboundAmount(TrimmedAmount amount, uint16 chainId_) internal { if (rateLimitDuration == 0) return; _backfillRateLimitAmount( amount, _getCurrentCapacity(getInboundLimitParams(chainId_)), _getInboundLimitParamsStorage()[chainId_] ); } function _consumeRateLimitAmount( TrimmedAmount amount, TrimmedAmount capacity, RateLimitParams storage rateLimitParams ) internal { rateLimitParams.lastTxTimestamp = uint64(block.timestamp); rateLimitParams.currentCapacity = capacity - amount; } /// @dev Refills the capacity by the given amount. /// This is used to replenish the capacity via backflows. function _backfillRateLimitAmount( TrimmedAmount amount, TrimmedAmount capacity, RateLimitParams storage rateLimitParams ) internal { rateLimitParams.lastTxTimestamp = uint64(block.timestamp); rateLimitParams.currentCapacity = capacity.saturatingAdd(amount).min(rateLimitParams.limit); } function _isOutboundAmountRateLimited(TrimmedAmount amount) internal view returns (bool) { return rateLimitDuration != 0 ? _isAmountRateLimited(_getCurrentCapacity(getOutboundLimitParams()), amount) : false; } function _isInboundAmountRateLimited( TrimmedAmount amount, uint16 chainId_ ) internal view returns (bool) { return rateLimitDuration != 0 ? _isAmountRateLimited(_getCurrentCapacity(getInboundLimitParams(chainId_)), amount) : false; } function _isAmountRateLimited( TrimmedAmount capacity, TrimmedAmount amount ) internal pure returns (bool) { return capacity < amount; } function _enqueueOutboundTransfer( uint64 sequence, TrimmedAmount amount, uint16 recipientChain, bytes32 recipient, bytes32 refundAddress, address senderAddress, bytes memory transceiverInstructions ) internal { _getOutboundQueueStorage()[sequence] = OutboundQueuedTransfer({ amount: amount, recipientChain: recipientChain, recipient: recipient, refundAddress: refundAddress, txTimestamp: uint64(block.timestamp), sender: senderAddress, transceiverInstructions: transceiverInstructions }); emit OutboundTransferQueued(sequence); } function _enqueueInboundTransfer( bytes32 digest, TrimmedAmount amount, address recipient ) internal { _getInboundQueueStorage()[digest] = InboundQueuedTransfer({ amount: amount, recipient: recipient, txTimestamp: uint64(block.timestamp) }); emit InboundTransferQueued(digest); } function tokenDecimals() public view virtual returns (uint8); }
// SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; import "../libraries/TrimmedAmount.sol"; import "../libraries/TransceiverStructs.sol"; import "./IManagerBase.sol"; interface INttManager is IManagerBase { /// @dev The peer on another chain. struct NttManagerPeer { bytes32 peerAddress; uint8 tokenDecimals; } /// @notice Emitted when a message is sent from the nttManager. /// @dev Topic0 /// 0x9cc8ade41ef46b98ba8bcad8c6bfa643934e6b84d3ce066cd38b5f0813bb2ae5. /// @param recipient The recipient of the message. /// @param refundAddress The address on the destination chain to which the /// refund of unused gas will be paid /// @param amount The amount transferred. /// @param fee The amount of ether sent along with the tx to cover the delivery fee. /// @param recipientChain The chain ID of the recipient. /// @param msgSequence The unique sequence ID of the message. event TransferSent( bytes32 recipient, bytes32 refundAddress, uint256 amount, uint256 fee, uint16 recipientChain, uint64 msgSequence ); /// @notice Emitted when the peer contract is updated. /// @dev Topic0 /// 0x1456404e7f41f35c3daac941bb50bad417a66275c3040061b4287d787719599d. /// @param chainId_ The chain ID of the peer contract. /// @param oldPeerContract The old peer contract address. /// @param oldPeerDecimals The old peer contract decimals. /// @param peerContract The new peer contract address. /// @param peerDecimals The new peer contract decimals. event PeerUpdated( uint16 indexed chainId_, bytes32 oldPeerContract, uint8 oldPeerDecimals, bytes32 peerContract, uint8 peerDecimals ); /// @notice Emitted when a transfer has been redeemed /// (either minted or unlocked on the recipient chain). /// @dev Topic0 /// 0x504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a91. /// @param digest The digest of the message. event TransferRedeemed(bytes32 indexed digest); /// @notice Emitted when an outbound transfer has been cancelled /// @dev Topic0 /// 0xf80e572ae1b63e2449629b6c7d783add85c36473926f216077f17ee002bcfd07. /// @param sequence The sequence number being cancelled /// @param recipient The canceller and recipient of the funds /// @param amount The amount of the transfer being cancelled event OutboundTransferCancelled(uint256 sequence, address recipient, uint256 amount); /// @notice The transfer has some dust. /// @dev Selector 0x71f0634a /// @dev This is a security measure to prevent users from losing funds. /// This is the result of trimming the amount and then untrimming it. /// @param amount The amount to transfer. error TransferAmountHasDust(uint256 amount, uint256 dust); /// @notice The mode is invalid. It is neither in LOCKING or BURNING mode. /// @dev Selector 0x66001a89 /// @param mode The mode. error InvalidMode(uint8 mode); /// @notice Error when trying to execute a message on an unintended target chain. /// @dev Selector 0x3dcb204a. /// @param targetChain The target chain. /// @param thisChain The current chain. error InvalidTargetChain(uint16 targetChain, uint16 thisChain); /// @notice Error when the transfer amount is zero. /// @dev Selector 0x9993626a. error ZeroAmount(); /// @notice Error when the recipient is invalid. /// @dev Selector 0x9c8d2cd2. error InvalidRecipient(); /// @notice Error when the recipient is invalid. /// @dev Selector 0xe2fe2726. error InvalidRefundAddress(); /// @notice Error when the amount burned is different than the balance difference, /// since NTT does not support burn fees. /// @dev Selector 0x02156a8f. /// @param burnAmount The amount burned. /// @param balanceDiff The balance after burning. error BurnAmountDifferentThanBalanceDiff(uint256 burnAmount, uint256 balanceDiff); /// @notice The caller is not the deployer. error UnexpectedDeployer(address expectedOwner, address owner); /// @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 Peer chain ID cannot be zero. error InvalidPeerChainIdZero(); /// @notice Peer cannot be the zero address. error InvalidPeerZeroAddress(); /// @notice Peer cannot have zero decimals. error InvalidPeerDecimals(); /// @notice Error when someone other than the original sender tries to cancel a queued outbound transfer. /// @dev Selector 0xceb40a85. /// @param canceller The address trying to cancel the transfer. /// @param sender The original sender that initiated the transfer that was queued. error CancellerNotSender(address canceller, address sender); /// @notice Transfer a given amount to a recipient on a given chain. This function is called /// by the user to send the token cross-chain. This function will either lock or burn the /// sender's tokens. Finally, this function will call into registered `Endpoint` contracts /// to send a message with the incrementing sequence number and the token transfer payload. /// @param amount The amount to transfer. /// @param recipientChain The chain ID for the destination. /// @param recipient The recipient address. function transfer( uint256 amount, uint16 recipientChain, bytes32 recipient ) external payable returns (uint64 msgId); /// @notice Transfer a given amount to a recipient on a given chain. This function is called /// by the user to send the token cross-chain. This function will either lock or burn the /// sender's tokens. Finally, this function will call into registered `Endpoint` contracts /// to send a message with the incrementing sequence number and the token transfer payload. /// @dev Transfers are queued if the outbound limit is hit and must be completed by the client. /// @param amount The amount to transfer. /// @param recipientChain The chain ID for the destination. /// @param recipient The recipient address. /// @param refundAddress The address to which a refund for unussed gas is issued on the recipient chain. /// @param shouldQueue Whether the transfer should be queued if the outbound limit is hit. /// @param encodedInstructions Additional instructions to be forwarded to the recipient chain. function transfer( uint256 amount, uint16 recipientChain, bytes32 recipient, bytes32 refundAddress, bool shouldQueue, bytes memory encodedInstructions ) external payable returns (uint64 msgId); /// @notice Complete an outbound transfer that's been queued. /// @dev This method is called by the client to complete an outbound transfer that's been queued. /// @param queueSequence The sequence of the message in the queue. /// @return msgSequence The sequence of the message. function completeOutboundQueuedTransfer(uint64 queueSequence) external payable returns (uint64 msgSequence); /// @notice Cancels an outbound transfer that's been queued. /// @dev This method is called by the client to cancel an outbound transfer that's been queued. /// @param queueSequence The sequence of the message in the queue. function cancelOutboundQueuedTransfer(uint64 queueSequence) external; /// @notice Complete an inbound queued transfer. /// @param digest The digest of the message to complete. function completeInboundQueuedTransfer(bytes32 digest) external; /// @notice Called by an Endpoint 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 chain id of the sender. /// @param sourceNttManagerAddress The address of the sender's nttManager 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. This function will decode the payload /// as an NttManagerMessage to extract the sequence, msgType, and other parameters. /// @dev This function is exposed as a fallback for when an `Transceiver` is deregistered /// when a message is in flight. /// @param sourceChainId The 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 Returns the number of decimals of the token managed by the NttManager. /// @return decimals The number of decimals of the token. function tokenDecimals() external view returns (uint8); /// @notice Returns registered peer contract for a given chain. /// @param chainId_ chain ID. function getPeer(uint16 chainId_) external view returns (NttManagerPeer memory); /// @notice Sets the corresponding peer. /// @dev The nttManager that executes the message sets the source nttManager as the peer. /// @param peerChainId The chain ID of the peer. /// @param peerContract The address of the peer nttManager contract. /// @param decimals The number of decimals of the token on the peer chain. /// @param inboundLimit The inbound rate limit for the peer chain id function setPeer( uint16 peerChainId, bytes32 peerContract, uint8 decimals, uint256 inboundLimit ) external; /// @notice Sets the outbound transfer limit for a given chain. /// @dev This method can only be executed by the `owner`. /// @param limit The new outbound limit. function setOutboundLimit(uint256 limit) external; /// @notice Sets the inbound transfer limit for a given chain. /// @dev This method can only be executed by the `owner`. /// @param limit The new limit. /// @param chainId The chain to set the limit for. function setInboundLimit(uint256 limit, uint16 chainId) external; }
// SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; interface INttToken { /// @notice Error when the caller is not the minter. /// @dev Selector 0x5fb5729e. /// @param caller The caller of the function. error CallerNotMinter(address caller); /// @notice Error when the minter is the zero address. /// @dev Selector 0x04a208c7. error InvalidMinterZeroAddress(); /// @notice Error when insufficient balance to burn the amount. /// @dev Selector 0xcf479181. /// @param balance The balance of the account. /// @param amount The amount to burn. error InsufficientBalance(uint256 balance, uint256 amount); /// @notice The minter has been changed. /// @dev Topic0 /// 0x0b5e7be615a67a819aff3f47c967d1535cead1b98db60fafdcbf22dcaa8fa5a9. /// @param newMinter The new minter. event NewMinter(address previousMinter, address newMinter); // NOTE: the `mint` method is not present in the standard ERC20 interface. function mint(address account, uint256 amount) external; // NOTE: the `setMinter` method is not present in the standard ERC20 interface. function setMinter(address newMinter) external; // NOTE: NttTokens in `burn` mode require the `burn` method to be present. // This method is not present in the standard ERC20 interface, but is // found in the `ERC20Burnable` interface. function burn(uint256 amount) external; }
// 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 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. 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. function upgrade(address newImplementation) external; /// @notice Transfers the ownership of the transceiver to a new address. function transferTransceiverOwnership(address newOwner) external; }
// 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 ============================================================ address public immutable token; address immutable deployer; Mode public immutable mode; uint16 public immutable chainId; uint256 immutable evmChainId; // =============== Setup ================================================================= constructor(address _token, Mode _mode, uint16 _chainId) { token = _token; mode = _mode; chainId = _chainId; evmChainId = block.chainid; // save the deployer (check this on initialization) deployer = msg.sender; } function _migrate() internal virtual override { _checkThresholdInvariants(); _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); bytes32 private constant THRESHOLD_SLOT = bytes32(uint256(keccak256("ntt.threshold")) - 1); // =============== Storage Getters/Setters ============================================== function _getThresholdStorage() private pure returns (_Threshold storage $) { uint256 slot = uint256(THRESHOLD_SLOT); assembly ("memory-safe") { $.slot := slot } } 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 ============================================================= /// @inheritdoc IManagerBase function quoteDeliveryPrice( uint16 recipientChain, bytes memory transceiverInstructions ) public view returns (uint256[] memory, uint256) { address[] memory enabledTransceivers = _getEnabledTransceiversStorage(); TransceiverStructs.TransceiverInstruction[] memory instructions = TransceiverStructs .parseTransceiverInstructions(transceiverInstructions, enabledTransceivers.length); 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 (!isMessageApproved(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 ) { // cache enabled transceivers to avoid multiple storage reads address[] memory enabledTransceivers = _getEnabledTransceiversStorage(); 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 ======================================================== /// @inheritdoc IManagerBase function getMode() public view returns (uint8) { return uint8(mode); } /// @inheritdoc IManagerBase function getThreshold() public view returns (uint8) { return _getThresholdStorage().num; } /// @inheritdoc IManagerBase function isMessageApproved(bytes32 digest) public view returns (bool) { uint8 threshold = getThreshold(); return messageAttestations(digest) >= threshold && threshold > 0; } /// @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)); } // =============== Admin ============================================================== /// @inheritdoc IManagerBase function upgrade(address newImplementation) external onlyOwner { _upgrade(newImplementation); } /// @inheritdoc IManagerBase function pause() public onlyOwnerOrPauser { _pause(); } function unpause() public onlyOwnerOrPauser { _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); _Threshold storage _threshold = _getThresholdStorage(); // We do not automatically increase the threshold here. // Automatically increasing the threshold can result in a scenario // where in-flight messages can't be redeemed. // For example: Assume there is 1 Transceiver and the threshold is 1. // If we were to add a new Transceiver, the threshold would increase to 2. // However, all messages that are either in-flight or that are sent on // a source chain that does not yet have 2 Transceivers will only have been // sent from a single transceiver, so they would never be able to get // redeemed. // Instead, we leave it up to the owner to manually update the threshold // after some period of time, ideally once all chains have the new Transceiver // and transfers that were sent via the old configuration are all complete. // However if the threshold is 0 (the initial case) we do increment to 1. if (_threshold.num == 0) { _threshold.num = 1; } emit TransceiverAdded(transceiver, _getNumTransceiversStorage().enabled, _threshold.num); } /// @inheritdoc IManagerBase function removeTransceiver(address transceiver) external onlyOwner { _removeTransceiver(transceiver); _Threshold storage _threshold = _getThresholdStorage(); uint8 numEnabledTransceivers = _getNumTransceiversStorage().enabled; if (numEnabledTransceivers < _threshold.num) { _threshold.num = numEnabledTransceivers; } emit TransceiverRemoved(transceiver, _threshold.num); } /// @inheritdoc IManagerBase function setThreshold(uint8 threshold) external onlyOwner { if (threshold == 0) { revert ZeroThreshold(); } _Threshold storage _threshold = _getThresholdStorage(); uint8 oldThreshold = _threshold.num; _threshold.num = threshold; _checkThresholdInvariants(); emit ThresholdChanged(oldThreshold, threshold); } // =============== Internal ============================================================== 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; } 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 { assert(this.token() == token); assert(this.mode() == mode); assert(this.chainId() == chainId); } function _checkRegisteredTransceiversInvariants() internal view { if (_getRegisteredTransceiversStorage().length != _getNumTransceiversStorage().registered) { revert RetrievedIncorrectRegisteredTransceivers( _getRegisteredTransceiversStorage().length, _getNumTransceiversStorage().registered ); } } function _checkThresholdInvariants() internal view { uint8 threshold = _getThresholdStorage().num; _NumTransceivers memory numTransceivers = _getNumTransceiversStorage(); // invariant: threshold <= enabledTransceivers.length if (threshold > numTransceivers.enabled) { revert ThresholdTooHigh(threshold, numTransceivers.enabled); } if (numTransceivers.registered > 0) { if (threshold == 0) { revert ZeroThreshold(); } } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol) pragma solidity ^0.8.0; /** * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612]. * * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't * need to send a transaction, and thus is not required to hold Ether at all. */ interface IERC20Permit { /** * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens, * given ``owner``'s signed approval. * * IMPORTANT: The same issues {IERC20-approve} has related to transaction * ordering also apply here. * * Emits an {Approval} event. * * Requirements: * * - `spender` cannot be the zero address. * - `deadline` must be a timestamp in the future. * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner` * over the EIP712-formatted function arguments. * - the signature must use ``owner``'s current nonce (see {nonces}). * * For more information on the signature format, see the * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP * section]. */ function permit( address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s ) external; /** * @dev Returns the current nonce for `owner`. This value must be * included whenever a signature is generated for {permit}. * * Every successful call to {permit} increases ``owner``'s nonce by one. This * prevents a signature from being used multiple times. */ function nonces(address owner) external view returns (uint256); /** * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}. */ // solhint-disable-next-line func-name-mixedcase function DOMAIN_SEPARATOR() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (token/ERC20/ERC20.sol) pragma solidity ^0.8.0; import "./IERC20.sol"; import "./extensions/IERC20Metadata.sol"; import "../../utils/Context.sol"; /** * @dev Implementation of the {IERC20} interface. * * This implementation is agnostic to the way tokens are created. This means * that a supply mechanism has to be added in a derived contract using {_mint}. * For a generic mechanism see {ERC20PresetMinterPauser}. * * TIP: For a detailed writeup see our guide * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How * to implement supply mechanisms]. * * We have followed general OpenZeppelin Contracts guidelines: functions revert * instead returning `false` on failure. This behavior is nonetheless * conventional and does not conflict with the expectations of ERC20 * applications. * * Additionally, an {Approval} event is emitted on calls to {transferFrom}. * This allows applications to reconstruct the allowance for all accounts just * by listening to said events. Other implementations of the EIP may not emit * these events, as it isn't required by the specification. * * Finally, the non-standard {decreaseAllowance} and {increaseAllowance} * functions have been added to mitigate the well-known issues around setting * allowances. See {IERC20-approve}. */ contract ERC20 is Context, IERC20, IERC20Metadata { mapping(address => uint256) private _balances; mapping(address => mapping(address => uint256)) private _allowances; uint256 private _totalSupply; string private _name; string private _symbol; /** * @dev Sets the values for {name} and {symbol}. * * The default value of {decimals} is 18. To select a different value for * {decimals} you should overload it. * * All two of these values are immutable: they can only be set once during * construction. */ constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; } /** * @dev Returns the name of the token. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the symbol of the token, usually a shorter version of the * name. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the number of decimals used to get its user representation. * For example, if `decimals` equals `2`, a balance of `505` tokens should * be displayed to a user as `5.05` (`505 / 10 ** 2`). * * Tokens usually opt for a value of 18, imitating the relationship between * Ether and Wei. This is the value {ERC20} uses, unless this function is * overridden; * * NOTE: This information is only used for _display_ purposes: it in * no way affects any of the arithmetic of the contract, including * {IERC20-balanceOf} and {IERC20-transfer}. */ function decimals() public view virtual override returns (uint8) { return 18; } /** * @dev See {IERC20-totalSupply}. */ function totalSupply() public view virtual override returns (uint256) { return _totalSupply; } /** * @dev See {IERC20-balanceOf}. */ function balanceOf(address account) public view virtual override returns (uint256) { return _balances[account]; } /** * @dev See {IERC20-transfer}. * * Requirements: * * - `to` cannot be the zero address. * - the caller must have a balance of at least `amount`. */ function transfer(address to, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _transfer(owner, to, amount); return true; } /** * @dev See {IERC20-allowance}. */ function allowance(address owner, address spender) public view virtual override returns (uint256) { return _allowances[owner][spender]; } /** * @dev See {IERC20-approve}. * * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on * `transferFrom`. This is semantically equivalent to an infinite approval. * * Requirements: * * - `spender` cannot be the zero address. */ function approve(address spender, uint256 amount) public virtual override returns (bool) { address owner = _msgSender(); _approve(owner, spender, amount); return true; } /** * @dev See {IERC20-transferFrom}. * * Emits an {Approval} event indicating the updated allowance. This is not * required by the EIP. See the note at the beginning of {ERC20}. * * NOTE: Does not update the allowance if the current allowance * is the maximum `uint256`. * * Requirements: * * - `from` and `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. * - the caller must have allowance for ``from``'s tokens of at least * `amount`. */ function transferFrom( address from, address to, uint256 amount ) public virtual override returns (bool) { address spender = _msgSender(); _spendAllowance(from, spender, amount); _transfer(from, to, amount); return true; } /** * @dev Atomically increases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. */ function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) { address owner = _msgSender(); _approve(owner, spender, allowance(owner, spender) + addedValue); return true; } /** * @dev Atomically decreases the allowance granted to `spender` by the caller. * * This is an alternative to {approve} that can be used as a mitigation for * problems described in {IERC20-approve}. * * Emits an {Approval} event indicating the updated allowance. * * Requirements: * * - `spender` cannot be the zero address. * - `spender` must have allowance for the caller of at least * `subtractedValue`. */ function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) { address owner = _msgSender(); uint256 currentAllowance = allowance(owner, spender); require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero"); unchecked { _approve(owner, spender, currentAllowance - subtractedValue); } return true; } /** * @dev Moves `amount` of tokens from `from` to `to`. * * This internal function is equivalent to {transfer}, and can be used to * e.g. implement automatic token fees, slashing mechanisms, etc. * * Emits a {Transfer} event. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `from` must have a balance of at least `amount`. */ function _transfer( address from, address to, uint256 amount ) internal virtual { require(from != address(0), "ERC20: transfer from the zero address"); require(to != address(0), "ERC20: transfer to the zero address"); _beforeTokenTransfer(from, to, amount); uint256 fromBalance = _balances[from]; require(fromBalance >= amount, "ERC20: transfer amount exceeds balance"); unchecked { _balances[from] = fromBalance - amount; // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by // decrementing then incrementing. _balances[to] += amount; } emit Transfer(from, to, amount); _afterTokenTransfer(from, to, amount); } /** @dev Creates `amount` tokens and assigns them to `account`, increasing * the total supply. * * Emits a {Transfer} event with `from` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. */ function _mint(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: mint to the zero address"); _beforeTokenTransfer(address(0), account, amount); _totalSupply += amount; unchecked { // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above. _balances[account] += amount; } emit Transfer(address(0), account, amount); _afterTokenTransfer(address(0), account, amount); } /** * @dev Destroys `amount` tokens from `account`, reducing the * total supply. * * Emits a {Transfer} event with `to` set to the zero address. * * Requirements: * * - `account` cannot be the zero address. * - `account` must have at least `amount` tokens. */ function _burn(address account, uint256 amount) internal virtual { require(account != address(0), "ERC20: burn from the zero address"); _beforeTokenTransfer(account, address(0), amount); uint256 accountBalance = _balances[account]; require(accountBalance >= amount, "ERC20: burn amount exceeds balance"); unchecked { _balances[account] = accountBalance - amount; // Overflow not possible: amount <= accountBalance <= totalSupply. _totalSupply -= amount; } emit Transfer(account, address(0), amount); _afterTokenTransfer(account, address(0), amount); } /** * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens. * * This internal function is equivalent to `approve`, and can be used to * e.g. set automatic allowances for certain subsystems, etc. * * Emits an {Approval} event. * * Requirements: * * - `owner` cannot be the zero address. * - `spender` cannot be the zero address. */ function _approve( address owner, address spender, uint256 amount ) internal virtual { require(owner != address(0), "ERC20: approve from the zero address"); require(spender != address(0), "ERC20: approve to the zero address"); _allowances[owner][spender] = amount; emit Approval(owner, spender, amount); } /** * @dev Updates `owner` s allowance for `spender` based on spent `amount`. * * Does not update the allowance amount in case of infinite allowance. * Revert if not enough allowance is available. * * Might emit an {Approval} event. */ function _spendAllowance( address owner, address spender, uint256 amount ) internal virtual { uint256 currentAllowance = allowance(owner, spender); if (currentAllowance != type(uint256).max) { require(currentAllowance >= amount, "ERC20: insufficient allowance"); unchecked { _approve(owner, spender, currentAllowance - amount); } } } /** * @dev Hook that is called before any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * will be transferred to `to`. * - when `from` is zero, `amount` tokens will be minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens will be burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _beforeTokenTransfer( address from, address to, uint256 amount ) internal virtual {} /** * @dev Hook that is called after any transfer of tokens. This includes * minting and burning. * * Calling conditions: * * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens * has been transferred to `to`. * - when `from` is zero, `amount` tokens have been minted for `to`. * - when `to` is zero, `amount` of ``from``'s tokens have been burned. * - `from` and `to` are never both zero. * * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks]. */ function _afterTokenTransfer( address from, address to, uint256 amount ) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @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 Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
// 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: Apache 2 pragma solidity >=0.8.8 <0.9.0; import "../libraries/TrimmedAmount.sol"; import "../libraries/TransceiverStructs.sol"; interface IRateLimiter { /// @notice Not enough capacity to send the transfer. /// @dev Selector 0x26fb55dd. /// @param currentCapacity The current capacity. /// @param amount The amount of the transfer. error NotEnoughCapacity(uint256 currentCapacity, uint256 amount); /// @notice Outbound transfer is not longer queued. /// @dev Selector 0xbfd5f462. /// @param queueSequence The sequence of the queue. error OutboundQueuedTransferNotFound(uint64 queueSequence); /// @notice Cannot complete the outbound transfer, the transfer is still queued. /// @dev Selector 0xc06cf05f. /// @param queueSequence The sequence of the queue. /// @param transferTimestamp The timestamp of when the transfer was queued. error OutboundQueuedTransferStillQueued(uint64 queueSequence, uint256 transferTimestamp); /// @notice The inbound transfer is not longer queued. /// @dev Selector 0xc06f2bc0. /// @param digest The digest of the transfer. error InboundQueuedTransferNotFound(bytes32 digest); /// @notice The transfer is still queued. /// @dev Selector 0xe5b9ce80. /// @param digest The digest of the transfer. /// @param transferTimestamp The timestamp of the transfer. error InboundQueuedTransferStillQueued(bytes32 digest, uint256 transferTimestamp); /// @notice The new capacity cannot exceed the limit. /// @dev Selector 0x0f85ba52. /// @param newCurrentCapacity The new current capacity. /// @param newLimit The new limit. error CapacityCannotExceedLimit(TrimmedAmount newCurrentCapacity, TrimmedAmount newLimit); /// @notice If the rate limiting behaviour isn't explicitly defined in the constructor. /// @dev Selector 0xe543ef05. error UndefinedRateLimiting(); /// @notice Parameters used in determining rate limits and queuing. /// @dev /// - limit: current rate limit value. /// - currentCapacity: the current capacity left. /// - lastTxTimestamp: the timestamp of when the /// capacity was previously consumption. struct RateLimitParams { TrimmedAmount limit; TrimmedAmount currentCapacity; uint64 lastTxTimestamp; } /// @notice Parameters for an outbound queued transfer. /// @dev /// - recipient: the recipient of the transfer. /// - amount: the amount of the transfer, trimmed. /// - txTimestamp: the timestamp of the transfer. /// - recipientChain: the chain of the recipient. /// - sender: the sender of the transfer. /// - transceiverInstructions: additional instructions to be forwarded to the recipient chain. struct OutboundQueuedTransfer { bytes32 recipient; bytes32 refundAddress; TrimmedAmount amount; uint64 txTimestamp; uint16 recipientChain; address sender; bytes transceiverInstructions; } /// @notice Parameters for an inbound queued transfer. /// @dev /// - amount: the amount of the transfer, trimmed. /// - txTimestamp: the timestamp of the transfer. /// - recipient: the recipient of the transfer. struct InboundQueuedTransfer { TrimmedAmount amount; uint64 txTimestamp; address recipient; } function getCurrentOutboundCapacity() external view returns (uint256); function getOutboundQueuedTransfer(uint64 queueSequence) external view returns (OutboundQueuedTransfer memory); function getCurrentInboundCapacity(uint16 chainId) external view returns (uint256); function getInboundQueuedTransfer(bytes32 digest) external view returns (InboundQueuedTransfer memory); }
// SPDX-License-Identifier: Apache 2 pragma solidity >=0.8.8 <0.9.0; import "../libraries/TrimmedAmount.sol"; interface IRateLimiterEvents { /// @notice Emitted when an inbound transfer is queued /// @dev Topic0 /// 0x7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f3162. /// @param digest The digest of the message. event InboundTransferQueued(bytes32 digest); /// @notice Emitted whenn an outbound transfer is queued. /// @dev Topic0 /// 0x69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f. /// @param queueSequence The location of the transfer in the queue. event OutboundTransferQueued(uint64 queueSequence); /// @notice Emitted when an outbound transfer is rate limited. /// @dev Topic0 /// 0x754d657d1363ee47d967b415652b739bfe96d5729ccf2f26625dcdbc147db68b. /// @param sender The initial sender of the transfer. /// @param amount The amount to be transferred. /// @param currentCapacity The capacity left for transfers within the 24-hour window. event OutboundTransferRateLimited( address indexed sender, uint64 sequence, uint256 amount, uint256 currentCapacity ); }
// 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 "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 ) public pure returns (bytes32) { return keccak256(abi.encodePacked(sourceChainId, encodeNttManagerMessage(m))); } function encodeNttManagerMessage(NttManagerMessage memory m) public 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) public 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 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; } function encodeNativeTokenTransfer(NativeTokenTransfer memory m) public 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; 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) public 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); 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 ) public 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 ) public 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 ) public 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) public 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 ) public 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) public 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) public 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 ) public 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) public pure returns (bytes memory) { return abi.encodePacked( init.transceiverIdentifier, init.nttManagerAddress, init.nttManagerMode, init.tokenAddress, init.tokenDecimals ); } function decodeTransceiverInit(bytes memory encoded) public 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) public pure returns (bytes memory) { return abi.encodePacked( registration.transceiverIdentifier, registration.transceiverChainId, registration.transceiverAddress ); } function decodeTransceiverRegistration(bytes memory encoded) public 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 /// @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); } 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: 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: Apache 2 pragma solidity >=0.8.8 <0.9.0; import "../libraries/TransceiverStructs.sol"; interface IManagerBase { /// @notice The mode is either LOCKING or BURNING. In LOCKING mode, the NttManager locks the /// tokens of the sender and mints an equivalent amount on the target chain. In BURNING /// mode, the NttManager burns the tokens of the sender and mints an equivalent amount /// on the target chain.LOCKING mode preserves the total supply of the tokens. enum Mode { LOCKING, BURNING } /// @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 /// 0xc6289e62021fd0421276d06677862d6b328d9764cdd4490ca5ac78b173f25883. /// @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 /// 0x638e631f34d9501a3ff0295873b29f50d0207b5400bf0e48b9b34719e6b1a39e. /// @param transceiver The address of the transceiver. /// @param threshold The current threshold of transceivers. event TransceiverRemoved(address transceiver, 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 manager doesn't have a peer registered for the destination chain /// @dev Selector 0x3af256bc. /// @param chainId The target chain id error PeerNotRegistered(uint16 chainId); /// @notice Fetch the delivery price for a given recipient chain transfer. /// @param recipientChain The 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 /// to be considered valid. /// @param threshold The new threshold. /// @dev This method can only be executed by the `owner`. function setThreshold(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; /// @notice Checks if a message has been approved. The message should have at least /// the minimum threshold of attestations from distinct endpoints. /// @param digest The digest of the message. /// @return - Boolean indicating if message has been approved. function isMessageApproved(bytes32 digest) external view returns (bool); /// @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 mode (locking or burning) of the NttManager. /// @return mode A uint8 corresponding to the mode function getMode() external view returns (uint8); /// @notice Returns the number of Transceivers that must attest to a msgId for /// it to be considered valid and acted upon. function getThreshold() external view returns (uint8); /// @notice Returns a boolean indicating if the transceiver has attested to the message. function transceiverAttestedToMessage( bytes32 digest, uint8 index ) external view returns (bool); /// @notice Returns the number of attestations for a given message. function messageAttestations(bytes32 digest) external view returns (uint8 count); /// @notice Returns of the address of the token managed by this contract. function token() external view returns (address); /// @notice Returns the chain ID. function chainId() external view returns (uint16); }
// 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 "./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 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; /// @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 { constructor() { _checkTransceiversInvariants(); } /// @dev Information about registered transceivers. struct TransceiverInfo { // whether this transceiver is registered bool registered; // whether this transceiver is enabled bool enabled; 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; } 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); modifier onlyTransceiver() { 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); 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 } } // =============== 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 registered via governance. function getTransceivers() external pure returns (address[] memory result) { result = _getEnabledTransceiversStorage(); } // ============== 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); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol) pragma solidity ^0.8.0; import "../IERC20.sol"; /** * @dev Interface for the optional metadata functions from the ERC20 standard. * * _Available since v4.1._ */ interface IERC20Metadata is IERC20 { /** * @dev Returns the name of the token. */ function name() external view returns (string memory); /** * @dev Returns the symbol of the token. */ function symbol() external view returns (string memory); /** * @dev Returns the decimals places of the token. */ function decimals() external view returns (uint8); }
// 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 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: 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.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/=lib/openzeppelin-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": true, "libraries": { "src/libraries/TransceiverStructs.sol": { "TransceiverStructs": "0x370D05C1F7e88312056bF2df462976219CA0FED4" } } }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_token","type":"address"},{"internalType":"enum IManagerBase.Mode","name":"_mode","type":"uint8"},{"internalType":"uint16","name":"_chainId","type":"uint16"},{"internalType":"uint64","name":"_rateLimitDuration","type":"uint64"},{"internalType":"bool","name":"_skipRateLimiting","type":"bool"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"uint256","name":"burnAmount","type":"uint256"},{"internalType":"uint256","name":"balanceDiff","type":"uint256"}],"name":"BurnAmountDifferentThanBalanceDiff","type":"error"},{"inputs":[{"internalType":"address","name":"caller","type":"address"}],"name":"CallerNotTransceiver","type":"error"},{"inputs":[{"internalType":"address","name":"canceller","type":"address"},{"internalType":"address","name":"sender","type":"address"}],"name":"CancellerNotSender","type":"error"},{"inputs":[{"internalType":"TrimmedAmount","name":"newCurrentCapacity","type":"uint72"},{"internalType":"TrimmedAmount","name":"newLimit","type":"uint72"}],"name":"CapacityCannotExceedLimit","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":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"InboundQueuedTransferNotFound","type":"error"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"},{"internalType":"uint256","name":"transferTimestamp","type":"uint256"}],"name":"InboundQueuedTransferStillQueued","type":"error"},{"inputs":[{"internalType":"uint256","name":"evmChainId","type":"uint256"},{"internalType":"uint256","name":"blockChainId","type":"uint256"}],"name":"InvalidFork","type":"error"},{"inputs":[],"name":"InvalidInitialization","type":"error"},{"inputs":[{"internalType":"uint8","name":"mode","type":"uint8"}],"name":"InvalidMode","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":"InvalidPeerDecimals","type":"error"},{"inputs":[],"name":"InvalidPeerZeroAddress","type":"error"},{"inputs":[],"name":"InvalidRecipient","type":"error"},{"inputs":[],"name":"InvalidRefundAddress","type":"error"},{"inputs":[{"internalType":"uint16","name":"targetChain","type":"uint16"},{"internalType":"uint16","name":"thisChain","type":"uint16"}],"name":"InvalidTargetChain","type":"error"},{"inputs":[],"name":"InvalidTransceiverZeroAddress","type":"error"},{"inputs":[{"internalType":"bytes32","name":"msgHash","type":"bytes32"}],"name":"MessageNotApproved","type":"error"},{"inputs":[],"name":"NoEnabledTransceivers","type":"error"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"NonRegisteredTransceiver","type":"error"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"NotAnEvmAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentCapacity","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"NotEnoughCapacity","type":"error"},{"inputs":[],"name":"NotInitializing","type":"error"},{"inputs":[],"name":"NotMigrating","type":"error"},{"inputs":[{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint8","name":"decimalsOther","type":"uint8"}],"name":"NumberOfDecimalsNotEqual","type":"error"},{"inputs":[],"name":"OnlyDelegateCall","type":"error"},{"inputs":[{"internalType":"uint64","name":"queueSequence","type":"uint64"}],"name":"OutboundQueuedTransferNotFound","type":"error"},{"inputs":[{"internalType":"uint64","name":"queueSequence","type":"uint64"},{"internalType":"uint256","name":"transferTimestamp","type":"uint256"}],"name":"OutboundQueuedTransferStillQueued","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":"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":"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":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"dust","type":"uint256"}],"name":"TransferAmountHasDust","type":"error"},{"inputs":[],"name":"UndefinedRateLimiting","type":"error"},{"inputs":[{"internalType":"address","name":"expectedOwner","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"UnexpectedDeployer","type":"error"},{"inputs":[],"name":"ZeroAmount","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":"bytes32","name":"digest","type":"bytes32"}],"name":"InboundTransferQueued","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":false,"internalType":"bool","name":"notPaused","type":"bool"}],"name":"NotPaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"sequence","type":"uint256"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"OutboundTransferCancelled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"queueSequence","type":"uint64"}],"name":"OutboundTransferQueued","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint64","name":"sequence","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"currentCapacity","type":"uint256"}],"name":"OutboundTransferRateLimited","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":"oldPeerContract","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"oldPeerDecimals","type":"uint8"},{"indexed":false,"internalType":"bytes32","name":"peerContract","type":"bytes32"},{"indexed":false,"internalType":"uint8","name":"peerDecimals","type":"uint8"}],"name":"PeerUpdated","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":"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":"bytes32","name":"digest","type":"bytes32"}],"name":"TransferRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"recipient","type":"bytes32"},{"indexed":false,"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint16","name":"recipientChain","type":"uint16"},{"indexed":false,"internalType":"uint64","name":"msgSequence","type":"uint64"}],"name":"TransferSent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"NTT_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":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"name":"cancelOutboundQueuedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"completeInboundQueuedTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"messageSequence","type":"uint64"}],"name":"completeOutboundQueuedTransfer","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","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":"message","type":"tuple"}],"name":"executeMsg","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"getCurrentInboundCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentOutboundCapacity","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"getInboundLimitParams","outputs":[{"components":[{"internalType":"TrimmedAmount","name":"limit","type":"uint72"},{"internalType":"TrimmedAmount","name":"currentCapacity","type":"uint72"},{"internalType":"uint64","name":"lastTxTimestamp","type":"uint64"}],"internalType":"struct IRateLimiter.RateLimitParams","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"getInboundQueuedTransfer","outputs":[{"components":[{"internalType":"TrimmedAmount","name":"amount","type":"uint72"},{"internalType":"uint64","name":"txTimestamp","type":"uint64"},{"internalType":"address","name":"recipient","type":"address"}],"internalType":"struct IRateLimiter.InboundQueuedTransfer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMigratesImmutables","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getMode","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getOutboundLimitParams","outputs":[{"components":[{"internalType":"TrimmedAmount","name":"limit","type":"uint72"},{"internalType":"TrimmedAmount","name":"currentCapacity","type":"uint72"},{"internalType":"uint64","name":"lastTxTimestamp","type":"uint64"}],"internalType":"struct IRateLimiter.RateLimitParams","name":"","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint64","name":"queueSequence","type":"uint64"}],"name":"getOutboundQueuedTransfer","outputs":[{"components":[{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"TrimmedAmount","name":"amount","type":"uint72"},{"internalType":"uint64","name":"txTimestamp","type":"uint64"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"address","name":"sender","type":"address"},{"internalType":"bytes","name":"transceiverInstructions","type":"bytes"}],"internalType":"struct IRateLimiter.OutboundQueuedTransfer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"getPeer","outputs":[{"components":[{"internalType":"bytes32","name":"peerAddress","type":"bytes32"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"}],"internalType":"struct INttManager.NttManagerPeer","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getThreshold","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransceivers","outputs":[{"internalType":"address[]","name":"result","type":"address[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"digest","type":"bytes32"}],"name":"isMessageApproved","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":[],"name":"migrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mode","outputs":[{"internalType":"enum IManagerBase.Mode","name":"","type":"uint8"}],"stateMutability":"view","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":[],"name":"rateLimitDuration","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"transceiver","type":"address"}],"name":"removeTransceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"},{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"setInboundLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"limit","type":"uint256"}],"name":"setOutboundLimit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"peerChainId","type":"uint16"},{"internalType":"bytes32","name":"peerContract","type":"bytes32"},{"internalType":"uint8","name":"decimals","type":"uint8"},{"internalType":"uint256","name":"inboundLimit","type":"uint256"}],"name":"setPeer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"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":[],"name":"token","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"tokenDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","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":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"}],"name":"transfer","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"bytes32","name":"refundAddress","type":"bytes32"},{"internalType":"bool","name":"shouldQueue","type":"bool"},{"internalType":"bytes","name":"transceiverInstructions","type":"bytes"}],"name":"transfer","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"payable","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
61016034620005a857601f620062e138819003918201601f19168301916001600160401b038311848410176200055b5780849260a094604052833981010312620005a8578051906001600160a01b0382168203620005a8576020810151916002831015620005a85760408201519161ffff83168303620005a8576060810151906001600160401b03821690818303620005a8576080015180159182158203620005a857158092816200059f575b50821562000583575b505062000571576080527f8561949d1c6242cee5c5a5aeb6b9c190ee611d7742fcec65d9e5b1341ea04d8954620001147e758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e15460ff8360081c1614620005ad565b7ffd6568c039679b3b7cc93c26c41d9379b7b1bec1677120493b467688302cb11f5460005b60ff8360081c168110620003ce57505060005b60ff8260081c1681106200033a5750604060ff6200016d92161115620005ad565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1662000328576002600160401b03196001600160401b03821601620002dc575b50503060a05260c0526101009182526101209081526101404681523360e05260405191615cb693846200062b85396080518481816112ee0152818161192e01528181611d7f015281816127c501528181613241015281816137e701528181613e3a015281816152ca015281816153dd0152818161549d015281816155bc0152615684015260a05184614cf1015260c051848181610285015281816104e00152818161052d015281816126b10152818161365701528181613cb8015281816145240152818161494301526149f3015260e05184611a7801525183818161047701528181611df801528181611f3e015281816126ff015281816136d901528181613d3501526148cb0152518281816111960152818161276801526131cb0152518161312d0152f35b6001600160401b0319166001600160401b039081179091556040519081527fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d290602090a13880620001b6565b60405163f92ee8a960e01b8152600490fd5b60018101808211620003b8575b60ff8360081c1681106200036757506200036190620005cb565b6200014c565b620003b290620003ac6200037b84620005db565b90546200038884620005db565b9054600391821b1c6001600160a01b039081169390911b9190911c161415620005ad565b620005cb565b62000347565b634e487b7160e01b600052601160045260246000fd5b620003d981620005db565b9054600382901b81901c6001600160a01b031660009081527f49bca747e973430e858f2f5de357b8dba36ea6d375b81bdb5d53dfaabf0b3a7f602052604090819020905192906001600160401b0360608501908111908511176200055b5760608401604052546200047b60ff821615801592838752602087019360ff808360081c1615928315875260101c16908160408a0152926200053e575b5050620005ad565b60018060401b03600160ff6040870151161b87161615159051151592600092835b60ff8a60081c168110620004ec575b50505082620004e6959492620004cb620003ac95620004d49414620005ad565b151514620005ad565b60ff60408188169201511610620005ad565b62000139565b620004f781620005db565b9054600391821b1c6001600160a01b039081169184901b85901c161462000529576200052390620005cb565b6200049c565b5060019350849150829050620004cb620004ab565b9091508162000551575b50388062000473565b9050153862000548565b634e487b7160e01b600052604160045260246000fd5b60405163e543ef0560e01b8152600490fd5b1591508162000596575b503880620000b5565b9050386200058d565b925038620000ac565b600080fd5b15620005b557565b634e487b7160e01b600052600160045260246000fd5b6000198114620003b85760010190565b7e758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e18054821015620006145760005260206000200190600090565b634e487b7160e01b600052603260045260246000fdfe6080604052600436101561001257600080fd5b6000803560e01c80630271725014612a42578063036de8af146129b75780630677df54146129985780630900f01014612531578063186ce612146124dc57806319017175146124a65780631f97c9a8146122b4578063203e4a9b14611fb657806323d75e3114611f82578063295a521214611f28578063396c16b714611eec5780633b97e85614611ed15780633f4ba83a14611e435780634b4fd03b14611de5578063689f90c314611da357806374aa7bfc14611d5f5780637c91863414611c0a5780638129fc1c146119e75780638413bcba146118cb5780638456cb591461184e57806386e11ffa1461182957806389c619dd146117c95780638da5cb5b146117935780638e3ba8c91461175c5780638fd3ab801461161d5780639057412d146114a0578063961b94d01461144257806397c35146146111ba5780639a8a05921461117b5780639d78245414610f405780639f86029c14610c2f5780639fd0506d14610bf9578063b187bd2614610bcb578063b293f97f14610b35578063b4d591bb14610a74578063c0b07bde14610a2e578063c128d170146109b2578063d788c14714610927578063da4856a1146108f4578063e5a9860314610848578063e75235b81461081a578063f2fde38b146106d5578063f5cfec18146106b2578063f7514fbc146102b4578063fc0c546a1461026f5763fd96063c1461021757600080fd5b3461026c57602036600319011261026c576060610235600435615228565b6040805182516001600160481b031681526020808401516001600160401b031690820152918101516001600160a01b031690820152f35b80fd5b503461026c578060031936011261026c576040517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b503461026c57602036600319011261026c576004356001600160401b03811681036106ae576102e1615a50565b6002600080516020615b21833981519152541461069c576001600160401b038116600052600080516020615c0183398151915260205260406000206040519061032982612b1a565b805482526001810154602083015261ffff60028201546001600160481b03811660408501526001600160401b038160481c16606085015260881c16608083015260018060a01b0360038201541660a083015260405190818560048301549261039084613587565b808452936001811690811561067a5750600114610636575b506103b592500382612ba1565b60c08201526001600160401b03606082015116156106155760a08101516001600160a01b03163381036105e85750606061045860407ff80e572ae1b63e2449629b6c7d783add85c36473926f216077f17ee002bcfd07936001600160401b038616600052600080516020615c01833981519152602052610437826000206135d8565b01516104416149cd565b906001600160401b0360ff82169160081c166158bf565b926001600160401b0360405191168152336020820152836040820152a17f000000000000000000000000000000000000000000000000000000000000000060028110156105d25780610522575060405163a9059cbb60e01b6020820152336024820152604481019190915261050d906104de81606481015b03601f198101835282612ba1565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316614218565b6001600080516020615c218339815191525580f35b600181036105b657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0316803b156105b1576040516340c10f1960e01b815233600482015260248101929092526000908290604490829084905af180156105a557610596575b5061050d565b61059f90612b07565b38610590565b6040513d6000823e3d90fd5b600080fd5b6040516366001a8960e01b815260ff9091166004820152602490fd5b634e487b7160e01b600052602160045260246000fd5b60405163ceb40a8560e01b81523360048201526001600160a01b03919091166024820152604490fd5b0390fd5b604051635feafa3160e11b81526001600160401b0383166004820152602490fd5b60040187525060208620909186915b81831061065e5750509060206103b592820101386103a8565b6020919350806001915483858801015201910190918392610645565b9050602092506103b594915060ff191682840152151560051b820101386103a8565b6040516309e3d0f360e11b8152600490fd5b5080fd5b503461026c578060031936011261026c5760206106cd615211565b604051908152f35b503461026c57602036600319011261026c576001600160a01b03600435818116908181036107e55761071690610709615a17565b610711615a17565b6159a3565b7f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed97891825460ff600080516020615ba183398151915254168082036107fc575050908391825b84548110156107f8578460005281817f357eda4c1707ce60b55a439f3dc12fcacea5ca0fd863e2fc179a916cf05fccd1015416803b156107f457848091602460405180948193632c7b84dd60e11b83528960048401525af19081156107e95785916107d1575b50506107cc90612de1565b61075b565b6107da90612b07565b6107e55783386107c1565b8380fd5b6040513d87823e3d90fd5b8480fd5b8380f35b604492506040519163d2a13a2960e01b835260048301526024820152fd5b503461026c578060031936011261026c57602060ff600080516020615aa18339815191525416604051908152f35b503461026c57602036600319011261026c5760043560ff8116908181036105b157610871615a17565b81156108e2577f2a855b929b9a53c6fb5b5ed248b27e502b709c088e036a5aa17620c8fc5085a9916108dc60ff92600080516020615aa1833981519152805493851985161790556108c0613060565b6040805160ff9490951684168552921660208401528291820190565b0390a180f35b60405163831761d760e01b8152600490fd5b503461026c5761090336612c24565b906002600080516020615b21833981519152541461069c5761092492613129565b80f35b503461026c57602036600319011261026c5761ffff610944612a9d565b61094c6151f2565b5016600052600080516020615bc18339815191526020526109ae6109736040600020614dcd565b6040519182918291909160406001600160401b038160608401956001600160481b038082511686526020820151166020860152015116910152565b0390f35b503461026c57602036600319011261026c5761ffff906109d0612a9d565b9060206040516109df81612b50565b828152015216600052600080516020615a8183398151915260205260408060002060ff8251610a0d81612b50565b60208260018554958685520154169101908152835192835251166020820152f35b503461026c578060031936011261026c576109ae604051610a4e81612b50565b60058152640302e312e360dc1b6020820152604051918291602083526020830190612ae2565b503461026c578060031936011261026c576040518091600080516020615b6183398151915290815480845260208094019081938352600080516020615ac183398151915290835b818110610b185750505084610ad1910385612ba1565b60405193838594850191818652518092526040850193925b828110610af857505050500390f35b83516001600160a01b031685528695509381019392810192600101610ae9565b82546001600160a01b031684529286019260019283019201610abb565b5060c036600319011261026c57610b4a612aae565b906084359182151583036106ae5760a4356001600160401b039283821161026c5750610b7a903690600401612bdd565b610b82615a50565b6002600080516020615b21833981519152541461069c57602093610bb0926064359060443590600435613c9c565b6001600080516020615c218339815191525560405191168152f35b503461026c578060031936011261026c5760206002600080516020615b218339815191525414604051908152f35b503461026c578060031936011261026c57600080516020615c41833981519152546040516001600160a01b039091168152602090f35b503461026c576020806003193601126106ae576001600160a01b039060043582811691908281036107f457610c62615a17565b8215610f2e5782600052600080516020615be183398151915280835260ff91826040600020541615610f1557846000528184528260406000205460081c1615610efc5784600052818452604060002061ff001990818154169055600080516020615ba1833981519152928354858160081c16928315610ee85761ff0060001980950160081b169116178455600080516020615b418339815191528054918860005287526001600160401b03600192610d2f82858a60406000205460101c161b198316169282168310614a9f565b6001600160401b0319161790558897600080516020615b618339815191528054938b5b858110610de2575b505050505050918091610da26040969594610d957f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f99614a9f565b610d9d614abc565b614ba7565b5460081c16600080516020615aa18339815191529081548381168210610dd4575b50505416908351928352820152a180f35b60ff19161781553880610dc3565b838b610ded8361302f565b929054600393841b1c1614610e0b5750610e0690612de1565b610d52565b9590918093959798999a9b9c508101908111610ed45790610e3f84610e32610e5e9461302f565b905490891b1c169161302f565b90919082549060031b9160018060a01b03809116831b921b1916179055565b82548015610ec057946040999794610da2948a9894610d95947f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f9e9c990192610ea68461302f565b81939154921b1b1916905555998496979899839650610d5a565b634e487b7160e01b8c52603160045260248cfd5b634e487b7160e01b8d52601160045260248dfd5b634e487b7160e01b8b52601160045260248bfd5b6040516307d86e9160e21b815260048101869052602490fd5b604051630d583f4760e41b815260048101869052602490fd5b604051632f44bd7760e01b8152600490fd5b503461026c57610f4f36612c24565b9033600052600080516020615be183398151915260209080825260ff60406000205460081c161561116357600080516020615b2183398151915291600283541461069c5761ffff861680600052600080516020615a8183398151915282528460406000205403611145575060405163b3f07bbd60e01b815291818380610fd9898b600484016130ff565b038173370d05c1f7e88312056bf2df462976219ca0fed45af492831561113a57889361110b575b503360005280825261101d60ff60406000205460101c1684612ff9565b6110f25760606110d193927f35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e592336000528082528a6001600160401b03610100600160481b03604082600160ff836000205460101c161b1693898152600080516020615ae1833981519152875220928354928360081c161760081b1690610100600160481b03191617905533600052815260ff60406000205460101c166040519185835233908301526040820152a1612f8c565b6110d9578480f35b5460021461069c576110ea92613129565b388080808480f35b604051631089c4a160e11b815260048101849052602490fd5b9092508181813d8311611133575b6111238183612ba1565b810103126105b157519138611000565b503d611119565b6040513d8a823e3d90fd5b6044908560405191635788c0fd60e11b835260048301526024820152fd5b60405163a0ae911d60e01b8152336004820152602490fd5b503461026c578060031936011261026c57602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000000168152f35b50602036600319011261026c576001600160401b036004351690816004350361026c576111e5615a50565b6002600080516020615b21833981519152541461069c5781600052600080516020615c018339815191526020526040600020916040519261122584612b1a565b805484526001810154602085015261ffff60028201546001600160481b03811660408701526001600160401b038160481c16606087015260881c16608085015260018060a01b0360038201541660a08501526040518381949060048401549361128d85613587565b808552946001811690811561141e57506001146113d9575b50506112b392500383612ba1565b60c083019182526001600160401b03606084015116156113c1576112e46001600160401b0360608501511642612f7f565b6001600160401b037f00000000000000000000000000000000000000000000000000000000000000001611611396579161137391602093600052600080516020615c01833981519152845261133c60406000206135d8565b6001600160481b036040830151169161ffff608082015116815190868301519260a0600180821b0391015116935194600435614412565b6001600080516020615c21833981519152556001600160401b0360405191168152f35b6044906001600160401b036060850151166040519163c06cf05f60e01b835260048301526024820152fd5b60249060405190635feafa3160e11b82526004820152fd5b60049193949250018252602082205b8183106114025750509060206112b39282010138806112a5565b60209193508060019154838589010152019101909184926113e8565b915050602092506112b394915060ff191682840152151560051b82010138806112a5565b50606036600319011261026c57611457612aae565b604435611462615a50565b6002600080516020615b21833981519152541461069c5760209181611373926040519261148e84612b50565b6001845285368186013760043561363a565b503461026c57604036600319011261026c576114ba612a9d565b6024356001600160401b038111611619576114d9903690600401612bdd565b91604051918290600080516020615b61833981519152828154918287526020809701908652600080516020615ac183398151915292865b888282106115fa5750505061152792500383612ba1565b826115518351966040519788928392635b10743960e11b8452604060048501526044840190612ae2565b906024830152038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156115ef5783949561158a94926115cb575b50612e24565b604051926040840160408552835180915285606086019401915b8181106115b75750505082938301520390f35b8251855293860193918601916001016115a4565b6115e89192503d8087833e6115e08183612ba1565b810190612d0f565b9038611584565b6040513d85823e3d90fd5b85546001600160a01b0316845260019586019588955093019201611510565b8280fd5b503461026c578060031936011261026c57611636614cee565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0080546001600160401b038082169060018201918183116117465760ff8460401c16908115611739575b5061172757600160401b911680926001600160481b03191617179081835560ff7f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4e541615611715577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2926020926116f5613060565b6116fd614abc565b68ff000000000000000019169055604051908152a180f35b604051632866815360e11b8152600490fd5b60405163f92ee8a960e01b8152600490fd5b9050818316111538611680565b634e487b7160e01b600052601160045260246000fd5b503461026c57604036600319011261026c5760243560ff811681036105b157611789602091600435612ff9565b6040519015158152f35b503461026c578060031936011261026c57600080516020615b01833981519152546040516001600160a01b039091168152602090f35b503461026c57602036600319011261026c5761181e6001600160401b036020926040600080516020615b4183398151915254916004358152600080516020615ae18339815191528652205460081c16166157e1565b60ff60405191168152f35b503461026c578060031936011261026c576118426151f2565b506109ae610973614d85565b503461026c578060031936011261026c57600080516020615b0183398151915254611881906001600160a01b0316614d32565b600080516020615b21833981519152600281541461069c57600290557f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2602060405160018152a180f35b503461026c57602036600319011261026c576004356118e8615a50565b6002600080516020615b21833981519152541461069c5761190881615228565b602081016001600160401b039081815116156119ce5761192b8282511642612f7f565b827f000000000000000000000000000000000000000000000000000000000000000016116119ac578385527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b860205260408086208681556001018690558301518351869161050d916001600160481b0316906001600160a01b031687614893565b516040516301cb739d60e71b8152600481019490945216602483015250604490fd5b604051630301bcaf60e61b815260048101859052602490fd5b503461026c578060031936011261026c57611a00614cee565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1615906001600160401b03811680159081611c02575b6001149081611bf8575b159081611bef575b506117275767ffffffffffffffff198116600117835581611bd0575b50611a76615962565b7f00000000000000000000000000000000000000000000000000000000000000006001600160a01b0381163303611ba75750611ab0615962565b611ab8615962565b611ac0615962565b6001600080516020615b2183398151915255600080516020615c4183398151915280546001600160a01b03191633179055611af9615962565b611b01615962565b611b0a336159a3565b611b12615962565b611b1a615962565b6001600080516020615c2183398151915255611b51610100600160481b0360ff611b4a611b456149cd565b615888565b1617614e2d565b611b59613060565b611b61614abc565b611b69575080f35b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b604051636345072160e11b81526001600160a01b03919091166004820152336024820152604490fd5b68ffffffffffffffffff19166801000000000000000117825538611a6d565b90501538611a51565b303b159150611a49565b839150611a3f565b503461026c57608036600319011261026c57611c24612a9d565b6024356044359160ff83168093036105b15761ffff90611c42615a17565b16918215611d4d578115611d3b578015611d29577f1456404e7f41f35c3daac941bb50bad417a66275c3040061b4287d787719599d9160809184600052600080516020615a81833981519152918260205260ff604060002081600160405192611caa84612b50565b805484520154169460208201958652886000526020526001604060002084815501848319825416179055611d0c611ceb611ce26149cd565b8060643561591a565b89600052600080516020615bc183398151915260205260406000209061502b565b51935116604051938452602084015260408301526060820152a280f35b60405163ade64f0b60e01b8152600490fd5b60405163f839a0cb60e01b8152600490fd5b60405163100b0f2760e11b8152600490fd5b503461026c578060031936011261026c5760206040516001600160401b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461026c578060031936011261026c57602060ff7f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cb54166040519015158152f35b503461026c578060031936011261026c577f0000000000000000000000000000000000000000000000000000000000000000906002821015611e2f5760208260ff60405191168152f35b634e487b7160e01b81526021600452602490fd5b503461026c578060031936011261026c57600080516020615b0183398151915254611e76906001600160a01b0316614d32565b600080516020615b218339815191526002815403611ebf57600190557fe11c2112add17fb763d3bd59f63b10429c3e11373da4fb8ef6725107a2fdc4b06020604051838152a180f35b604051637e38d1d360e11b8152600490fd5b503461026c578060031936011261026c57602061181e6149cd565b503461026c57602036600319011261026c5760ff60406020926004358152600080516020615ae183398151915284522054166040519015158152f35b503461026c578060031936011261026c576040517f00000000000000000000000000000000000000000000000000000000000000006002811015611f6e57602092508152f35b634e487b7160e01b83526021600452602483fd5b503461026c578060031936011261026c5760206001600160401b03600080516020615b818339815191525416604051908152f35b503461026c576020806003193601126106ae576004356001600160a01b038116918282036107e557611fe6615a17565b8215610f2e5782600052600080516020615be18339815191529182825260ff90816040600020541660001461218a5784600052838352604060002061010061ff00198254161790555b600080516020615b6183398151915290815491600160401b8310156121745782610e3f9160016120619501905561302f565b600080516020615ba183398151915292835461ff00612084848360081c16614a8e565b60081b169061ff00191617809455600080516020615b4183398151915280546001600160401b0390818116918860005284875260018660406000205460101c161b16821791821461215b5767ffffffffffffffff19161790557ff05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda594606094909390929091612110614abc565b84600052825280600080516020615aa183398151915280548281161561214c575b5054169260405194855260081c16908301526040820152a180f35b60ff1916600117815538612131565b604051638d68f84d60e01b815260048101899052602490fd5b634e487b7160e01b600052604160045260246000fd5b600080516020615ba18339815191528281541660408110156122a257604051906121b382612b35565b6001825285820190600182526040830190815288600052878752604060002092511515918662ff000061ff0086549351151560081b16935160101b1693169062ffffff1916171717905580548361220b818316614a8e565b169060ff19161790557f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed978805490600160401b821015612174576001820180825582101561228c576000527f357eda4c1707ce60b55a439f3dc12fcacea5ca0fd863e2fc179a916cf05fccd10180546001600160a01b0319168617905561202f565b634e487b7160e01b600052603260045260246000fd5b60405163891684c360e01b8152600490fd5b503461026c57602036600319011261026c576004356001600160401b0381168091036106ae57606060c06040516122ea81612b1a565b84815284602082015284604082015284838201528460808201528460a08201520152600052600080516020615c0183398151915260205260406000206040519061233382612b1a565b805482526001810154602083015261ffff60028201546001600160481b03811660408501526001600160401b038160481c16606085015260881c16608083015260018060a01b0360038201541660a08301526040518381949060048401549361239b85613587565b8085529460018116908115612482575060011461243d575b50506123c192500383612ba1565b60c081019182526109ae6040519283926020845280516020850152602081015160408501526001600160481b0360408201511660608501526001600160401b03606082015116608085015261ffff60808201511660a085015260a0600180821b039101511660c08401525160e080840152610100830190612ae2565b60049193949250018252602082205b8183106124665750509060206123c19282010138806123b3565b602091935080600191548385890101520191019091849261244c565b915050602092506123c194915060ff191682840152151560051b82010138806123b3565b503461026c57602036600319011261026c576124c0615a17565b6109246124d76124ce6149cd565b8060043561591a565b614e2d565b503461026c57604036600319011261026c576109246124f9612aae565b612501615a17565b61ffff61250f6124ce6149cd565b9116600052600080516020615bc183398151915260205260406000209061502b565b503461026c576020806003193601126106ae576001600160a01b03600435818116908181036107f457612562615a17565b61256a614cee565b3b1561293d577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a27f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4e918254916125f760ff841615614a9f565b60ff199283166001178455303b156107f45760405163011fa75760e71b8152858160048183305af180156128f25761292a575b5060405163689f90c360e01b81528281600481305afa9081156128f25786916128fd575b5015612686575b50507f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cb818154169055815416905580f35b604051637e062a3560e11b81528281600481305afa9081156128f25786916128b4575b50816126d9927f000000000000000000000000000000000000000000000000000000000000000016911614614a9f565b6040516314ad290960e11b81528181600481305afa9081156107e957859161287e575b507f000000000000000000000000000000000000000000000000000000000000000090600282101561286a57600281101561286a5761273b9114614a9f565b604051634d4502c960e11b81528181600481305afa80156107e9578590612834575b612790915061ffff807f000000000000000000000000000000000000000000000000000000000000000016911614614a9f565b604051631d2a9eff60e21b8152908082600481305afa9081156107e95785916127f4575b506127ed91506001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016911614614a9f565b3880612655565b905081813d831161282d575b61280a8183612ba1565b810103126107e557516001600160401b03811681036107e5576127ed90386127b4565b503d612800565b508181813d8311612863575b61284a8183612ba1565b810103126107f45761285e6127909161311a565b61275d565b503d612840565b634e487b7160e01b86526021600452602486fd5b90508181813d83116128ad575b6128958183612ba1565b810103126107f4575160028110156107f457386126fc565b503d61288b565b90508281813d83116128eb575b6128cb8183612ba1565b810103126128e757519080821682036128e757906126d96126a9565b8580fd5b503d6128c1565b6040513d88823e3d90fd5b61291d9150833d8511612923575b6129158183612ba1565b810190614200565b3861264e565b503d61290b565b61293690959195612b07565b933861262a565b60405162461bcd60e51b815260048101849052602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b503461026c57602036600319011261026c576020611789600435612f8c565b503461026c57602036600319011261026c576004356001600160a01b0381811691829003611619576129f981600080516020615b018339815191525416614d32565b600080516020615c4183398151915280546001600160a01b031981168417909155167f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef68380a380f35b503461026c57602036600319011261026c576106cd612a95612a90604060209461ffff612a6d612a9d565b612a756151f2565b50168152600080516020615bc1833981519152865220614dcd565b6152be565b6104416149cd565b6004359061ffff821682036105b157565b6024359061ffff821682036105b157565b60005b838110612ad25750506000910152565b8181015183820152602001612ac2565b90602091612afb81518092818552858086019101612abf565b601f01601f1916010190565b6001600160401b03811161217457604052565b60e081019081106001600160401b0382111761217457604052565b606081019081106001600160401b0382111761217457604052565b604081019081106001600160401b0382111761217457604052565b608081019081106001600160401b0382111761217457604052565b60a081019081106001600160401b0382111761217457604052565b90601f801991011681019081106001600160401b0382111761217457604052565b6001600160401b03811161217457601f01601f191660200190565b81601f820112156105b157803590612bf482612bc2565b92612c026040519485612ba1565b828452602083830101116105b157816000926020809301838601378301015290565b90600319906060828401126105b15760043561ffff811681036105b1579260243592604435916001600160401b03918284116105b15760609084830301126105b15760405192612c7384612b35565b806004013584526024810135602085015260448101359283116105b157612c9d9201600401612bdd565b604082015290565b6001600160401b0381116121745760051b60200190565b519060ff821682036105b157565b81601f820112156105b1578051612ce081612bc2565b92612cee6040519485612ba1565b818452602082840101116105b157612d0c9160208085019101612abf565b90565b9060209081838203126105b15782516001600160401b03938482116105b157019080601f830112156105b1578151612d4681612ca5565b94604090612d5682519788612ba1565b828752858088019360051b860101948486116105b157868101935b868510612d8357505050505050505090565b84518381116105b15782019084601f1983890301126105b157845190612da882612b50565b612db38a8401612cbc565b825285830151918583116105b157612dd2898c80969581960101612cca565b83820152815201940193612d71565b60001981146117465760010190565b805182101561228c5760209160051b010190565b9060406020612d0c9360ff81511684520151918160208201520190612ae2565b909291805191612e3383612ca5565b92604091612e4383519586612ba1565b818552601f19612e5283612ca5565b01602090368288013760009788955b848710612e7357505050505050509190565b909192939495988685612eec868d612e9260018060a01b039188612df0565b511680600052600080516020615be18339815191528252612ebd60ff866000205460101c1689612df0565b51908551808095819463b5634c7360e01b835261ffff60049916898401526024998a8401526044830190612e04565b03915afa908115612f7457908d91600091612f42575b50612f0e81928d612df0565b528301809311612f2f575050612f249099612de1565b959493929190612e61565b601190634e487b7160e01b600052526000fd5b91508782813d8311612f6d575b612f598183612ba1565b8101031261026c5750518c90612f0e612f02565b503d612f4f565b8a513d6000823e3d90fd5b9190820391821161174657565b6001600160401b039060ff612fe581600080516020615aa18339815191525416938493600080516020615b418339815191525490600052600080516020615ae183398151915260205260406000205460081c16166157e1565b1610159081612ff2575090565b9050151590565b906001600160401b0391600052600080516020615ae1833981519152602052600160ff60406000205460081c92161b1616151590565b600080516020615b61833981519152805482101561228c57600052600080516020615ac18339815191520190600090565b60ff600080516020615aa1833981519152541660405161307f81612b50565b60ff600080516020615ba183398151915254818116835260081c168060208301528083116130ba57505160ff166130b35750565b156108e257565b82604491604051916313c3d1b160e01b835260048301526024820152fd5b9060606040612d0c9380518452602081015160208501520151918160408201520190612ae2565b60409061ffff612d0c949316815281602082015201906130d8565b519061ffff821682036105b157565b91907f000000000000000000000000000000000000000000000000000000000000000046810361344957508161315f9184613467565b9190916134445760408091015191815192635399ded560e11b8452608084806131946020948560048401526024830190612ae2565b038173370d05c1f7e88312056bf2df462976219ca0fed45af4938415613439576000946133c4575b5061ffff9283606086015116847f0000000000000000000000000000000000000000000000000000000000000000168082036133a95750506131fc6149cd565b8161322587519280613220816001600160401b03968760ff82169160081c166158bf565b61591a565b960151908160a01c613392576001600160a01b039182169560007f000000000000000000000000000000000000000000000000000000000000000083161561338b57506132706151f2565b508816600052600080516020615bc18339815191528452613296612a9084600020614dcd565b6132a08882615853565b81808960081c169160081c16105b6132d357505050506132c36132d194846155b1565b6132cc83615491565b614893565b565b7f7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f316297509561336f839596949760019394519261330e84612b35565b6001600160481b038091168452898401908242168252888501978852896000527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b88b52886000209451166001600160481b03198554161784555116826157a0565b019151166001600160601b0360a01b82541617905551908152a1565b90506132ae565b50602491519063033b960d60e41b82526004820152fd5b6044925191631ee5902560e11b835260048301526024820152fd5b6080949194813d8211613431575b816133df60809383612ba1565b810103126106ae578351916133f383612b6b565b8151906001600160481b038216820361026c57508252848101518583015283810151848301526134259060600161311a565b606082015292386131bc565b3d91506133d2565b83513d6000823e3d90fd5b505050565b604490604051906377d879fb60e01b82526004820152466024820152fd5b60405163b3f07bbd60e01b81529193926020918391829161348c9190600484016130ff565b038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156105a55760009161351d575b506134be81612f8c565b15613505576134cc8161354e565b92836134da57509150600090565b7f4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2600080a360009190565b60249060405190630451c4fb60e41b82526004820152fd5b906020823d8211613546575b8161353660209383612ba1565b8101031261026c575051386134b4565b3d9150613529565b600052600080516020615ae18339815191526020526040600020805460ff81166135805760ff19166001179055600090565b5050600190565b90600182811c921680156135b7575b60208310146135a157565b634e487b7160e01b600052602260045260246000fd5b91607f1691613596565b8181106135cc575050565b600081556001016135c1565b6004600091828155826001820155826002820155826003820155016135fd8154613587565b8061360757505050565b82601f821160011461361857505055565b9091808252613636601f60208420940160051c8401600185016135c1565b5555565b9194939290946000958315613c8a578115613c78578215613c66577f00000000000000000000000000000000000000000000000000000000000000006136803082614a36565b906136c360018060a01b03821696604051906323b872dd60e01b60208301523360248301523060448301526064820152606481526136bd81612b86565b87614218565b6136d6826136d13084614a36565b612f7f565b957f00000000000000000000000000000000000000000000000000000000000000006002811015613c52579060018b9214613bcb575b5050505061ffff8116600052600080516020615a8183398151915260205260ff600160406000200154168015611d295761374f6137476149cd565b91828761591a565b906001600160401b038260081c1661376c60ff84169283836158bf565b808803613ba4575061378e61379391613786611b456149cd565b9384916158bf565b615369565b98600080516020615b8183398151915254966001600160401b0380891614613b905767ffffffffffffffff1988166001600160401b03898116600101811691909117600080516020615b81833981519152557f00000000000000000000000000000000000000000000000000000000000000001615613b8a576138146151f2565b50613820612a90614d85565b61383d8c610100600160481b0360ff87169160081b161782615853565b6001600160401b03808d610100600160481b0360ff88169160081b161760081c169160081c16105b613b64578180613b5c575b6138b957505082612d0c9899610100600160481b0360ff8461389d826138a99716848660081b16176153d1565b169160081b1617615679565b6001600160401b03339516614412565b61ffff95979896919a506001600160481b039392506138d6615211565b604051916001600160401b038b168352602083015260408201527ff33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a60603392a26040519661392388612b1a565b875260208701521660408501526001600160401b03421660608501521660808301523360a083015260c08201526001600160401b038216600052600080516020615c0183398151915260205260c0600460406000208351815560208401516001820155600281016001600160481b036040860151166001600160481b03198254161781556139be6001600160401b03606087015116826157a0565b608085015181549061ffff60881b9060881b169061ffff60881b19161790556003810160018060a01b0360a0860151166001600160601b0360a01b82541617905501910151938451906001600160401b038211613b4857613a1f8354613587565b601f8111613b0d575b50602090601f8311600114613aa157906001600160401b03959683613a96575b50508160011b916000199060031b1c19161790555b7f69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f60206040518484168152a1613a92346143bb565b1690565b015190503880613a48565b95601f19831684885260208820975b818110613af55750916001600160401b03969791846001959410613adc575b505050811b019055613a5d565b015160001960f88460031b161c19169055388080613acf565b83830151895560019098019760209384019301613ab0565b613b389084835260208320601f850160051c81019160208610613b3e575b601f0160051c01906135c1565b38613a28565b9091508190613b2b565b634e487b7160e01b81526041600452602490fd5b506000613870565b604490613b6f615211565b90604051916326fb55dd60e01b835260048301526024820152fd5b81613865565b634e487b7160e01b82526011600452602482fd5b87613bb160449282612f7f565b604051916338f831a560e11b835260048301526024820152fd5b803b156106ae578190602460405180948193630852cd8d60e31b83528c60048401525af18015613c4757613c32575b50613c06903090614a36565b808203613c1457888161370c565b60449250604051916302156a8f60e01b835260048301526024820152fd5b98613c40613c06929a612b07565b9890613bfa565b6040513d8c823e3d90fd5b634e487b7160e01b8b52602160045260248bfd5b60405163717f139360e11b8152600490fd5b604051634e46966960e11b8152600490fd5b604051631f2a200560e01b8152600490fd5b95949392919060008715613c8a578215613c78578315613c66577f0000000000000000000000000000000000000000000000000000000000000000613ce13082614a36565b90613d2460018060a01b0382169a604051906323b872dd60e01b6020830152336024830152306044830152606482015260648152613d1e81612b86565b8b614218565b613d32826136d13084614a36565b997f000000000000000000000000000000000000000000000000000000000000000060028110156141ec57600114614182575b50505061ffff8216600052600080516020615a8183398151915260205260ff600160406000200154168015611d2957613da7613d9f6149cd565b91828b61591a565b916001600160401b038360081c16613dc460ff85169384836158bf565b808c03614175575061378e613de691613dde611b456149cd565b9485916158bf565b99600080516020615b8183398151915254976001600160401b03808a16146141615767ffffffffffffffff1989166001600160401b038a8116600101811691909117600080516020615b81833981519152557f0000000000000000000000000000000000000000000000000000000000000000161561415b57613e676151f2565b508b6001600160401b0380613e7d612a90614d85565b9260081b610100600160481b031660ff881617613e9a8185615853565b60081c169160081c16105b811580614154575b6141495781614141575b50613ee857505082612d0c9899610100600160481b0360ff6138a994169160081b1617613ee3816153d1565b615679565b61ffff95979896919a506001600160481b03939250613f05615211565b604051916001600160401b038b168352602083015260408201527ff33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a60603392a260405196613f5288612b1a565b875260208701521660408501526001600160401b03421660608501521660808301523360a083015260c08201526001600160401b038216600052600080516020615c0183398151915260205260c0600460406000208351815560208401516001820155600281016001600160481b036040860151166001600160481b0319825416178155613fed6001600160401b03606087015116826157a0565b608085015181549061ffff60881b9060881b169061ffff60881b19161790556003810160018060a01b0360a0860151166001600160601b0360a01b82541617905501910151938451906001600160401b038211613b485761404e8354613587565b601f8111614111575b50602090601f83116001146140bf57906001600160401b03959683613a965750508160011b916000199060031b1c19161790557f69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f60206040518484168152a1613a92346143bb565b95601f19831684885260208820975b8181106140f95750916001600160401b03969791846001959410613adc57505050811b019055613a5d565b838301518955600190980197602093840193016140ce565b61413b9084835260208320601f850160051c81019160208610613b3e57601f0160051c01906135c1565b38614057565b905038613eb7565b604483613b6f615211565b5080613ead565b82613ea5565b634e487b7160e01b83526011600452602483fd5b8b613bb160449282612f7f565b803b156107e55783809160248d6040519485938492630852cd8d60e31b845260048401525af180156141e1576141cc575b506141bf903090614a36565b808203613c145780613d65565b926141da6141bf9294612b07565b92906141b3565b6040513d86823e3d90fd5b634e487b7160e01b85526021600452602485fd5b908160209103126105b1575180151581036105b15790565b604051614276916001600160a01b031661423182612b50565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16142706142f2565b91614322565b8051908161428357505050565b8280614293938301019101614200565b1561429b5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b3d1561431d573d9061430382612bc2565b916143116040519384612ba1565b82523d6000602084013e565b606090565b919290156143845750815115614336575090565b3b1561433f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156143975750805190602001fd5b60405162461bcd60e51b815260206004820152908190610611906024830190612ae2565b600080808084335af16143cc6142f2565b50156143d55750565b60249060405190630b288dc560e21b82526004820152fd5b906020828203126105b15781516001600160401b0381116105b157612d0c9201612cca565b959492949391936040518081600080516020615b6183398151915260208154938481520190600052600080516020615ac18339815191529260005b81811061487157505061446292500382612ba1565b7f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed978549181511561485f576144b56000916040519485928392635b10743960e11b8452604060048501526044840190612ae2565b906024830152038173370d05c1f7e88312056bf2df462976219ca0fed45af49182156105a557600092614842575b506144ef818388612e24565b95863410614823576145018734612f7f565b80614814575b506040519061451582612b6b565b6001600160481b0386811683527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166020840190815260408085018d815261ffff8d81166060880190815292516315cfa3cb60e11b81529651909416600487015291516024860152905160448501525116606483015260008260848173370d05c1f7e88312056bf2df462976219ca0fed45af49182156105a557614614926000928d9284926147f8575b506001600160401b03604051936145dd85612b35565b16835260018060a01b031660208301526040820152604051809381926311692f3760e31b83526020600484015260248301906130d8565b038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156105a5576000916147d5575b5061ffff8816600052600080516020615a818339815191526020526040600020549383519385156147b95760005b8581106146dd5750505050505050927fe54e51e42099622516fa3b48e9733581c9dbdcb771cafb093f745a0532a35982949261ffff926146ae60c0966104416149cd565b906040519586526020860152604085015260608401521660808201526001600160401b03841660a0820152a190565b6001600160a01b036146ef8284612df0565b5116906146fc8187612df0565b5182600052600080516020615be183398151915260205261472860ff60406000205460101c1686612df0565b51833b156105b15761476e9361ffff8f936000948f8e906147808d6040519b8c998a988997634b5b050560e01b895216600488015260a0602488015260a4870190612e04565b85810360031901604487015290612ae2565b916064840152608483015203925af19182156105a5576147a5926147aa575b50612de1565b61466a565b6147b390612b07565b3861479f565b604051630ebc95af60e21b815261ffff8b166004820152602490fd5b6147f291503d806000833e6147ea8183612ba1565b8101906143ed565b3861463c565b61480d9192503d8086833e6147ea8183612ba1565b90386145c7565b61481d906143bb565b38614507565b6040516306a91e3760e51b815260048101889052346024820152604490fd5b6148589192503d806000833e6115e08183612ba1565b90386144e3565b6040516334e7b19560e11b8152600490fd5b84546001600160a01b031683526001948501948694506020909301920161444d565b92916148a1906104416149cd565b906000937f504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a918580a27f0000000000000000000000000000000000000000000000000000000000000000936002851015611e2f5784614936575060405163a9059cbb60e01b60208201526001600160a01b03909116602482015260448101919091529091506132d1906104de81606481016104d0565b9193600181036105b657507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690813b15611619576040516340c10f1960e01b81526001600160a01b03919091166004820152602481019490945291929181908390604490829084905af19081156149c157506149b85750565b6132d190612b07565b604051903d90823e3d90fd5b600080604051602081019063313ce56760e01b8252600481526149ef81612b50565b51907f00000000000000000000000000000000000000000000000000000000000000005afa50614a1d6142f2565b6020818051810103126105b1576020612d0c9101612cbc565b6040516370a0823160e01b602082019081526001600160a01b039093166024808301919091528152600092839291614a6d81612b35565b51915afa50614a7a6142f2565b6020818051810103126105b1576020015190565b60ff1660ff81146117465760010190565b15614aa657565b634e487b7160e01b600052600160045260246000fd5b600080516020615ba18339815191525460ff8160081c16614aed600080516020615b61833981519152548214614a9f565b60005b818110614b7b575060005b818110614b14575050604060ff6132d192161115614a9f565b60018101808211611746575b828110614b365750614b3190612de1565b614afb565b614b7690614b71614b468461302f565b905490614b528461302f565b92909160018060a01b03809354600395861b1c16931b1c161415614a9f565b612de1565b614b20565b80614b71614b8b614ba29361302f565b905460039190911b1c6001600160a01b0316614ba7565b614af0565b6001600160a01b039081166000818152600080516020615be18339815191526020526040908190209051929190614bdd84612b35565b5460ff91614c19838316158015938488526020880197604087808460081c16159384158c5260101c1691019581875292614cd4575b5050614a9f565b600080516020615b4183398151915254946001600160401b0360019687868651161b1616151590511515916000968791600080516020615ba18339815191525497878960081c16935b848110614c96575b5050505050816132d196614c84869594614c8c9414614a9f565b151514614a9f565b5116911611614a9f565b8282614ca18361302f565b90549060031b1c1614614cbc57614cb790612de1565b614c62565b50919850849250839150614c849050826132d1614c6a565b90915081614ce5575b503880614c12565b90501538614cdd565b307f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031614614d2057565b604051633c64f99360e21b8152600490fd5b600080516020615c4183398151915254336001600160a01b039182161415919082614d78575b5050614d6057565b60405163e2a08e5d60e01b8152336004820152602490fd5b1633141590503880614d58565b60405190614d9282612b35565b8160406001600160401b03600080516020615c61833981519152546001600160481b0380821685528160481c16602085015260901c16910152565b90604051614dda81612b35565b60406001600160401b038294546001600160481b0380821685528160481c16602085015260901c16910152565b90600160481b600160901b0382549160481b1690600160481b600160901b031916179055565b600080516020615c618339815191529081546001600160481b03908181166001600160401b036008918184841c16801580615020575b15614ed1575050855471ffffffffffffffffff0000000000000000001916604886901b600160481b600160901b03161786555050505b825479ffffffffffffffff000000000000000000ffffffffffffffffff19169116174260901b67ffffffffffffffff60901b16179055565b86614edd612a90614d85565b926000614eea8383615831565b15614fb65750614f099291614efe91615853565b8388861c16906157c8565b610100600160481b039290841b831660ff861617614f278184615831565b15614fa8578160ff9282614f3e614f4b9487615853565b871c169084871c166157c8565b9116921b16175b614f5c8482615831565b614f8657600160481b600160901b039060481b1690600160481b600160901b031916178355614e99565b604051631e74e8fb60e31b815290831660048201528383166024820152604490fd5b5050905060ff915016614f52565b9493959290614fc890614fd293615853565b8389841c166157c8565b9260ff881694838087610100600160481b038098871b1617614ff48185615853565b851c1691841c160192831161500c57501b1617614f52565b634e487b7160e01b81526011600452602490fd5b5060ff851615614e63565b919080546001600160481b03808216916001600160401b03926008908483831c168015806151e7575b156150ba57505050508461506c6132d1959685614e07565b835467ffffffffffffffff60901b19919092161679ffffffffffffffff000000000000000000ffffffffffffffffff1990911617429190911660901b67ffffffffffffffff60901b16179055565b8590896150c9612a908a614dcd565b9360006150d68383615831565b156151915750916150ee6150f99260ff979894615853565b838c881c16906157c8565b610100600160481b039490861b85169116176151158184615831565b156151835760ff918161512b6151389386615853565b861c168784871c166157c8565b9116921b16175b6151498682615831565b615161579461515c6132d1959685614e07565b61506c565b604051631e74e8fb60e31b815290821660048201529085166024820152604490fd5b5050905060ff91501661513f565b9496506151ac93506151a291615853565b868a851c166157c8565b9160ff891693868086610100600160481b038097861b16176151ce8185615853565b841c1691831c16019186831161500c57501b161761513f565b5060ff841615615054565b604051906151ff82612b35565b60006040838281528260208201520152565b6152196151f2565b50612d0c612a95612a90614d85565b6152306151f2565b506000527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b860205260406000206040519061526a82612b35565b80546001600160481b038116835260481c6001600160401b03166020830152600101546001600160a01b0316604082015290565b81156152a8570490565b634e487b7160e01b600052601260045260246000fd5b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000169182156153525761533f828260ff936040610100600160481b0396015116420381615323602085019889519383875160081c160261529e565b9160081c1601915160081c1680821060001461534b5750615369565b9251169160081b161790565b9050615369565b506020015160ff16610100600160481b0317919050565b6001600160401b039081811161537d571690565b60405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608490fd5b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000161561548d5761540a6151f2565b50600160481b600160901b03615421612a90614d85565b610100600160481b0360ff61545c600080516020615c61833981519152968088549761544d8188615853565b60081c16908560081c166157c8565b92169160081b161760481b16906001600160401b0360901b4260901b1690600160481b600160d01b03191617179055565b5050565b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000161561548d576154ca6151f2565b506154d6612a90614d85565b90600160481b600160901b03600080516020615c6183398151915293845493816001600160401b0360901b4260901b16946155118184615853565b60081c16828260081c160182811160001461559d5750610100600160481b0360ff61553b84615369565b92169160081b1617906001600160481b038516906155598284615853565b80856001600160401b0360901b1988161760081c16908360081c161060001461559657505b60481b1691600160481b600160d01b03191617179055565b905061557e565b60ff61553b610100600160481b0392615369565b6001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000161561344457610100600160481b0360ff61566b61ffff6132d1966155fe6151f2565b50169384600052600080516020615bc183398151915280602052615628612a906040600020614dcd565b60009687526020919091526040909520805467ffffffffffffffff60901b191642831660901b67ffffffffffffffff60901b1617815595819061544d8188615853565b92169160081b161790614e07565b6001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016156134445761ffff6132d1936156b86151f2565b5016600090808252600080516020615bc1833981519152806020526156e2612a9060408520614dcd565b91835260205260408220805467ffffffffffffffff60901b191642851660901b67ffffffffffffffff60901b1617815593839061571f8184615853565b60081c16838260081c160183811160001461578c5750610100600160481b0360ff61574985615369565b92169160081b1617918084546001600160481b0381169361576a8587615853565b5060081c16908360081c1610600014615784575090614e07565b905090614e07565b60ff615749610100600160481b0392615369565b9067ffffffffffffffff60481b82549160481b169067ffffffffffffffff60481b1916179055565b6001600160401b03918216908216039190821161174657565b60009182915b6001600160401b03908181168015615829576000190191821161581557169161580f90614a8e565b916157e7565b634e487b7160e01b85526011600452602485fd5b505050915090565b9061583c8183615853565b6001600160401b03809160081c169160081c161190565b60ff9182169116818103615865575050565b604051635ce6db6160e11b815260ff918216600482015291166024820152604490fd5b60ff811660081015612d0c5750600890565b9060ff8091169116039060ff821161174657565b60ff16604d811161174657600a0a90565b919060ff821660ff82168181146159135711156158f2576158e7612d0c93926158ec9261589a565b6158ae565b9061529e565b6158e7906158ff9261589a565b908181029181830414901517156117465790565b5050505090565b61594d61378e60ff92610100600160481b03949561593787615888565b90858116868316101561595857509586916158bf565b92169160081b161790565b90509586916158bf565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561599157565b604051631afcd79f60e31b8152600490fd5b6001600160a01b039081169081156159fe57600080516020615b0183398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020615b01833981519152546001600160a01b03163303615a3857565b60405163118cdaa760e01b8152336004820152602490fd5b600080516020615c218339815191526002815414615a6e5760029055565b604051633ee5aeb560e01b8152600490fdfeebcc9f646b0f459ff8f387587d536b0af3484cf442e1577400f322334e7d1ef047028352a8b3feae1a85fba43bc13f990568bb1637dce33d3dbfd791a0808b7f6c3cb3f3ae91330f31ba2bc0ff8855fc834fb66dc27e8e0b1a398617dabaa5a668dfeeddfa5e4e9adceec01a3aba274bdcbab3f6ac9956417a4332f2b08abdda9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930064bacf405c5d7f563d3ba5252584a52c37e4fee380fd825b10666c27b8258022fd6568c039679b3b7cc93c26c41d9379b7b1bec1677120493b467688302cb11f00758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e1ad78307a8b51804c575f26039dcb87c58925afb3b7c08732f3b21b942aed7a768561949d1c6242cee5c5a5aeb6b9c190ee611d7742fcec65d9e5b1341ea04d89efb21dcaedea63b55c44882f329622e13a8d0f5b947b3a372826208a9003da1549bca747e973430e858f2f5de357b8dba36ea6d375b81bdb5d53dfaabf0b3a7f852fa0677fef8612c6c15b518c9fa56761e9ed15cfd5c6e5399e5467985ac7ed9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00bfa91572ce1e5fe8776a160d3b1f862e83f5ee2c080a7423b4761602a3ad12497c25289a27ec8c9be54d4a154cf80490d69bda989cdb8328232e08fea9220420a2646970667358221220ff24bb6218d11a60fad2e17b2c54e55dfe3f8155f61d7f10dfd1f2886b23efbc64736f6c63430008130033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
Deployed Bytecode
0x6080604052600436101561001257600080fd5b6000803560e01c80630271725014612a42578063036de8af146129b75780630677df54146129985780630900f01014612531578063186ce612146124dc57806319017175146124a65780631f97c9a8146122b4578063203e4a9b14611fb657806323d75e3114611f82578063295a521214611f28578063396c16b714611eec5780633b97e85614611ed15780633f4ba83a14611e435780634b4fd03b14611de5578063689f90c314611da357806374aa7bfc14611d5f5780637c91863414611c0a5780638129fc1c146119e75780638413bcba146118cb5780638456cb591461184e57806386e11ffa1461182957806389c619dd146117c95780638da5cb5b146117935780638e3ba8c91461175c5780638fd3ab801461161d5780639057412d146114a0578063961b94d01461144257806397c35146146111ba5780639a8a05921461117b5780639d78245414610f405780639f86029c14610c2f5780639fd0506d14610bf9578063b187bd2614610bcb578063b293f97f14610b35578063b4d591bb14610a74578063c0b07bde14610a2e578063c128d170146109b2578063d788c14714610927578063da4856a1146108f4578063e5a9860314610848578063e75235b81461081a578063f2fde38b146106d5578063f5cfec18146106b2578063f7514fbc146102b4578063fc0c546a1461026f5763fd96063c1461021757600080fd5b3461026c57602036600319011261026c576060610235600435615228565b6040805182516001600160481b031681526020808401516001600160401b031690820152918101516001600160a01b031690820152f35b80fd5b503461026c578060031936011261026c576040517f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03168152602090f35b503461026c57602036600319011261026c576004356001600160401b03811681036106ae576102e1615a50565b6002600080516020615b21833981519152541461069c576001600160401b038116600052600080516020615c0183398151915260205260406000206040519061032982612b1a565b805482526001810154602083015261ffff60028201546001600160481b03811660408501526001600160401b038160481c16606085015260881c16608083015260018060a01b0360038201541660a083015260405190818560048301549261039084613587565b808452936001811690811561067a5750600114610636575b506103b592500382612ba1565b60c08201526001600160401b03606082015116156106155760a08101516001600160a01b03163381036105e85750606061045860407ff80e572ae1b63e2449629b6c7d783add85c36473926f216077f17ee002bcfd07936001600160401b038616600052600080516020615c01833981519152602052610437826000206135d8565b01516104416149cd565b906001600160401b0360ff82169160081c166158bf565b926001600160401b0360405191168152336020820152836040820152a17f000000000000000000000000000000000000000000000000000000000000000060028110156105d25780610522575060405163a9059cbb60e01b6020820152336024820152604481019190915261050d906104de81606481015b03601f198101835282612ba1565b7f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316614218565b6001600080516020615c218339815191525580f35b600181036105b657507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b0316803b156105b1576040516340c10f1960e01b815233600482015260248101929092526000908290604490829084905af180156105a557610596575b5061050d565b61059f90612b07565b38610590565b6040513d6000823e3d90fd5b600080fd5b6040516366001a8960e01b815260ff9091166004820152602490fd5b634e487b7160e01b600052602160045260246000fd5b60405163ceb40a8560e01b81523360048201526001600160a01b03919091166024820152604490fd5b0390fd5b604051635feafa3160e11b81526001600160401b0383166004820152602490fd5b60040187525060208620909186915b81831061065e5750509060206103b592820101386103a8565b6020919350806001915483858801015201910190918392610645565b9050602092506103b594915060ff191682840152151560051b820101386103a8565b6040516309e3d0f360e11b8152600490fd5b5080fd5b503461026c578060031936011261026c5760206106cd615211565b604051908152f35b503461026c57602036600319011261026c576001600160a01b03600435818116908181036107e55761071690610709615a17565b610711615a17565b6159a3565b7f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed97891825460ff600080516020615ba183398151915254168082036107fc575050908391825b84548110156107f8578460005281817f357eda4c1707ce60b55a439f3dc12fcacea5ca0fd863e2fc179a916cf05fccd1015416803b156107f457848091602460405180948193632c7b84dd60e11b83528960048401525af19081156107e95785916107d1575b50506107cc90612de1565b61075b565b6107da90612b07565b6107e55783386107c1565b8380fd5b6040513d87823e3d90fd5b8480fd5b8380f35b604492506040519163d2a13a2960e01b835260048301526024820152fd5b503461026c578060031936011261026c57602060ff600080516020615aa18339815191525416604051908152f35b503461026c57602036600319011261026c5760043560ff8116908181036105b157610871615a17565b81156108e2577f2a855b929b9a53c6fb5b5ed248b27e502b709c088e036a5aa17620c8fc5085a9916108dc60ff92600080516020615aa1833981519152805493851985161790556108c0613060565b6040805160ff9490951684168552921660208401528291820190565b0390a180f35b60405163831761d760e01b8152600490fd5b503461026c5761090336612c24565b906002600080516020615b21833981519152541461069c5761092492613129565b80f35b503461026c57602036600319011261026c5761ffff610944612a9d565b61094c6151f2565b5016600052600080516020615bc18339815191526020526109ae6109736040600020614dcd565b6040519182918291909160406001600160401b038160608401956001600160481b038082511686526020820151166020860152015116910152565b0390f35b503461026c57602036600319011261026c5761ffff906109d0612a9d565b9060206040516109df81612b50565b828152015216600052600080516020615a8183398151915260205260408060002060ff8251610a0d81612b50565b60208260018554958685520154169101908152835192835251166020820152f35b503461026c578060031936011261026c576109ae604051610a4e81612b50565b60058152640302e312e360dc1b6020820152604051918291602083526020830190612ae2565b503461026c578060031936011261026c576040518091600080516020615b6183398151915290815480845260208094019081938352600080516020615ac183398151915290835b818110610b185750505084610ad1910385612ba1565b60405193838594850191818652518092526040850193925b828110610af857505050500390f35b83516001600160a01b031685528695509381019392810192600101610ae9565b82546001600160a01b031684529286019260019283019201610abb565b5060c036600319011261026c57610b4a612aae565b906084359182151583036106ae5760a4356001600160401b039283821161026c5750610b7a903690600401612bdd565b610b82615a50565b6002600080516020615b21833981519152541461069c57602093610bb0926064359060443590600435613c9c565b6001600080516020615c218339815191525560405191168152f35b503461026c578060031936011261026c5760206002600080516020615b218339815191525414604051908152f35b503461026c578060031936011261026c57600080516020615c41833981519152546040516001600160a01b039091168152602090f35b503461026c576020806003193601126106ae576001600160a01b039060043582811691908281036107f457610c62615a17565b8215610f2e5782600052600080516020615be183398151915280835260ff91826040600020541615610f1557846000528184528260406000205460081c1615610efc5784600052818452604060002061ff001990818154169055600080516020615ba1833981519152928354858160081c16928315610ee85761ff0060001980950160081b169116178455600080516020615b418339815191528054918860005287526001600160401b03600192610d2f82858a60406000205460101c161b198316169282168310614a9f565b6001600160401b0319161790558897600080516020615b618339815191528054938b5b858110610de2575b505050505050918091610da26040969594610d957f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f99614a9f565b610d9d614abc565b614ba7565b5460081c16600080516020615aa18339815191529081548381168210610dd4575b50505416908351928352820152a180f35b60ff19161781553880610dc3565b838b610ded8361302f565b929054600393841b1c1614610e0b5750610e0690612de1565b610d52565b9590918093959798999a9b9c508101908111610ed45790610e3f84610e32610e5e9461302f565b905490891b1c169161302f565b90919082549060031b9160018060a01b03809116831b921b1916179055565b82548015610ec057946040999794610da2948a9894610d95947f697a3853515b88013ad432f29f53d406debc9509ed6d9313dcfe115250fcd18f9e9c990192610ea68461302f565b81939154921b1b1916905555998496979899839650610d5a565b634e487b7160e01b8c52603160045260248cfd5b634e487b7160e01b8d52601160045260248dfd5b634e487b7160e01b8b52601160045260248bfd5b6040516307d86e9160e21b815260048101869052602490fd5b604051630d583f4760e41b815260048101869052602490fd5b604051632f44bd7760e01b8152600490fd5b503461026c57610f4f36612c24565b9033600052600080516020615be183398151915260209080825260ff60406000205460081c161561116357600080516020615b2183398151915291600283541461069c5761ffff861680600052600080516020615a8183398151915282528460406000205403611145575060405163b3f07bbd60e01b815291818380610fd9898b600484016130ff565b038173370d05c1f7e88312056bf2df462976219ca0fed45af492831561113a57889361110b575b503360005280825261101d60ff60406000205460101c1684612ff9565b6110f25760606110d193927f35a2101eaac94b493e0dfca061f9a7f087913fde8678e7cde0aca9897edba0e592336000528082528a6001600160401b03610100600160481b03604082600160ff836000205460101c161b1693898152600080516020615ae1833981519152875220928354928360081c161760081b1690610100600160481b03191617905533600052815260ff60406000205460101c166040519185835233908301526040820152a1612f8c565b6110d9578480f35b5460021461069c576110ea92613129565b388080808480f35b604051631089c4a160e11b815260048101849052602490fd5b9092508181813d8311611133575b6111238183612ba1565b810103126105b157519138611000565b503d611119565b6040513d8a823e3d90fd5b6044908560405191635788c0fd60e11b835260048301526024820152fd5b60405163a0ae911d60e01b8152336004820152602490fd5b503461026c578060031936011261026c57602060405161ffff7f0000000000000000000000000000000000000000000000000000000000000002168152f35b50602036600319011261026c576001600160401b036004351690816004350361026c576111e5615a50565b6002600080516020615b21833981519152541461069c5781600052600080516020615c018339815191526020526040600020916040519261122584612b1a565b805484526001810154602085015261ffff60028201546001600160481b03811660408701526001600160401b038160481c16606087015260881c16608085015260018060a01b0360038201541660a08501526040518381949060048401549361128d85613587565b808552946001811690811561141e57506001146113d9575b50506112b392500383612ba1565b60c083019182526001600160401b03606084015116156113c1576112e46001600160401b0360608501511642612f7f565b6001600160401b037f00000000000000000000000000000000000000000000000000000000000000001611611396579161137391602093600052600080516020615c01833981519152845261133c60406000206135d8565b6001600160481b036040830151169161ffff608082015116815190868301519260a0600180821b0391015116935194600435614412565b6001600080516020615c21833981519152556001600160401b0360405191168152f35b6044906001600160401b036060850151166040519163c06cf05f60e01b835260048301526024820152fd5b60249060405190635feafa3160e11b82526004820152fd5b60049193949250018252602082205b8183106114025750509060206112b39282010138806112a5565b60209193508060019154838589010152019101909184926113e8565b915050602092506112b394915060ff191682840152151560051b82010138806112a5565b50606036600319011261026c57611457612aae565b604435611462615a50565b6002600080516020615b21833981519152541461069c5760209181611373926040519261148e84612b50565b6001845285368186013760043561363a565b503461026c57604036600319011261026c576114ba612a9d565b6024356001600160401b038111611619576114d9903690600401612bdd565b91604051918290600080516020615b61833981519152828154918287526020809701908652600080516020615ac183398151915292865b888282106115fa5750505061152792500383612ba1565b826115518351966040519788928392635b10743960e11b8452604060048501526044840190612ae2565b906024830152038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156115ef5783949561158a94926115cb575b50612e24565b604051926040840160408552835180915285606086019401915b8181106115b75750505082938301520390f35b8251855293860193918601916001016115a4565b6115e89192503d8087833e6115e08183612ba1565b810190612d0f565b9038611584565b6040513d85823e3d90fd5b85546001600160a01b0316845260019586019588955093019201611510565b8280fd5b503461026c578060031936011261026c57611636614cee565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a0080546001600160401b038082169060018201918183116117465760ff8460401c16908115611739575b5061172757600160401b911680926001600160481b03191617179081835560ff7f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4e541615611715577fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2926020926116f5613060565b6116fd614abc565b68ff000000000000000019169055604051908152a180f35b604051632866815360e11b8152600490fd5b60405163f92ee8a960e01b8152600490fd5b9050818316111538611680565b634e487b7160e01b600052601160045260246000fd5b503461026c57604036600319011261026c5760243560ff811681036105b157611789602091600435612ff9565b6040519015158152f35b503461026c578060031936011261026c57600080516020615b01833981519152546040516001600160a01b039091168152602090f35b503461026c57602036600319011261026c5761181e6001600160401b036020926040600080516020615b4183398151915254916004358152600080516020615ae18339815191528652205460081c16166157e1565b60ff60405191168152f35b503461026c578060031936011261026c576118426151f2565b506109ae610973614d85565b503461026c578060031936011261026c57600080516020615b0183398151915254611881906001600160a01b0316614d32565b600080516020615b21833981519152600281541461069c57600290557f0e2fb031ee032dc02d8011dc50b816eb450cf856abd8261680dac74f72165bd2602060405160018152a180f35b503461026c57602036600319011261026c576004356118e8615a50565b6002600080516020615b21833981519152541461069c5761190881615228565b602081016001600160401b039081815116156119ce5761192b8282511642612f7f565b827f000000000000000000000000000000000000000000000000000000000000000016116119ac578385527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b860205260408086208681556001018690558301518351869161050d916001600160481b0316906001600160a01b031687614893565b516040516301cb739d60e71b8152600481019490945216602483015250604490fd5b604051630301bcaf60e61b815260048101859052602490fd5b503461026c578060031936011261026c57611a00614cee565b7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a00805460ff8160401c1615906001600160401b03811680159081611c02575b6001149081611bf8575b159081611bef575b506117275767ffffffffffffffff198116600117835581611bd0575b50611a76615962565b7f000000000000000000000000fdefcd1d1cd700cb9ee3c37cb8a2013a3f417e8c6001600160a01b0381163303611ba75750611ab0615962565b611ab8615962565b611ac0615962565b6001600080516020615b2183398151915255600080516020615c4183398151915280546001600160a01b03191633179055611af9615962565b611b01615962565b611b0a336159a3565b611b12615962565b611b1a615962565b6001600080516020615c2183398151915255611b51610100600160481b0360ff611b4a611b456149cd565b615888565b1617614e2d565b611b59613060565b611b61614abc565b611b69575080f35b68ff00000000000000001981541690557fc7f505b2f371ae2175ee4913f4499e1f2633a7b5936321eed1cdaeb6115181d2602060405160018152a180f35b604051636345072160e11b81526001600160a01b03919091166004820152336024820152604490fd5b68ffffffffffffffffff19166801000000000000000117825538611a6d565b90501538611a51565b303b159150611a49565b839150611a3f565b503461026c57608036600319011261026c57611c24612a9d565b6024356044359160ff83168093036105b15761ffff90611c42615a17565b16918215611d4d578115611d3b578015611d29577f1456404e7f41f35c3daac941bb50bad417a66275c3040061b4287d787719599d9160809184600052600080516020615a81833981519152918260205260ff604060002081600160405192611caa84612b50565b805484520154169460208201958652886000526020526001604060002084815501848319825416179055611d0c611ceb611ce26149cd565b8060643561591a565b89600052600080516020615bc183398151915260205260406000209061502b565b51935116604051938452602084015260408301526060820152a280f35b60405163ade64f0b60e01b8152600490fd5b60405163f839a0cb60e01b8152600490fd5b60405163100b0f2760e11b8152600490fd5b503461026c578060031936011261026c5760206040516001600160401b037f0000000000000000000000000000000000000000000000000000000000000000168152f35b503461026c578060031936011261026c57602060ff7f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cb54166040519015158152f35b503461026c578060031936011261026c577f0000000000000000000000000000000000000000000000000000000000000000906002821015611e2f5760208260ff60405191168152f35b634e487b7160e01b81526021600452602490fd5b503461026c578060031936011261026c57600080516020615b0183398151915254611e76906001600160a01b0316614d32565b600080516020615b218339815191526002815403611ebf57600190557fe11c2112add17fb763d3bd59f63b10429c3e11373da4fb8ef6725107a2fdc4b06020604051838152a180f35b604051637e38d1d360e11b8152600490fd5b503461026c578060031936011261026c57602061181e6149cd565b503461026c57602036600319011261026c5760ff60406020926004358152600080516020615ae183398151915284522054166040519015158152f35b503461026c578060031936011261026c576040517f00000000000000000000000000000000000000000000000000000000000000006002811015611f6e57602092508152f35b634e487b7160e01b83526021600452602483fd5b503461026c578060031936011261026c5760206001600160401b03600080516020615b818339815191525416604051908152f35b503461026c576020806003193601126106ae576004356001600160a01b038116918282036107e557611fe6615a17565b8215610f2e5782600052600080516020615be18339815191529182825260ff90816040600020541660001461218a5784600052838352604060002061010061ff00198254161790555b600080516020615b6183398151915290815491600160401b8310156121745782610e3f9160016120619501905561302f565b600080516020615ba183398151915292835461ff00612084848360081c16614a8e565b60081b169061ff00191617809455600080516020615b4183398151915280546001600160401b0390818116918860005284875260018660406000205460101c161b16821791821461215b5767ffffffffffffffff19161790557ff05962b5774c658e85ed80c91a75af9d66d2af2253dda480f90bce78aff5eda594606094909390929091612110614abc565b84600052825280600080516020615aa183398151915280548281161561214c575b5054169260405194855260081c16908301526040820152a180f35b60ff1916600117815538612131565b604051638d68f84d60e01b815260048101899052602490fd5b634e487b7160e01b600052604160045260246000fd5b600080516020615ba18339815191528281541660408110156122a257604051906121b382612b35565b6001825285820190600182526040830190815288600052878752604060002092511515918662ff000061ff0086549351151560081b16935160101b1693169062ffffff1916171717905580548361220b818316614a8e565b169060ff19161790557f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed978805490600160401b821015612174576001820180825582101561228c576000527f357eda4c1707ce60b55a439f3dc12fcacea5ca0fd863e2fc179a916cf05fccd10180546001600160a01b0319168617905561202f565b634e487b7160e01b600052603260045260246000fd5b60405163891684c360e01b8152600490fd5b503461026c57602036600319011261026c576004356001600160401b0381168091036106ae57606060c06040516122ea81612b1a565b84815284602082015284604082015284838201528460808201528460a08201520152600052600080516020615c0183398151915260205260406000206040519061233382612b1a565b805482526001810154602083015261ffff60028201546001600160481b03811660408501526001600160401b038160481c16606085015260881c16608083015260018060a01b0360038201541660a08301526040518381949060048401549361239b85613587565b8085529460018116908115612482575060011461243d575b50506123c192500383612ba1565b60c081019182526109ae6040519283926020845280516020850152602081015160408501526001600160481b0360408201511660608501526001600160401b03606082015116608085015261ffff60808201511660a085015260a0600180821b039101511660c08401525160e080840152610100830190612ae2565b60049193949250018252602082205b8183106124665750509060206123c19282010138806123b3565b602091935080600191548385890101520191019091849261244c565b915050602092506123c194915060ff191682840152151560051b82010138806123b3565b503461026c57602036600319011261026c576124c0615a17565b6109246124d76124ce6149cd565b8060043561591a565b614e2d565b503461026c57604036600319011261026c576109246124f9612aae565b612501615a17565b61ffff61250f6124ce6149cd565b9116600052600080516020615bc183398151915260205260406000209061502b565b503461026c576020806003193601126106ae576001600160a01b03600435818116908181036107f457612562615a17565b61256a614cee565b3b1561293d577f360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc80546001600160a01b031916821790557fbc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b8480a27f7487ca88d037ca20519908b1ee7556206bef53bce0226a348750cb9d4f688e4e918254916125f760ff841615614a9f565b60ff199283166001178455303b156107f45760405163011fa75760e71b8152858160048183305af180156128f25761292a575b5060405163689f90c360e01b81528281600481305afa9081156128f25786916128fd575b5015612686575b50507f5443fea4dc453d96b81ce55b62e11a4094cc4cbb8a360956a7253cfdb42506cb818154169055815416905580f35b604051637e062a3560e11b81528281600481305afa9081156128f25786916128b4575b50816126d9927f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4816911614614a9f565b6040516314ad290960e11b81528181600481305afa9081156107e957859161287e575b507f000000000000000000000000000000000000000000000000000000000000000090600282101561286a57600281101561286a5761273b9114614a9f565b604051634d4502c960e11b81528181600481305afa80156107e9578590612834575b612790915061ffff807f000000000000000000000000000000000000000000000000000000000000000216911614614a9f565b604051631d2a9eff60e21b8152908082600481305afa9081156107e95785916127f4575b506127ed91506001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016911614614a9f565b3880612655565b905081813d831161282d575b61280a8183612ba1565b810103126107e557516001600160401b03811681036107e5576127ed90386127b4565b503d612800565b508181813d8311612863575b61284a8183612ba1565b810103126107f45761285e6127909161311a565b61275d565b503d612840565b634e487b7160e01b86526021600452602486fd5b90508181813d83116128ad575b6128958183612ba1565b810103126107f4575160028110156107f457386126fc565b503d61288b565b90508281813d83116128eb575b6128cb8183612ba1565b810103126128e757519080821682036128e757906126d96126a9565b8580fd5b503d6128c1565b6040513d88823e3d90fd5b61291d9150833d8511612923575b6129158183612ba1565b810190614200565b3861264e565b503d61290b565b61293690959195612b07565b933861262a565b60405162461bcd60e51b815260048101849052602d60248201527f455243313936373a206e657720696d706c656d656e746174696f6e206973206e60448201526c1bdd08184818dbdb9d1c9858dd609a1b6064820152608490fd5b503461026c57602036600319011261026c576020611789600435612f8c565b503461026c57602036600319011261026c576004356001600160a01b0381811691829003611619576129f981600080516020615b018339815191525416614d32565b600080516020615c4183398151915280546001600160a01b031981168417909155167f51c4874e0f23f262e04a38c51751336dde72126d67f53eb672aaff02996b3ef68380a380f35b503461026c57602036600319011261026c576106cd612a95612a90604060209461ffff612a6d612a9d565b612a756151f2565b50168152600080516020615bc1833981519152865220614dcd565b6152be565b6104416149cd565b6004359061ffff821682036105b157565b6024359061ffff821682036105b157565b60005b838110612ad25750506000910152565b8181015183820152602001612ac2565b90602091612afb81518092818552858086019101612abf565b601f01601f1916010190565b6001600160401b03811161217457604052565b60e081019081106001600160401b0382111761217457604052565b606081019081106001600160401b0382111761217457604052565b604081019081106001600160401b0382111761217457604052565b608081019081106001600160401b0382111761217457604052565b60a081019081106001600160401b0382111761217457604052565b90601f801991011681019081106001600160401b0382111761217457604052565b6001600160401b03811161217457601f01601f191660200190565b81601f820112156105b157803590612bf482612bc2565b92612c026040519485612ba1565b828452602083830101116105b157816000926020809301838601378301015290565b90600319906060828401126105b15760043561ffff811681036105b1579260243592604435916001600160401b03918284116105b15760609084830301126105b15760405192612c7384612b35565b806004013584526024810135602085015260448101359283116105b157612c9d9201600401612bdd565b604082015290565b6001600160401b0381116121745760051b60200190565b519060ff821682036105b157565b81601f820112156105b1578051612ce081612bc2565b92612cee6040519485612ba1565b818452602082840101116105b157612d0c9160208085019101612abf565b90565b9060209081838203126105b15782516001600160401b03938482116105b157019080601f830112156105b1578151612d4681612ca5565b94604090612d5682519788612ba1565b828752858088019360051b860101948486116105b157868101935b868510612d8357505050505050505090565b84518381116105b15782019084601f1983890301126105b157845190612da882612b50565b612db38a8401612cbc565b825285830151918583116105b157612dd2898c80969581960101612cca565b83820152815201940193612d71565b60001981146117465760010190565b805182101561228c5760209160051b010190565b9060406020612d0c9360ff81511684520151918160208201520190612ae2565b909291805191612e3383612ca5565b92604091612e4383519586612ba1565b818552601f19612e5283612ca5565b01602090368288013760009788955b848710612e7357505050505050509190565b909192939495988685612eec868d612e9260018060a01b039188612df0565b511680600052600080516020615be18339815191528252612ebd60ff866000205460101c1689612df0565b51908551808095819463b5634c7360e01b835261ffff60049916898401526024998a8401526044830190612e04565b03915afa908115612f7457908d91600091612f42575b50612f0e81928d612df0565b528301809311612f2f575050612f249099612de1565b959493929190612e61565b601190634e487b7160e01b600052526000fd5b91508782813d8311612f6d575b612f598183612ba1565b8101031261026c5750518c90612f0e612f02565b503d612f4f565b8a513d6000823e3d90fd5b9190820391821161174657565b6001600160401b039060ff612fe581600080516020615aa18339815191525416938493600080516020615b418339815191525490600052600080516020615ae183398151915260205260406000205460081c16166157e1565b1610159081612ff2575090565b9050151590565b906001600160401b0391600052600080516020615ae1833981519152602052600160ff60406000205460081c92161b1616151590565b600080516020615b61833981519152805482101561228c57600052600080516020615ac18339815191520190600090565b60ff600080516020615aa1833981519152541660405161307f81612b50565b60ff600080516020615ba183398151915254818116835260081c168060208301528083116130ba57505160ff166130b35750565b156108e257565b82604491604051916313c3d1b160e01b835260048301526024820152fd5b9060606040612d0c9380518452602081015160208501520151918160408201520190612ae2565b60409061ffff612d0c949316815281602082015201906130d8565b519061ffff821682036105b157565b91907f000000000000000000000000000000000000000000000000000000000000000146810361344957508161315f9184613467565b9190916134445760408091015191815192635399ded560e11b8452608084806131946020948560048401526024830190612ae2565b038173370d05c1f7e88312056bf2df462976219ca0fed45af4938415613439576000946133c4575b5061ffff9283606086015116847f0000000000000000000000000000000000000000000000000000000000000002168082036133a95750506131fc6149cd565b8161322587519280613220816001600160401b03968760ff82169160081c166158bf565b61591a565b960151908160a01c613392576001600160a01b039182169560007f000000000000000000000000000000000000000000000000000000000000000083161561338b57506132706151f2565b508816600052600080516020615bc18339815191528452613296612a9084600020614dcd565b6132a08882615853565b81808960081c169160081c16105b6132d357505050506132c36132d194846155b1565b6132cc83615491565b614893565b565b7f7f63c9251d82a933210c2b6d0b0f116252c3c116788120e64e8e8215df6f316297509561336f839596949760019394519261330e84612b35565b6001600160481b038091168452898401908242168252888501978852896000527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b88b52886000209451166001600160481b03198554161784555116826157a0565b019151166001600160601b0360a01b82541617905551908152a1565b90506132ae565b50602491519063033b960d60e41b82526004820152fd5b6044925191631ee5902560e11b835260048301526024820152fd5b6080949194813d8211613431575b816133df60809383612ba1565b810103126106ae578351916133f383612b6b565b8151906001600160481b038216820361026c57508252848101518583015283810151848301526134259060600161311a565b606082015292386131bc565b3d91506133d2565b83513d6000823e3d90fd5b505050565b604490604051906377d879fb60e01b82526004820152466024820152fd5b60405163b3f07bbd60e01b81529193926020918391829161348c9190600484016130ff565b038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156105a55760009161351d575b506134be81612f8c565b15613505576134cc8161354e565b92836134da57509150600090565b7f4069dff8c9df7e38d2867c0910bd96fd61787695e5380281148c04932d02bef2600080a360009190565b60249060405190630451c4fb60e41b82526004820152fd5b906020823d8211613546575b8161353660209383612ba1565b8101031261026c575051386134b4565b3d9150613529565b600052600080516020615ae18339815191526020526040600020805460ff81166135805760ff19166001179055600090565b5050600190565b90600182811c921680156135b7575b60208310146135a157565b634e487b7160e01b600052602260045260246000fd5b91607f1691613596565b8181106135cc575050565b600081556001016135c1565b6004600091828155826001820155826002820155826003820155016135fd8154613587565b8061360757505050565b82601f821160011461361857505055565b9091808252613636601f60208420940160051c8401600185016135c1565b5555565b9194939290946000958315613c8a578115613c78578215613c66577f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486136803082614a36565b906136c360018060a01b03821696604051906323b872dd60e01b60208301523360248301523060448301526064820152606481526136bd81612b86565b87614218565b6136d6826136d13084614a36565b612f7f565b957f00000000000000000000000000000000000000000000000000000000000000006002811015613c52579060018b9214613bcb575b5050505061ffff8116600052600080516020615a8183398151915260205260ff600160406000200154168015611d295761374f6137476149cd565b91828761591a565b906001600160401b038260081c1661376c60ff84169283836158bf565b808803613ba4575061378e61379391613786611b456149cd565b9384916158bf565b615369565b98600080516020615b8183398151915254966001600160401b0380891614613b905767ffffffffffffffff1988166001600160401b03898116600101811691909117600080516020615b81833981519152557f00000000000000000000000000000000000000000000000000000000000000001615613b8a576138146151f2565b50613820612a90614d85565b61383d8c610100600160481b0360ff87169160081b161782615853565b6001600160401b03808d610100600160481b0360ff88169160081b161760081c169160081c16105b613b64578180613b5c575b6138b957505082612d0c9899610100600160481b0360ff8461389d826138a99716848660081b16176153d1565b169160081b1617615679565b6001600160401b03339516614412565b61ffff95979896919a506001600160481b039392506138d6615211565b604051916001600160401b038b168352602083015260408201527ff33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a60603392a26040519661392388612b1a565b875260208701521660408501526001600160401b03421660608501521660808301523360a083015260c08201526001600160401b038216600052600080516020615c0183398151915260205260c0600460406000208351815560208401516001820155600281016001600160481b036040860151166001600160481b03198254161781556139be6001600160401b03606087015116826157a0565b608085015181549061ffff60881b9060881b169061ffff60881b19161790556003810160018060a01b0360a0860151166001600160601b0360a01b82541617905501910151938451906001600160401b038211613b4857613a1f8354613587565b601f8111613b0d575b50602090601f8311600114613aa157906001600160401b03959683613a96575b50508160011b916000199060031b1c19161790555b7f69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f60206040518484168152a1613a92346143bb565b1690565b015190503880613a48565b95601f19831684885260208820975b818110613af55750916001600160401b03969791846001959410613adc575b505050811b019055613a5d565b015160001960f88460031b161c19169055388080613acf565b83830151895560019098019760209384019301613ab0565b613b389084835260208320601f850160051c81019160208610613b3e575b601f0160051c01906135c1565b38613a28565b9091508190613b2b565b634e487b7160e01b81526041600452602490fd5b506000613870565b604490613b6f615211565b90604051916326fb55dd60e01b835260048301526024820152fd5b81613865565b634e487b7160e01b82526011600452602482fd5b87613bb160449282612f7f565b604051916338f831a560e11b835260048301526024820152fd5b803b156106ae578190602460405180948193630852cd8d60e31b83528c60048401525af18015613c4757613c32575b50613c06903090614a36565b808203613c1457888161370c565b60449250604051916302156a8f60e01b835260048301526024820152fd5b98613c40613c06929a612b07565b9890613bfa565b6040513d8c823e3d90fd5b634e487b7160e01b8b52602160045260248bfd5b60405163717f139360e11b8152600490fd5b604051634e46966960e11b8152600490fd5b604051631f2a200560e01b8152600490fd5b95949392919060008715613c8a578215613c78578315613c66577f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48613ce13082614a36565b90613d2460018060a01b0382169a604051906323b872dd60e01b6020830152336024830152306044830152606482015260648152613d1e81612b86565b8b614218565b613d32826136d13084614a36565b997f000000000000000000000000000000000000000000000000000000000000000060028110156141ec57600114614182575b50505061ffff8216600052600080516020615a8183398151915260205260ff600160406000200154168015611d2957613da7613d9f6149cd565b91828b61591a565b916001600160401b038360081c16613dc460ff85169384836158bf565b808c03614175575061378e613de691613dde611b456149cd565b9485916158bf565b99600080516020615b8183398151915254976001600160401b03808a16146141615767ffffffffffffffff1989166001600160401b038a8116600101811691909117600080516020615b81833981519152557f0000000000000000000000000000000000000000000000000000000000000000161561415b57613e676151f2565b508b6001600160401b0380613e7d612a90614d85565b9260081b610100600160481b031660ff881617613e9a8185615853565b60081c169160081c16105b811580614154575b6141495781614141575b50613ee857505082612d0c9899610100600160481b0360ff6138a994169160081b1617613ee3816153d1565b615679565b61ffff95979896919a506001600160481b03939250613f05615211565b604051916001600160401b038b168352602083015260408201527ff33512b84e24a49905c26c6991942fc5a9652411769fc1e448f967cdb049f08a60603392a260405196613f5288612b1a565b875260208701521660408501526001600160401b03421660608501521660808301523360a083015260c08201526001600160401b038216600052600080516020615c0183398151915260205260c0600460406000208351815560208401516001820155600281016001600160481b036040860151166001600160481b0319825416178155613fed6001600160401b03606087015116826157a0565b608085015181549061ffff60881b9060881b169061ffff60881b19161790556003810160018060a01b0360a0860151166001600160601b0360a01b82541617905501910151938451906001600160401b038211613b485761404e8354613587565b601f8111614111575b50602090601f83116001146140bf57906001600160401b03959683613a965750508160011b916000199060031b1c19161790557f69add1952a6a6b9cb86f04d05f0cb605cbb469a50ae916139d34495a9991481f60206040518484168152a1613a92346143bb565b95601f19831684885260208820975b8181106140f95750916001600160401b03969791846001959410613adc57505050811b019055613a5d565b838301518955600190980197602093840193016140ce565b61413b9084835260208320601f850160051c81019160208610613b3e57601f0160051c01906135c1565b38614057565b905038613eb7565b604483613b6f615211565b5080613ead565b82613ea5565b634e487b7160e01b83526011600452602483fd5b8b613bb160449282612f7f565b803b156107e55783809160248d6040519485938492630852cd8d60e31b845260048401525af180156141e1576141cc575b506141bf903090614a36565b808203613c145780613d65565b926141da6141bf9294612b07565b92906141b3565b6040513d86823e3d90fd5b634e487b7160e01b85526021600452602485fd5b908160209103126105b1575180151581036105b15790565b604051614276916001600160a01b031661423182612b50565b6000806020958685527f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c656487860152868151910182855af16142706142f2565b91614322565b8051908161428357505050565b8280614293938301019101614200565b1561429b5750565b6084906040519062461bcd60e51b82526004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152fd5b3d1561431d573d9061430382612bc2565b916143116040519384612ba1565b82523d6000602084013e565b606090565b919290156143845750815115614336575090565b3b1561433f5790565b60405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606490fd5b8251909150156143975750805190602001fd5b60405162461bcd60e51b815260206004820152908190610611906024830190612ae2565b600080808084335af16143cc6142f2565b50156143d55750565b60249060405190630b288dc560e21b82526004820152fd5b906020828203126105b15781516001600160401b0381116105b157612d0c9201612cca565b959492949391936040518081600080516020615b6183398151915260208154938481520190600052600080516020615ac18339815191529260005b81811061487157505061446292500382612ba1565b7f3031d39df71efbb605646fc51d7571499445af538fa6dd17ce8c07e8118ed978549181511561485f576144b56000916040519485928392635b10743960e11b8452604060048501526044840190612ae2565b906024830152038173370d05c1f7e88312056bf2df462976219ca0fed45af49182156105a557600092614842575b506144ef818388612e24565b95863410614823576145018734612f7f565b80614814575b506040519061451582612b6b565b6001600160481b0386811683527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b03166020840190815260408085018d815261ffff8d81166060880190815292516315cfa3cb60e11b81529651909416600487015291516024860152905160448501525116606483015260008260848173370d05c1f7e88312056bf2df462976219ca0fed45af49182156105a557614614926000928d9284926147f8575b506001600160401b03604051936145dd85612b35565b16835260018060a01b031660208301526040820152604051809381926311692f3760e31b83526020600484015260248301906130d8565b038173370d05c1f7e88312056bf2df462976219ca0fed45af49081156105a5576000916147d5575b5061ffff8816600052600080516020615a818339815191526020526040600020549383519385156147b95760005b8581106146dd5750505050505050927fe54e51e42099622516fa3b48e9733581c9dbdcb771cafb093f745a0532a35982949261ffff926146ae60c0966104416149cd565b906040519586526020860152604085015260608401521660808201526001600160401b03841660a0820152a190565b6001600160a01b036146ef8284612df0565b5116906146fc8187612df0565b5182600052600080516020615be183398151915260205261472860ff60406000205460101c1686612df0565b51833b156105b15761476e9361ffff8f936000948f8e906147808d6040519b8c998a988997634b5b050560e01b895216600488015260a0602488015260a4870190612e04565b85810360031901604487015290612ae2565b916064840152608483015203925af19182156105a5576147a5926147aa575b50612de1565b61466a565b6147b390612b07565b3861479f565b604051630ebc95af60e21b815261ffff8b166004820152602490fd5b6147f291503d806000833e6147ea8183612ba1565b8101906143ed565b3861463c565b61480d9192503d8086833e6147ea8183612ba1565b90386145c7565b61481d906143bb565b38614507565b6040516306a91e3760e51b815260048101889052346024820152604490fd5b6148589192503d806000833e6115e08183612ba1565b90386144e3565b6040516334e7b19560e11b8152600490fd5b84546001600160a01b031683526001948501948694506020909301920161444d565b92916148a1906104416149cd565b906000937f504e6efe18ab9eed10dc6501a417f5b12a2f7f2b1593aed9b89f9bce3cf29a918580a27f0000000000000000000000000000000000000000000000000000000000000000936002851015611e2f5784614936575060405163a9059cbb60e01b60208201526001600160a01b03909116602482015260448101919091529091506132d1906104de81606481016104d0565b9193600181036105b657507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb486001600160a01b031690813b15611619576040516340c10f1960e01b81526001600160a01b03919091166004820152602481019490945291929181908390604490829084905af19081156149c157506149b85750565b6132d190612b07565b604051903d90823e3d90fd5b600080604051602081019063313ce56760e01b8252600481526149ef81612b50565b51907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb485afa50614a1d6142f2565b6020818051810103126105b1576020612d0c9101612cbc565b6040516370a0823160e01b602082019081526001600160a01b039093166024808301919091528152600092839291614a6d81612b35565b51915afa50614a7a6142f2565b6020818051810103126105b1576020015190565b60ff1660ff81146117465760010190565b15614aa657565b634e487b7160e01b600052600160045260246000fd5b600080516020615ba18339815191525460ff8160081c16614aed600080516020615b61833981519152548214614a9f565b60005b818110614b7b575060005b818110614b14575050604060ff6132d192161115614a9f565b60018101808211611746575b828110614b365750614b3190612de1565b614afb565b614b7690614b71614b468461302f565b905490614b528461302f565b92909160018060a01b03809354600395861b1c16931b1c161415614a9f565b612de1565b614b20565b80614b71614b8b614ba29361302f565b905460039190911b1c6001600160a01b0316614ba7565b614af0565b6001600160a01b039081166000818152600080516020615be18339815191526020526040908190209051929190614bdd84612b35565b5460ff91614c19838316158015938488526020880197604087808460081c16159384158c5260101c1691019581875292614cd4575b5050614a9f565b600080516020615b4183398151915254946001600160401b0360019687868651161b1616151590511515916000968791600080516020615ba18339815191525497878960081c16935b848110614c96575b5050505050816132d196614c84869594614c8c9414614a9f565b151514614a9f565b5116911611614a9f565b8282614ca18361302f565b90549060031b1c1614614cbc57614cb790612de1565b614c62565b50919850849250839150614c849050826132d1614c6a565b90915081614ce5575b503880614c12565b90501538614cdd565b307f0000000000000000000000004d573bc8ce236be2609333206776c5b6fb8f4a106001600160a01b031614614d2057565b604051633c64f99360e21b8152600490fd5b600080516020615c4183398151915254336001600160a01b039182161415919082614d78575b5050614d6057565b60405163e2a08e5d60e01b8152336004820152602490fd5b1633141590503880614d58565b60405190614d9282612b35565b8160406001600160401b03600080516020615c61833981519152546001600160481b0380821685528160481c16602085015260901c16910152565b90604051614dda81612b35565b60406001600160401b038294546001600160481b0380821685528160481c16602085015260901c16910152565b90600160481b600160901b0382549160481b1690600160481b600160901b031916179055565b600080516020615c618339815191529081546001600160481b03908181166001600160401b036008918184841c16801580615020575b15614ed1575050855471ffffffffffffffffff0000000000000000001916604886901b600160481b600160901b03161786555050505b825479ffffffffffffffff000000000000000000ffffffffffffffffff19169116174260901b67ffffffffffffffff60901b16179055565b86614edd612a90614d85565b926000614eea8383615831565b15614fb65750614f099291614efe91615853565b8388861c16906157c8565b610100600160481b039290841b831660ff861617614f278184615831565b15614fa8578160ff9282614f3e614f4b9487615853565b871c169084871c166157c8565b9116921b16175b614f5c8482615831565b614f8657600160481b600160901b039060481b1690600160481b600160901b031916178355614e99565b604051631e74e8fb60e31b815290831660048201528383166024820152604490fd5b5050905060ff915016614f52565b9493959290614fc890614fd293615853565b8389841c166157c8565b9260ff881694838087610100600160481b038098871b1617614ff48185615853565b851c1691841c160192831161500c57501b1617614f52565b634e487b7160e01b81526011600452602490fd5b5060ff851615614e63565b919080546001600160481b03808216916001600160401b03926008908483831c168015806151e7575b156150ba57505050508461506c6132d1959685614e07565b835467ffffffffffffffff60901b19919092161679ffffffffffffffff000000000000000000ffffffffffffffffff1990911617429190911660901b67ffffffffffffffff60901b16179055565b8590896150c9612a908a614dcd565b9360006150d68383615831565b156151915750916150ee6150f99260ff979894615853565b838c881c16906157c8565b610100600160481b039490861b85169116176151158184615831565b156151835760ff918161512b6151389386615853565b861c168784871c166157c8565b9116921b16175b6151498682615831565b615161579461515c6132d1959685614e07565b61506c565b604051631e74e8fb60e31b815290821660048201529085166024820152604490fd5b5050905060ff91501661513f565b9496506151ac93506151a291615853565b868a851c166157c8565b9160ff891693868086610100600160481b038097861b16176151ce8185615853565b841c1691831c16019186831161500c57501b161761513f565b5060ff841615615054565b604051906151ff82612b35565b60006040838281528260208201520152565b6152196151f2565b50612d0c612a95612a90614d85565b6152306151f2565b506000527f4e8909a01183a67951f5a6147d6e76ed02ea890c72afea01a9edee91edc609b860205260406000206040519061526a82612b35565b80546001600160481b038116835260481c6001600160401b03166020830152600101546001600160a01b0316604082015290565b81156152a8570490565b634e487b7160e01b600052601260045260246000fd5b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000169182156153525761533f828260ff936040610100600160481b0396015116420381615323602085019889519383875160081c160261529e565b9160081c1601915160081c1680821060001461534b5750615369565b9251169160081b161790565b9050615369565b506020015160ff16610100600160481b0317919050565b6001600160401b039081811161537d571690565b60405162461bcd60e51b815260206004820152602660248201527f53616665436173743a2076616c756520646f65736e27742066697420696e203660448201526534206269747360d01b6064820152608490fd5b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000161561548d5761540a6151f2565b50600160481b600160901b03615421612a90614d85565b610100600160481b0360ff61545c600080516020615c61833981519152968088549761544d8188615853565b60081c16908560081c166157c8565b92169160081b161760481b16906001600160401b0360901b4260901b1690600160481b600160d01b03191617179055565b5050565b6001600160401b0390817f0000000000000000000000000000000000000000000000000000000000000000161561548d576154ca6151f2565b506154d6612a90614d85565b90600160481b600160901b03600080516020615c6183398151915293845493816001600160401b0360901b4260901b16946155118184615853565b60081c16828260081c160182811160001461559d5750610100600160481b0360ff61553b84615369565b92169160081b1617906001600160481b038516906155598284615853565b80856001600160401b0360901b1988161760081c16908360081c161060001461559657505b60481b1691600160481b600160d01b03191617179055565b905061557e565b60ff61553b610100600160481b0392615369565b6001600160401b03807f0000000000000000000000000000000000000000000000000000000000000000161561344457610100600160481b0360ff61566b61ffff6132d1966155fe6151f2565b50169384600052600080516020615bc183398151915280602052615628612a906040600020614dcd565b60009687526020919091526040909520805467ffffffffffffffff60901b191642831660901b67ffffffffffffffff60901b1617815595819061544d8188615853565b92169160081b161790614e07565b6001600160401b03807f000000000000000000000000000000000000000000000000000000000000000016156134445761ffff6132d1936156b86151f2565b5016600090808252600080516020615bc1833981519152806020526156e2612a9060408520614dcd565b91835260205260408220805467ffffffffffffffff60901b191642851660901b67ffffffffffffffff60901b1617815593839061571f8184615853565b60081c16838260081c160183811160001461578c5750610100600160481b0360ff61574985615369565b92169160081b1617918084546001600160481b0381169361576a8587615853565b5060081c16908360081c1610600014615784575090614e07565b905090614e07565b60ff615749610100600160481b0392615369565b9067ffffffffffffffff60481b82549160481b169067ffffffffffffffff60481b1916179055565b6001600160401b03918216908216039190821161174657565b60009182915b6001600160401b03908181168015615829576000190191821161581557169161580f90614a8e565b916157e7565b634e487b7160e01b85526011600452602485fd5b505050915090565b9061583c8183615853565b6001600160401b03809160081c169160081c161190565b60ff9182169116818103615865575050565b604051635ce6db6160e11b815260ff918216600482015291166024820152604490fd5b60ff811660081015612d0c5750600890565b9060ff8091169116039060ff821161174657565b60ff16604d811161174657600a0a90565b919060ff821660ff82168181146159135711156158f2576158e7612d0c93926158ec9261589a565b6158ae565b9061529e565b6158e7906158ff9261589a565b908181029181830414901517156117465790565b5050505090565b61594d61378e60ff92610100600160481b03949561593787615888565b90858116868316101561595857509586916158bf565b92169160081b161790565b90509586916158bf565b60ff7ff0c57e16840df040f15088dc2f81fe391c3923bec73e23a9662efc9c229c6a005460401c161561599157565b604051631afcd79f60e31b8152600490fd5b6001600160a01b039081169081156159fe57600080516020615b0183398151915280546001600160a01b031981168417909155167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3565b604051631e4fbdf760e01b815260006004820152602490fd5b600080516020615b01833981519152546001600160a01b03163303615a3857565b60405163118cdaa760e01b8152336004820152602490fd5b600080516020615c218339815191526002815414615a6e5760029055565b604051633ee5aeb560e01b8152600490fdfeebcc9f646b0f459ff8f387587d536b0af3484cf442e1577400f322334e7d1ef047028352a8b3feae1a85fba43bc13f990568bb1637dce33d3dbfd791a0808b7f6c3cb3f3ae91330f31ba2bc0ff8855fc834fb66dc27e8e0b1a398617dabaa5a668dfeeddfa5e4e9adceec01a3aba274bdcbab3f6ac9956417a4332f2b08abdda9016d09d72d40fdae2fd8ceac6b6234c7706214fd39c1cd1e609a0528c19930064bacf405c5d7f563d3ba5252584a52c37e4fee380fd825b10666c27b8258022fd6568c039679b3b7cc93c26c41d9379b7b1bec1677120493b467688302cb11f00758a264b9bdbe3295fe36bd6ff7abaa122f48bf70e90af04a1b8a32d21e4e1ad78307a8b51804c575f26039dcb87c58925afb3b7c08732f3b21b942aed7a768561949d1c6242cee5c5a5aeb6b9c190ee611d7742fcec65d9e5b1341ea04d89efb21dcaedea63b55c44882f329622e13a8d0f5b947b3a372826208a9003da1549bca747e973430e858f2f5de357b8dba36ea6d375b81bdb5d53dfaabf0b3a7f852fa0677fef8612c6c15b518c9fa56761e9ed15cfd5c6e5399e5467985ac7ed9b779b17422d0df92223018b32b4d1fa46e071723d6817e2486d003becc55f00bfa91572ce1e5fe8776a160d3b1f862e83f5ee2c080a7423b4761602a3ad12497c25289a27ec8c9be54d4a154cf80490d69bda989cdb8328232e08fea9220420a2646970667358221220ff24bb6218d11a60fad2e17b2c54e55dfe3f8155f61d7f10dfd1f2886b23efbc64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001
-----Decoded View---------------
Arg [0] : _token (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _mode (uint8): 0
Arg [2] : _chainId (uint16): 2
Arg [3] : _rateLimitDuration (uint64): 0
Arg [4] : _skipRateLimiting (bool): True
-----Encoded View---------------
5 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000001
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 26 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.