Amoy Testnet

Token

Phinance.Gold (PHIGOLD)
ERC-20

Overview

Max Total Supply

10,000 PHIGOLD

Holders

35

Total Transfers

-

Market

Price

$0.00 @ 0.000000 POL

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 6 Decimals)

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

Click here to update the token information / general information

Contract Source Code Verified (Exact Match)

Contract Name:
PhiPay

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 200 runs

Other Settings:
paris EvmVersion

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 16 : PhiPay.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import '@openzeppelin/contracts/token/ERC20/ERC20.sol';
import '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol';
import '@openzeppelin/contracts/token/ERC20/extensions/ERC20Pausable.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC721/IERC721.sol';
import '@openzeppelin/contracts/token/ERC721/utils/ERC721Holder.sol';
import '@openzeppelin/contracts/metatx/ERC2771Context.sol';

interface IPhigoldBond is IERC721 {
    struct Bond {
        uint256 phigoldAmount;
        uint256 maturityDate;
        bool redeemed;
        uint8 status;
        bytes32 purchaseOrderHash;
        bytes32 auditReportHash;
    }

    function getBondDetails(uint256 tokenId) external view returns (Bond memory);
    function setRedeemed(uint256 tokenId) external;
    function burn(uint256 tokenId) external;
}

contract PhiPay is ERC20, ERC20Burnable, ERC20Pausable, Ownable, ERC721Holder, ERC2771Context {
    uint256 phigoldUsdPrice = 70000000;
    uint256 supportedTokenCount;
    IPhigoldBond public phigoldBondContract;
    address private feeAccount;
    uint256 public phipayFeeRate = 200;

    mapping(address => TokenInfo) public supportedTokens;
    mapping(uint256 => string) public mintAuditReports;
    mapping(address => uint256) public nonces;
    mapping(address => bool) public isAdmin;

    modifier onlyAdmins() {
        require(isAdmin[msg.sender], 'Only admins can call this function');
        _;
    }

    struct TokenInfo {
        IERC20 paymentToken;
        uint256 decimals;
        uint256 exchangeRate;
    }
    event MintEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink);
    event PurchaseOrderEvent(address triggerer, uint256 amount, uint256 timestamp, string purchaseOrderLink);
    event VaultDepositEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink);
    event VaultWithdrawalEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink);
    event BurnEvent(address triggerer, uint256 amount, uint256 timestamp, string auditReportLink);
    event PurchaseCompleted(address sender, address recipient, uint256 amount, uint256 timestamp, string sku);
    event SwapCompleted(
        address sender,
        uint256 paidAmount,
        uint256 receivedAmount,
        address paymentTokenAddress,
        string receivedToken,
        uint256 timestamp
    );
    event FeePaid(address feeAccount, uint256 feeAmount, uint256 timestamp);
    event BondRedeemed(uint256 tokenId, address redeemer, uint256 amount, uint timestamp);
    event FeeAccountUpdated(address newFeeAccount, uint256 timestamp);

    constructor(
        address trustedForwarder
    ) ERC20('Phinance.Gold', 'PHIGOLD') Ownable(msg.sender) ERC2771Context(trustedForwarder) {
        feeAccount = owner();
        isAdmin[msg.sender] = true;
        isAdmin[0x0D58CCB8F40C46AFf980DD7457EE346f92908f29] = true;
    }

    modifier onlyTrustedForwarder() {
        require(msg.sender == trustedForwarder(), 'Caller is not the trusted forwarder');
        _;
    }

    function _update(address from, address to, uint256 value) internal override(ERC20, ERC20Pausable) {
        super._update(from, to, value);
    }

    function getNonce(address user) public view returns (uint256) {
        return nonces[user];
    }

    function setFeeAccount(address _feeAccount) public onlyOwner {
        feeAccount = _feeAccount;
        emit FeeAccountUpdated(_feeAccount, block.timestamp);
    }

    function _transferWithFee(
        address sender,
        address recipient,
        uint256 amount,
        uint256 _feeRate
    ) internal returns (bool) {
        require(recipient != address(0), 'Recipient address must be provided');
        require(amount != 0, 'Phigold amount must be greater than 0');

        uint256 feeRate = _feeRate != 0 ? _feeRate : phipayFeeRate;
        uint256 fee = (amount * feeRate) / 10000;
        uint256 totalAmount = amount + fee;

        require(balanceOf(sender) >= totalAmount, 'Insufficient balance');

        _transfer(sender, recipient, amount);

        if (fee != 0) {
            _transfer(sender, feeAccount, fee);
            emit FeePaid(feeAccount, fee, block.timestamp);
        }

        return true;
    }

    function forwardedMakePurchase(
        address sender,
        address recipient,
        uint256 amount,
        string memory sku,
        uint256 nonce,
        uint256 _feeRate
    ) public onlyTrustedForwarder {
        require(nonces[sender] == nonce, 'Invalid nonce');
        nonces[sender]++;

        require(_transferWithFee(sender, recipient, amount, _feeRate));

        emit PurchaseCompleted(sender, recipient, amount, block.timestamp, sku);
    }

    function forwardedTransferWithFee(
        address sender,
        address recipient,
        uint256 amount,
        uint256 nonce,
        uint256 _feeRate
    ) public onlyTrustedForwarder {
        require(nonces[sender] == nonce, 'Invalid nonce');
        nonces[sender]++;

        require(_transferWithFee(sender, recipient, amount, _feeRate));
    }

    function makePurchase(address recipient, uint256 amount, string memory sku, uint256 _feeRate) public {
        require(_transferWithFee(msg.sender, recipient, amount, _feeRate));

        emit PurchaseCompleted(msg.sender, recipient, amount, block.timestamp, sku);
    }

    function isValidIPFSAddress(string memory _ipfsAddress) internal pure returns (bool) {
        bytes memory addressBytes = bytes(_ipfsAddress);
        if (addressBytes.length == 46 && addressBytes[0] == 'Q' && addressBytes[1] == 'm') {
            return true; // CIDv0
        }
        if (addressBytes.length == 59 && addressBytes[0] == 'b') {
            return true; // CIDv1
        }
        return false;
    }

    function addSupportedToken(address _tokenAddress, uint256 _tokenDecimals, uint256 _exchangeRate) public onlyOwner {
        require(_tokenAddress != address(0), 'Token address must be provided');
        require(_tokenDecimals != 0, 'Number of decimals must be greater than 0');
        require(_exchangeRate != 0, 'Exchange Rate must be greater than 0');
        supportedTokens[_tokenAddress] = TokenInfo(IERC20(_tokenAddress), _tokenDecimals, _exchangeRate);
        supportedTokenCount++;
    }

    function removeSupportedToken(address _tokenAddress) public onlyOwner {
        require(_tokenAddress != address(0), 'Token address must be provided');
        require(supportedTokens[_tokenAddress].paymentToken != IERC20(address(0)), 'Token not found');
        delete supportedTokens[_tokenAddress];
        supportedTokenCount--;
    }

    function getSupportedTokenCount() public view returns (uint256) {
        return supportedTokenCount;
    }

    function setUsdExchangeRate(uint256 _newPhigoldUsdPrice) public onlyAdmins {
        phigoldUsdPrice = _newPhigoldUsdPrice;
    }

    function checkIsAdmin(address _adminAccount) public view returns (bool) {
        return isAdmin[_adminAccount];
    }

    function setAdminAccount(address _adminAccount) public onlyOwner {
        isAdmin[_adminAccount] = true;
    }

    function removeAdminAccount(address _adminAccount) public onlyOwner {
        isAdmin[_adminAccount] = false;
    }

    function setPaymentTokenExchangeRate(address _paymentTokenAddress, uint256 _newExchangeRate) public onlyOwner {
        supportedTokens[_paymentTokenAddress].exchangeRate = _newExchangeRate;
    }

    function getPaymentTokenExchangeRate(address _paymentTokenAddress) public view returns (uint256) {
        return supportedTokens[_paymentTokenAddress].exchangeRate;
    }

    function getUsdExchangeRate() public view returns (uint256) {
        return phigoldUsdPrice;
    }

    function mintPhigoldSupply(uint256 _amount, string memory _ipfsAuditReportLink) public onlyAdmins {
        require(bytes(_ipfsAuditReportLink).length != 0, 'Audit report IPFS link must be provided');
        require(isValidIPFSAddress(_ipfsAuditReportLink), 'Invalid IPFS address format');

        _mint(address(this), _amount);

        emit MintEvent(_msgSender(), _amount, block.timestamp, _ipfsAuditReportLink);
    }

    function swapSupportedTokenForPhigold(address _paymentTokenAddress, uint256 _phigoldAmount, bool _isUsd) public {
        TokenInfo storage tokenInfo = supportedTokens[_paymentTokenAddress];
        uint256 phigoldDecimals = decimals();
        uint256 exchangeRate = _isUsd ? phigoldUsdPrice : tokenInfo.exchangeRate;
        uint256 paymentTokenDecimals = tokenInfo.decimals;
        uint256 paymentTokenAmount;

        if (paymentTokenDecimals > phigoldDecimals) {
            uint256 decimalsDifference = paymentTokenDecimals - phigoldDecimals;
            paymentTokenAmount = (_phigoldAmount * exchangeRate) / (10 ** decimalsDifference) / 1000000;
        } else {
            uint256 decimalsDifference = phigoldDecimals - paymentTokenDecimals;
            paymentTokenAmount = ((_phigoldAmount * exchangeRate) * (10 ** decimalsDifference)) / 1000000;
        }
        require(paymentTokenAmount != 0, 'Payment token amount must be greater than 0');
        require(
            tokenInfo.paymentToken.balanceOf(_msgSender()) >= paymentTokenAmount,
            'Insufficient payment token balance'
        );
        require(
            tokenInfo.paymentToken.allowance(_msgSender(), address(this)) >= paymentTokenAmount,
            'Insufficient payment token allowance'
        );

        require(
            tokenInfo.paymentToken.transferFrom(_msgSender(), owner(), paymentTokenAmount),
            'Payment token transfer failed'
        );

        _transfer(address(this), _msgSender(), _phigoldAmount);

        emit SwapCompleted(
            _msgSender(),
            paymentTokenAmount,
            _phigoldAmount,
            _paymentTokenAddress,
            this.symbol(),
            block.timestamp
        );
    }

    function forwardedSwapWithPermit(
        address sender,
        address paymentTokenAddress,
        uint256 permittedSpendAmount,
        uint256 phigoldAmount,
        bool isUsd,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s,
        uint256 phipayNonce
    ) public onlyTrustedForwarder {
        require(nonces[sender] == phipayNonce, 'Invalid PhiPay nonce');
        nonces[sender]++;

        IERC20Permit(paymentTokenAddress).permit(sender, address(this), permittedSpendAmount, deadline, v, r, s);

        TokenInfo storage tokenInfo = supportedTokens[paymentTokenAddress];
        uint256 phigoldDecimals = decimals();
        uint256 exchangeRate = isUsd ? phigoldUsdPrice : tokenInfo.exchangeRate;
        uint256 paymentTokenDecimals = tokenInfo.decimals;
        uint256 paymentTokenAmount;

        if (paymentTokenDecimals > phigoldDecimals) {
            uint256 decimalsDifference = paymentTokenDecimals - phigoldDecimals;
            paymentTokenAmount = (phigoldAmount * exchangeRate) / (10 ** decimalsDifference) / 1000000;
        } else {
            uint256 decimalsDifference = phigoldDecimals - paymentTokenDecimals;
            paymentTokenAmount = ((phigoldAmount * exchangeRate) * (10 ** decimalsDifference)) / 1000000;
        }
        require(paymentTokenAmount != 0, 'Payment token amount must be greater than 0');
        require(
            IERC20(paymentTokenAddress).balanceOf(sender) >= paymentTokenAmount,
            'Insufficient payment token balance'
        );
        require(
            IERC20(paymentTokenAddress).allowance(sender, address(this)) >= paymentTokenAmount,
            'Insufficient payment token allowance'
        );

        require(
            IERC20(paymentTokenAddress).transferFrom(sender, owner(), paymentTokenAmount),
            'Payment token transfer failed'
        );

        _transfer(address(this), sender, phigoldAmount);

        emit SwapCompleted(
            sender,
            paymentTokenAmount,
            phigoldAmount,
            paymentTokenAddress,
            this.symbol(),
            block.timestamp
        );
    }

    function redeemPhigold(uint256 _amount, string memory _purchaseId) public {
        require(_amount != 0, 'Phigold amount must be greater than 0');
        _burn(_msgSender(), _amount);

        emit BurnEvent(
            _msgSender(),
            _amount,
            block.timestamp,
            string(abi.encodePacked('Phigold Redeemed: ', _purchaseId))
        );
    }

    function withdrawERC20Token(address _tokenAddress) public onlyOwner {
        IERC20 token = IERC20(_tokenAddress);
        require(token.balanceOf(address(this)) != 0, 'Insufficient payment token balance');

        uint256 amount = token.balanceOf(address(this));
        token.transfer(_msgSender(), amount);
    }

    function decimals() public pure override returns (uint8) {
        return 6;
    }

    function pause() public onlyOwner {
        _pause();
    }

    function unpause() public onlyOwner {
        _unpause();
    }

    function setPhigoldBondContract(address _bondContractAddress) public onlyOwner {
        phigoldBondContract = IPhigoldBond(_bondContractAddress);
    }

    function redeemPhigoldBond(uint256 _tokenId) public {
        require(address(phigoldBondContract) != address(0), 'PhigoldBond contract not set');
        require(phigoldBondContract.ownerOf(_tokenId) == _msgSender(), 'Not the bond owner');

        IPhigoldBond bondContract = IPhigoldBond(address(phigoldBondContract));
        IPhigoldBond.Bond memory bond = bondContract.getBondDetails(_tokenId);

        require(block.timestamp >= bond.maturityDate, 'Bond not yet matured');
        require(!bond.redeemed, 'Bond already redeemed');
        require(bond.status == 2, 'Bond must be in the Vaulted status');
        require(
            phigoldBondContract.getApproved(_tokenId) == address(this) ||
                phigoldBondContract.isApprovedForAll(_msgSender(), address(this)),
            'PhiPay not approved to transfer bond'
        );

        phigoldBondContract.burn(_tokenId);
        bondContract.setRedeemed(_tokenId);
        _transfer(address(this), _msgSender(), bond.phigoldAmount);

        emit BondRedeemed(_tokenId, _msgSender(), bond.phigoldAmount, block.timestamp);
    }

    // Override _msgSender() to support EIP-2771
    function _msgSender() internal view override(Context, ERC2771Context) returns (address sender) {
        return ERC2771Context._msgSender();
    }

    // Override _msgData() to support EIP-2771
    function _msgData() internal view override(Context, ERC2771Context) returns (bytes calldata) {
        return ERC2771Context._msgData();
    }

    function _contextSuffixLength() internal view override(Context, ERC2771Context) returns (uint256) {
        return ERC2771Context._contextSuffixLength();
    }
}

File 2 of 16 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)

pragma solidity ^0.8.20;

import {Context} from "../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.
 *
 * The initial owner is set to the address provided by the deployer. This can
 * later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    /**
     * @dev The caller account is not authorized to perform an operation.
     */
    error OwnableUnauthorizedAccount(address account);

    /**
     * @dev The owner is not a valid owner account. (eg. `address(0)`)
     */
    error OwnableInvalidOwner(address owner);

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

    /**
     * @dev Initializes the contract setting the address provided by the deployer as the initial owner.
     */
    constructor(address initialOwner) {
        if (initialOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(initialOwner);
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        if (owner() != _msgSender()) {
            revert OwnableUnauthorizedAccount(_msgSender());
        }
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby disabling 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 {
        if (newOwner == address(0)) {
            revert OwnableInvalidOwner(address(0));
        }
        _transferOwnership(newOwner);
    }

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

File 3 of 16 : draft-IERC6093.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;

/**
 * @dev Standard ERC20 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
 */
interface IERC20Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC20InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC20InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     * @param allowance Amount of tokens a `spender` is allowed to operate with.
     * @param needed Minimum amount required to perform a transfer.
     */
    error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC20InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `spender` to be approved. Used in approvals.
     * @param spender Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC20InvalidSpender(address spender);
}

/**
 * @dev Standard ERC721 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
 */
interface IERC721Errors {
    /**
     * @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
     * Used in balance queries.
     * @param owner Address of the current owner of a token.
     */
    error ERC721InvalidOwner(address owner);

    /**
     * @dev Indicates a `tokenId` whose `owner` is the zero address.
     * @param tokenId Identifier number of a token.
     */
    error ERC721NonexistentToken(uint256 tokenId);

    /**
     * @dev Indicates an error related to the ownership over a particular token. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param tokenId Identifier number of a token.
     * @param owner Address of the current owner of a token.
     */
    error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC721InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC721InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param tokenId Identifier number of a token.
     */
    error ERC721InsufficientApproval(address operator, uint256 tokenId);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC721InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC721InvalidOperator(address operator);
}

/**
 * @dev Standard ERC1155 Errors
 * Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
 */
interface IERC1155Errors {
    /**
     * @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     * @param balance Current balance for the interacting account.
     * @param needed Minimum amount required to perform a transfer.
     * @param tokenId Identifier number of a token.
     */
    error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);

    /**
     * @dev Indicates a failure with the token `sender`. Used in transfers.
     * @param sender Address whose tokens are being transferred.
     */
    error ERC1155InvalidSender(address sender);

    /**
     * @dev Indicates a failure with the token `receiver`. Used in transfers.
     * @param receiver Address to which tokens are being transferred.
     */
    error ERC1155InvalidReceiver(address receiver);

    /**
     * @dev Indicates a failure with the `operator`’s approval. Used in transfers.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     * @param owner Address of the current owner of a token.
     */
    error ERC1155MissingApprovalForAll(address operator, address owner);

    /**
     * @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
     * @param approver Address initiating an approval operation.
     */
    error ERC1155InvalidApprover(address approver);

    /**
     * @dev Indicates a failure with the `operator` to be approved. Used in approvals.
     * @param operator Address that may be allowed to operate on tokens without being their owner.
     */
    error ERC1155InvalidOperator(address operator);

    /**
     * @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
     * Used in batch transfers.
     * @param idsLength Length of the array of token identifiers
     * @param valuesLength Length of the array of token amounts
     */
    error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}

File 4 of 16 : ERC2771Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (metatx/ERC2771Context.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Context variant with ERC2771 support.
 *
 * WARNING: Avoid using this pattern in contracts that rely in a specific calldata length as they'll
 * be affected by any forwarder whose `msg.data` is suffixed with the `from` address according to the ERC2771
 * specification adding the address size in bytes (20) to the calldata size. An example of an unexpected
 * behavior could be an unintended fallback (or another function) invocation while trying to invoke the `receive`
 * function only accessible if `msg.data.length == 0`.
 *
 * WARNING: The usage of `delegatecall` in this contract is dangerous and may result in context corruption.
 * Any forwarded request to this contract triggering a `delegatecall` to itself will result in an invalid {_msgSender}
 * recovery.
 */
abstract contract ERC2771Context is Context {
    /// @custom:oz-upgrades-unsafe-allow state-variable-immutable
    address private immutable _trustedForwarder;

    /**
     * @dev Initializes the contract with a trusted forwarder, which will be able to
     * invoke functions on this contract on behalf of other accounts.
     *
     * NOTE: The trusted forwarder can be replaced by overriding {trustedForwarder}.
     */
    /// @custom:oz-upgrades-unsafe-allow constructor
    constructor(address trustedForwarder_) {
        _trustedForwarder = trustedForwarder_;
    }

    /**
     * @dev Returns the address of the trusted forwarder.
     */
    function trustedForwarder() public view virtual returns (address) {
        return _trustedForwarder;
    }

    /**
     * @dev Indicates whether any particular address is the trusted forwarder.
     */
    function isTrustedForwarder(address forwarder) public view virtual returns (bool) {
        return forwarder == trustedForwarder();
    }

    /**
     * @dev Override for `msg.sender`. Defaults to the original `msg.sender` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgSender() internal view virtual override returns (address) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return address(bytes20(msg.data[calldataLength - contextSuffixLength:]));
        } else {
            return super._msgSender();
        }
    }

    /**
     * @dev Override for `msg.data`. Defaults to the original `msg.data` whenever
     * a call is not performed by the trusted forwarder or the calldata length is less than
     * 20 bytes (an address length).
     */
    function _msgData() internal view virtual override returns (bytes calldata) {
        uint256 calldataLength = msg.data.length;
        uint256 contextSuffixLength = _contextSuffixLength();
        if (isTrustedForwarder(msg.sender) && calldataLength >= contextSuffixLength) {
            return msg.data[:calldataLength - contextSuffixLength];
        } else {
            return super._msgData();
        }
    }

    /**
     * @dev ERC-2771 specifies the context as being a single address (20 bytes).
     */
    function _contextSuffixLength() internal view virtual override returns (uint256) {
        return 20;
    }
}

File 5 of 16 : ERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/ERC20.sol)

pragma solidity ^0.8.20;

import {IERC20} from "./IERC20.sol";
import {IERC20Metadata} from "./extensions/IERC20Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {IERC20Errors} from "../../interfaces/draft-IERC6093.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}.
 *
 * 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].
 *
 * The default value of {decimals} is 18. To change this, you should override
 * this function so it returns a different value.
 *
 * 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.
 */
abstract contract ERC20 is Context, IERC20, IERC20Metadata, IERC20Errors {
    mapping(address account => uint256) private _balances;

    mapping(address account => mapping(address spender => uint256)) private _allowances;

    uint256 private _totalSupply;

    string private _name;
    string private _symbol;

    /**
     * @dev Sets the values for {name} and {symbol}.
     *
     * 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 returns (string memory) {
        return _name;
    }

    /**
     * @dev Returns the symbol of the token, usually a shorter version of the
     * name.
     */
    function symbol() public view virtual 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 default value returned by this function, unless
     * it's 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 returns (uint8) {
        return 18;
    }

    /**
     * @dev See {IERC20-totalSupply}.
     */
    function totalSupply() public view virtual returns (uint256) {
        return _totalSupply;
    }

    /**
     * @dev See {IERC20-balanceOf}.
     */
    function balanceOf(address account) public view virtual 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 `value`.
     */
    function transfer(address to, uint256 value) public virtual returns (bool) {
        address owner = _msgSender();
        _transfer(owner, to, value);
        return true;
    }

    /**
     * @dev See {IERC20-allowance}.
     */
    function allowance(address owner, address spender) public view virtual returns (uint256) {
        return _allowances[owner][spender];
    }

    /**
     * @dev See {IERC20-approve}.
     *
     * NOTE: If `value` 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 value) public virtual returns (bool) {
        address owner = _msgSender();
        _approve(owner, spender, value);
        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 `value`.
     * - the caller must have allowance for ``from``'s tokens of at least
     * `value`.
     */
    function transferFrom(address from, address to, uint256 value) public virtual returns (bool) {
        address spender = _msgSender();
        _spendAllowance(from, spender, value);
        _transfer(from, to, value);
        return true;
    }

    /**
     * @dev Moves a `value` 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.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _transfer(address from, address to, uint256 value) internal {
        if (from == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        if (to == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(from, to, value);
    }

    /**
     * @dev Transfers a `value` amount of tokens from `from` to `to`, or alternatively mints (or burns) if `from`
     * (or `to`) is the zero address. All customizations to transfers, mints, and burns should be done by overriding
     * this function.
     *
     * Emits a {Transfer} event.
     */
    function _update(address from, address to, uint256 value) internal virtual {
        if (from == address(0)) {
            // Overflow check required: The rest of the code assumes that totalSupply never overflows
            _totalSupply += value;
        } else {
            uint256 fromBalance = _balances[from];
            if (fromBalance < value) {
                revert ERC20InsufficientBalance(from, fromBalance, value);
            }
            unchecked {
                // Overflow not possible: value <= fromBalance <= totalSupply.
                _balances[from] = fromBalance - value;
            }
        }

        if (to == address(0)) {
            unchecked {
                // Overflow not possible: value <= totalSupply or value <= fromBalance <= totalSupply.
                _totalSupply -= value;
            }
        } else {
            unchecked {
                // Overflow not possible: balance + value is at most totalSupply, which we know fits into a uint256.
                _balances[to] += value;
            }
        }

        emit Transfer(from, to, value);
    }

    /**
     * @dev Creates a `value` amount of tokens and assigns them to `account`, by transferring it from address(0).
     * Relies on the `_update` mechanism
     *
     * Emits a {Transfer} event with `from` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead.
     */
    function _mint(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidReceiver(address(0));
        }
        _update(address(0), account, value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, lowering the total supply.
     * Relies on the `_update` mechanism.
     *
     * Emits a {Transfer} event with `to` set to the zero address.
     *
     * NOTE: This function is not virtual, {_update} should be overridden instead
     */
    function _burn(address account, uint256 value) internal {
        if (account == address(0)) {
            revert ERC20InvalidSender(address(0));
        }
        _update(account, address(0), value);
    }

    /**
     * @dev Sets `value` 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.
     *
     * Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
     */
    function _approve(address owner, address spender, uint256 value) internal {
        _approve(owner, spender, value, true);
    }

    /**
     * @dev Variant of {_approve} with an optional flag to enable or disable the {Approval} event.
     *
     * By default (when calling {_approve}) the flag is set to true. On the other hand, approval changes made by
     * `_spendAllowance` during the `transferFrom` operation set the flag to false. This saves gas by not emitting any
     * `Approval` event during `transferFrom` operations.
     *
     * Anyone who wishes to continue emitting `Approval` events on the`transferFrom` operation can force the flag to
     * true using the following override:
     * ```
     * function _approve(address owner, address spender, uint256 value, bool) internal virtual override {
     *     super._approve(owner, spender, value, true);
     * }
     * ```
     *
     * Requirements are the same as {_approve}.
     */
    function _approve(address owner, address spender, uint256 value, bool emitEvent) internal virtual {
        if (owner == address(0)) {
            revert ERC20InvalidApprover(address(0));
        }
        if (spender == address(0)) {
            revert ERC20InvalidSpender(address(0));
        }
        _allowances[owner][spender] = value;
        if (emitEvent) {
            emit Approval(owner, spender, value);
        }
    }

    /**
     * @dev Updates `owner` s allowance for `spender` based on spent `value`.
     *
     * Does not update the allowance value in case of infinite allowance.
     * Revert if not enough allowance is available.
     *
     * Does not emit an {Approval} event.
     */
    function _spendAllowance(address owner, address spender, uint256 value) internal virtual {
        uint256 currentAllowance = allowance(owner, spender);
        if (currentAllowance != type(uint256).max) {
            if (currentAllowance < value) {
                revert ERC20InsufficientAllowance(spender, currentAllowance, value);
            }
            unchecked {
                _approve(owner, spender, currentAllowance - value, false);
            }
        }
    }
}

File 6 of 16 : ERC20Burnable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Burnable.sol)

pragma solidity ^0.8.20;

import {ERC20} from "../ERC20.sol";
import {Context} from "../../../utils/Context.sol";

/**
 * @dev Extension of {ERC20} that allows token holders to destroy both their own
 * tokens and those that they have an allowance for, in a way that can be
 * recognized off-chain (via event analysis).
 */
abstract contract ERC20Burnable is Context, ERC20 {
    /**
     * @dev Destroys a `value` amount of tokens from the caller.
     *
     * See {ERC20-_burn}.
     */
    function burn(uint256 value) public virtual {
        _burn(_msgSender(), value);
    }

    /**
     * @dev Destroys a `value` amount of tokens from `account`, deducting from
     * the caller's allowance.
     *
     * See {ERC20-_burn} and {ERC20-allowance}.
     *
     * Requirements:
     *
     * - the caller must have allowance for ``accounts``'s tokens of at least
     * `value`.
     */
    function burnFrom(address account, uint256 value) public virtual {
        _spendAllowance(account, _msgSender(), value);
        _burn(account, value);
    }
}

File 7 of 16 : ERC20Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/ERC20Pausable.sol)

pragma solidity ^0.8.20;

import {ERC20} from "../ERC20.sol";
import {Pausable} from "../../../utils/Pausable.sol";

/**
 * @dev ERC20 token with pausable token transfers, minting and burning.
 *
 * Useful for scenarios such as preventing trades until the end of an evaluation
 * period, or having an emergency switch for freezing all token transfers in the
 * event of a large bug.
 *
 * IMPORTANT: This contract does not include public pause and unpause functions. In
 * addition to inheriting this contract, you must define both functions, invoking the
 * {Pausable-_pause} and {Pausable-_unpause} internal functions, with appropriate
 * access control, e.g. using {AccessControl} or {Ownable}. Not doing so will
 * make the contract pause mechanism of the contract unreachable, and thus unusable.
 */
abstract contract ERC20Pausable is ERC20, Pausable {
    /**
     * @dev See {ERC20-_update}.
     *
     * Requirements:
     *
     * - the contract must not be paused.
     */
    function _update(address from, address to, uint256 value) internal virtual override whenNotPaused {
        super._update(from, to, value);
    }
}

File 8 of 16 : IERC20Metadata.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Metadata.sol)

pragma solidity ^0.8.20;

import {IERC20} from "../IERC20.sol";

/**
 * @dev Interface for the optional metadata functions from the ERC20 standard.
 */
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 9 of 16 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.20;

/**
 * @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.
 *
 * ==== Security Considerations
 *
 * There are two important considerations concerning the use of `permit`. The first is that a valid permit signature
 * expresses an allowance, and it should not be assumed to convey additional meaning. In particular, it should not be
 * considered as an intention to spend the allowance in any specific way. The second is that because permits have
 * built-in replay protection and can be submitted by anyone, they can be frontrun. A protocol that uses permits should
 * take this into consideration and allow a `permit` call to fail. Combining these two aspects, a pattern that may be
 * generally recommended is:
 *
 * ```solidity
 * function doThingWithPermit(..., uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) public {
 *     try token.permit(msg.sender, address(this), value, deadline, v, r, s) {} catch {}
 *     doThing(..., value);
 * }
 *
 * function doThing(..., uint256 value) public {
 *     token.safeTransferFrom(msg.sender, address(this), value);
 *     ...
 * }
 * ```
 *
 * Observe that: 1) `msg.sender` is used as the owner, leaving no ambiguity as to the signer intent, and 2) the use of
 * `try/catch` allows the permit to fail and makes the code tolerant to frontrunning. (See also
 * {SafeERC20-safeTransferFrom}).
 *
 * Additionally, note that smart contract wallets (such as Argent or Safe) are not able to produce permit signatures, so
 * contracts should have entry points that don't rely on permit.
 */
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].
     *
     * CAUTION: See Security Considerations above.
     */
    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 10 of 16 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.20;

/**
 * @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 value of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the value of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves a `value` amount of 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 value) 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 a `value` amount of tokens 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 value) external returns (bool);

    /**
     * @dev Moves a `value` amount of tokens from `from` to `to` using the
     * allowance mechanism. `value` 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 value) external returns (bool);
}

File 11 of 16 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.20;

import {IERC165} from "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
     *   {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon
     *   a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 tokenId) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the address zero.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 12 of 16 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.20;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be
     * reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 13 of 16 : ERC721Holder.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/utils/ERC721Holder.sol)

pragma solidity ^0.8.20;

import {IERC721Receiver} from "../IERC721Receiver.sol";

/**
 * @dev Implementation of the {IERC721Receiver} interface.
 *
 * Accepts all token transfers.
 * Make sure the contract is able to use its token with {IERC721-safeTransferFrom}, {IERC721-approve} or
 * {IERC721-setApprovalForAll}.
 */
abstract contract ERC721Holder is IERC721Receiver {
    /**
     * @dev See {IERC721Receiver-onERC721Received}.
     *
     * Always returns `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(address, address, uint256, bytes memory) public virtual returns (bytes4) {
        return this.onERC721Received.selector;
    }
}

File 14 of 16 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)

pragma solidity ^0.8.20;

/**
 * @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;
    }

    function _contextSuffixLength() internal view virtual returns (uint256) {
        return 0;
    }
}

File 15 of 16 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)

pragma solidity ^0.8.20;

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

File 16 of 16 : Pausable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Pausable.sol)

pragma solidity ^0.8.20;

import {Context} from "../utils/Context.sol";

/**
 * @dev Contract module which allows children to implement an emergency stop
 * mechanism that can be triggered by an authorized account.
 *
 * This module is used through inheritance. It will make available the
 * modifiers `whenNotPaused` and `whenPaused`, which can be applied to
 * the functions of your contract. Note that they will not be pausable by
 * simply including this module, only once the modifiers are put in place.
 */
abstract contract Pausable is Context {
    bool private _paused;

    /**
     * @dev Emitted when the pause is triggered by `account`.
     */
    event Paused(address account);

    /**
     * @dev Emitted when the pause is lifted by `account`.
     */
    event Unpaused(address account);

    /**
     * @dev The operation failed because the contract is paused.
     */
    error EnforcedPause();

    /**
     * @dev The operation failed because the contract is not paused.
     */
    error ExpectedPause();

    /**
     * @dev Initializes the contract in unpaused state.
     */
    constructor() {
        _paused = false;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is not paused.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    modifier whenNotPaused() {
        _requireNotPaused();
        _;
    }

    /**
     * @dev Modifier to make a function callable only when the contract is paused.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    modifier whenPaused() {
        _requirePaused();
        _;
    }

    /**
     * @dev Returns true if the contract is paused, and false otherwise.
     */
    function paused() public view virtual returns (bool) {
        return _paused;
    }

    /**
     * @dev Throws if the contract is paused.
     */
    function _requireNotPaused() internal view virtual {
        if (paused()) {
            revert EnforcedPause();
        }
    }

    /**
     * @dev Throws if the contract is not paused.
     */
    function _requirePaused() internal view virtual {
        if (!paused()) {
            revert ExpectedPause();
        }
    }

    /**
     * @dev Triggers stopped state.
     *
     * Requirements:
     *
     * - The contract must not be paused.
     */
    function _pause() internal virtual whenNotPaused {
        _paused = true;
        emit Paused(_msgSender());
    }

    /**
     * @dev Returns to normal state.
     *
     * Requirements:
     *
     * - The contract must be paused.
     */
    function _unpause() internal virtual whenPaused {
        _paused = false;
        emit Unpaused(_msgSender());
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "viaIR": true,
  "evmVersion": "paris",
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "libraries": {}
}

Contract ABI

[{"inputs":[{"internalType":"address","name":"trustedForwarder","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"allowance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientAllowance","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"needed","type":"uint256"}],"name":"ERC20InsufficientBalance","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC20InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC20InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC20InvalidSender","type":"error"},{"inputs":[{"internalType":"address","name":"spender","type":"address"}],"name":"ERC20InvalidSpender","type":"error"},{"inputs":[],"name":"EnforcedPause","type":"error"},{"inputs":[],"name":"ExpectedPause","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"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":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"redeemer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"BondRedeemed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"BurnEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newFeeAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeeAccountUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"feeAccount","type":"address"},{"indexed":false,"internalType":"uint256","name":"feeAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"FeePaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"MintEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"account","type":"address"}],"name":"Paused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"address","name":"recipient","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"sku","type":"string"}],"name":"PurchaseCompleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"purchaseOrderLink","type":"string"}],"name":"PurchaseOrderEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"sender","type":"address"},{"indexed":false,"internalType":"uint256","name":"paidAmount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"receivedAmount","type":"uint256"},{"indexed":false,"internalType":"address","name":"paymentTokenAddress","type":"address"},{"indexed":false,"internalType":"string","name":"receivedToken","type":"string"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"}],"name":"SwapCompleted","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":"address","name":"account","type":"address"}],"name":"Unpaused","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"VaultDepositEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"triggerer","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"timestamp","type":"uint256"},{"indexed":false,"internalType":"string","name":"auditReportLink","type":"string"}],"name":"VaultWithdrawalEvent","type":"event"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"},{"internalType":"uint256","name":"_tokenDecimals","type":"uint256"},{"internalType":"uint256","name":"_exchangeRate","type":"uint256"}],"name":"addSupportedToken","outputs":[],"stateMutability":"nonpayable","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":"value","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":"value","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"checkIsAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"sku","type":"string"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"forwardedMakePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"permittedSpendAmount","type":"uint256"},{"internalType":"uint256","name":"phigoldAmount","type":"uint256"},{"internalType":"bool","name":"isUsd","type":"bool"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"},{"internalType":"uint256","name":"phipayNonce","type":"uint256"}],"name":"forwardedSwapWithPermit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"forwardedTransferWithFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"getNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"}],"name":"getPaymentTokenExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getSupportedTokenCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getUsdExchangeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"string","name":"sku","type":"string"},{"internalType":"uint256","name":"_feeRate","type":"uint256"}],"name":"makePurchase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintAuditReports","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_ipfsAuditReportLink","type":"string"}],"name":"mintPhigoldSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phigoldBondContract","outputs":[{"internalType":"contract IPhigoldBond","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"phipayFeeRate","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"string","name":"_purchaseId","type":"string"}],"name":"redeemPhigold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"redeemPhigoldBond","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"removeAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"removeSupportedToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_adminAccount","type":"address"}],"name":"setAdminAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_feeAccount","type":"address"}],"name":"setFeeAccount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"_newExchangeRate","type":"uint256"}],"name":"setPaymentTokenExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_bondContractAddress","type":"address"}],"name":"setPhigoldBondContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPhigoldUsdPrice","type":"uint256"}],"name":"setUsdExchangeRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"supportedTokens","outputs":[{"internalType":"contract IERC20","name":"paymentToken","type":"address"},{"internalType":"uint256","name":"decimals","type":"uint256"},{"internalType":"uint256","name":"exchangeRate","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_paymentTokenAddress","type":"address"},{"internalType":"uint256","name":"_phigoldAmount","type":"uint256"},{"internalType":"bool","name":"_isUsd","type":"bool"}],"name":"swapSupportedTokenForPhigold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"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":"value","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":"value","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":"trustedForwarder","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"unpause","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_tokenAddress","type":"address"}],"name":"withdrawERC20Token","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60a0346200045d57601f19906001600160401b0390601f90620031c738819003838101861683018581118482101762000361578392829160405283396020928391810103126200045d5751926001600160a01b039081851685036200045d576200006862000462565b93600d85526c141a1a5b985b98d94b91dbdb19609a1b848601526200008c62000462565b90600782526614121251d3d31160ca1b85830152855191838311620003615760039283546001988982811c9216801562000452575b898310146200043c578185849311620003e6575b508890858311600114620003835760009262000377575b505060001982861b1c191690881b1783555b8051938411620003615760049889548881811c9116801562000356575b888210146200034157908184879695949311620002e5575b50879285116001146200027d575060009362000271575b505082861b92600019911b1c19161785555b60055493331562000259576001600160a81b0319851633600881811b610100600160a81b031692909217600581905560405197600e96959491939192911c84167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a360805263042c1d8060065560c8600a5560081c1660018060a01b03196009541617600955336000525260406000209060ff19918183825416179055730d58ccb8f40c46aff980dd7457ee346f92908f29600052604060002091825416179055612d4490816200048382396080518181816102c601528181610ae00152818161111b01528181611b1e01528181611bb40152612cb80152f35b604051631e4fbdf760e01b8152600081880152602490fd5b0151915038806200014a565b88959392919316928a600052876000209360005b89828210620002ce5750508511620002b3575b50505050811b0185556200015c565b01519060f884600019921b161c1916905538808080620002a4565b8385015187558b9890960195938401930162000291565b9091929394508a600052876000208480880160051c8201928a891062000337575b918b91899897969594930160051c01915b8281106200032757505062000133565b600081558897508b910162000317565b9250819262000306565b60228b634e487b7160e01b6000525260246000fd5b90607f16906200011b565b634e487b7160e01b600052604160045260246000fd5b015190503880620000ec565b908c8b941691876000528a6000209260005b8c828210620003cf5750508411620003b6575b505050811b018355620000fe565b015160001983881b60f8161c19169055388080620003a8565b8385015186558e9790950194938401930162000395565b90915085600052886000208580850160051c8201928b861062000432575b918c91869594930160051c01915b82811062000422575050620000d5565b600081558594508c910162000412565b9250819262000404565b634e487b7160e01b600052602260045260246000fd5b91607f1691620000c1565b600080fd5b60408051919082016001600160401b03811183821017620003615760405256fe608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde03146120ed57508163095ea7b31461203b578163150b7a0214611fd457816318160ddd14611fb557816323b872dd14611f7c57816323da140e14611f5d57816324d7806c14610a4c5781632d0335ab146110ce578163313ce56714611f415781633bdebbe114611db05781633f4ba83a14611d4657816342966c6814611d265781634b023cf814611caa5781635219716e14611c6557816356ce8ab814611bdb578163572b6c0514611b895781635761764014611ae85781635c975abb14611ac457816367675ad514611a9b57816367a89a7214611a5b57816368c4ac2614611a095781636e896ac11461195f57816370a0823114611928578163715018a6146118c75781637327d6e6146113c6578163763191901461130357816379cc6790146112c95781637ba147f11461114a5781637da0a877146111065781637ecebe00146110ce5781638456cb59146110605781638a77834814610d7c5781638d6830de14610d3c5781638da5cb5b14610d0f57816395d89b4114610c2c578163a6c3cb8414610c0d578163a9059cbb14610bd5578163ae7fcb1714610ba3578163ce67be2614610b84578163cef2841a14610a8a578163d953689d14610a4c578163dd62ed3e146109fe578163e8ef9f22146109bb578163edd9587b14610848578163f100049014610736578163f2fde38b14610698578163f3851fda14610273575063ff73870b1461023557600080fd5b3461026f57602036600319011261026f5760209160029082906001600160a01b0361025e612212565b168152600b85522001549051908152f35b5080fd5b905034610694576101403660031901126106945761028f612212565b610297612228565b90606435926084359283151584036105c55760c43560ff8116809103610584576001600160a01b03946102ed337f0000000000000000000000000000000000000000000000000000000000000000881614612610565b85851695868a52602091600d8352610124358a8c20540361065a57878b52600d8352898b2061031c81546126a4565b90558a82861694853b1561026f578b519063d505accf60e01b82528a89830152306024830152604435604483015260a4356064830152608482015260e43560a48201526101043560c4820152818160e481838a5af1801561065057610638575b50849052600b8352898b20620f4240911561062b576001600654915b015490600682111561060c576103c36103bd6103b66103c994612a75565b928d612740565b91612a84565b90612753565b04965b6103d7881515612a92565b8951906370a0823160e01b8252868201528281602481875afa80156105d15788908c906105db575b61040b92501015612af2565b8851636eb1769f60e11b81526001600160a01b0387168682019081523060208201529091908390839081906040010381875afa80156105d15788928c91610599575b5093829161046185946104a1971015612b49565b60055460081c168c8c518097819582946323b872dd60e01b84528d8d850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af190811561058f578991610554575b506104be9150612bae565b6104c985843061236f565b86865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575b5051958695429487612c59565b0390a180f35b6105439193503d808b833e61053b8183612268565b810190612bfa565b9138610513565b86513d89823e3d90fd5b905081813d8311610588575b61056a8183612268565b810103126105845761057e6104be91612ba1565b386104b3565b8780fd5b503d610560565b88513d8b823e3d90fd5b80929350848092503d83116105ca575b6105b38183612268565b810103126105c557518791908361044d565b600080fd5b503d6105a9565b8a513d8d823e3d90fd5b50508281813d8311610605575b6105f28183612268565b810103126105c5578761040b91516103ff565b503d6105e8565b61061e6103bd6103b661062494612a67565b90612740565b04966103cc565b6001600282015491610398565b6106419061223e565b61064c578a3861037c565b8a80fd5b8c513d84823e3d90fd5b895162461bcd60e51b81528087018490526014602482015273496e76616c696420506869506179206e6f6e636560601b6044820152606490fd5b8280fd5b905034610694576020366003190112610694576106b3612212565b6106bb61232b565b6001600160a01b0381811693909290841561072057505060058054610100600160a81b03198116600893841b610100600160a81b031617909155901c167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b51631e4fbdf760e01b8152908101859052602490fd5b828434610845576020908160031936011261084557829084358152600c8352209180519260009080549060019082821c92828116801561083b575b8785108114610828578899509688969785829a5291826000146108015750506001146107be575b5050506107ba92916107ab910385612268565b519282849384528301906121ed565b0390f35b86935060009291925282600020916000925b8284106107e957505050820101816107ab6107ba610798565b8054848a0186015288955087949093019281016107d0565b60ff19168782015293151560051b860190930193508492506107ab91506107ba9050610798565b634e487b7160e01b865260228a52602486fd5b93607f1693610771565b80fd5b83833461026f57606036600319011261026f57610863612212565b6024356044359161087261232b565b6001600160a01b03908116936108898515156128dd565b8215610967578315610919578051946060860186811067ffffffffffffffff821117610904576002969798508252808752602087019384528187019485528752600b60205286209451166bffffffffffffffffffffffff60a01b855416178455516001840155519101556108fe6007546126a4565b60075580f35b604189634e487b7160e01b6000525260246000fd5b5162461bcd60e51b81526020818801526024808201527f45786368616e67652052617465206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b5162461bcd60e51b8152602081880152602960248201527f4e756d626572206f6620646563696d616c73206d75737420626520677265617460448201526806572207468616e20360bc1b6064820152608490fd5b50503461026f57602036600319011261026f576109d6612212565b6109de61232b565b6001600160a01b03168252600e6020528120805460ff1916600117905580f35b50503461026f578060031936011261026f57602091610a1b612212565b82610a24612228565b6001600160a01b03928316845260018652922091166000908152908352819020549051908152f35b50503461026f57602036600319011261026f5760209160ff9082906001600160a01b03610a77612212565b168152600e855220541690519015158152f35b9050346106945760c036600319011261069457610aa5612212565b91610aae612228565b90604435926064359067ffffffffffffffff8211610b8057610ad2913691016122dd565b6001600160a01b03610b07337f0000000000000000000000000000000000000000000000000000000000000000831614612610565b8516808752600d602052610b216084358489205414612668565b8652600d602052818620610b3581546126a4565b9055610b4560a435858588612773565b15610b7c577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e9461052092519485944292866126b3565b8580fd5b8680fd5b50503461026f578160031936011261026f576020906007549051908152f35b919050346106945760203660031901126106945760ff610bce91338552600e60205284205416612929565b3560065580f35b50503461026f578060031936011261026f57602090610c06610bf5612212565b60243590610c01612cb5565b61236f565b5160018152f35b50503461026f578160031936011261026f57602090600a549051908152f35b82843461084557806003193601126108455750805190600090835491600183811c90808516948515610d05575b6020958684108114610cf2579086889992858a98999a529182600014610801575050600114610c95575050506107ba92916107ab910385612268565b600090815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610cda57505050820101816107ab6107ba610798565b8054848a018601528895508794909301928101610cc1565b634e487b7160e01b855260228952602485fd5b91607f1691610c59565b50503461026f578160031936011261026f57600554905160089190911c6001600160a01b03168152602090f35b50503461026f578060031936011261026f57610d56612212565b610d5e61232b565b6001600160a01b03168252600b602052812060243560029091015580f35b90503461069457606036600319011261069457610d97612212565b90602435916044359182151583036105c5576001600160a01b038281168752600b602090815286882094156110515781620f42406006545b6001880154906006821115611038576103c36103bd610df0610df794612a75565b928c612740565b04955b610e05871515612a92565b541691610e10612cb5565b88516370a0823160e01b815290821685820152908282602481875afa8015610ff95787928b91611003575b50610e8592610e4b911015612af2565b82610e54612cb5565b8a51636eb1769f60e11b81526001600160a01b03909116878201908152306020820152909384918291604090910190565b0381875afa8015610ff95787928b91610fc6575b50938291610ead8594610ef7971015612b49565b8b610eb6612cb5565b9160055460081c16918c51978895869485936323b872dd60e01b85528c850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af1908115610fbc578891610f85575b50610f149150612bae565b610f2684610f20612cb5565b3061236f565b610f2e612cb5565b9186865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575051958695429487612c59565b905081813d8311610fb5575b610f9b8183612268565b81010312610b8057610faf610f1491612ba1565b38610f09565b503d610f91565b87513d8a823e3d90fd5b80929350848092503d8311610ff2575b610fe08183612268565b810103126105c5575186919083610e99565b503d610fd6565b89513d8c823e3d90fd5b809350848092503d8311611031575b61101c8183612268565b810103126105c5579051869190610e85610e3b565b503d611012565b61061e6103bd610df061104a94612a67565b0495610dfa565b81620f42406002870154610dcf565b50503461026f578160031936011261026f5760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589161109e61232b565b6110a66125f2565b600160ff1960055416176005556110bb612cb5565b90516001600160a01b039091168152a180f35b50503461026f57602036600319011261026f5760209181906001600160a01b036110f6612212565b168152600d845220549051908152f35b50503461026f578160031936011261026f57517f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03168152602090f35b83833461026f5761115a366122fb565b93338452600e60205261117260ff8486205416612929565b84511561127657611182856129ab565b1561123357301561121c57506105207f9e31786833642f5b8cf977c95ad5e181542fa9238c9c3105757e05b20e2597d893946111bc6125f2565b6111c8836002546125cf565b600255308652856020528386208381540190558351838152867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203093a361120f612cb5565b9351938493429185612980565b825163ec442f0560e01b8152908101849052602490fd5b606490602084519162461bcd60e51b8352820152601b60248201527f496e76616c69642049504653206164647265737320666f726d617400000000006044820152fd5b608490602084519162461bcd60e51b8352820152602760248201527f4175646974207265706f72742049504653206c696e6b206d75737420626520706044820152661c9bdd9a59195960ca1b6064820152fd5b50503461026f57366003190112610845576113006112e5612212565b602435906112fb826112f5612cb5565b83612455565b612528565b80f35b919050346106945760203660031901126106945761131f612212565b61132761232b565b6001600160a01b039081169061133e8215156128dd565b818552600b6020528285205416156113915783916002918352600b6020528220828155826001820155015560075490811561137e57506000190160075580f35b634e487b7160e01b835260119052602482fd5b815162461bcd60e51b8152602081850152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b6044820152606490fd5b91905034610694576020918260031936011261159757600854813592906001600160a01b0390811680156118845782516331a9108f60e11b815284810186905260249087818381865afa908115611827578991611867575b508380611429612cb5565b1691160361183157835163021b797b60e11b81528581018790529460c0868381865afa958615611827578996611783575b5087860151421061174c578486015161171457600260ff606088015116036116c957845163020604bf60e21b815281810188905288818481875afa9081156115b2578a9161169c575b5084163014801561160c575b156115c057823b156115bc578451630852cd8d60e31b81528181018890528981848183885af180156115b25761159b575b5090829189933b1561159757839188918388519586948593630cd7a19560e41b85528401525af1801561158d57611571575b507fe305dcd5197faa39ababe23510783dbec4f835cfdcc3b347e68bae90f022a3a160808686868a8761154f611546612cb5565b8551903061236f565b611557612cb5565b93519383519586521690840152820152426060820152a180f35b61157f90959493929561223e565b610b7c579091928538611512565b84513d84823e3d90fd5b8380fd5b6115a990999193929961223e565b979091386114e0565b86513d8c823e3d90fd5b8880fd5b6084918886519262461bcd60e51b8452830152808201527f506869506179206e6f7420617070726f76656420746f207472616e7366657220604482015263189bdb9960e21b6064820152fd5b5061164a88611619612cb5565b875163e985e9c560e01b81526001600160a01b03909116848201908152306020820152909283918291604090910190565b0381875afa9081156115b2578a91611663575b506114af565b90508881813d8311611695575b61167a8183612268565b810103126116915761168b90612ba1565b3861165d565b8980fd5b503d611670565b6116bc9150893d8b116116c2575b6116b48183612268565b810190612c96565b386114a3565b503d6116aa565b60226084928987519362461bcd60e51b85528401528201527f426f6e64206d75737420626520696e20746865205661756c7465642073746174604482015261757360f01b6064820152fd5b60156064928987519362461bcd60e51b855284015282015274109bdb9908185b1c9958591e481c995919595b5959605a1b6044820152fd5b60146064928987519362461bcd60e51b855284015282015273109bdb99081b9bdd081e595d081b585d1d5c995960621b6044820152fd5b90955060c0813d821161181f575b8161179e60c09383612268565b810103126115bc5784519060c0820182811067ffffffffffffffff82111761180d5786528051825288810151898301526117d9868201612ba1565b8683015260608101519060ff8216820361064c5760a091606084015260808101516080840152015160a0820152943861145a565b634e487b7160e01b8b5260418852838bfd5b3d9150611791565b85513d8b823e3d90fd5b8460126064928987519362461bcd60e51b8552840152820152712737ba103a3432903137b7321037bbb732b960711b6044820152fd5b61187e9150883d8a116116c2576116b48183612268565b3861141e565b825162461bcd60e51b8152808501879052601c60248201527f506869676f6c64426f6e6420636f6e7472616374206e6f7420736574000000006044820152606490fd5b83346108455780600319360112610845576118e061232b565b60058054610100600160a81b03198116909155819060081c6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50503461026f57602036600319011261026f5760209181906001600160a01b03611950612212565b16815280845220549051908152f35b50503461026f577fc136285a46e61d975decf1d79f2b6bc4a858b008859bf182aaa16137e4e255dd90610520611994366122fb565b6119a182939215156126e6565b6119ad836112fb612cb5565b6119b5612cb5565b936119fd603282518094710283434b3b7b632102932b232b2b6b2b21d160751b60208301526119ed81518092602086860191016121ca565b8101036012810185520183612268565b51938493429185612980565b50503461026f57602036600319011261026f576060916001600160a01b0390829082611a33612212565b168152600b602052209081541691600260018301549201549181519384526020840152820152f35b50503461026f57602036600319011261026f57611a76612212565b611a7e61232b565b6001600160a01b03168252600e6020528120805460ff1916905580f35b50503461026f578160031936011261026f5760085490516001600160a01b039091168152602090f35b50503461026f578160031936011261026f5760209060ff6005541690519015158152f35b50503461026f5760a036600319011261026f57611b8190611b07612212565b611b0f612228565b916001600160a01b03611b45337f0000000000000000000000000000000000000000000000000000000000000000831614612610565b8216808652600d602052611b5f6064358388205414612668565b8552600d6020528420611b7281546126a4565b90556084359160443591612773565b156108455780f35b50503461026f57602036600319011261026f57602090611ba7612212565b90519060018060a01b03807f0000000000000000000000000000000000000000000000000000000000000000169116148152f35b90503461069457608036600319011261069457611bf6612212565b90602435906044359067ffffffffffffffff8211610b7c57611c1a913691016122dd565b92611c29606435838533612773565b15611c61577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e936105209151938493429133866126b3565b8480fd5b833461084557602036600319011261084557611c7f612212565b611c8761232b565b60018060a01b03166bffffffffffffffffffffffff60a01b600854161760085580f35b50503461026f57602036600319011261026f576105207f9fee46258bf9d123a7d66bbda27a92d2fe75e3bac91217431cf8875396aeae5c91611cea612212565b90611cf361232b565b600980546001600160a01b0319166001600160a01b03939093169283179055519081524260208201529081906040820190565b83903461026f57602036600319011261026f5761130090356112fb612cb5565b905034610694578260031936011261069457611d6061232b565b6005549060ff821615611da2575060ff19166005557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020906110bb612cb5565b8251638dfc202b60e01b8152fd5b91905034610694576020908160031936011261159757611dce612212565b611dd661232b565b81516370a0823160e01b80825230828701526001600160a01b039290921694908481602481895afa8015611f37578790611f08575b611e1791501515612af2565b825191825230818301528382602481885afa918215611efe578692611ecd575b5090611e7d94849287611e48612cb5565b865163a9059cbb60e01b81526001600160a01b0390911692810192835260208301949094529296879384929091839160400190565b03925af1908115611ec45750611e91578280f35b81813d8311611ebd575b611ea58183612268565b8101031261026f57611eb690612ba1565b5038808280f35b503d611e9b565b513d85823e3d90fd5b91508382813d8311611ef7575b611ee48183612268565b81010312610b7c57905190611e7d611e37565b503d611eda565b83513d88823e3d90fd5b508481813d8311611f30575b611f1e8183612268565b81010312610b8057611e179051611e0b565b503d611f14565b84513d89823e3d90fd5b50503461026f578160031936011261026f576020905160068152f35b50503461026f578160031936011261026f576020906006549051908152f35b50503461026f57606036600319011261026f57602090610c06611f9d612212565b611fa5612228565b60443591610c01836112f5612cb5565b50503461026f578160031936011261026f576020906002549051908152f35b82843461084557608036600319011261084557611fef612212565b50611ff8612228565b506064359067ffffffffffffffff82116108455736602383011215610845575060209281602461202d933693013591016122a6565b5051630a85bd0160e11b8152f35b905034610694578160031936011261069457612055612212565b602435936001600160a01b038061206a612cb5565b169283156120d657169283156120c1575060208581968684867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925965260018552818120888252855220558551908152a35160018152f35b602491855191634a1406b160e11b8352820152fd5b855163e602df0560e01b8152808601849052602490fd5b84843461026f578160031936011261026f578160035492600184811c918186169586156121c0575b60209687851081146121ad578899509688969785829a529182600014610801575050600114612151575050506107ba92916107ab910385612268565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061219557505050820101816107ab6107ba610798565b8054848a01860152889550879490930192810161217c565b634e487b7160e01b835260228a52602483fd5b92607f1692612115565b60005b8381106121dd5750506000910152565b81810151838201526020016121cd565b90602091612206815180928185528580860191016121ca565b601f01601f1916010190565b600435906001600160a01b03821682036105c557565b602435906001600160a01b03821682036105c557565b67ffffffffffffffff811161225257604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761225257604052565b67ffffffffffffffff811161225257601f01601f191660200190565b9291926122b28261228a565b916122c06040519384612268565b8294818452818301116105c5578281602093846000960137010152565b9080601f830112156105c5578160206122f8933591016122a6565b90565b9060406003198301126105c557600435916024359067ffffffffffffffff82116105c5576122f8916004016122dd565b6005546001600160a01b039060081c811681612345612cb5565b160361234e5750565b602490612359612cb5565b60405163118cdaa760e01b815291166004820152fd5b916001600160a01b0380841692831561243c5716928315612423576123926125f2565b600090838252816020526040822054908382106123f1575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403612494575b50505050505050565b8484106124f8575080156124e05781156124c85785526001602052838520908552602052039120553880808080808061248b565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b906001600160a01b03821690811561243c576125426125f2565b6000928284528360205260408420549082821061259d5750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b919082018092116125dc57565b634e487b7160e01b600052601160045260246000fd5b60ff600554166125fe57565b60405163d93c066560e01b8152600490fd5b1561261757565b60405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865207472757374656420666f727761726044820152623232b960e91b6064820152608490fd5b1561266f57565b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606490fd5b60001981146125dc5760010190565b91926122f895949160a094600180871b0380921685521660208401526040830152606082015281608082015201906121ed565b156126ed57565b60405162461bcd60e51b815260206004820152602560248201527f506869676f6c6420616d6f756e74206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608490fd5b818102929181159184041417156125dc57565b811561275d570490565b634e487b7160e01b600052601260045260246000fd5b926001600160a01b0391908282161561288d576127918415156126e6565b801561287e576127a5612710915b85612740565b04926127b184826125cf565b838616600052600060205260406000205410612842576127d1918561236f565b816127df575b505050600190565b612810827ff3816d9cce3442fbfe3e4d36ad047b3362efdc9f2e283e77b0ecd768a0a01ef29483600954169061236f565b60095460408051929091166001600160a01b0316825260208201929092524291810191909152606090a13880806127d7565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b506127106127a5600a5461279f565b60405162461bcd60e51b815260206004820152602260248201527f526563697069656e742061646472657373206d7573742062652070726f766964604482015261195960f21b6064820152608490fd5b156128e457565b60405162461bcd60e51b815260206004820152601e60248201527f546f6b656e2061646472657373206d7573742062652070726f766964656400006044820152606490fd5b1561293057565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c792061646d696e732063616e2063616c6c20746869732066756e63746960448201526137b760f11b6064820152608490fd5b90926080926122f8959460018060a01b031683526020830152604082015281606082015201906121ed565b8051602e81149081612a45575b5080612a20575b612a1a57805190603b821491826129e1575b50506129dc57600090565b600190565b90915015612a0457602001516001600160f81b031916603160f91b1438806129d1565b634e487b7160e01b600052603260045260246000fd5b50600190565b50805160011015612a045760218101516001600160f81b031916606d60f81b146129bf565b905015612a045760208101516001600160f81b031916605160f81b14386129b8565b60060390600682116125dc57565b6005198101919082116125dc57565b604d81116125dc57600a0a90565b15612a9957565b60405162461bcd60e51b815260206004820152602b60248201527f5061796d656e7420746f6b656e20616d6f756e74206d7573742062652067726560448201526a061746572207468616e20360ac1b6064820152608490fd5b15612af957565b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e74207061796d656e7420746f6b656e2062616c616e604482015261636560f01b6064820152608490fd5b15612b5057565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e74207061796d656e7420746f6b656e20616c6c6f77604482015263616e636560e01b6064820152608490fd5b519081151582036105c557565b15612bb557565b60405162461bcd60e51b815260206004820152601d60248201527f5061796d656e7420746f6b656e207472616e73666572206661696c65640000006044820152606490fd5b6020818303126105c55780519067ffffffffffffffff82116105c5570181601f820112156105c5578051612c2d8161228a565b92612c3b6040519485612268565b818452602082840101116105c5576122f891602080850191016121ca565b9695949193612c919360a095600180881b038094168a5260208a0152604089015216606087015260c0608087015260c08601906121ed565b930152565b908160209103126105c557516001600160a01b03811681036105c55790565b337f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03161480612d03575b15612cff5760131936013681116125dc573560601c90565b3390565b506014361015612ce756fea2646970667358221220761afc950b717a7e4358657fd190b6c91f62bb885f7eee91c43d1855b67cc38564736f6c63430008140033000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a

Deployed Bytecode

0x608060408181526004918236101561001657600080fd5b600092833560e01c91826306fdde03146120ed57508163095ea7b31461203b578163150b7a0214611fd457816318160ddd14611fb557816323b872dd14611f7c57816323da140e14611f5d57816324d7806c14610a4c5781632d0335ab146110ce578163313ce56714611f415781633bdebbe114611db05781633f4ba83a14611d4657816342966c6814611d265781634b023cf814611caa5781635219716e14611c6557816356ce8ab814611bdb578163572b6c0514611b895781635761764014611ae85781635c975abb14611ac457816367675ad514611a9b57816367a89a7214611a5b57816368c4ac2614611a095781636e896ac11461195f57816370a0823114611928578163715018a6146118c75781637327d6e6146113c6578163763191901461130357816379cc6790146112c95781637ba147f11461114a5781637da0a877146111065781637ecebe00146110ce5781638456cb59146110605781638a77834814610d7c5781638d6830de14610d3c5781638da5cb5b14610d0f57816395d89b4114610c2c578163a6c3cb8414610c0d578163a9059cbb14610bd5578163ae7fcb1714610ba3578163ce67be2614610b84578163cef2841a14610a8a578163d953689d14610a4c578163dd62ed3e146109fe578163e8ef9f22146109bb578163edd9587b14610848578163f100049014610736578163f2fde38b14610698578163f3851fda14610273575063ff73870b1461023557600080fd5b3461026f57602036600319011261026f5760209160029082906001600160a01b0361025e612212565b168152600b85522001549051908152f35b5080fd5b905034610694576101403660031901126106945761028f612212565b610297612228565b90606435926084359283151584036105c55760c43560ff8116809103610584576001600160a01b03946102ed337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a881614612610565b85851695868a52602091600d8352610124358a8c20540361065a57878b52600d8352898b2061031c81546126a4565b90558a82861694853b1561026f578b519063d505accf60e01b82528a89830152306024830152604435604483015260a4356064830152608482015260e43560a48201526101043560c4820152818160e481838a5af1801561065057610638575b50849052600b8352898b20620f4240911561062b576001600654915b015490600682111561060c576103c36103bd6103b66103c994612a75565b928d612740565b91612a84565b90612753565b04965b6103d7881515612a92565b8951906370a0823160e01b8252868201528281602481875afa80156105d15788908c906105db575b61040b92501015612af2565b8851636eb1769f60e11b81526001600160a01b0387168682019081523060208201529091908390839081906040010381875afa80156105d15788928c91610599575b5093829161046185946104a1971015612b49565b60055460081c168c8c518097819582946323b872dd60e01b84528d8d850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af190811561058f578991610554575b506104be9150612bae565b6104c985843061236f565b86865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575b5051958695429487612c59565b0390a180f35b6105439193503d808b833e61053b8183612268565b810190612bfa565b9138610513565b86513d89823e3d90fd5b905081813d8311610588575b61056a8183612268565b810103126105845761057e6104be91612ba1565b386104b3565b8780fd5b503d610560565b88513d8b823e3d90fd5b80929350848092503d83116105ca575b6105b38183612268565b810103126105c557518791908361044d565b600080fd5b503d6105a9565b8a513d8d823e3d90fd5b50508281813d8311610605575b6105f28183612268565b810103126105c5578761040b91516103ff565b503d6105e8565b61061e6103bd6103b661062494612a67565b90612740565b04966103cc565b6001600282015491610398565b6106419061223e565b61064c578a3861037c565b8a80fd5b8c513d84823e3d90fd5b895162461bcd60e51b81528087018490526014602482015273496e76616c696420506869506179206e6f6e636560601b6044820152606490fd5b8280fd5b905034610694576020366003190112610694576106b3612212565b6106bb61232b565b6001600160a01b0381811693909290841561072057505060058054610100600160a81b03198116600893841b610100600160a81b031617909155901c167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a380f35b51631e4fbdf760e01b8152908101859052602490fd5b828434610845576020908160031936011261084557829084358152600c8352209180519260009080549060019082821c92828116801561083b575b8785108114610828578899509688969785829a5291826000146108015750506001146107be575b5050506107ba92916107ab910385612268565b519282849384528301906121ed565b0390f35b86935060009291925282600020916000925b8284106107e957505050820101816107ab6107ba610798565b8054848a0186015288955087949093019281016107d0565b60ff19168782015293151560051b860190930193508492506107ab91506107ba9050610798565b634e487b7160e01b865260228a52602486fd5b93607f1693610771565b80fd5b83833461026f57606036600319011261026f57610863612212565b6024356044359161087261232b565b6001600160a01b03908116936108898515156128dd565b8215610967578315610919578051946060860186811067ffffffffffffffff821117610904576002969798508252808752602087019384528187019485528752600b60205286209451166bffffffffffffffffffffffff60a01b855416178455516001840155519101556108fe6007546126a4565b60075580f35b604189634e487b7160e01b6000525260246000fd5b5162461bcd60e51b81526020818801526024808201527f45786368616e67652052617465206d75737420626520677265617465722074686044820152630616e20360e41b6064820152608490fd5b5162461bcd60e51b8152602081880152602960248201527f4e756d626572206f6620646563696d616c73206d75737420626520677265617460448201526806572207468616e20360bc1b6064820152608490fd5b50503461026f57602036600319011261026f576109d6612212565b6109de61232b565b6001600160a01b03168252600e6020528120805460ff1916600117905580f35b50503461026f578060031936011261026f57602091610a1b612212565b82610a24612228565b6001600160a01b03928316845260018652922091166000908152908352819020549051908152f35b50503461026f57602036600319011261026f5760209160ff9082906001600160a01b03610a77612212565b168152600e855220541690519015158152f35b9050346106945760c036600319011261069457610aa5612212565b91610aae612228565b90604435926064359067ffffffffffffffff8211610b8057610ad2913691016122dd565b6001600160a01b03610b07337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a831614612610565b8516808752600d602052610b216084358489205414612668565b8652600d602052818620610b3581546126a4565b9055610b4560a435858588612773565b15610b7c577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e9461052092519485944292866126b3565b8580fd5b8680fd5b50503461026f578160031936011261026f576020906007549051908152f35b919050346106945760203660031901126106945760ff610bce91338552600e60205284205416612929565b3560065580f35b50503461026f578060031936011261026f57602090610c06610bf5612212565b60243590610c01612cb5565b61236f565b5160018152f35b50503461026f578160031936011261026f57602090600a549051908152f35b82843461084557806003193601126108455750805190600090835491600183811c90808516948515610d05575b6020958684108114610cf2579086889992858a98999a529182600014610801575050600114610c95575050506107ba92916107ab910385612268565b600090815286935091907f8a35acfbc15ff81a39ae7d344fd709f28e8600b4aa8c65c6b64bfe7fe36bd19b5b828410610cda57505050820101816107ab6107ba610798565b8054848a018601528895508794909301928101610cc1565b634e487b7160e01b855260228952602485fd5b91607f1691610c59565b50503461026f578160031936011261026f57600554905160089190911c6001600160a01b03168152602090f35b50503461026f578060031936011261026f57610d56612212565b610d5e61232b565b6001600160a01b03168252600b602052812060243560029091015580f35b90503461069457606036600319011261069457610d97612212565b90602435916044359182151583036105c5576001600160a01b038281168752600b602090815286882094156110515781620f42406006545b6001880154906006821115611038576103c36103bd610df0610df794612a75565b928c612740565b04955b610e05871515612a92565b541691610e10612cb5565b88516370a0823160e01b815290821685820152908282602481875afa8015610ff95787928b91611003575b50610e8592610e4b911015612af2565b82610e54612cb5565b8a51636eb1769f60e11b81526001600160a01b03909116878201908152306020820152909384918291604090910190565b0381875afa8015610ff95787928b91610fc6575b50938291610ead8594610ef7971015612b49565b8b610eb6612cb5565b9160055460081c16918c51978895869485936323b872dd60e01b85528c850160409194939294606082019560018060a01b0380921683521660208201520152565b03925af1908115610fbc578891610f85575b50610f149150612bae565b610f2684610f20612cb5565b3061236f565b610f2e612cb5565b9186865180936395d89b4160e01b825281305afa91821561054a57907f60cd11ca617b0758c3cc25e1445e01a198b67383b98aa98703fbcbe083ca912b966105209493928993610526575051958695429487612c59565b905081813d8311610fb5575b610f9b8183612268565b81010312610b8057610faf610f1491612ba1565b38610f09565b503d610f91565b87513d8a823e3d90fd5b80929350848092503d8311610ff2575b610fe08183612268565b810103126105c5575186919083610e99565b503d610fd6565b89513d8c823e3d90fd5b809350848092503d8311611031575b61101c8183612268565b810103126105c5579051869190610e85610e3b565b503d611012565b61061e6103bd610df061104a94612a67565b0495610dfa565b81620f42406002870154610dcf565b50503461026f578160031936011261026f5760207f62e78cea01bee320cd4e420270b5ea74000d11b0c9f74754ebdbfc544b05a2589161109e61232b565b6110a66125f2565b600160ff1960055416176005556110bb612cb5565b90516001600160a01b039091168152a180f35b50503461026f57602036600319011261026f5760209181906001600160a01b036110f6612212565b168152600d845220549051908152f35b50503461026f578160031936011261026f57517f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a6001600160a01b03168152602090f35b83833461026f5761115a366122fb565b93338452600e60205261117260ff8486205416612929565b84511561127657611182856129ab565b1561123357301561121c57506105207f9e31786833642f5b8cf977c95ad5e181542fa9238c9c3105757e05b20e2597d893946111bc6125f2565b6111c8836002546125cf565b600255308652856020528386208381540190558351838152867fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef60203093a361120f612cb5565b9351938493429185612980565b825163ec442f0560e01b8152908101849052602490fd5b606490602084519162461bcd60e51b8352820152601b60248201527f496e76616c69642049504653206164647265737320666f726d617400000000006044820152fd5b608490602084519162461bcd60e51b8352820152602760248201527f4175646974207265706f72742049504653206c696e6b206d75737420626520706044820152661c9bdd9a59195960ca1b6064820152fd5b50503461026f57366003190112610845576113006112e5612212565b602435906112fb826112f5612cb5565b83612455565b612528565b80f35b919050346106945760203660031901126106945761131f612212565b61132761232b565b6001600160a01b039081169061133e8215156128dd565b818552600b6020528285205416156113915783916002918352600b6020528220828155826001820155015560075490811561137e57506000190160075580f35b634e487b7160e01b835260119052602482fd5b815162461bcd60e51b8152602081850152600f60248201526e151bdad95b881b9bdd08199bdd5b99608a1b6044820152606490fd5b91905034610694576020918260031936011261159757600854813592906001600160a01b0390811680156118845782516331a9108f60e11b815284810186905260249087818381865afa908115611827578991611867575b508380611429612cb5565b1691160361183157835163021b797b60e11b81528581018790529460c0868381865afa958615611827578996611783575b5087860151421061174c578486015161171457600260ff606088015116036116c957845163020604bf60e21b815281810188905288818481875afa9081156115b2578a9161169c575b5084163014801561160c575b156115c057823b156115bc578451630852cd8d60e31b81528181018890528981848183885af180156115b25761159b575b5090829189933b1561159757839188918388519586948593630cd7a19560e41b85528401525af1801561158d57611571575b507fe305dcd5197faa39ababe23510783dbec4f835cfdcc3b347e68bae90f022a3a160808686868a8761154f611546612cb5565b8551903061236f565b611557612cb5565b93519383519586521690840152820152426060820152a180f35b61157f90959493929561223e565b610b7c579091928538611512565b84513d84823e3d90fd5b8380fd5b6115a990999193929961223e565b979091386114e0565b86513d8c823e3d90fd5b8880fd5b6084918886519262461bcd60e51b8452830152808201527f506869506179206e6f7420617070726f76656420746f207472616e7366657220604482015263189bdb9960e21b6064820152fd5b5061164a88611619612cb5565b875163e985e9c560e01b81526001600160a01b03909116848201908152306020820152909283918291604090910190565b0381875afa9081156115b2578a91611663575b506114af565b90508881813d8311611695575b61167a8183612268565b810103126116915761168b90612ba1565b3861165d565b8980fd5b503d611670565b6116bc9150893d8b116116c2575b6116b48183612268565b810190612c96565b386114a3565b503d6116aa565b60226084928987519362461bcd60e51b85528401528201527f426f6e64206d75737420626520696e20746865205661756c7465642073746174604482015261757360f01b6064820152fd5b60156064928987519362461bcd60e51b855284015282015274109bdb9908185b1c9958591e481c995919595b5959605a1b6044820152fd5b60146064928987519362461bcd60e51b855284015282015273109bdb99081b9bdd081e595d081b585d1d5c995960621b6044820152fd5b90955060c0813d821161181f575b8161179e60c09383612268565b810103126115bc5784519060c0820182811067ffffffffffffffff82111761180d5786528051825288810151898301526117d9868201612ba1565b8683015260608101519060ff8216820361064c5760a091606084015260808101516080840152015160a0820152943861145a565b634e487b7160e01b8b5260418852838bfd5b3d9150611791565b85513d8b823e3d90fd5b8460126064928987519362461bcd60e51b8552840152820152712737ba103a3432903137b7321037bbb732b960711b6044820152fd5b61187e9150883d8a116116c2576116b48183612268565b3861141e565b825162461bcd60e51b8152808501879052601c60248201527f506869676f6c64426f6e6420636f6e7472616374206e6f7420736574000000006044820152606490fd5b83346108455780600319360112610845576118e061232b565b60058054610100600160a81b03198116909155819060081c6001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a380f35b50503461026f57602036600319011261026f5760209181906001600160a01b03611950612212565b16815280845220549051908152f35b50503461026f577fc136285a46e61d975decf1d79f2b6bc4a858b008859bf182aaa16137e4e255dd90610520611994366122fb565b6119a182939215156126e6565b6119ad836112fb612cb5565b6119b5612cb5565b936119fd603282518094710283434b3b7b632102932b232b2b6b2b21d160751b60208301526119ed81518092602086860191016121ca565b8101036012810185520183612268565b51938493429185612980565b50503461026f57602036600319011261026f576060916001600160a01b0390829082611a33612212565b168152600b602052209081541691600260018301549201549181519384526020840152820152f35b50503461026f57602036600319011261026f57611a76612212565b611a7e61232b565b6001600160a01b03168252600e6020528120805460ff1916905580f35b50503461026f578160031936011261026f5760085490516001600160a01b039091168152602090f35b50503461026f578160031936011261026f5760209060ff6005541690519015158152f35b50503461026f5760a036600319011261026f57611b8190611b07612212565b611b0f612228565b916001600160a01b03611b45337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a831614612610565b8216808652600d602052611b5f6064358388205414612668565b8552600d6020528420611b7281546126a4565b90556084359160443591612773565b156108455780f35b50503461026f57602036600319011261026f57602090611ba7612212565b90519060018060a01b03807f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a169116148152f35b90503461069457608036600319011261069457611bf6612212565b90602435906044359067ffffffffffffffff8211610b7c57611c1a913691016122dd565b92611c29606435838533612773565b15611c61577f42bdb50e0f9f5bf372eab7ce6b4ffefc203629ba351ca5be62662afdc4ee628e936105209151938493429133866126b3565b8480fd5b833461084557602036600319011261084557611c7f612212565b611c8761232b565b60018060a01b03166bffffffffffffffffffffffff60a01b600854161760085580f35b50503461026f57602036600319011261026f576105207f9fee46258bf9d123a7d66bbda27a92d2fe75e3bac91217431cf8875396aeae5c91611cea612212565b90611cf361232b565b600980546001600160a01b0319166001600160a01b03939093169283179055519081524260208201529081906040820190565b83903461026f57602036600319011261026f5761130090356112fb612cb5565b905034610694578260031936011261069457611d6061232b565b6005549060ff821615611da2575060ff19166005557f5db9ee0a495bf2e6ff9c91a7834c1ba4fdd244a5e8aa4e537bd38aeae4b073aa906020906110bb612cb5565b8251638dfc202b60e01b8152fd5b91905034610694576020908160031936011261159757611dce612212565b611dd661232b565b81516370a0823160e01b80825230828701526001600160a01b039290921694908481602481895afa8015611f37578790611f08575b611e1791501515612af2565b825191825230818301528382602481885afa918215611efe578692611ecd575b5090611e7d94849287611e48612cb5565b865163a9059cbb60e01b81526001600160a01b0390911692810192835260208301949094529296879384929091839160400190565b03925af1908115611ec45750611e91578280f35b81813d8311611ebd575b611ea58183612268565b8101031261026f57611eb690612ba1565b5038808280f35b503d611e9b565b513d85823e3d90fd5b91508382813d8311611ef7575b611ee48183612268565b81010312610b7c57905190611e7d611e37565b503d611eda565b83513d88823e3d90fd5b508481813d8311611f30575b611f1e8183612268565b81010312610b8057611e179051611e0b565b503d611f14565b84513d89823e3d90fd5b50503461026f578160031936011261026f576020905160068152f35b50503461026f578160031936011261026f576020906006549051908152f35b50503461026f57606036600319011261026f57602090610c06611f9d612212565b611fa5612228565b60443591610c01836112f5612cb5565b50503461026f578160031936011261026f576020906002549051908152f35b82843461084557608036600319011261084557611fef612212565b50611ff8612228565b506064359067ffffffffffffffff82116108455736602383011215610845575060209281602461202d933693013591016122a6565b5051630a85bd0160e11b8152f35b905034610694578160031936011261069457612055612212565b602435936001600160a01b038061206a612cb5565b169283156120d657169283156120c1575060208581968684867f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925965260018552818120888252855220558551908152a35160018152f35b602491855191634a1406b160e11b8352820152fd5b855163e602df0560e01b8152808601849052602490fd5b84843461026f578160031936011261026f578160035492600184811c918186169586156121c0575b60209687851081146121ad578899509688969785829a529182600014610801575050600114612151575050506107ba92916107ab910385612268565b9190869350600383527fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b82841061219557505050820101816107ab6107ba610798565b8054848a01860152889550879490930192810161217c565b634e487b7160e01b835260228a52602483fd5b92607f1692612115565b60005b8381106121dd5750506000910152565b81810151838201526020016121cd565b90602091612206815180928185528580860191016121ca565b601f01601f1916010190565b600435906001600160a01b03821682036105c557565b602435906001600160a01b03821682036105c557565b67ffffffffffffffff811161225257604052565b634e487b7160e01b600052604160045260246000fd5b90601f8019910116810190811067ffffffffffffffff82111761225257604052565b67ffffffffffffffff811161225257601f01601f191660200190565b9291926122b28261228a565b916122c06040519384612268565b8294818452818301116105c5578281602093846000960137010152565b9080601f830112156105c5578160206122f8933591016122a6565b90565b9060406003198301126105c557600435916024359067ffffffffffffffff82116105c5576122f8916004016122dd565b6005546001600160a01b039060081c811681612345612cb5565b160361234e5750565b602490612359612cb5565b60405163118cdaa760e01b815291166004820152fd5b916001600160a01b0380841692831561243c5716928315612423576123926125f2565b600090838252816020526040822054908382106123f1575091604082827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef958760209652828652038282205586815220818154019055604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101839052606490fd5b60405163ec442f0560e01b815260006004820152602490fd5b604051634b637e8f60e11b815260006004820152602490fd5b9160018060a01b038093169160009383855260016020526040938486209183169182875260205284862054926000198403612494575b50505050505050565b8484106124f8575080156124e05781156124c85785526001602052838520908552602052039120553880808080808061248b565b8451634a1406b160e11b815260048101879052602490fd5b845163e602df0560e01b815260048101879052602490fd5b8551637dc7a0d960e11b81526001600160a01b039190911660048201526024810184905260448101859052606490fd5b906001600160a01b03821690811561243c576125426125f2565b6000928284528360205260408420549082821061259d5750817fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef926020928587528684520360408620558060025403600255604051908152a3565b60405163391434e360e21b81526001600160a01b03919091166004820152602481019190915260448101829052606490fd5b919082018092116125dc57565b634e487b7160e01b600052601160045260246000fd5b60ff600554166125fe57565b60405163d93c066560e01b8152600490fd5b1561261757565b60405162461bcd60e51b815260206004820152602360248201527f43616c6c6572206973206e6f7420746865207472757374656420666f727761726044820152623232b960e91b6064820152608490fd5b1561266f57565b60405162461bcd60e51b815260206004820152600d60248201526c496e76616c6964206e6f6e636560981b6044820152606490fd5b60001981146125dc5760010190565b91926122f895949160a094600180871b0380921685521660208401526040830152606082015281608082015201906121ed565b156126ed57565b60405162461bcd60e51b815260206004820152602560248201527f506869676f6c6420616d6f756e74206d75737420626520677265617465722074604482015264068616e20360dc1b6064820152608490fd5b818102929181159184041417156125dc57565b811561275d570490565b634e487b7160e01b600052601260045260246000fd5b926001600160a01b0391908282161561288d576127918415156126e6565b801561287e576127a5612710915b85612740565b04926127b184826125cf565b838616600052600060205260406000205410612842576127d1918561236f565b816127df575b505050600190565b612810827ff3816d9cce3442fbfe3e4d36ad047b3362efdc9f2e283e77b0ecd768a0a01ef29483600954169061236f565b60095460408051929091166001600160a01b0316825260208201929092524291810191909152606090a13880806127d7565b60405162461bcd60e51b8152602060048201526014602482015273496e73756666696369656e742062616c616e636560601b6044820152606490fd5b506127106127a5600a5461279f565b60405162461bcd60e51b815260206004820152602260248201527f526563697069656e742061646472657373206d7573742062652070726f766964604482015261195960f21b6064820152608490fd5b156128e457565b60405162461bcd60e51b815260206004820152601e60248201527f546f6b656e2061646472657373206d7573742062652070726f766964656400006044820152606490fd5b1561293057565b60405162461bcd60e51b815260206004820152602260248201527f4f6e6c792061646d696e732063616e2063616c6c20746869732066756e63746960448201526137b760f11b6064820152608490fd5b90926080926122f8959460018060a01b031683526020830152604082015281606082015201906121ed565b8051602e81149081612a45575b5080612a20575b612a1a57805190603b821491826129e1575b50506129dc57600090565b600190565b90915015612a0457602001516001600160f81b031916603160f91b1438806129d1565b634e487b7160e01b600052603260045260246000fd5b50600190565b50805160011015612a045760218101516001600160f81b031916606d60f81b146129bf565b905015612a045760208101516001600160f81b031916605160f81b14386129b8565b60060390600682116125dc57565b6005198101919082116125dc57565b604d81116125dc57600a0a90565b15612a9957565b60405162461bcd60e51b815260206004820152602b60248201527f5061796d656e7420746f6b656e20616d6f756e74206d7573742062652067726560448201526a061746572207468616e20360ac1b6064820152608490fd5b15612af957565b60405162461bcd60e51b815260206004820152602260248201527f496e73756666696369656e74207061796d656e7420746f6b656e2062616c616e604482015261636560f01b6064820152608490fd5b15612b5057565b60405162461bcd60e51b8152602060048201526024808201527f496e73756666696369656e74207061796d656e7420746f6b656e20616c6c6f77604482015263616e636560e01b6064820152608490fd5b519081151582036105c557565b15612bb557565b60405162461bcd60e51b815260206004820152601d60248201527f5061796d656e7420746f6b656e207472616e73666572206661696c65640000006044820152606490fd5b6020818303126105c55780519067ffffffffffffffff82116105c5570181601f820112156105c5578051612c2d8161228a565b92612c3b6040519485612268565b818452602082840101116105c5576122f891602080850191016121ca565b9695949193612c919360a095600180881b038094168a5260208a0152604089015216606087015260c0608087015260c08601906121ed565b930152565b908160209103126105c557516001600160a01b03811681036105c55790565b337f000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a6001600160a01b03161480612d03575b15612cff5760131936013681116125dc573560601c90565b3390565b506014361015612ce756fea2646970667358221220761afc950b717a7e4358657fd190b6c91f62bb885f7eee91c43d1855b67cc38564736f6c63430008140033

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

000000000000000000000000d297ef4b1291a03027c5d190e251b47b0052f16a

-----Decoded View---------------
Arg [0] : trustedForwarder (address): 0xd297EF4b1291a03027c5d190e251B47B0052F16A

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


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