POL Price: $0.641829 (+3.90%)
 

Overview

Max Total Supply

200,000,010 GX

Holders

4 (0.00%)

Total Transfers

-

Market

Price

$0.00 @ 0.000000 POL

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

Grindery Wallet is a self-custodial EVM wallet integrated with Telegram, enabling gasless transactions and easy asset management. The Grindery X (GX) token enhances DeFi activities and user experience.

Contract Source Code Verified (Exact Match)

Contract Name:
CATERC20

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 800 runs

Other Settings:
default evmVersion
File 1 of 23 : CATERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC20/ERC20.sol";
import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

import "../interfaces/IWormholeReceiver.sol";
import "../interfaces/ICATERC20.sol";
import "./Governance.sol";
import "./Structs.sol";

contract CATERC20 is Context, ERC20, CATERC20Governance, CATERC20Events, ERC165, IWormholeReceiver {
    using SafeERC20 for IERC20;

    constructor(string memory name, string memory symbol, uint8 decimal) ERC20(name, symbol) {
        setEvmChainId(block.chainid);
        setDecimals(decimal);
    }

    function initialize(
        uint16 chainId,
        address wormhole,
        uint256 maxSupply
    ) public onlyOwner {
        require(isInitialized() == false, "Already Initialized");

        setChainId(chainId);
        setWormhole(wormhole);
        setMaxSupply(maxSupply);
        setMintedSupply(0);
        setIsInitialized();
    }

    function decimals() public view virtual override returns (uint8) {
        return getDecimals();
    }

    function supportsInterface(
        bytes4 interfaceId
    ) public view virtual override(ERC165) returns (bool) {
        return interfaceId == type(ICATERC20).interfaceId || super.supportsInterface(interfaceId);
    }

    /**
     * @dev To bridge tokens to other chains.
     */
    function bridgeOut(
        uint256 amount,
        uint16 recipientChain,
        bytes32 recipient,
        bytes32 tokenAddress
    ) external payable returns (uint64 sequence) {
        require(isInitialized() == true, "Not Initialized");
        require(evmChainId() == block.chainid, "unsupported fork");

        (uint256 cost, ) = wormhole().quoteEVMDeliveryPrice(recipientChain, 0, 300000);
        require(msg.value >= cost, "Insufficient wormhole gas");
        
        uint16 tokenChain = chainId();

        _burn(_msgSender(), amount);

        CATERC20Structs.CrossChainPayload memory transfer = CATERC20Structs.CrossChainPayload({
            amount: amount,
            tokenAddress: tokenAddress,
            tokenChain: tokenChain,
            toAddress: recipient,
            toChain: recipientChain,
            tokenDecimals: getDecimals()
        });

        sequence = wormhole().sendPayloadToEvm{value: cost}(
            recipientChain,
            bytesToAddress(tokenAddress),
            encodeTransfer(transfer),
            0,
            300000,
            chainId(),
            msg.sender
        );

        emit bridgeOutEvent(
            amount,
            tokenChain,
            recipientChain,
            addressToBytes(_msgSender()),
            recipient
        );
    } // end of function

    function bridgeIn(bytes memory encodedPayload, bytes32 deliveryHash) internal returns (bytes memory) {
        CATERC20Structs.CrossChainPayload memory transfer = decodeTransfer(encodedPayload);
        address transferRecipient = bytesToAddress(transfer.toAddress);

        require(!isTransferCompleted(deliveryHash), "transfer already completed");
        setTransferCompleted(deliveryHash);

        require(transfer.toChain == chainId(), "invalid target chain");

        uint256 nativeAmount = normalizeAmount(
            transfer.amount,
            transfer.tokenDecimals,
            getDecimals()
        );

        _mint(transferRecipient, nativeAmount);

        emit bridgeInEvent(nativeAmount, transfer.tokenChain, transfer.toChain, transfer.toAddress);

        return encodedPayload;
    }

    function receiveWormholeMessages(
        bytes memory payload,
        bytes[] memory,
        bytes32 srcAddress,
        uint16 srcChain,
        bytes32 deliveryHash
    ) external payable override {
        require(isInitialized() == true, "Not Initialized");
        require(evmChainId() == block.chainid, "unsupported fork");

        require(
            msg.sender == address(wormhole()),
            "Invalid Wormhole Relayer"
        );

        require(
            bytesToAddress(srcAddress) == address(this) ||
                tokenContracts(srcChain) == srcAddress,
            "Invalid Emitter"
        );

        bridgeIn(payload, deliveryHash);
    }

    /**
     * @dev To calculate the cross chain transfer fee.
     */
    function wormholeEstimatedFee(
        uint16 recipientChain
    ) public view returns (uint256) {
        require(isInitialized() == true, "Not Initialized");
        require(evmChainId() == block.chainid, "unsupported fork");

        (uint256 cost, ) = wormhole().quoteEVMDeliveryPrice(recipientChain, 0, 300000);
        return cost;
    }

    function mint(address recipient, uint256 amount) public onlyOwner {
        require(mintedSupply() + amount <= maxSupply(), "MAX SUPPLY REACHED");
        setMintedSupply(mintedSupply() + amount);
        _mint(recipient, amount);
    }
}

File 2 of 23 : ICATERC20.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

interface ICATERC20 {
    function initialize(
        uint16 chainId,
        address wormhole,
        uint8 finality,
        uint256 maxSupply
    ) external;

    /**
     * @dev To bridge tokens to other chains.
     */
    function bridgeOut(
        uint256 amount,
        uint16 recipientChain,
        bytes32 recipient,
        uint32 nonce
    ) external payable returns (uint64 sequence);

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

    function mint(address recipient, uint256 amount) external;
}

File 3 of 23 : IWormholeReceiver.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;


interface IWormholeReceiver {
    
    function receiveWormholeMessages(
        bytes memory payload,
        bytes[] memory additionalVaas,
        bytes32 sourceAddress,
        uint16 sourceChain,
        bytes32 deliveryHash
    ) external payable;
}

File 4 of 23 : Structs.sol
// contracts/Structs.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

contract CATERC20Structs {
    struct CrossChainPayload {
        // Amount being transferred (big-endian uint256)
        uint256 amount;
        // Address of the token. Left-zero-padded if shorter than 32 bytes
        bytes32 tokenAddress;
        // Chain ID of the token
        uint16 tokenChain;
        // Address of the recipient. Left-zero-padded if shorter than 32 bytes
        bytes32 toAddress;
        // Chain ID of the recipient
        uint16 toChain;
        // Token Decimals of sender chain
        uint8 tokenDecimals;
    }

    struct SignatureVerification {
        // Address of custodian the user has delegated to sign transaction on behalf of
        address custodian;
        // Timestamp the transaction will be valid till
        uint256 validTill;
        // Signed Signature
        bytes signature;
    }
}

File 5 of 23 : Governance.sol
// contracts/Bridge.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/access/Ownable.sol";

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

import "./Getters.sol";
import "./Setters.sol";
import "./Structs.sol";

import "../interfaces/IWormhole.sol";

contract CATERC20Governance is CATERC20Getters, CATERC20Setters, Ownable {
    /// builds a prefixed hash to mimic the behavior of eth_sign.
    function prefixed(bytes32 _hash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _hash));
    }

    /// signature methods.
    function splitSignature(
        bytes memory sig
    ) internal pure returns (uint8 v, bytes32 r, bytes32 s) {
        require(sig.length == 65);

        assembly {
            // first 32 bytes, after the length prefix.
            r := mload(add(sig, 32))
            // second 32 bytes.
            s := mload(add(sig, 64))
            // final byte (first byte of the next 32 bytes).
            v := byte(0, mload(add(sig, 96)))
        }

        return (v, r, s);
    }

    function verifySignature(
        bytes32 message,
        bytes memory signature,
        address authority
    ) internal pure returns (bool) {
        (uint8 v, bytes32 r, bytes32 s) = splitSignature(signature);
        address recovered = ecrecover(message, v, r, s);
        if (recovered == authority) {
            return true;
        } else {
            return false;
        }
    }

    /// @dev verify owner is caller or the caller has valid owner signature
    modifier onlyOwnerOrOwnerSignature(
        CATERC20Structs.SignatureVerification memory signatureArguments
    ) {
        if (_msgSender() == owner()) {
            _;
        } else {
            bytes32 encodedHashData = prefixed(
                keccak256(
                    abi.encodePacked(signatureArguments.custodian, signatureArguments.validTill)
                )
            );
            require(signatureArguments.custodian == _msgSender(), "custodian can call only");
            require(signatureArguments.validTill > block.timestamp, "signed transaction expired");
            require(
                isSignatureUsed(signatureArguments.signature) == false,
                "cannot re-use signatures"
            );
            setSignatureUsed(signatureArguments.signature);
            require(
                verifySignature(encodedHashData, signatureArguments.signature, owner()),
                "unauthorized signature"
            );
            _;
        }
    }

    // Execute a RegisterChain governance message
    function registerChain(
        uint16 chainId,
        bytes32 tokenContract,
        CATERC20Structs.SignatureVerification memory signatureArguments
    ) public onlyOwnerOrOwnerSignature(signatureArguments) {
        setTokenImplementation(chainId, tokenContract);
    }

    function registerChains(
        uint16[] memory chainId,
        bytes32[] memory tokenContract,
        CATERC20Structs.SignatureVerification memory signatureArguments
    ) public onlyOwnerOrOwnerSignature(signatureArguments) {
        require(chainId.length == tokenContract.length, "Invalid Input");
        for (uint256 i = 0; i < tokenContract.length; i++) {
            setTokenImplementation(chainId[i], tokenContract[i]);
        }
    }
}

File 6 of 23 : SafeERC20.sol
// 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");
        }
    }
}

File 7 of 23 : ERC20.sol
// 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 {}
}

File 8 of 23 : IERC20.sol
// 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);
}

File 9 of 23 : ERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)

pragma solidity ^0.8.0;

import "./IERC165.sol";

/**
 * @dev Implementation of the {IERC165} interface.
 *
 * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
 * for the additional interface id that will be supported. For example:
 *
 * ```solidity
 * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
 *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
 * }
 * ```
 *
 * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
 */
abstract contract ERC165 is IERC165 {
    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
        return interfaceId == type(IERC165).interfaceId;
    }
}

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

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

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

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

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

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

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

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

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

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

        return tempBytes;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

        bytes memory tempBytes;

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

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

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

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

                mstore(tempBytes, _length)

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

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

        return tempBytes;
    }

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

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

        return tempAddress;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempUint;
    }

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

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

        return tempBytes32;
    }

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

        assembly {
            let length := mload(_preBytes)

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

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

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

        return success;
    }

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

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

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

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

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

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

                        // the next line is the loop condition:
                        // while(uint256(mc < end) + cb == 2)
                        for {

                        } eq(add(lt(mc, end), cb), 2) {
                            sc := add(sc, 1)
                            mc := add(mc, 0x20)
                        } {
                            if iszero(eq(sload(sc), mload(mc))) {
                                // unsuccess:
                                success := 0
                                cb := 0
                            }
                        }
                    }
                }
            }
            default {
                // unsuccess:
                success := 0
            }
        }

        return success;
    }
}

File 11 of 23 : Setters.sol
// contracts/Setters.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "./State.sol";

contract CATERC20Setters is CATERC20State {
    function setTransferCompleted(bytes32 hash) internal {
        _state.completedTransfers[hash] = true;
    }

    function setTokenImplementation(uint16 chainId, bytes32 tokenContract) internal {
        _state.tokenImplementations[chainId] = tokenContract;
    }

    function setWormhole(address wh) internal {
        _state.wormhole = payable(wh);
    }

    function setChainId(uint16 chainId) internal {
        _state.provider.chainId = chainId;
    }

    function setEvmChainId(uint256 evmChainId) internal {
        require(evmChainId == block.chainid, "invalid evmChainId");
        _state.evmChainId = evmChainId;
    }

    function setDecimals(uint8 decimals) internal {
        _state.decimals = decimals;
    }

    function setMaxSupply(uint256 maxSupply) internal {
        _state.maxSupply = maxSupply;
    }

    function setMintedSupply(uint256 mintedSupply) internal {
        _state.mintedSupply = mintedSupply;
    }

    function setNativeAsset(address nativeAsset) internal {
        _state.nativeAsset = nativeAsset;
    }

    function setIsInitialized() internal {
        _state.isInitialized = true;
    }

    function setSignatureUsed(bytes memory signature) internal {
        _state.signaturesUsed[signature] = true;
    }
}

File 12 of 23 : Getters.sol
// contracts/Getters.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "../interfaces/IERC20Extended.sol";
import "../interfaces/IWormholeRelayer.sol";

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

contract CATERC20Getters is CATERC20State {
    using BytesLib for bytes;

    function isTransferCompleted(bytes32 hash) public view returns (bool) {
        return _state.completedTransfers[hash];
    }

    function wormhole() public view returns (IWormholeRelayer) {
        return IWormholeRelayer(_state.wormhole);
    }

    function chainId() public view returns (uint16) {
        return _state.provider.chainId;
    }

    function evmChainId() public view returns (uint256) {
        return _state.evmChainId;
    }

    function tokenContracts(uint16 chainId_) public view returns (bytes32) {
        return _state.tokenImplementations[chainId_];
    }

    function getDecimals() public view returns (uint8) {
        return _state.decimals;
    }

    function maxSupply() public view returns (uint256) {
        return _state.maxSupply;
    }

    function mintedSupply() public view returns (uint256) {
        return _state.mintedSupply;
    }

    function nativeAsset() public view returns (IERC20Extended) {
        return IERC20Extended(_state.nativeAsset);
    }

    function isInitialized() public view returns (bool) {
        return _state.isInitialized;
    }

    function isSignatureUsed(bytes memory signature) public view returns (bool) {
        return _state.signaturesUsed[signature];
    }

    function normalizeAmount(
        uint256 amount,
        uint8 foreignDecimals,
        uint8 localDecimals
    ) internal pure returns (uint256) {
        if (foreignDecimals > localDecimals) {
            amount /= 10 ** (foreignDecimals - localDecimals);
        }
        if (localDecimals > foreignDecimals) {
            amount *= 10 ** (localDecimals - foreignDecimals);
        }
        return amount;
    }

    /*
     * @dev Truncate a 32 byte array to a 20 byte address.
     *      Reverts if the array contains non-0 bytes in the first 12 bytes.
     *
     * @param bytes32 bytes The 32 byte array to be converted.
     */
    function bytesToAddress(bytes32 b) public pure returns (address) {
        require(bytes12(b) == 0, "invalid EVM address");
        return address(uint160(uint256(b)));
    }

    function addressToBytes(address a) public pure returns (bytes32) {
        return bytes32(uint256(uint160(a)));
    }

    function encodeTransfer(
        CATERC20Structs.CrossChainPayload memory transfer
    ) public pure returns (bytes memory encoded) {
        encoded = abi.encodePacked(
            transfer.amount,
            transfer.tokenAddress,
            transfer.tokenChain,
            transfer.toAddress,
            transfer.toChain,
            transfer.tokenDecimals
        );
    }

    function decodeTransfer(
        bytes memory encoded
    ) public pure returns (CATERC20Structs.CrossChainPayload memory transfer) {
        uint index = 0;

        transfer.amount = encoded.toUint256(index);
        index += 32;

        transfer.tokenAddress = encoded.toBytes32(index);
        index += 32;

        transfer.tokenChain = encoded.toUint16(index);
        index += 2;

        transfer.toAddress = encoded.toBytes32(index);
        index += 32;

        transfer.toChain = encoded.toUint16(index);
        index += 2;

        transfer.tokenDecimals = encoded.toUint8(index);
        index += 1;

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

File 13 of 23 : IWormhole.sol
// contracts/interfaces/IWormhole.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "../shared/WormholeStructs.sol";

interface IWormhole is WormholeStructs {
    event LogMessagePublished(
        address indexed sender,
        uint64 sequence,
        uint32 nonce,
        bytes payload,
        uint8 consistencyLevel
    );

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

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

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

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

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

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

    function getCurrentGuardianSetIndex() external view returns (uint32);

    function getGuardianSetExpiry() external view returns (uint32);

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

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

    function chainId() external view returns (uint16);

    function governanceChainId() external view returns (uint16);

    function governanceContract() external view returns (bytes32);

    function messageFee() external view returns (uint256);
}

File 14 of 23 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.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.
 *
 * By default, the owner account will be the one that deploys the contract. 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 Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @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) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @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 {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 15 of 23 : State.sol
// contracts/State.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

import "./Structs.sol";

contract CATERC20Events {
    event bridgeInEvent(
        uint256 tokenAmount,
        uint256 fromChain,
        uint256 toChain,
        bytes32 indexed toAddress
    );

    event bridgeOutEvent(
        uint256 tokenAmount,
        uint256 fromChain,
        uint256 toChain,
        bytes32 indexed fromAddress,
        bytes32 indexed toAddress
    );
}

contract CATERC20Storage {
    struct Provider {
        uint16 chainId;
    }

    struct State {
        Provider provider;
        address wormhole;
        // Mapping of consumed token transfers
        mapping(bytes32 => bool) completedTransfers;
        // Mapping of token contracts on other chains
        mapping(uint16 => bytes32) tokenImplementations;
        // EIP-155 Chain ID
        uint256 evmChainId;
        address nativeAsset;
        bool isInitialized;
        uint8 decimals;
        uint256 maxSupply;
        uint256 mintedSupply;
        // Mapping for storing used signatures
        mapping(bytes => bool) signaturesUsed;
    }
}

contract CATERC20State {
    CATERC20Storage.State _state;
}

File 16 of 23 : IERC20Extended.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

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

interface IERC20Extended is IERC20 {
    function decimals() external view returns (uint8);
}

File 17 of 23 : IWormholeRelayer.sol
// 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 VAAs)
 * 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;
}

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

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

/**
 * @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 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 Performs the same function as a `send`, except:
     * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
     * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
     * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
     *
     * The refund from the delivery currently in progress will not be sent to the user; it will instead
     * be paid to the delivery provider to perform the instruction specified here
     *
     * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain)
     * to relay a payload to the address `targetAddress` on chain `targetChain`
     * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue`
     *
     * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
     * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
     * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)]
     *
     * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
     *
     * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery.
     *
     * @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 gasLimit gas limit with which to call `targetAddress`.
     */
    function forwardPayloadToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        uint256 receiverValue,
        uint256 gasLimit
    ) external payable;

    /**
     * @notice Performs the same function as a `send`, except:
     * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
     * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
     * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
     *
     * The refund from the delivery currently in progress will not be sent to the user; it will instead
     * be paid to the delivery provider to perform the instruction specified here
     *
     * Publishes an instruction for the same delivery provider (or default, if the same one doesn't support the new target chain)
     * to relay a payload and VAAs specified by `vaaKeys` to the address `targetAddress` on chain `targetChain`
     * with gas limit `gasLimit` and with `msg.value` equal to `receiverValue`
     *
     * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
     * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
     * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f)]
     *
     * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
     *
     * Any refunds (from leftover gas) from this forward will be paid to the same refundChain and refundAddress specified for the current delivery.
     *
     * @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 gasLimit gas limit with which to call `targetAddress`.
     * @param vaaKeys Additional VAAs to pass in as parameter in call to `targetAddress`
     */
    function forwardVaasToEvm(
        uint16 targetChain,
        address targetAddress,
        bytes memory payload,
        uint256 receiverValue,
        uint256 gasLimit,
        VaaKey[] memory vaaKeys
    ) external payable;

    /**
     * @notice Performs the same function as a `send`, except:
     * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
     * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
     * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
     *
     * The refund from the delivery currently in progress will not be sent to the user; it will instead
     * be paid to the delivery provider to perform the instruction specified here
     *
     * 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 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
     *
     * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
     * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
     * >= sum_f [quoteEVMDeliveryPrice(targetChain_f, receiverValue_f, gasLimit_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f]
     *
     * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
     *
     * @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 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, 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
     */
    function forwardToEvm(
        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;

    /**
     * @notice Performs the same function as a `send`, except:
     * 1)  Can only be used during a delivery (i.e. in execution of `receiveWormholeMessages`)
     * 2)  Is paid for (along with any other calls to forward) by (any msg.value passed in) + (refund leftover from current delivery)
     * 3)  Only executes after `receiveWormholeMessages` is completed (and thus does not return a sequence number)
     *
     * The refund from the delivery currently in progress will not be sent to the user; it will instead
     * be paid to the delivery provider to perform the instruction specified here
     *
     * 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
     *
     * The following equation must be satisfied (sum_f indicates summing over all forwards requested in `receiveWormholeMessages`):
     * (refund amount from current execution of receiveWormholeMessages) + sum_f [msg.value_f]
     * >= sum_f [quoteDeliveryPrice(targetChain_f, receiverValue_f, encodedExecutionParameters_f, deliveryProviderAddress_f) + paymentForExtraReceiverValue_f]
     *
     * The difference between the two sides of the above inequality will be added to `paymentForExtraReceiverValue` of the first forward requested
     *
     * @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
     */
    function forward(
        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;

    /**
     * @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
     *         - newDeliveryProvider's `targetChainRefundPerGasUnused` >= old relay provider's `targetChainRefundPerGasUnused`
     */
    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
     */
    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
     */
    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,
        FORWARD_REQUEST_FAILURE,
        FORWARD_REQUEST_SUCCESS
    }

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

    /**
     * @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 and no forwards were requested
     *   - FORWARD_REQUEST_FAILURE, if the target contract doesn't revert, forwards were requested,
     *       but provided/leftover funds were not sufficient to cover them all
     *   - FORWARD_REQUEST_SUCCESS, if the target contract doesn't revert and all forwards are covered
     * @custom:member additionalStatusInfo:
     *   - If status is SUCCESS or FORWARD_REQUEST_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).
     *   - If status is FORWARD_REQUEST_FAILURE, this is also the revert data - the reason the forward failed.
     *     This will be either an encoded Cancelled, DeliveryProviderReverted, or DeliveryProviderPaymentFailed error
     * @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
     * @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();

//When calling `forward()` on the WormholeRelayer if no delivery is in progress
error NoDeliveryInProgress();
//When calling `delivery()` a second time even though a delivery is already in progress
error ReentrantDelivery(address msgSender, address lockedBy);
//When any other contract but the delivery target calls `forward()` on the WormholeRelayer while a
//  delivery is in progress
error ForwardRequestFromWrongAddress(address msgSender, address deliveryTarget);

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

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 VaaKeysLengthDoesNotMatchVaasLength(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);
error ForwardNotSufficientlyFunded(uint256 amountOfFunds, uint256 amountOfFundsNeeded);
//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);

File 18 of 23 : WormholeStructs.sol
// contracts/shared/WormholeStructs.sol
// SPDX-License-Identifier: Apache 2

pragma solidity ^0.8.0;

interface WormholeStructs {
    struct Provider {
        uint16 chainId;
        uint16 governanceChainId;
        bytes32 governanceContract;
    }

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

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

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

File 19 of 23 : Context.sol
// 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;
    }
}

File 20 of 23 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // Look for revert reason and bubble it up if present
        if (returndata.length > 0) {
            // The easiest way to bubble the revert reason is using memory via assembly
            /// @solidity memory-safe-assembly
            assembly {
                let returndata_size := mload(returndata)
                revert(add(32, returndata), returndata_size)
            }
        } else {
            revert(errorMessage);
        }
    }
}

File 21 of 23 : draft-IERC20Permit.sol
// 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);
}

File 22 of 23 : IERC20Metadata.sol
// 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);
}

File 23 of 23 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

Settings
{
  "metadata": {
    "bytecodeHash": "none",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 800
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"symbol","type":"string"},{"internalType":"uint8","name":"decimal","type":"uint8"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","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":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChain","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"toAddress","type":"bytes32"}],"name":"bridgeInEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"fromChain","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toChain","type":"uint256"},{"indexed":true,"internalType":"bytes32","name":"fromAddress","type":"bytes32"},{"indexed":true,"internalType":"bytes32","name":"toAddress","type":"bytes32"}],"name":"bridgeOutEvent","type":"event"},{"inputs":[{"internalType":"address","name":"a","type":"address"}],"name":"addressToBytes","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint16","name":"recipientChain","type":"uint16"},{"internalType":"bytes32","name":"recipient","type":"bytes32"},{"internalType":"bytes32","name":"tokenAddress","type":"bytes32"}],"name":"bridgeOut","outputs":[{"internalType":"uint64","name":"sequence","type":"uint64"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"b","type":"bytes32"}],"name":"bytesToAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"chainId","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"name":"decodeTransfer","outputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"tokenAddress","type":"bytes32"},{"internalType":"uint16","name":"tokenChain","type":"uint16"},{"internalType":"bytes32","name":"toAddress","type":"bytes32"},{"internalType":"uint16","name":"toChain","type":"uint16"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"}],"internalType":"struct CATERC20Structs.CrossChainPayload","name":"transfer","type":"tuple"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"subtractedValue","type":"uint256"}],"name":"decreaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes32","name":"tokenAddress","type":"bytes32"},{"internalType":"uint16","name":"tokenChain","type":"uint16"},{"internalType":"bytes32","name":"toAddress","type":"bytes32"},{"internalType":"uint16","name":"toChain","type":"uint16"},{"internalType":"uint8","name":"tokenDecimals","type":"uint8"}],"internalType":"struct CATERC20Structs.CrossChainPayload","name":"transfer","type":"tuple"}],"name":"encodeTransfer","outputs":[{"internalType":"bytes","name":"encoded","type":"bytes"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"evmChainId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getDecimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"addedValue","type":"uint256"}],"name":"increaseAllowance","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"address","name":"wormhole","type":"address"},{"internalType":"uint256","name":"maxSupply","type":"uint256"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"isInitialized","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"isSignatureUsed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"}],"name":"isTransferCompleted","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintedSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"nativeAsset","outputs":[{"internalType":"contract IERC20Extended","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes","name":"payload","type":"bytes"},{"internalType":"bytes[]","name":"","type":"bytes[]"},{"internalType":"bytes32","name":"srcAddress","type":"bytes32"},{"internalType":"uint16","name":"srcChain","type":"uint16"},{"internalType":"bytes32","name":"deliveryHash","type":"bytes32"}],"name":"receiveWormholeMessages","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId","type":"uint16"},{"internalType":"bytes32","name":"tokenContract","type":"bytes32"},{"components":[{"internalType":"address","name":"custodian","type":"address"},{"internalType":"uint256","name":"validTill","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CATERC20Structs.SignatureVerification","name":"signatureArguments","type":"tuple"}],"name":"registerChain","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16[]","name":"chainId","type":"uint16[]"},{"internalType":"bytes32[]","name":"tokenContract","type":"bytes32[]"},{"components":[{"internalType":"address","name":"custodian","type":"address"},{"internalType":"uint256","name":"validTill","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"internalType":"struct CATERC20Structs.SignatureVerification","name":"signatureArguments","type":"tuple"}],"name":"registerChains","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"chainId_","type":"uint16"}],"name":"tokenContracts","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"wormhole","outputs":[{"internalType":"contract IWormholeRelayer","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint16","name":"recipientChain","type":"uint16"}],"name":"wormholeEstimatedFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"}]

60806040523480156200001157600080fd5b50604051620031e6380380620031e68339810160408190526200003491620002c3565b8251839083906200004d90600c90602085019062000150565b5080516200006390600d90602084019062000150565b505050620000806200007a620000ac60201b60201c565b620000b0565b6200008b4662000102565b6005805460ff60a81b1916600160a81b60ff84160217905550505062000385565b3390565b600e80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b4681146200014b5760405162461bcd60e51b81526020600482015260126024820152711a5b9d985b1a5908195d9b50da185a5b925960721b604482015260640160405180910390fd5b600455565b8280546200015e9062000348565b90600052602060002090601f016020900481019282620001825760008555620001cd565b82601f106200019d57805160ff1916838001178555620001cd565b82800160010185558215620001cd579182015b82811115620001cd578251825591602001919060010190620001b0565b50620001db929150620001df565b5090565b5b80821115620001db5760008155600101620001e0565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200021e57600080fd5b81516001600160401b03808211156200023b576200023b620001f6565b604051601f8301601f19908116603f01168101908282118183101715620002665762000266620001f6565b816040528381526020925086838588010111156200028357600080fd5b600091505b83821015620002a7578582018301518183018401529082019062000288565b83821115620002b95760008385830101525b9695505050505050565b600080600060608486031215620002d957600080fd5b83516001600160401b0380821115620002f157600080fd5b620002ff878388016200020c565b945060208601519150808211156200031657600080fd5b5062000325868287016200020c565b925050604084015160ff811681146200033d57600080fd5b809150509250925092565b600181811c908216806200035d57607f821691505b602082108114156200037f57634e487b7160e01b600052602260045260246000fd5b50919050565b612e5180620003956000396000f3fe60806040526004361061026a5760003560e01c80637d557a3f11610153578063c1bd8cf9116100cb578063ded8454a1161007f578063f2fde38b11610064578063f2fde38b14610757578063f7ee999814610777578063f9b833e1146107a857600080fd5b8063ded8454a14610711578063f0141d841461073857600080fd5b8063d5abeb01116100b0578063d5abeb011461063d578063dc02f45614610652578063dd62ed3e146106cb57600080fd5b8063c1bd8cf914610608578063c599efdd1461061d57600080fd5b806395d89b4111610122578063a457c2d711610107578063a457c2d714610598578063a9059cbb146105b8578063aa4efa5b146105d857600080fd5b806395d89b41146105605780639a8a05921461057557600080fd5b80637d557a3f146104e457806384acd1bb14610504578063860369cc146105225780638da5cb5b1461054257600080fd5b806339509351116101e657806370a08231116101b5578063715018a61161019a578063715018a61461047157806373ee799b1461048657806374d32ad4146104b257600080fd5b806370a082311461041b578063711055a21461045157600080fd5b806339509351146103b357806340c10f19146103d3578063529dca32146103f357806364d42b171461040657600080fd5b806318160ddd1161023d5780632c5485f4116102225780632c5485f414610345578063313ce56714610367578063392e53cd1461039457600080fd5b806318160ddd1461030657806323b872dd1461032557600080fd5b806301ffc9a71461026f57806306fdde03146102a4578063095ea7b3146102c65780631150f0f3146102e6575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046124d3565b6107c8565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102b96107ff565b60405161029b9190612555565b3480156102d257600080fd5b5061028f6102e1366004612584565b610891565b3480156102f257600080fd5b5061028f610301366004612665565b6108a9565b34801561031257600080fd5b50600b545b60405190815260200161029b565b34801561033157600080fd5b5061028f6103403660046126a2565b6108d6565b34801561035157600080fd5b50610365610360366004612770565b6108fc565b005b34801561037357600080fd5b50600554600160a81b900460ff165b60405160ff909116815260200161029b565b3480156103a057600080fd5b50600554600160a01b900460ff1661028f565b3480156103bf57600080fd5b5061028f6103ce366004612584565b610b85565b3480156103df57600080fd5b506103656103ee366004612584565b610bc4565b6103656104013660046127eb565b610c5b565b34801561041257600080fd5b50600454610317565b34801561042757600080fd5b506103176104363660046128e6565b6001600160a01b031660009081526009602052604090205490565b34801561045d57600080fd5b5061036561046c366004612901565b610de4565b34801561047d57600080fd5b50610365610eca565b61049961049436600461291f565b610ede565b60405167ffffffffffffffff909116815260200161029b565b3480156104be57600080fd5b506005546001600160a01b03165b6040516001600160a01b03909116815260200161029b565b3480156104f057600080fd5b506103656104ff3660046129c0565b6111c6565b34801561051057600080fd5b506001546001600160a01b03166104cc565b34801561052e57600080fd5b506102b961053d366004612a9a565b6114ed565b34801561054e57600080fd5b50600e546001600160a01b03166104cc565b34801561056c57600080fd5b506102b96115ad565b34801561058157600080fd5b5060005460405161ffff909116815260200161029b565b3480156105a457600080fd5b5061028f6105b3366004612584565b6115bc565b3480156105c457600080fd5b5061028f6105d3366004612584565b611671565b3480156105e457600080fd5b5061028f6105f3366004612b2e565b60009081526002602052604090205460ff1690565b34801561061457600080fd5b50600754610317565b34801561062957600080fd5b506104cc610638366004612b2e565b61167f565b34801561064957600080fd5b50600654610317565b34801561065e57600080fd5b5061067261066d366004612665565b6116ea565b60405161029b9190600060c0820190508251825260208301516020830152604083015161ffff808216604085015260608501516060850152806080860151166080850152505060ff60a08401511660a083015292915050565b3480156106d757600080fd5b506103176106e6366004612b47565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205490565b34801561071d57600080fd5b5061031761072c3660046128e6565b6001600160a01b031690565b34801561074457600080fd5b50600554600160a81b900460ff16610382565b34801561076357600080fd5b506103656107723660046128e6565b611825565b34801561078357600080fd5b50610317610792366004612b7a565b61ffff1660009081526003602052604090205490565b3480156107b457600080fd5b506103176107c3366004612b7a565b6118b5565b60006001600160e01b0319821663adf0604b60e01b14806107f957506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600c805461080e90612b95565b80601f016020809104026020016040519081016040528092919081815260200182805461083a90612b95565b80156108875780601f1061085c57610100808354040283529160200191610887565b820191906000526020600020905b81548152906001019060200180831161086a57829003601f168201915b5050505050905090565b60003361089f8185856119eb565b5060019392505050565b600080600801826040516108bd9190612bca565b9081526040519081900360200190205460ff1692915050565b6000336108e4858285611b0f565b6108ef858585611b9b565b60019150505b9392505050565b8061090f600e546001600160a01b031690565b6001600160a01b0316336001600160a01b031614156109435761ffff84166000908152600360205260409020839055610b7f565b60006109e08260000151836020015160405160200161098092919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b82519091506001600160a01b03163314610a415760405162461bcd60e51b815260206004820152601760248201527f637573746f6469616e2063616e2063616c6c206f6e6c7900000000000000000060448201526064015b60405180910390fd5b42826020015111610a945760405162461bcd60e51b815260206004820152601a60248201527f7369676e6564207472616e73616374696f6e20657870697265640000000000006044820152606401610a38565b610aa182604001516108a9565b15610aee5760405162461bcd60e51b815260206004820152601860248201527f63616e6e6f742072652d757365207369676e61747572657300000000000000006044820152606401610a38565b610afb8260400151611d75565b610b1b818360400151610b16600e546001600160a01b031690565b611dad565b610b675760405162461bcd60e51b815260206004820152601660248201527f756e617574686f72697a6564207369676e6174757265000000000000000000006044820152606401610a38565b61ffff85166000908152600360205260409020849055505b50505050565b336000818152600a602090815260408083206001600160a01b038716845290915281205490919061089f9082908690610bbf908790612bfc565b6119eb565b610bcc611e62565b60065481610bd960075490565b610be39190612bfc565b1115610c315760405162461bcd60e51b815260206004820152601260248201527f4d415820535550504c59205245414348454400000000000000000000000000006044820152606401610a38565b610c4d81610c3e60075490565b610c489190612bfc565b600755565b610c578282611ebc565b5050565b600554600160a01b900460ff161515600114610cab5760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b46610cb560045490565b14610cf55760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b6001546001600160a01b03163314610d4f5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420576f726d686f6c652052656c6179657200000000000000006044820152606401610a38565b30610d598461167f565b6001600160a01b03161480610d86575082610d848361ffff1660009081526003602052604090205490565b145b610dd25760405162461bcd60e51b815260206004820152600f60248201527f496e76616c696420456d697474657200000000000000000000000000000000006044820152606401610a38565b610ddc8582611f7d565b505050505050565b610dec611e62565b600554600160a01b900460ff1615610e465760405162461bcd60e51b815260206004820152601360248201527f416c726561647920496e697469616c697a6564000000000000000000000000006044820152606401610a38565b6000805461ffff191661ffff85161790556001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055610e8881600655565b610e926000600755565b610ec5600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b179055565b505050565b610ed2611e62565b610edc6000612118565b565b600554600090600160a01b900460ff161515600114610f315760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b46610f3b60045490565b14610f7b5760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b6000610f8f6001546001600160a01b031690565b60405163c23ee3c360e01b815261ffff8716600482015260006024820152620493e060448201526001600160a01b03919091169063c23ee3c3906064016040805180830381865afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190612c14565b5090508034101561105f5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420776f726d686f6c6520676173000000000000006044820152606401610a38565b60005461ffff166110703388612177565b60006040518060c001604052808981526020018681526020018361ffff1681526020018781526020018861ffff1681526020016110b760055460ff600160a81b9091041690565b60ff16905290506110d06001546001600160a01b031690565b6001600160a01b0316634b5ca6f484896110e98961167f565b6110f2866114ed565b6000620493e061110560005461ffff1690565b336040518963ffffffff1660e01b81526004016111289796959493929190612c38565b60206040518083038185885af1158015611146573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061116b9190612c92565b9350856111773361072c565b604080518b815261ffff86811660208301528b168183015290517fce2636d514abb08349f7cf4369885a4ac22355555ff0e1c6f99afc895a77f3669181900360600190a3505050949350505050565b806111d9600e546001600160a01b031690565b6001600160a01b0316336001600160a01b031614156112a55782518451146112335760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b6044820152606401610a38565b60005b835181101561129f5761128d85828151811061125457611254612cbc565b602002602001015185838151811061126e5761126e612cbc565b602002602001015161ffff909116600090815260036020526040902055565b8061129781612cd2565b915050611236565b50610b7f565b60006112e28260000151836020015160405160200161098092919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b82519091506001600160a01b0316331461133e5760405162461bcd60e51b815260206004820152601760248201527f637573746f6469616e2063616e2063616c6c206f6e6c790000000000000000006044820152606401610a38565b428260200151116113915760405162461bcd60e51b815260206004820152601a60248201527f7369676e6564207472616e73616374696f6e20657870697265640000000000006044820152606401610a38565b61139e82604001516108a9565b156113eb5760405162461bcd60e51b815260206004820152601860248201527f63616e6e6f742072652d757365207369676e61747572657300000000000000006044820152606401610a38565b6113f88260400151611d75565b611413818360400151610b16600e546001600160a01b031690565b61145f5760405162461bcd60e51b815260206004820152601660248201527f756e617574686f72697a6564207369676e6174757265000000000000000000006044820152606401610a38565b83518551146114a05760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b6044820152606401610a38565b60005b8451811015610ddc576114db8682815181106114c1576114c1612cbc565b602002602001015186838151811061126e5761126e612cbc565b806114e581612cd2565b9150506114a3565b6060816000015182602001518360400151846060015185608001518660a0015160405160200161159796959493929190958652602086019490945260f092831b7fffff0000000000000000000000000000000000000000000000000000000000009081166040870152604286019290925290911b16606283015260f81b7fff0000000000000000000000000000000000000000000000000000000000000016606482015260650190565b6040516020818303038152906040529050919050565b6060600d805461080e90612b95565b336000818152600a602090815260408083206001600160a01b0387168452909152812054909190838110156116595760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610a38565b61166682868684036119eb565b506001949350505050565b60003361089f818585611b9b565b600073ffffffffffffffffffffffffffffffffffffffff198216156116e65760405162461bcd60e51b815260206004820152601360248201527f696e76616c69642045564d2061646472657373000000000000000000000000006044820152606401610a38565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529061172683826122ab565b8252611733602082612bfc565b905061173f8382612311565b6020808401919091526117529082612bfc565b905061175e838261236e565b61ffff166040830152611772600282612bfc565b905061177e8382612311565b606083015261178e602082612bfc565b905061179a838261236e565b61ffff1660808301526117ae600282612bfc565b90506117ba83826123d4565b60ff1660a08301526117cd600182612bfc565b90508083511461181f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964205472616e73666572000000000000000000000000000000006044820152606401610a38565b50919050565b61182d611e62565b6001600160a01b0381166118a95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a38565b6118b281612118565b50565b600554600090600160a01b900460ff1615156001146119085760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b4661191260045490565b146119525760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b60006119666001546001600160a01b031690565b60405163c23ee3c360e01b815261ffff8516600482015260006024820152620493e060448201526001600160a01b03919091169063c23ee3c3906064016040805180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612c14565b509392505050565b6001600160a01b038316611a4d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a38565b6001600160a01b038216611aae5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a38565b6001600160a01b038381166000818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b038381166000908152600a60209081526040808320938616835292905220546000198114610b7f5781811015611b8e5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a38565b610b7f84848484036119eb565b6001600160a01b038316611c175760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a38565b6001600160a01b038216611c795760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a38565b6001600160a01b03831660009081526009602052604090205481811015611d085760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610a38565b6001600160a01b0380851660008181526009602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611d689086815260200190565b60405180910390a3610b7f565b6001600060080182604051611d8a9190612bca565b908152604051908190036020019020805491151560ff1990921691909117905550565b600080600080611dbc8661243a565b925092509250600060018885858560405160008152602001604052604051611e00949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611e22573d6000803e3d6000fd5b505050602060405103519050856001600160a01b0316816001600160a01b03161415611e555760019450505050506108f5565b60009450505050506108f5565b600e546001600160a01b03163314610edc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a38565b6001600160a01b038216611f125760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a38565b80600b6000828254611f249190612bfc565b90915550506001600160a01b0382166000818152600960209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60606000611f8a846116ea565b90506000611f9b826060015161167f565b60008581526002602052604090205490915060ff1615611ffd5760405162461bcd60e51b815260206004820152601a60248201527f7472616e7366657220616c726561647920636f6d706c657465640000000000006044820152606401610a38565b61201c846000908152600260205260409020805460ff19166001179055565b60005461ffff1661ffff16826080015161ffff161461207d5760405162461bcd60e51b815260206004820152601460248201527f696e76616c69642074617267657420636861696e0000000000000000000000006044820152606401610a38565b60006120a583600001518460a001516120a060055460ff600160a81b9091041690565b612469565b90506120b18282611ebc565b82606001517fdf5e04c9235e5b4ddaec2baee15dc9c74de339075fa433a8dd25ebbc0719857b82856040015186608001516040516121069392919092835261ffff918216602084015216604082015260600190565b60405180910390a25093949350505050565b600e80546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166121d75760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a38565b6001600160a01b0382166000908152600960205260409020548181101561224b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a38565b6001600160a01b03831660008181526009602090815260408083208686039055600b80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60006122b8826020612bfc565b835110156123085760405162461bcd60e51b815260206004820152601560248201527f746f55696e743235365f6f75744f66426f756e647300000000000000000000006044820152606401610a38565b50016020015190565b600061231e826020612bfc565b835110156123085760405162461bcd60e51b815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e647300000000000000000000006044820152606401610a38565b600061237b826002612bfc565b835110156123cb5760405162461bcd60e51b815260206004820152601460248201527f746f55696e7431365f6f75744f66426f756e64730000000000000000000000006044820152606401610a38565b50016002015190565b60006123e1826001612bfc565b835110156124315760405162461bcd60e51b815260206004820152601360248201527f746f55696e74385f6f75744f66426f756e6473000000000000000000000000006044820152606401610a38565b50016001015190565b6000806000835160411461244d57600080fd5b5050506020810151604082015160609092015160001a92909190565b60008160ff168360ff16111561249b576124838284612ced565b61248e90600a612df4565b6124989085612e03565b93505b8260ff168260ff1611156124cb576124b38383612ced565b6124be90600a612df4565b6124c89085612e25565b93505b509192915050565b6000602082840312156124e557600080fd5b81356001600160e01b0319811681146108f557600080fd5b60005b83811015612518578181015183820152602001612500565b83811115610b7f5750506000910152565b600081518084526125418160208601602086016124fd565b601f01601f19169290920160200192915050565b6020815260006108f56020830184612529565b80356001600160a01b038116811461257f57600080fd5b919050565b6000806040838503121561259757600080fd5b6125a083612568565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156125ed576125ed6125ae565b604052919050565b600082601f83011261260657600080fd5b813567ffffffffffffffff811115612620576126206125ae565b612633601f8201601f19166020016125c4565b81815284602083860101111561264857600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561267757600080fd5b813567ffffffffffffffff81111561268e57600080fd5b61269a848285016125f5565b949350505050565b6000806000606084860312156126b757600080fd5b6126c084612568565b92506126ce60208501612568565b9150604084013590509250925092565b803561ffff8116811461257f57600080fd5b60006060828403121561270257600080fd5b6040516060810167ffffffffffffffff8282108183111715612726576127266125ae565b8160405282935061273685612568565b835260208501356020840152604085013591508082111561275657600080fd5b50612763858286016125f5565b6040830152505092915050565b60008060006060848603121561278557600080fd5b61278e846126de565b925060208401359150604084013567ffffffffffffffff8111156127b157600080fd5b6127bd868287016126f0565b9150509250925092565b600067ffffffffffffffff8211156127e1576127e16125ae565b5060051b60200190565b600080600080600060a0868803121561280357600080fd5b853567ffffffffffffffff8082111561281b57600080fd5b61282789838a016125f5565b965060209150818801358181111561283e57600080fd5b8801601f81018a1361284f57600080fd5b803561286261285d826127c7565b6125c4565b81815260059190911b8201840190848101908c83111561288157600080fd5b8584015b838110156128b95780358681111561289d5760008081fd5b6128ab8f89838901016125f5565b845250918601918601612885565b509850505050604088013594506128d5915050606087016126de565b949793965091946080013592915050565b6000602082840312156128f857600080fd5b6108f582612568565b60008060006060848603121561291657600080fd5b6126c0846126de565b6000806000806080858703121561293557600080fd5b84359350612945602086016126de565b93969395505050506040820135916060013590565b600082601f83011261296b57600080fd5b8135602061297b61285d836127c7565b82815260059290921b8401810191818101908684111561299a57600080fd5b8286015b848110156129b5578035835291830191830161299e565b509695505050505050565b6000806000606084860312156129d557600080fd5b833567ffffffffffffffff808211156129ed57600080fd5b818601915086601f830112612a0157600080fd5b81356020612a1161285d836127c7565b82815260059290921b8401810191818101908a841115612a3057600080fd5b948201945b83861015612a5557612a46866126de565b82529482019490820190612a35565b97505087013592505080821115612a6b57600080fd5b612a778783880161295a565b93506040860135915080821115612a8d57600080fd5b506127bd868287016126f0565b600060c08284031215612aac57600080fd5b60405160c0810181811067ffffffffffffffff82111715612acf57612acf6125ae565b80604052508235815260208301356020820152612aee604084016126de565b604082015260608301356060820152612b09608084016126de565b608082015260a083013560ff81168114612b2257600080fd5b60a08201529392505050565b600060208284031215612b4057600080fd5b5035919050565b60008060408385031215612b5a57600080fd5b612b6383612568565b9150612b7160208401612568565b90509250929050565b600060208284031215612b8c57600080fd5b6108f5826126de565b600181811c90821680612ba957607f821691505b6020821081141561181f57634e487b7160e01b600052602260045260246000fd5b60008251612bdc8184602087016124fd565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612c0f57612c0f612be6565b500190565b60008060408385031215612c2757600080fd5b505080516020909101519092909150565b600061ffff808a1683526001600160a01b03808a16602085015260e06040850152612c6660e085018a612529565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b600060208284031215612ca457600080fd5b815167ffffffffffffffff811681146108f557600080fd5b634e487b7160e01b600052603260045260246000fd5b6000600019821415612ce657612ce6612be6565b5060010190565b600060ff821660ff841680821015612d0757612d07612be6565b90039392505050565b600181815b80851115612d4b578160001904821115612d3157612d31612be6565b80851615612d3e57918102915b93841c9390800290612d15565b509250929050565b600082612d62575060016107f9565b81612d6f575060006107f9565b8160018114612d855760028114612d8f57612dab565b60019150506107f9565b60ff841115612da057612da0612be6565b50506001821b6107f9565b5060208310610133831016604e8410600b8410161715612dce575081810a6107f9565b612dd88383612d10565b8060001904821115612dec57612dec612be6565b029392505050565b60006108f560ff841683612d53565b600082612e2057634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615612e3f57612e3f612be6565b50029056fea164736f6c634300080a000a000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a4772696e6465727920580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024758000000000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x60806040526004361061026a5760003560e01c80637d557a3f11610153578063c1bd8cf9116100cb578063ded8454a1161007f578063f2fde38b11610064578063f2fde38b14610757578063f7ee999814610777578063f9b833e1146107a857600080fd5b8063ded8454a14610711578063f0141d841461073857600080fd5b8063d5abeb01116100b0578063d5abeb011461063d578063dc02f45614610652578063dd62ed3e146106cb57600080fd5b8063c1bd8cf914610608578063c599efdd1461061d57600080fd5b806395d89b4111610122578063a457c2d711610107578063a457c2d714610598578063a9059cbb146105b8578063aa4efa5b146105d857600080fd5b806395d89b41146105605780639a8a05921461057557600080fd5b80637d557a3f146104e457806384acd1bb14610504578063860369cc146105225780638da5cb5b1461054257600080fd5b806339509351116101e657806370a08231116101b5578063715018a61161019a578063715018a61461047157806373ee799b1461048657806374d32ad4146104b257600080fd5b806370a082311461041b578063711055a21461045157600080fd5b806339509351146103b357806340c10f19146103d3578063529dca32146103f357806364d42b171461040657600080fd5b806318160ddd1161023d5780632c5485f4116102225780632c5485f414610345578063313ce56714610367578063392e53cd1461039457600080fd5b806318160ddd1461030657806323b872dd1461032557600080fd5b806301ffc9a71461026f57806306fdde03146102a4578063095ea7b3146102c65780631150f0f3146102e6575b600080fd5b34801561027b57600080fd5b5061028f61028a3660046124d3565b6107c8565b60405190151581526020015b60405180910390f35b3480156102b057600080fd5b506102b96107ff565b60405161029b9190612555565b3480156102d257600080fd5b5061028f6102e1366004612584565b610891565b3480156102f257600080fd5b5061028f610301366004612665565b6108a9565b34801561031257600080fd5b50600b545b60405190815260200161029b565b34801561033157600080fd5b5061028f6103403660046126a2565b6108d6565b34801561035157600080fd5b50610365610360366004612770565b6108fc565b005b34801561037357600080fd5b50600554600160a81b900460ff165b60405160ff909116815260200161029b565b3480156103a057600080fd5b50600554600160a01b900460ff1661028f565b3480156103bf57600080fd5b5061028f6103ce366004612584565b610b85565b3480156103df57600080fd5b506103656103ee366004612584565b610bc4565b6103656104013660046127eb565b610c5b565b34801561041257600080fd5b50600454610317565b34801561042757600080fd5b506103176104363660046128e6565b6001600160a01b031660009081526009602052604090205490565b34801561045d57600080fd5b5061036561046c366004612901565b610de4565b34801561047d57600080fd5b50610365610eca565b61049961049436600461291f565b610ede565b60405167ffffffffffffffff909116815260200161029b565b3480156104be57600080fd5b506005546001600160a01b03165b6040516001600160a01b03909116815260200161029b565b3480156104f057600080fd5b506103656104ff3660046129c0565b6111c6565b34801561051057600080fd5b506001546001600160a01b03166104cc565b34801561052e57600080fd5b506102b961053d366004612a9a565b6114ed565b34801561054e57600080fd5b50600e546001600160a01b03166104cc565b34801561056c57600080fd5b506102b96115ad565b34801561058157600080fd5b5060005460405161ffff909116815260200161029b565b3480156105a457600080fd5b5061028f6105b3366004612584565b6115bc565b3480156105c457600080fd5b5061028f6105d3366004612584565b611671565b3480156105e457600080fd5b5061028f6105f3366004612b2e565b60009081526002602052604090205460ff1690565b34801561061457600080fd5b50600754610317565b34801561062957600080fd5b506104cc610638366004612b2e565b61167f565b34801561064957600080fd5b50600654610317565b34801561065e57600080fd5b5061067261066d366004612665565b6116ea565b60405161029b9190600060c0820190508251825260208301516020830152604083015161ffff808216604085015260608501516060850152806080860151166080850152505060ff60a08401511660a083015292915050565b3480156106d757600080fd5b506103176106e6366004612b47565b6001600160a01b039182166000908152600a6020908152604080832093909416825291909152205490565b34801561071d57600080fd5b5061031761072c3660046128e6565b6001600160a01b031690565b34801561074457600080fd5b50600554600160a81b900460ff16610382565b34801561076357600080fd5b506103656107723660046128e6565b611825565b34801561078357600080fd5b50610317610792366004612b7a565b61ffff1660009081526003602052604090205490565b3480156107b457600080fd5b506103176107c3366004612b7a565b6118b5565b60006001600160e01b0319821663adf0604b60e01b14806107f957506301ffc9a760e01b6001600160e01b03198316145b92915050565b6060600c805461080e90612b95565b80601f016020809104026020016040519081016040528092919081815260200182805461083a90612b95565b80156108875780601f1061085c57610100808354040283529160200191610887565b820191906000526020600020905b81548152906001019060200180831161086a57829003601f168201915b5050505050905090565b60003361089f8185856119eb565b5060019392505050565b600080600801826040516108bd9190612bca565b9081526040519081900360200190205460ff1692915050565b6000336108e4858285611b0f565b6108ef858585611b9b565b60019150505b9392505050565b8061090f600e546001600160a01b031690565b6001600160a01b0316336001600160a01b031614156109435761ffff84166000908152600360205260409020839055610b7f565b60006109e08260000151836020015160405160200161098092919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b60408051601f1981840301815282825280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000084830152603c8085019190915282518085039091018152605c909301909152815191012090565b82519091506001600160a01b03163314610a415760405162461bcd60e51b815260206004820152601760248201527f637573746f6469616e2063616e2063616c6c206f6e6c7900000000000000000060448201526064015b60405180910390fd5b42826020015111610a945760405162461bcd60e51b815260206004820152601a60248201527f7369676e6564207472616e73616374696f6e20657870697265640000000000006044820152606401610a38565b610aa182604001516108a9565b15610aee5760405162461bcd60e51b815260206004820152601860248201527f63616e6e6f742072652d757365207369676e61747572657300000000000000006044820152606401610a38565b610afb8260400151611d75565b610b1b818360400151610b16600e546001600160a01b031690565b611dad565b610b675760405162461bcd60e51b815260206004820152601660248201527f756e617574686f72697a6564207369676e6174757265000000000000000000006044820152606401610a38565b61ffff85166000908152600360205260409020849055505b50505050565b336000818152600a602090815260408083206001600160a01b038716845290915281205490919061089f9082908690610bbf908790612bfc565b6119eb565b610bcc611e62565b60065481610bd960075490565b610be39190612bfc565b1115610c315760405162461bcd60e51b815260206004820152601260248201527f4d415820535550504c59205245414348454400000000000000000000000000006044820152606401610a38565b610c4d81610c3e60075490565b610c489190612bfc565b600755565b610c578282611ebc565b5050565b600554600160a01b900460ff161515600114610cab5760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b46610cb560045490565b14610cf55760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b6001546001600160a01b03163314610d4f5760405162461bcd60e51b815260206004820152601860248201527f496e76616c696420576f726d686f6c652052656c6179657200000000000000006044820152606401610a38565b30610d598461167f565b6001600160a01b03161480610d86575082610d848361ffff1660009081526003602052604090205490565b145b610dd25760405162461bcd60e51b815260206004820152600f60248201527f496e76616c696420456d697474657200000000000000000000000000000000006044820152606401610a38565b610ddc8582611f7d565b505050505050565b610dec611e62565b600554600160a01b900460ff1615610e465760405162461bcd60e51b815260206004820152601360248201527f416c726561647920496e697469616c697a6564000000000000000000000000006044820152606401610a38565b6000805461ffff191661ffff85161790556001805473ffffffffffffffffffffffffffffffffffffffff19166001600160a01b038416179055610e8881600655565b610e926000600755565b610ec5600580547fffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff16600160a01b179055565b505050565b610ed2611e62565b610edc6000612118565b565b600554600090600160a01b900460ff161515600114610f315760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b46610f3b60045490565b14610f7b5760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b6000610f8f6001546001600160a01b031690565b60405163c23ee3c360e01b815261ffff8716600482015260006024820152620493e060448201526001600160a01b03919091169063c23ee3c3906064016040805180830381865afa158015610fe8573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061100c9190612c14565b5090508034101561105f5760405162461bcd60e51b815260206004820152601960248201527f496e73756666696369656e7420776f726d686f6c6520676173000000000000006044820152606401610a38565b60005461ffff166110703388612177565b60006040518060c001604052808981526020018681526020018361ffff1681526020018781526020018861ffff1681526020016110b760055460ff600160a81b9091041690565b60ff16905290506110d06001546001600160a01b031690565b6001600160a01b0316634b5ca6f484896110e98961167f565b6110f2866114ed565b6000620493e061110560005461ffff1690565b336040518963ffffffff1660e01b81526004016111289796959493929190612c38565b60206040518083038185885af1158015611146573d6000803e3d6000fd5b50505050506040513d601f19601f8201168201806040525081019061116b9190612c92565b9350856111773361072c565b604080518b815261ffff86811660208301528b168183015290517fce2636d514abb08349f7cf4369885a4ac22355555ff0e1c6f99afc895a77f3669181900360600190a3505050949350505050565b806111d9600e546001600160a01b031690565b6001600160a01b0316336001600160a01b031614156112a55782518451146112335760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b6044820152606401610a38565b60005b835181101561129f5761128d85828151811061125457611254612cbc565b602002602001015185838151811061126e5761126e612cbc565b602002602001015161ffff909116600090815260036020526040902055565b8061129781612cd2565b915050611236565b50610b7f565b60006112e28260000151836020015160405160200161098092919060609290921b6bffffffffffffffffffffffff19168252601482015260340190565b82519091506001600160a01b0316331461133e5760405162461bcd60e51b815260206004820152601760248201527f637573746f6469616e2063616e2063616c6c206f6e6c790000000000000000006044820152606401610a38565b428260200151116113915760405162461bcd60e51b815260206004820152601a60248201527f7369676e6564207472616e73616374696f6e20657870697265640000000000006044820152606401610a38565b61139e82604001516108a9565b156113eb5760405162461bcd60e51b815260206004820152601860248201527f63616e6e6f742072652d757365207369676e61747572657300000000000000006044820152606401610a38565b6113f88260400151611d75565b611413818360400151610b16600e546001600160a01b031690565b61145f5760405162461bcd60e51b815260206004820152601660248201527f756e617574686f72697a6564207369676e6174757265000000000000000000006044820152606401610a38565b83518551146114a05760405162461bcd60e51b815260206004820152600d60248201526c125b9d985b1a5908125b9c1d5d609a1b6044820152606401610a38565b60005b8451811015610ddc576114db8682815181106114c1576114c1612cbc565b602002602001015186838151811061126e5761126e612cbc565b806114e581612cd2565b9150506114a3565b6060816000015182602001518360400151846060015185608001518660a0015160405160200161159796959493929190958652602086019490945260f092831b7fffff0000000000000000000000000000000000000000000000000000000000009081166040870152604286019290925290911b16606283015260f81b7fff0000000000000000000000000000000000000000000000000000000000000016606482015260650190565b6040516020818303038152906040529050919050565b6060600d805461080e90612b95565b336000818152600a602090815260408083206001600160a01b0387168452909152812054909190838110156116595760405162461bcd60e51b815260206004820152602560248201527f45524332303a2064656372656173656420616c6c6f77616e63652062656c6f7760448201527f207a65726f0000000000000000000000000000000000000000000000000000006064820152608401610a38565b61166682868684036119eb565b506001949350505050565b60003361089f818585611b9b565b600073ffffffffffffffffffffffffffffffffffffffff198216156116e65760405162461bcd60e51b815260206004820152601360248201527f696e76616c69642045564d2061646472657373000000000000000000000000006044820152606401610a38565b5090565b6040805160c081018252600080825260208201819052918101829052606081018290526080810182905260a081018290529061172683826122ab565b8252611733602082612bfc565b905061173f8382612311565b6020808401919091526117529082612bfc565b905061175e838261236e565b61ffff166040830152611772600282612bfc565b905061177e8382612311565b606083015261178e602082612bfc565b905061179a838261236e565b61ffff1660808301526117ae600282612bfc565b90506117ba83826123d4565b60ff1660a08301526117cd600182612bfc565b90508083511461181f5760405162461bcd60e51b815260206004820152601060248201527f696e76616c6964205472616e73666572000000000000000000000000000000006044820152606401610a38565b50919050565b61182d611e62565b6001600160a01b0381166118a95760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610a38565b6118b281612118565b50565b600554600090600160a01b900460ff1615156001146119085760405162461bcd60e51b815260206004820152600f60248201526e139bdd08125b9a5d1a585b1a5e9959608a1b6044820152606401610a38565b4661191260045490565b146119525760405162461bcd60e51b815260206004820152601060248201526f756e737570706f7274656420666f726b60801b6044820152606401610a38565b60006119666001546001600160a01b031690565b60405163c23ee3c360e01b815261ffff8516600482015260006024820152620493e060448201526001600160a01b03919091169063c23ee3c3906064016040805180830381865afa1580156119bf573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906119e39190612c14565b509392505050565b6001600160a01b038316611a4d5760405162461bcd60e51b8152602060048201526024808201527f45524332303a20617070726f76652066726f6d20746865207a65726f206164646044820152637265737360e01b6064820152608401610a38565b6001600160a01b038216611aae5760405162461bcd60e51b815260206004820152602260248201527f45524332303a20617070726f766520746f20746865207a65726f206164647265604482015261737360f01b6064820152608401610a38565b6001600160a01b038381166000818152600a602090815260408083209487168084529482529182902085905590518481527f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a3505050565b6001600160a01b038381166000908152600a60209081526040808320938616835292905220546000198114610b7f5781811015611b8e5760405162461bcd60e51b815260206004820152601d60248201527f45524332303a20696e73756666696369656e7420616c6c6f77616e63650000006044820152606401610a38565b610b7f84848484036119eb565b6001600160a01b038316611c175760405162461bcd60e51b815260206004820152602560248201527f45524332303a207472616e736665722066726f6d20746865207a65726f20616460448201527f64726573730000000000000000000000000000000000000000000000000000006064820152608401610a38565b6001600160a01b038216611c795760405162461bcd60e51b815260206004820152602360248201527f45524332303a207472616e7366657220746f20746865207a65726f206164647260448201526265737360e81b6064820152608401610a38565b6001600160a01b03831660009081526009602052604090205481811015611d085760405162461bcd60e51b815260206004820152602660248201527f45524332303a207472616e7366657220616d6f756e742065786365656473206260448201527f616c616e636500000000000000000000000000000000000000000000000000006064820152608401610a38565b6001600160a01b0380851660008181526009602052604080822086860390559286168082529083902080548601905591517fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef90611d689086815260200190565b60405180910390a3610b7f565b6001600060080182604051611d8a9190612bca565b908152604051908190036020019020805491151560ff1990921691909117905550565b600080600080611dbc8661243a565b925092509250600060018885858560405160008152602001604052604051611e00949392919093845260ff9290921660208401526040830152606082015260800190565b6020604051602081039080840390855afa158015611e22573d6000803e3d6000fd5b505050602060405103519050856001600160a01b0316816001600160a01b03161415611e555760019450505050506108f5565b60009450505050506108f5565b600e546001600160a01b03163314610edc5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610a38565b6001600160a01b038216611f125760405162461bcd60e51b815260206004820152601f60248201527f45524332303a206d696e7420746f20746865207a65726f2061646472657373006044820152606401610a38565b80600b6000828254611f249190612bfc565b90915550506001600160a01b0382166000818152600960209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a35050565b60606000611f8a846116ea565b90506000611f9b826060015161167f565b60008581526002602052604090205490915060ff1615611ffd5760405162461bcd60e51b815260206004820152601a60248201527f7472616e7366657220616c726561647920636f6d706c657465640000000000006044820152606401610a38565b61201c846000908152600260205260409020805460ff19166001179055565b60005461ffff1661ffff16826080015161ffff161461207d5760405162461bcd60e51b815260206004820152601460248201527f696e76616c69642074617267657420636861696e0000000000000000000000006044820152606401610a38565b60006120a583600001518460a001516120a060055460ff600160a81b9091041690565b612469565b90506120b18282611ebc565b82606001517fdf5e04c9235e5b4ddaec2baee15dc9c74de339075fa433a8dd25ebbc0719857b82856040015186608001516040516121069392919092835261ffff918216602084015216604082015260600190565b60405180910390a25093949350505050565b600e80546001600160a01b0383811673ffffffffffffffffffffffffffffffffffffffff19831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b6001600160a01b0382166121d75760405162461bcd60e51b815260206004820152602160248201527f45524332303a206275726e2066726f6d20746865207a65726f206164647265736044820152607360f81b6064820152608401610a38565b6001600160a01b0382166000908152600960205260409020548181101561224b5760405162461bcd60e51b815260206004820152602260248201527f45524332303a206275726e20616d6f756e7420657863656564732062616c616e604482015261636560f01b6064820152608401610a38565b6001600160a01b03831660008181526009602090815260408083208686039055600b80548790039055518581529192917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef910160405180910390a3505050565b60006122b8826020612bfc565b835110156123085760405162461bcd60e51b815260206004820152601560248201527f746f55696e743235365f6f75744f66426f756e647300000000000000000000006044820152606401610a38565b50016020015190565b600061231e826020612bfc565b835110156123085760405162461bcd60e51b815260206004820152601560248201527f746f427974657333325f6f75744f66426f756e647300000000000000000000006044820152606401610a38565b600061237b826002612bfc565b835110156123cb5760405162461bcd60e51b815260206004820152601460248201527f746f55696e7431365f6f75744f66426f756e64730000000000000000000000006044820152606401610a38565b50016002015190565b60006123e1826001612bfc565b835110156124315760405162461bcd60e51b815260206004820152601360248201527f746f55696e74385f6f75744f66426f756e6473000000000000000000000000006044820152606401610a38565b50016001015190565b6000806000835160411461244d57600080fd5b5050506020810151604082015160609092015160001a92909190565b60008160ff168360ff16111561249b576124838284612ced565b61248e90600a612df4565b6124989085612e03565b93505b8260ff168260ff1611156124cb576124b38383612ced565b6124be90600a612df4565b6124c89085612e25565b93505b509192915050565b6000602082840312156124e557600080fd5b81356001600160e01b0319811681146108f557600080fd5b60005b83811015612518578181015183820152602001612500565b83811115610b7f5750506000910152565b600081518084526125418160208601602086016124fd565b601f01601f19169290920160200192915050565b6020815260006108f56020830184612529565b80356001600160a01b038116811461257f57600080fd5b919050565b6000806040838503121561259757600080fd5b6125a083612568565b946020939093013593505050565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f1916810167ffffffffffffffff811182821017156125ed576125ed6125ae565b604052919050565b600082601f83011261260657600080fd5b813567ffffffffffffffff811115612620576126206125ae565b612633601f8201601f19166020016125c4565b81815284602083860101111561264857600080fd5b816020850160208301376000918101602001919091529392505050565b60006020828403121561267757600080fd5b813567ffffffffffffffff81111561268e57600080fd5b61269a848285016125f5565b949350505050565b6000806000606084860312156126b757600080fd5b6126c084612568565b92506126ce60208501612568565b9150604084013590509250925092565b803561ffff8116811461257f57600080fd5b60006060828403121561270257600080fd5b6040516060810167ffffffffffffffff8282108183111715612726576127266125ae565b8160405282935061273685612568565b835260208501356020840152604085013591508082111561275657600080fd5b50612763858286016125f5565b6040830152505092915050565b60008060006060848603121561278557600080fd5b61278e846126de565b925060208401359150604084013567ffffffffffffffff8111156127b157600080fd5b6127bd868287016126f0565b9150509250925092565b600067ffffffffffffffff8211156127e1576127e16125ae565b5060051b60200190565b600080600080600060a0868803121561280357600080fd5b853567ffffffffffffffff8082111561281b57600080fd5b61282789838a016125f5565b965060209150818801358181111561283e57600080fd5b8801601f81018a1361284f57600080fd5b803561286261285d826127c7565b6125c4565b81815260059190911b8201840190848101908c83111561288157600080fd5b8584015b838110156128b95780358681111561289d5760008081fd5b6128ab8f89838901016125f5565b845250918601918601612885565b509850505050604088013594506128d5915050606087016126de565b949793965091946080013592915050565b6000602082840312156128f857600080fd5b6108f582612568565b60008060006060848603121561291657600080fd5b6126c0846126de565b6000806000806080858703121561293557600080fd5b84359350612945602086016126de565b93969395505050506040820135916060013590565b600082601f83011261296b57600080fd5b8135602061297b61285d836127c7565b82815260059290921b8401810191818101908684111561299a57600080fd5b8286015b848110156129b5578035835291830191830161299e565b509695505050505050565b6000806000606084860312156129d557600080fd5b833567ffffffffffffffff808211156129ed57600080fd5b818601915086601f830112612a0157600080fd5b81356020612a1161285d836127c7565b82815260059290921b8401810191818101908a841115612a3057600080fd5b948201945b83861015612a5557612a46866126de565b82529482019490820190612a35565b97505087013592505080821115612a6b57600080fd5b612a778783880161295a565b93506040860135915080821115612a8d57600080fd5b506127bd868287016126f0565b600060c08284031215612aac57600080fd5b60405160c0810181811067ffffffffffffffff82111715612acf57612acf6125ae565b80604052508235815260208301356020820152612aee604084016126de565b604082015260608301356060820152612b09608084016126de565b608082015260a083013560ff81168114612b2257600080fd5b60a08201529392505050565b600060208284031215612b4057600080fd5b5035919050565b60008060408385031215612b5a57600080fd5b612b6383612568565b9150612b7160208401612568565b90509250929050565b600060208284031215612b8c57600080fd5b6108f5826126de565b600181811c90821680612ba957607f821691505b6020821081141561181f57634e487b7160e01b600052602260045260246000fd5b60008251612bdc8184602087016124fd565b9190910192915050565b634e487b7160e01b600052601160045260246000fd5b60008219821115612c0f57612c0f612be6565b500190565b60008060408385031215612c2757600080fd5b505080516020909101519092909150565b600061ffff808a1683526001600160a01b03808a16602085015260e06040850152612c6660e085018a612529565b925087606085015286608085015281861660a085015280851660c0850152505098975050505050505050565b600060208284031215612ca457600080fd5b815167ffffffffffffffff811681146108f557600080fd5b634e487b7160e01b600052603260045260246000fd5b6000600019821415612ce657612ce6612be6565b5060010190565b600060ff821660ff841680821015612d0757612d07612be6565b90039392505050565b600181815b80851115612d4b578160001904821115612d3157612d31612be6565b80851615612d3e57918102915b93841c9390800290612d15565b509250929050565b600082612d62575060016107f9565b81612d6f575060006107f9565b8160018114612d855760028114612d8f57612dab565b60019150506107f9565b60ff841115612da057612da0612be6565b50506001821b6107f9565b5060208310610133831016604e8410600b8410161715612dce575081810a6107f9565b612dd88383612d10565b8060001904821115612dec57612dec612be6565b029392505050565b60006108f560ff841683612d53565b600082612e2057634e487b7160e01b600052601260045260246000fd5b500490565b6000816000190483118215151615612e3f57612e3f612be6565b50029056fea164736f6c634300080a000a

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

000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a00000000000000000000000000000000000000000000000000000000000000012000000000000000000000000000000000000000000000000000000000000000a4772696e6465727920580000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024758000000000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : name (string): Grindery X
Arg [1] : symbol (string): GX
Arg [2] : decimal (uint8): 18

-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [3] : 000000000000000000000000000000000000000000000000000000000000000a
Arg [4] : 4772696e64657279205800000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [6] : 4758000000000000000000000000000000000000000000000000000000000000


Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.