Address Details
contract

0x33c37B39F226823D23Bfe74aA538948C0e999293

Contract Name
PlastikCryptoV2
Creator
0x4c45c6–9e9f2c at 0x20fc29–4179ee
Balance
0 CELO ( )
Locked CELO Balance
0.00 CELO
Voting CELO Balance
0.00 CELO
Pending Unlocked Gold
0.00 CELO
Tokens
Fetching tokens...
Transactions
2 Transactions
Transfers
0 Transfers
Gas Used
57,253
Last Balance Update
23955601
This contract has been verified via Sourcify. View contract in Sourcify repository
Contract name:
PlastikCryptoV2




Optimization enabled
false
Compiler version
v0.8.9+commit.e5eed63a




EVM Version
london




Verified at
2022-11-14T15:33:41.414312Z

contracts/PlastikCryptoV2.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/cryptography/draft-EIP712.sol";
import "./UtilsV2.sol";

contract PlastikCryptoV2 is Ownable, EIP712 {

    address priceValidator;

    constructor(address _priceSigner) EIP712("PLASTIK", "2.0") {
        priceValidator = _priceSigner;
    }


    function setPriceValidator(address newValidator) public onlyOwner returns (bool) {
        priceValidator = newValidator;
        return true;
    }

    /// @notice Verifies the signature for a given NFTVoucher, returning the address of the signer.
    /// @dev Will revert if the signature is invalid. Does not verify that the signer is authorized to mint NFTs.
    /// @param voucher An NFTVoucher describing an unminted NFT.
    function verifyNFTVoucher(
        NFTVoucherV2 calldata voucher,
        bytes memory signature
    ) public view returns (address) {
        bytes32 digest = _hashTypedDataV4(
            keccak256(
                abi.encode(
                    Constants.NFTVOUCHERV2_TYPEHASH,
                    voucher.tokenAddress,
                    voucher.tokenId,
                    voucher.amount,
                    keccak256(bytes(voucher.tokenURI)),
                    voucher.creatorAddress,
                    voucher.royalty
                )
            )
        );
        return ECDSA.recover(digest, signature);
    }

    function verifyPriceSignature(
        address sender,
        PlastikSellPrice calldata item,
        bytes calldata signature,
        address ercToken
    ) public view returns (address) {
        bytes32 digest = _hashTypedDataV4(
            keccak256(
                abi.encode(
                    Constants.PLASTIKSELLPRICEREQUEST_TYPEHASH,
                    item.buyer,
                    item.ratio,
                    item.decimals,
                    item.currency,
                    item.timestamp,
                    item.tokenAddress
                )
            )
        );
        address sig = ECDSA.recover(digest, signature);
        require(sig == priceValidator, "Price validator invalid");
        require(sender == item.buyer, "Buyer sign price invalid");
        require(ercToken == item.tokenAddress, "ercToken invalid");
        require(
            block.timestamp < item.timestamp + 10 minutes,
            "Price is expired"
        );
        return sig;
    }

    function verifySellerSign(
        SellRequest calldata item,
        bytes calldata signature
    ) public view returns (address) {
        bytes32 digest = _hashTypedDataV4(
            keccak256(
                abi.encode(
                    Constants.SELLREQUEST_TYPEHASH,
                    item.tokenAddress,
                    item.tokenId,
                    item.price,
                    item.amount,
                    item.erc20Address,
                    item.ngoFeePct,
                    item.sellerAddress
                )
            )
        );
        return ECDSA.recover(digest, signature);
    }

    function verifySellerSellRequest(
        address seller,
        SellRequest calldata sellRequest,
        address tokenAddress,
        uint256 tokenId
    ) public pure {
        require(seller == sellRequest.sellerAddress, "Invalid seller address");
        require(
            sellRequest.tokenAddress == tokenAddress,
            "Invalid token address"
        );
        require(sellRequest.tokenId == tokenId, "Invalid token id");
    }

    function verifyPRGVoucher(PRGVoucher calldata voucher, bytes memory signature)
        public
        view
        returns (address)
    {
        bytes32 digest = _hashTypedDataV4(
            keccak256(
                abi.encode(
                    Constants.PRGVOUCHER_TYPEHASH,
                    voucher.tokenAddress,
                    voucher.tokenId,
                    voucher.amount,
                    keccak256(bytes(voucher.tokenURI)),
                    voucher.creatorAddress
                )
            )
        );
        return ECDSA.recover(digest, signature);
    }
}
        

/_openzeppelin/contracts/access/Ownable.sol

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

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

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

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

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

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

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

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

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

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

/_openzeppelin/contracts/utils/Context.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}
          

/_openzeppelin/contracts/utils/Strings.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)

pragma solidity ^0.8.0;

/**
 * @dev String operations.
 */
library Strings {
    bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
    uint8 private constant _ADDRESS_LENGTH = 20;

    /**
     * @dev Converts a `uint256` to its ASCII `string` decimal representation.
     */
    function toString(uint256 value) internal pure returns (string memory) {
        // Inspired by OraclizeAPI's implementation - MIT licence
        // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol

        if (value == 0) {
            return "0";
        }
        uint256 temp = value;
        uint256 digits;
        while (temp != 0) {
            digits++;
            temp /= 10;
        }
        bytes memory buffer = new bytes(digits);
        while (value != 0) {
            digits -= 1;
            buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
            value /= 10;
        }
        return string(buffer);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
     */
    function toHexString(uint256 value) internal pure returns (string memory) {
        if (value == 0) {
            return "0x00";
        }
        uint256 temp = value;
        uint256 length = 0;
        while (temp != 0) {
            length++;
            temp >>= 8;
        }
        return toHexString(value, length);
    }

    /**
     * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
     */
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
        bytes memory buffer = new bytes(2 * length + 2);
        buffer[0] = "0";
        buffer[1] = "x";
        for (uint256 i = 2 * length + 1; i > 1; --i) {
            buffer[i] = _HEX_SYMBOLS[value & 0xf];
            value >>= 4;
        }
        require(value == 0, "Strings: hex length insufficient");
        return string(buffer);
    }

    /**
     * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
     */
    function toHexString(address addr) internal pure returns (string memory) {
        return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
    }
}
          

/_openzeppelin/contracts/utils/cryptography/ECDSA.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/cryptography/ECDSA.sol)

pragma solidity ^0.8.0;

import "../Strings.sol";

/**
 * @dev Elliptic Curve Digital Signature Algorithm (ECDSA) operations.
 *
 * These functions can be used to verify that a message was signed by the holder
 * of the private keys of a given address.
 */
library ECDSA {
    enum RecoverError {
        NoError,
        InvalidSignature,
        InvalidSignatureLength,
        InvalidSignatureS,
        InvalidSignatureV
    }

    function _throwError(RecoverError error) private pure {
        if (error == RecoverError.NoError) {
            return; // no error: do nothing
        } else if (error == RecoverError.InvalidSignature) {
            revert("ECDSA: invalid signature");
        } else if (error == RecoverError.InvalidSignatureLength) {
            revert("ECDSA: invalid signature length");
        } else if (error == RecoverError.InvalidSignatureS) {
            revert("ECDSA: invalid signature 's' value");
        } else if (error == RecoverError.InvalidSignatureV) {
            revert("ECDSA: invalid signature 'v' value");
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature` or error string. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     *
     * Documentation for signature generation:
     * - with https://web3js.readthedocs.io/en/v1.3.4/web3-eth-accounts.html#sign[Web3.js]
     * - with https://docs.ethers.io/v5/api/signer/#Signer-signMessage[ethers]
     *
     * _Available since v4.3._
     */
    function tryRecover(bytes32 hash, bytes memory signature) internal pure returns (address, RecoverError) {
        // Check the signature length
        // - case 65: r,s,v signature (standard)
        // - case 64: r,vs signature (cf https://eips.ethereum.org/EIPS/eip-2098) _Available since v4.1._
        if (signature.length == 65) {
            bytes32 r;
            bytes32 s;
            uint8 v;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                s := mload(add(signature, 0x40))
                v := byte(0, mload(add(signature, 0x60)))
            }
            return tryRecover(hash, v, r, s);
        } else if (signature.length == 64) {
            bytes32 r;
            bytes32 vs;
            // ecrecover takes the signature parameters, and the only way to get them
            // currently is to use assembly.
            /// @solidity memory-safe-assembly
            assembly {
                r := mload(add(signature, 0x20))
                vs := mload(add(signature, 0x40))
            }
            return tryRecover(hash, r, vs);
        } else {
            return (address(0), RecoverError.InvalidSignatureLength);
        }
    }

    /**
     * @dev Returns the address that signed a hashed message (`hash`) with
     * `signature`. This address can then be used for verification purposes.
     *
     * The `ecrecover` EVM opcode allows for malleable (non-unique) signatures:
     * this function rejects them by requiring the `s` value to be in the lower
     * half order, and the `v` value to be either 27 or 28.
     *
     * IMPORTANT: `hash` _must_ be the result of a hash operation for the
     * verification to be secure: it is possible to craft signatures that
     * recover to arbitrary addresses for non-hashed data. A safe way to ensure
     * this is by receiving a hash of the original message (which may otherwise
     * be too long), and then calling {toEthSignedMessageHash} on it.
     */
    function recover(bytes32 hash, bytes memory signature) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, signature);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `r` and `vs` short-signature fields separately.
     *
     * See https://eips.ethereum.org/EIPS/eip-2098[EIP-2098 short signatures]
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address, RecoverError) {
        bytes32 s = vs & bytes32(0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff);
        uint8 v = uint8((uint256(vs) >> 255) + 27);
        return tryRecover(hash, v, r, s);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `r and `vs` short-signature fields separately.
     *
     * _Available since v4.2._
     */
    function recover(
        bytes32 hash,
        bytes32 r,
        bytes32 vs
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, r, vs);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Overload of {ECDSA-tryRecover} that receives the `v`,
     * `r` and `s` signature fields separately.
     *
     * _Available since v4.3._
     */
    function tryRecover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address, RecoverError) {
        // EIP-2 still allows signature malleability for ecrecover(). Remove this possibility and make the signature
        // unique. Appendix F in the Ethereum Yellow paper (https://ethereum.github.io/yellowpaper/paper.pdf), defines
        // the valid range for s in (301): 0 < s < secp256k1n ÷ 2 + 1, and for v in (302): v ∈ {27, 28}. Most
        // signatures from current libraries generate a unique signature with an s-value in the lower half order.
        //
        // If your library generates malleable signatures, such as s-values in the upper range, calculate a new s-value
        // with 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141 - s1 and flip v from 27 to 28 or
        // vice versa. If your library also generates signatures with 0/1 for v instead 27/28, add 27 to v to accept
        // these malleable signatures as well.
        if (uint256(s) > 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0) {
            return (address(0), RecoverError.InvalidSignatureS);
        }
        if (v != 27 && v != 28) {
            return (address(0), RecoverError.InvalidSignatureV);
        }

        // If the signature is valid (and not malleable), return the signer address
        address signer = ecrecover(hash, v, r, s);
        if (signer == address(0)) {
            return (address(0), RecoverError.InvalidSignature);
        }

        return (signer, RecoverError.NoError);
    }

    /**
     * @dev Overload of {ECDSA-recover} that receives the `v`,
     * `r` and `s` signature fields separately.
     */
    function recover(
        bytes32 hash,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal pure returns (address) {
        (address recovered, RecoverError error) = tryRecover(hash, v, r, s);
        _throwError(error);
        return recovered;
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from a `hash`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32) {
        // 32 is the length in bytes of hash,
        // enforced by the type signature above
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", hash));
    }

    /**
     * @dev Returns an Ethereum Signed Message, created from `s`. This
     * produces hash corresponding to the one signed with the
     * https://eth.wiki/json-rpc/API#eth_sign[`eth_sign`]
     * JSON-RPC method as part of EIP-191.
     *
     * See {recover}.
     */
    function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n", Strings.toString(s.length), s));
    }

    /**
     * @dev Returns an Ethereum Signed Typed Data, created from a
     * `domainSeparator` and a `structHash`. This produces hash corresponding
     * to the one signed with the
     * https://eips.ethereum.org/EIPS/eip-712[`eth_signTypedData`]
     * JSON-RPC method as part of EIP-712.
     *
     * See {recover}.
     */
    function toTypedDataHash(bytes32 domainSeparator, bytes32 structHash) internal pure returns (bytes32) {
        return keccak256(abi.encodePacked("\x19\x01", domainSeparator, structHash));
    }
}
          

/_openzeppelin/contracts/utils/cryptography/draft-EIP712.sol

// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/cryptography/draft-EIP712.sol)

pragma solidity ^0.8.0;

import "./ECDSA.sol";

/**
 * @dev https://eips.ethereum.org/EIPS/eip-712[EIP 712] is a standard for hashing and signing of typed structured data.
 *
 * The encoding specified in the EIP is very generic, and such a generic implementation in Solidity is not feasible,
 * thus this contract does not implement the encoding itself. Protocols need to implement the type-specific encoding
 * they need in their contracts using a combination of `abi.encode` and `keccak256`.
 *
 * This contract implements the EIP 712 domain separator ({_domainSeparatorV4}) that is used as part of the encoding
 * scheme, and the final step of the encoding to obtain the message digest that is then signed via ECDSA
 * ({_hashTypedDataV4}).
 *
 * The implementation of the domain separator was designed to be as efficient as possible while still properly updating
 * the chain id to protect against replay attacks on an eventual fork of the chain.
 *
 * NOTE: This contract implements the version of the encoding known as "v4", as implemented by the JSON RPC method
 * https://docs.metamask.io/guide/signing-data.html[`eth_signTypedDataV4` in MetaMask].
 *
 * _Available since v3.4._
 */
abstract contract EIP712 {
    /* solhint-disable var-name-mixedcase */
    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;
    address private immutable _CACHED_THIS;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    /* solhint-enable var-name-mixedcase */

    /**
     * @dev Initializes the domain separator and parameter caches.
     *
     * The meaning of `name` and `version` is specified in
     * https://eips.ethereum.org/EIPS/eip-712#definition-of-domainseparator[EIP 712]:
     *
     * - `name`: the user readable name of the signing domain, i.e. the name of the DApp or the protocol.
     * - `version`: the current major version of the signing domain.
     *
     * NOTE: These parameters cannot be changed except through a xref:learn::upgrading-smart-contracts.adoc[smart
     * contract upgrade].
     */
    constructor(string memory name, string memory version) {
        bytes32 hashedName = keccak256(bytes(name));
        bytes32 hashedVersion = keccak256(bytes(version));
        bytes32 typeHash = keccak256(
            "EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"
        );
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = block.chainid;
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion);
        _CACHED_THIS = address(this);
        _TYPE_HASH = typeHash;
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() internal view returns (bytes32) {
        if (address(this) == _CACHED_THIS && block.chainid == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION);
        }
    }

    function _buildDomainSeparator(
        bytes32 typeHash,
        bytes32 nameHash,
        bytes32 versionHash
    ) private view returns (bytes32) {
        return keccak256(abi.encode(typeHash, nameHash, versionHash, block.chainid, address(this)));
    }

    /**
     * @dev Given an already https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct[hashed struct], this
     * function returns the hash of the fully encoded EIP712 message for this domain.
     *
     * This hash can be used together with {ECDSA-recover} to obtain the signer of a message. For example:
     *
     * ```solidity
     * bytes32 digest = _hashTypedDataV4(keccak256(abi.encode(
     *     keccak256("Mail(address to,string contents)"),
     *     mailTo,
     *     keccak256(bytes(mailContents))
     * )));
     * address signer = ECDSA.recover(digest, signature);
     * ```
     */
    function _hashTypedDataV4(bytes32 structHash) internal view virtual returns (bytes32) {
        return ECDSA.toTypedDataHash(_domainSeparatorV4(), structHash);
    }
}
          

/contracts/UtilsV2.sol

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

library Constants {
    bytes32 public constant MINTER_ROLE = keccak256("MINTER_ROLE");
    bytes32 constant NFTVOUCHER_TYPEHASH =
        keccak256(
            "NFTVoucher(address tokenAddress,uint256 tokenId,string tokenURI,address creatorAddress,uint96 royalty)"
        );
    bytes32 constant NFTVOUCHERV2_TYPEHASH =
        keccak256(
            "NFTVoucherV2(address tokenAddress,uint256 tokenId,uint256 amount,string tokenURI,address creatorAddress,uint96 royalty)"
        );
    bytes32 constant PRGVOUCHER_TYPEHASH =
        keccak256(
            "PRGVoucher(address tokenAddress,uint256 tokenId,uint256 amount,string tokenURI,address creatorAddress)"
        );
    bytes32 constant SELLREQUEST_TYPEHASH =
        keccak256(
            "SellRequest(address tokenAddress,uint256 tokenId,uint256 price,uint256 amount,address erc20Address,uint96 ngoFeePct,address sellerAddress)"
        );
    bytes32 constant PLASTIKSELLPRICEREQUEST_TYPEHASH =
        keccak256(
            "PlastikSellPrice(address buyer,uint256 ratio,uint256 decimals,uint96 currency,uint256 timestamp,address tokenAddress)"
        );
    bytes32 constant BIDREQUEST_TYPEHASH =
        keccak256(
            "BidRequest(address tokenAddress,uint256 tokenId,address erc20Address,address sellerAddress,address bidderAddress,uint256 biddingPrice)"
        );
    string public constant BASE_URI = "https://plastiks.io/ipfs/";
}

/// @notice Represents an un-minted NFT, which has not yet been recorded into the blockchain. A signed voucher can be redeemed for a real NFT using the redeem function.
struct NFTVoucher {
    /// @notice The address of the ERC721 or ERC1155
    address tokenAddress;
    /// @notice The id of the token to be redeemed. Must be unique - if another token with this ID already exists, the redeem function will revert.
    uint256 tokenId;
    /// @notice The metadata URI to associate with this token.
    string tokenURI;
    /// @notice The address of the original signer of this lazy minting
    address creatorAddress;
    /// @notice The royalty percentage for the original creator (offset 2 digits)
    uint96 royalty;
}

/// @notice Represents an un-minted NFT, which has not yet been recorded into the blockchain. A signed voucher can be redeemed for a real NFT using the redeem function.
struct NFTVoucherV2 {
    /// @notice The address of the ERC721 or ERC1155
    address tokenAddress;
    /// @notice The id of the token to be redeemed. Must be unique - if another token with this ID already exists, the redeem function will revert.
    uint256 tokenId;
    /// @notice The amount of tokens to mint
    uint256 amount;
    /// @notice The metadata URI to associate with this token.
    string tokenURI;
    /// @notice The address of the original signer of this lazy minting
    address creatorAddress;
    /// @notice The royalty percentage for the original creator (offset 2 digits)
    uint96 royalty;
}

struct PRGVoucher {
    /// @notice The address of the ERC721 or ERC1155
    address tokenAddress;
    /// @notice The id of the token to be redeemed. Must be unique - if another token with this ID already exists, the redeem function will revert.
    uint256 tokenId;
    /// @notice The amount of tokens to mint
    uint256 amount;
    /// @notice The metadata URI to associate with this token.
    string tokenURI;
    /// @notice The address of the original signer of this lazy minting
    address creatorAddress;
}

struct SellRequest {
    address tokenAddress;
    uint256 tokenId;
    uint256 price;
    uint256 amount;
    address erc20Address;
    uint96 ngoFeePct;
    address sellerAddress;
}

struct PlastikSellPrice {
    address buyer;
    uint256 ratio;
    uint256 decimals;
    uint96 currency;
    uint256 timestamp;
    address tokenAddress;
}

interface IPlastikArtLazyMint {
    function safeLazyMint(
        address buyer,
        NFTVoucherV2 calldata voucher,
        bytes calldata signature
    ) external payable returns (uint256);
}

interface IPlastikRRGLazyMint {
    function safeLazyMint(
        address buyer,
        NFTVoucherV2 calldata voucher,
        bytes calldata signature
    ) external payable returns (uint256);
}

interface IPlastikPRGLazyMint {
    function safeLazyMint(
        address buyer,
        PRGVoucher calldata voucher,
        bytes calldata signature
    ) external payable returns (uint256);
}
          

Contract ABI

[{"type":"constructor","stateMutability":"nonpayable","inputs":[{"type":"address","name":"_priceSigner","internalType":"address"}]},{"type":"event","name":"OwnershipTransferred","inputs":[{"type":"address","name":"previousOwner","internalType":"address","indexed":true},{"type":"address","name":"newOwner","internalType":"address","indexed":true}],"anonymous":false},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"owner","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"renounceOwnership","inputs":[]},{"type":"function","stateMutability":"nonpayable","outputs":[{"type":"bool","name":"","internalType":"bool"}],"name":"setPriceValidator","inputs":[{"type":"address","name":"newValidator","internalType":"address"}]},{"type":"function","stateMutability":"nonpayable","outputs":[],"name":"transferOwnership","inputs":[{"type":"address","name":"newOwner","internalType":"address"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"verifyNFTVoucher","inputs":[{"type":"tuple","name":"voucher","internalType":"struct NFTVoucherV2","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"string","name":"tokenURI","internalType":"string"},{"type":"address","name":"creatorAddress","internalType":"address"},{"type":"uint96","name":"royalty","internalType":"uint96"}]},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"verifyPRGVoucher","inputs":[{"type":"tuple","name":"voucher","internalType":"struct PRGVoucher","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"string","name":"tokenURI","internalType":"string"},{"type":"address","name":"creatorAddress","internalType":"address"}]},{"type":"bytes","name":"signature","internalType":"bytes"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"verifyPriceSignature","inputs":[{"type":"address","name":"sender","internalType":"address"},{"type":"tuple","name":"item","internalType":"struct PlastikSellPrice","components":[{"type":"address","name":"buyer","internalType":"address"},{"type":"uint256","name":"ratio","internalType":"uint256"},{"type":"uint256","name":"decimals","internalType":"uint256"},{"type":"uint96","name":"currency","internalType":"uint96"},{"type":"uint256","name":"timestamp","internalType":"uint256"},{"type":"address","name":"tokenAddress","internalType":"address"}]},{"type":"bytes","name":"signature","internalType":"bytes"},{"type":"address","name":"ercToken","internalType":"address"}]},{"type":"function","stateMutability":"pure","outputs":[],"name":"verifySellerSellRequest","inputs":[{"type":"address","name":"seller","internalType":"address"},{"type":"tuple","name":"sellRequest","internalType":"struct SellRequest","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"erc20Address","internalType":"address"},{"type":"uint96","name":"ngoFeePct","internalType":"uint96"},{"type":"address","name":"sellerAddress","internalType":"address"}]},{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"}]},{"type":"function","stateMutability":"view","outputs":[{"type":"address","name":"","internalType":"address"}],"name":"verifySellerSign","inputs":[{"type":"tuple","name":"item","internalType":"struct SellRequest","components":[{"type":"address","name":"tokenAddress","internalType":"address"},{"type":"uint256","name":"tokenId","internalType":"uint256"},{"type":"uint256","name":"price","internalType":"uint256"},{"type":"uint256","name":"amount","internalType":"uint256"},{"type":"address","name":"erc20Address","internalType":"address"},{"type":"uint96","name":"ngoFeePct","internalType":"uint96"},{"type":"address","name":"sellerAddress","internalType":"address"}]},{"type":"bytes","name":"signature","internalType":"bytes"}]}]
              

Contract Creation Code

0x6101406040523480156200001257600080fd5b506040516200260d3803806200260d833981810160405281019062000038919062000330565b6040518060400160405280600781526020017f504c415354494b000000000000000000000000000000000000000000000000008152506040518060400160405280600381526020017f322e300000000000000000000000000000000000000000000000000000000000815250620000c4620000b8620001be60201b60201c565b620001c660201b60201c565b60008280519060200120905060008280519060200120905060007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f90508260e081815250508161010081815250504660a081815250506200012d8184846200028a60201b60201c565b608081815250503073ffffffffffffffffffffffffffffffffffffffff1660c08173ffffffffffffffffffffffffffffffffffffffff1681525050806101208181525050505050505080600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505062000406565b600033905090565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b60008383834630604051602001620002a7959493929190620003a9565b6040516020818303038152906040528051906020012090509392505050565b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b6000620002f882620002cb565b9050919050565b6200030a81620002eb565b81146200031657600080fd5b50565b6000815190506200032a81620002ff565b92915050565b600060208284031215620003495762000348620002c6565b5b6000620003598482850162000319565b91505092915050565b6000819050919050565b620003778162000362565b82525050565b6000819050919050565b62000392816200037d565b82525050565b620003a381620002eb565b82525050565b600060a082019050620003c060008301886200036c565b620003cf60208301876200036c565b620003de60408301866200036c565b620003ed606083018562000387565b620003fc608083018462000398565b9695505050505050565b60805160a05160c05160e05161010051610120516121b7620004566000396000610c0d01526000610c4f01526000610c2e01526000610b6301526000610bb901526000610be201526121b76000f3fe608060405234801561001057600080fd5b50600436106100935760003560e01c8063b0f271c511610066578063b0f271c51461010c578063d323c15f1461013c578063d879253a1461016c578063f2fde38b1461019c578063fae5a83f146101b857610093565b8063285588f814610098578063715018a6146100b45780638da5cb5b146100be578063adb0ae18146100dc575b600080fd5b6100b260048036038101906100ad9190611176565b6101e8565b005b6100bc610334565b005b6100c6610348565b6040516100d391906111ef565b60405180910390f35b6100f660048036038101906100f1919061126f565b610371565b60405161010391906111ef565b60405180910390f35b61012660048036038101906101219190611430565b61047f565b60405161013391906111ef565b60405180910390f35b610156600480360381019061015191906114c7565b610541565b60405161016391906111ef565b60405180910390f35b61018660048036038101906101819190611570565b610826565b60405161019391906111ef565b60405180910390f35b6101b660048036038101906101b191906115e8565b6108fc565b005b6101d260048036038101906101cd91906115e8565b610980565b6040516101df9190611630565b60405180910390f35b8260c00160208101906101fb91906115e8565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610268576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025f906116a8565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1683600001602081019061029291906115e8565b73ffffffffffffffffffffffffffffffffffffffff16146102e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102df90611714565b60405180910390fd5b8083602001351461032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611780565b60405180910390fd5b50505050565b61033c6109d4565b6103466000610a52565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806104257fd655ef9c1fdfa8ced56d15210cb6b6a72ba2741d5cb61e2fbed1502d3b46fd628660000160208101906103ab91906115e8565b8760200135886040013589606001358a60800160208101906103cd91906115e8565b8b60a00160208101906103e091906117e4565b8c60c00160208101906103f391906115e8565b60405160200161040a989796959493929190611848565b60405160208183030381529060405280519060200120610b16565b90506104758185858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610b30565b9150509392505050565b60008061052c7feab102e13e8b2f0be533294892d4cbb82f3a148bbd853e21c5fa281864e6f4e38560000160208101906104b991906115e8565b866020013587604001358880606001906104d391906118d5565b6040516104e1929190611968565b60405180910390208960800160208101906104fc91906115e8565b60405160200161051196959493929190611981565b60405160208183030381529060405280519060200120610b16565b90506105388184610b30565b91505092915050565b6000806105e17fe5579de087ffe1e52529a6be897e847ac3bf17870732c42155c69a1fe0c8f76487600001602081019061057b91906115e8565b886020013589604001358a606001602081019061059891906117e4565b8b608001358c60a00160208101906105b091906115e8565b6040516020016105c697969594939291906119e2565b60405160208183030381529060405280519060200120610b16565b905060006106338287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610b30565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146106c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106bc90611a9d565b60405180910390fd5b8660000160208101906106d891906115e8565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073c90611b09565b60405180910390fd5b8660a001602081019061075891906115e8565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146107c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107bc90611b75565b60405180910390fd5b61025887608001356107d79190611bc4565b4210610818576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161080f90611c66565b60405180910390fd5b809250505095945050505050565b6000806108e77fa07d5eb1ba88dd4c6fe41d236c1e206309358d1abcc749c4ec0a2394bfad42d685600001602081019061086091906115e8565b8660200135876040013588806060019061087a91906118d5565b604051610888929190611968565b60405180910390208960800160208101906108a391906115e8565b8a60a00160208101906108b691906117e4565b6040516020016108cc9796959493929190611c86565b60405160208183030381529060405280519060200120610b16565b90506108f38184610b30565b91505092915050565b6109046109d4565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096b90611d67565b60405180910390fd5b61097d81610a52565b50565b600061098a6109d4565b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050919050565b6109dc610b57565b73ffffffffffffffffffffffffffffffffffffffff166109fa610348565b73ffffffffffffffffffffffffffffffffffffffff1614610a50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4790611dd3565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000610b29610b23610b5f565b83610c79565b9050919050565b6000806000610b3f8585610cac565b91509150610b4c81610d2f565b819250505092915050565b600033905090565b60007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16148015610bdb57507f000000000000000000000000000000000000000000000000000000000000000046145b15610c08577f00000000000000000000000000000000000000000000000000000000000000009050610c76565b610c737f00000000000000000000000000000000000000000000000000000000000000007f00000000000000000000000000000000000000000000000000000000000000007f0000000000000000000000000000000000000000000000000000000000000000610f04565b90505b90565b60008282604051602001610c8e929190611e6b565b60405160208183030381529060405280519060200120905092915050565b600080604183511415610cee5760008060006020860151925060408601519150606086015160001a9050610ce287828585610f3e565b94509450505050610d28565b604083511415610d1f576000806020850151915060408501519050610d1486838361104b565b935093505050610d28565b60006002915091505b9250929050565b60006004811115610d4357610d42611ea2565b5b816004811115610d5657610d55611ea2565b5b1415610d6157610f01565b60016004811115610d7557610d74611ea2565b5b816004811115610d8857610d87611ea2565b5b1415610dc9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc090611f1d565b60405180910390fd5b60026004811115610ddd57610ddc611ea2565b5b816004811115610df057610def611ea2565b5b1415610e31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e2890611f89565b60405180910390fd5b60036004811115610e4557610e44611ea2565b5b816004811115610e5857610e57611ea2565b5b1415610e99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e909061201b565b60405180910390fd5b600480811115610eac57610eab611ea2565b5b816004811115610ebf57610ebe611ea2565b5b1415610f00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ef7906120ad565b60405180910390fd5b5b50565b60008383834630604051602001610f1f9594939291906120cd565b6040516020818303038152906040528051906020012090509392505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c1115610f79576000600391509150611042565b601b8560ff1614158015610f915750601c8560ff1614155b15610fa3576000600491509150611042565b600060018787878760405160008152602001604052604051610fc8949392919061213c565b6020604051602081039080840390855afa158015610fea573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561103957600060019250925050611042565b80600092509250505b94509492505050565b60008060007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b841690506000601b60ff8660001c901c61108e9190611bc4565b905061109c87828885610f3e565b935093505050935093915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006110e9826110be565b9050919050565b6110f9816110de565b811461110457600080fd5b50565b600081359050611116816110f0565b92915050565b600080fd5b600060e082840312156111375761113661111c565b5b81905092915050565b6000819050919050565b61115381611140565b811461115e57600080fd5b50565b6000813590506111708161114a565b92915050565b6000806000806101408587031215611191576111906110b4565b5b600061119f87828801611107565b94505060206111b087828801611121565b9350506101006111c287828801611107565b9250506101206111d487828801611161565b91505092959194509250565b6111e9816110de565b82525050565b600060208201905061120460008301846111e0565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261122f5761122e61120a565b5b8235905067ffffffffffffffff81111561124c5761124b61120f565b5b60208301915083600182028301111561126857611267611214565b5b9250929050565b60008060006101008486031215611289576112886110b4565b5b600061129786828701611121565b93505060e084013567ffffffffffffffff8111156112b8576112b76110b9565b5b6112c486828701611219565b92509250509250925092565b600060a082840312156112e6576112e561111c565b5b81905092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61133d826112f4565b810181811067ffffffffffffffff8211171561135c5761135b611305565b5b80604052505050565b600061136f6110aa565b905061137b8282611334565b919050565b600067ffffffffffffffff82111561139b5761139a611305565b5b6113a4826112f4565b9050602081019050919050565b82818337600083830152505050565b60006113d36113ce84611380565b611365565b9050828152602081018484840111156113ef576113ee6112ef565b5b6113fa8482856113b1565b509392505050565b600082601f8301126114175761141661120a565b5b81356114278482602086016113c0565b91505092915050565b60008060408385031215611447576114466110b4565b5b600083013567ffffffffffffffff811115611465576114646110b9565b5b611471858286016112d0565b925050602083013567ffffffffffffffff811115611492576114916110b9565b5b61149e85828601611402565b9150509250929050565b600060c082840312156114be576114bd61111c565b5b81905092915050565b600080600080600061012086880312156114e4576114e36110b4565b5b60006114f288828901611107565b9550506020611503888289016114a8565b94505060e086013567ffffffffffffffff811115611524576115236110b9565b5b61153088828901611219565b935093505061010061154488828901611107565b9150509295509295909350565b600060c082840312156115675761156661111c565b5b81905092915050565b60008060408385031215611587576115866110b4565b5b600083013567ffffffffffffffff8111156115a5576115a46110b9565b5b6115b185828601611551565b925050602083013567ffffffffffffffff8111156115d2576115d16110b9565b5b6115de85828601611402565b9150509250929050565b6000602082840312156115fe576115fd6110b4565b5b600061160c84828501611107565b91505092915050565b60008115159050919050565b61162a81611615565b82525050565b60006020820190506116456000830184611621565b92915050565b600082825260208201905092915050565b7f496e76616c69642073656c6c6572206164647265737300000000000000000000600082015250565b600061169260168361164b565b915061169d8261165c565b602082019050919050565b600060208201905081810360008301526116c181611685565b9050919050565b7f496e76616c696420746f6b656e20616464726573730000000000000000000000600082015250565b60006116fe60158361164b565b9150611709826116c8565b602082019050919050565b6000602082019050818103600083015261172d816116f1565b9050919050565b7f496e76616c696420746f6b656e20696400000000000000000000000000000000600082015250565b600061176a60108361164b565b915061177582611734565b602082019050919050565b600060208201905081810360008301526117998161175d565b9050919050565b60006bffffffffffffffffffffffff82169050919050565b6117c1816117a0565b81146117cc57600080fd5b50565b6000813590506117de816117b8565b92915050565b6000602082840312156117fa576117f96110b4565b5b6000611808848285016117cf565b91505092915050565b6000819050919050565b61182481611811565b82525050565b61183381611140565b82525050565b611842816117a0565b82525050565b60006101008201905061185e600083018b61181b565b61186b602083018a6111e0565b611878604083018961182a565b611885606083018861182a565b611892608083018761182a565b61189f60a08301866111e0565b6118ac60c0830185611839565b6118b960e08301846111e0565b9998505050505050505050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126118f2576118f16118c6565b5b80840192508235915067ffffffffffffffff821115611914576119136118cb565b5b6020830192506001820236038313156119305761192f6118d0565b5b509250929050565b600081905092915050565b600061194f8385611938565b935061195c8385846113b1565b82840190509392505050565b6000611975828486611943565b91508190509392505050565b600060c082019050611996600083018961181b565b6119a360208301886111e0565b6119b0604083018761182a565b6119bd606083018661182a565b6119ca608083018561181b565b6119d760a08301846111e0565b979650505050505050565b600060e0820190506119f7600083018a61181b565b611a0460208301896111e0565b611a11604083018861182a565b611a1e606083018761182a565b611a2b6080830186611839565b611a3860a083018561182a565b611a4560c08301846111e0565b98975050505050505050565b7f50726963652076616c696461746f7220696e76616c6964000000000000000000600082015250565b6000611a8760178361164b565b9150611a9282611a51565b602082019050919050565b60006020820190508181036000830152611ab681611a7a565b9050919050565b7f4275796572207369676e20707269636520696e76616c69640000000000000000600082015250565b6000611af360188361164b565b9150611afe82611abd565b602082019050919050565b60006020820190508181036000830152611b2281611ae6565b9050919050565b7f657263546f6b656e20696e76616c696400000000000000000000000000000000600082015250565b6000611b5f60108361164b565b9150611b6a82611b29565b602082019050919050565b60006020820190508181036000830152611b8e81611b52565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bcf82611140565b9150611bda83611140565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611c0f57611c0e611b95565b5b828201905092915050565b7f5072696365206973206578706972656400000000000000000000000000000000600082015250565b6000611c5060108361164b565b9150611c5b82611c1a565b602082019050919050565b60006020820190508181036000830152611c7f81611c43565b9050919050565b600060e082019050611c9b600083018a61181b565b611ca860208301896111e0565b611cb5604083018861182a565b611cc2606083018761182a565b611ccf608083018661181b565b611cdc60a08301856111e0565b611ce960c0830184611839565b98975050505050505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000611d5160268361164b565b9150611d5c82611cf5565b604082019050919050565b60006020820190508181036000830152611d8081611d44565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000611dbd60208361164b565b9150611dc882611d87565b602082019050919050565b60006020820190508181036000830152611dec81611db0565b9050919050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611e34600283611df3565b9150611e3f82611dfe565b600282019050919050565b6000819050919050565b611e65611e6082611811565b611e4a565b82525050565b6000611e7682611e27565b9150611e828285611e54565b602082019150611e928284611e54565b6020820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000611f0760188361164b565b9150611f1282611ed1565b602082019050919050565b60006020820190508181036000830152611f3681611efa565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000611f73601f8361164b565b9150611f7e82611f3d565b602082019050919050565b60006020820190508181036000830152611fa281611f66565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b600061200560228361164b565b915061201082611fa9565b604082019050919050565b6000602082019050818103600083015261203481611ff8565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b600061209760228361164b565b91506120a28261203b565b604082019050919050565b600060208201905081810360008301526120c68161208a565b9050919050565b600060a0820190506120e2600083018861181b565b6120ef602083018761181b565b6120fc604083018661181b565b612109606083018561182a565b61211660808301846111e0565b9695505050505050565b600060ff82169050919050565b61213681612120565b82525050565b6000608082019050612151600083018761181b565b61215e602083018661212d565b61216b604083018561181b565b612178606083018461181b565b9594505050505056fea26469706673582212203a24a3566302c766cb67980fa62a5e07c49b1c85a08c1d0e082a08f07900acce64736f6c634300080900330000000000000000000000004c45c6d2f8ccd5e90802e3caee85af67e89e9f2c

Deployed ByteCode

0x608060405234801561001057600080fd5b50600436106100935760003560e01c8063b0f271c511610066578063b0f271c51461010c578063d323c15f1461013c578063d879253a1461016c578063f2fde38b1461019c578063fae5a83f146101b857610093565b8063285588f814610098578063715018a6146100b45780638da5cb5b146100be578063adb0ae18146100dc575b600080fd5b6100b260048036038101906100ad9190611176565b6101e8565b005b6100bc610334565b005b6100c6610348565b6040516100d391906111ef565b60405180910390f35b6100f660048036038101906100f1919061126f565b610371565b60405161010391906111ef565b60405180910390f35b61012660048036038101906101219190611430565b61047f565b60405161013391906111ef565b60405180910390f35b610156600480360381019061015191906114c7565b610541565b60405161016391906111ef565b60405180910390f35b61018660048036038101906101819190611570565b610826565b60405161019391906111ef565b60405180910390f35b6101b660048036038101906101b191906115e8565b6108fc565b005b6101d260048036038101906101cd91906115e8565b610980565b6040516101df9190611630565b60405180910390f35b8260c00160208101906101fb91906115e8565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff1614610268576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161025f906116a8565b60405180910390fd5b8173ffffffffffffffffffffffffffffffffffffffff1683600001602081019061029291906115e8565b73ffffffffffffffffffffffffffffffffffffffff16146102e8576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016102df90611714565b60405180910390fd5b8083602001351461032e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161032590611780565b60405180910390fd5b50505050565b61033c6109d4565b6103466000610a52565b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff16905090565b6000806104257fd655ef9c1fdfa8ced56d15210cb6b6a72ba2741d5cb61e2fbed1502d3b46fd628660000160208101906103ab91906115e8565b8760200135886040013589606001358a60800160208101906103cd91906115e8565b8b60a00160208101906103e091906117e4565b8c60c00160208101906103f391906115e8565b60405160200161040a989796959493929190611848565b60405160208183030381529060405280519060200120610b16565b90506104758185858080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610b30565b9150509392505050565b60008061052c7feab102e13e8b2f0be533294892d4cbb82f3a148bbd853e21c5fa281864e6f4e38560000160208101906104b991906115e8565b866020013587604001358880606001906104d391906118d5565b6040516104e1929190611968565b60405180910390208960800160208101906104fc91906115e8565b60405160200161051196959493929190611981565b60405160208183030381529060405280519060200120610b16565b90506105388184610b30565b91505092915050565b6000806105e17fe5579de087ffe1e52529a6be897e847ac3bf17870732c42155c69a1fe0c8f76487600001602081019061057b91906115e8565b886020013589604001358a606001602081019061059891906117e4565b8b608001358c60a00160208101906105b091906115e8565b6040516020016105c697969594939291906119e2565b60405160208183030381529060405280519060200120610b16565b905060006106338287878080601f016020809104026020016040519081016040528093929190818152602001838380828437600081840152601f19601f82011690508083019250505050505050610b30565b9050600160009054906101000a900473ffffffffffffffffffffffffffffffffffffffff1673ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16146106c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016106bc90611a9d565b60405180910390fd5b8660000160208101906106d891906115e8565b73ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff1614610745576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161073c90611b09565b60405180910390fd5b8660a001602081019061075891906115e8565b73ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff16146107c5576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004016107bc90611b75565b60405180910390fd5b61025887608001356107d79190611bc4565b4210610818576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161080f90611c66565b60405180910390fd5b809250505095945050505050565b6000806108e77fa07d5eb1ba88dd4c6fe41d236c1e206309358d1abcc749c4ec0a2394bfad42d685600001602081019061086091906115e8565b8660200135876040013588806060019061087a91906118d5565b604051610888929190611968565b60405180910390208960800160208101906108a391906115e8565b8a60a00160208101906108b691906117e4565b6040516020016108cc9796959493929190611c86565b60405160208183030381529060405280519060200120610b16565b90506108f38184610b30565b91505092915050565b6109046109d4565b600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff161415610974576040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161096b90611d67565b60405180910390fd5b61097d81610a52565b50565b600061098a6109d4565b81600160006101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff16021790555060019050919050565b6109dc610b57565b73ffffffffffffffffffffffffffffffffffffffff166109fa610348565b73ffffffffffffffffffffffffffffffffffffffff1614610a50576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610a4790611dd3565b60405180910390fd5b565b60008060009054906101000a900473ffffffffffffffffffffffffffffffffffffffff169050816000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055508173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e060405160405180910390a35050565b6000610b29610b23610b5f565b83610c79565b9050919050565b6000806000610b3f8585610cac565b91509150610b4c81610d2f565b819250505092915050565b600033905090565b60007f00000000000000000000000033c37b39f226823d23bfe74aa538948c0e99929373ffffffffffffffffffffffffffffffffffffffff163073ffffffffffffffffffffffffffffffffffffffff16148015610bdb57507f000000000000000000000000000000000000000000000000000000000000a4ec46145b15610c08577f809e3e534df359682dbfbbdd76a77608bc231b8212ea59c6c6ed22dfc951db589050610c76565b610c737f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f7fe6a88b42d7ee6fb54ae3b6ba18e511a3a58451a4ec9f6ac2fc7674a5b76c06127f88f72b566ae0c96f6fffac4bc8ac74909f61512ac0c06a8124d5ed420d306f90610f04565b90505b90565b60008282604051602001610c8e929190611e6b565b60405160208183030381529060405280519060200120905092915050565b600080604183511415610cee5760008060006020860151925060408601519150606086015160001a9050610ce287828585610f3e565b94509450505050610d28565b604083511415610d1f576000806020850151915060408501519050610d1486838361104b565b935093505050610d28565b60006002915091505b9250929050565b60006004811115610d4357610d42611ea2565b5b816004811115610d5657610d55611ea2565b5b1415610d6157610f01565b60016004811115610d7557610d74611ea2565b5b816004811115610d8857610d87611ea2565b5b1415610dc9576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610dc090611f1d565b60405180910390fd5b60026004811115610ddd57610ddc611ea2565b5b816004811115610df057610def611ea2565b5b1415610e31576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e2890611f89565b60405180910390fd5b60036004811115610e4557610e44611ea2565b5b816004811115610e5857610e57611ea2565b5b1415610e99576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610e909061201b565b60405180910390fd5b600480811115610eac57610eab611ea2565b5b816004811115610ebf57610ebe611ea2565b5b1415610f00576040517f08c379a0000000000000000000000000000000000000000000000000000000008152600401610ef7906120ad565b60405180910390fd5b5b50565b60008383834630604051602001610f1f9594939291906120cd565b6040516020818303038152906040528051906020012090509392505050565b6000807f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a08360001c1115610f79576000600391509150611042565b601b8560ff1614158015610f915750601c8560ff1614155b15610fa3576000600491509150611042565b600060018787878760405160008152602001604052604051610fc8949392919061213c565b6020604051602081039080840390855afa158015610fea573d6000803e3d6000fd5b505050602060405103519050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16141561103957600060019250925050611042565b80600092509250505b94509492505050565b60008060007f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60001b841690506000601b60ff8660001c901c61108e9190611bc4565b905061109c87828885610f3e565b935093505050935093915050565b6000604051905090565b600080fd5b600080fd5b600073ffffffffffffffffffffffffffffffffffffffff82169050919050565b60006110e9826110be565b9050919050565b6110f9816110de565b811461110457600080fd5b50565b600081359050611116816110f0565b92915050565b600080fd5b600060e082840312156111375761113661111c565b5b81905092915050565b6000819050919050565b61115381611140565b811461115e57600080fd5b50565b6000813590506111708161114a565b92915050565b6000806000806101408587031215611191576111906110b4565b5b600061119f87828801611107565b94505060206111b087828801611121565b9350506101006111c287828801611107565b9250506101206111d487828801611161565b91505092959194509250565b6111e9816110de565b82525050565b600060208201905061120460008301846111e0565b92915050565b600080fd5b600080fd5b600080fd5b60008083601f84011261122f5761122e61120a565b5b8235905067ffffffffffffffff81111561124c5761124b61120f565b5b60208301915083600182028301111561126857611267611214565b5b9250929050565b60008060006101008486031215611289576112886110b4565b5b600061129786828701611121565b93505060e084013567ffffffffffffffff8111156112b8576112b76110b9565b5b6112c486828701611219565b92509250509250925092565b600060a082840312156112e6576112e561111c565b5b81905092915050565b600080fd5b6000601f19601f8301169050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b61133d826112f4565b810181811067ffffffffffffffff8211171561135c5761135b611305565b5b80604052505050565b600061136f6110aa565b905061137b8282611334565b919050565b600067ffffffffffffffff82111561139b5761139a611305565b5b6113a4826112f4565b9050602081019050919050565b82818337600083830152505050565b60006113d36113ce84611380565b611365565b9050828152602081018484840111156113ef576113ee6112ef565b5b6113fa8482856113b1565b509392505050565b600082601f8301126114175761141661120a565b5b81356114278482602086016113c0565b91505092915050565b60008060408385031215611447576114466110b4565b5b600083013567ffffffffffffffff811115611465576114646110b9565b5b611471858286016112d0565b925050602083013567ffffffffffffffff811115611492576114916110b9565b5b61149e85828601611402565b9150509250929050565b600060c082840312156114be576114bd61111c565b5b81905092915050565b600080600080600061012086880312156114e4576114e36110b4565b5b60006114f288828901611107565b9550506020611503888289016114a8565b94505060e086013567ffffffffffffffff811115611524576115236110b9565b5b61153088828901611219565b935093505061010061154488828901611107565b9150509295509295909350565b600060c082840312156115675761156661111c565b5b81905092915050565b60008060408385031215611587576115866110b4565b5b600083013567ffffffffffffffff8111156115a5576115a46110b9565b5b6115b185828601611551565b925050602083013567ffffffffffffffff8111156115d2576115d16110b9565b5b6115de85828601611402565b9150509250929050565b6000602082840312156115fe576115fd6110b4565b5b600061160c84828501611107565b91505092915050565b60008115159050919050565b61162a81611615565b82525050565b60006020820190506116456000830184611621565b92915050565b600082825260208201905092915050565b7f496e76616c69642073656c6c6572206164647265737300000000000000000000600082015250565b600061169260168361164b565b915061169d8261165c565b602082019050919050565b600060208201905081810360008301526116c181611685565b9050919050565b7f496e76616c696420746f6b656e20616464726573730000000000000000000000600082015250565b60006116fe60158361164b565b9150611709826116c8565b602082019050919050565b6000602082019050818103600083015261172d816116f1565b9050919050565b7f496e76616c696420746f6b656e20696400000000000000000000000000000000600082015250565b600061176a60108361164b565b915061177582611734565b602082019050919050565b600060208201905081810360008301526117998161175d565b9050919050565b60006bffffffffffffffffffffffff82169050919050565b6117c1816117a0565b81146117cc57600080fd5b50565b6000813590506117de816117b8565b92915050565b6000602082840312156117fa576117f96110b4565b5b6000611808848285016117cf565b91505092915050565b6000819050919050565b61182481611811565b82525050565b61183381611140565b82525050565b611842816117a0565b82525050565b60006101008201905061185e600083018b61181b565b61186b602083018a6111e0565b611878604083018961182a565b611885606083018861182a565b611892608083018761182a565b61189f60a08301866111e0565b6118ac60c0830185611839565b6118b960e08301846111e0565b9998505050505050505050565b600080fd5b600080fd5b600080fd5b600080833560016020038436030381126118f2576118f16118c6565b5b80840192508235915067ffffffffffffffff821115611914576119136118cb565b5b6020830192506001820236038313156119305761192f6118d0565b5b509250929050565b600081905092915050565b600061194f8385611938565b935061195c8385846113b1565b82840190509392505050565b6000611975828486611943565b91508190509392505050565b600060c082019050611996600083018961181b565b6119a360208301886111e0565b6119b0604083018761182a565b6119bd606083018661182a565b6119ca608083018561181b565b6119d760a08301846111e0565b979650505050505050565b600060e0820190506119f7600083018a61181b565b611a0460208301896111e0565b611a11604083018861182a565b611a1e606083018761182a565b611a2b6080830186611839565b611a3860a083018561182a565b611a4560c08301846111e0565b98975050505050505050565b7f50726963652076616c696461746f7220696e76616c6964000000000000000000600082015250565b6000611a8760178361164b565b9150611a9282611a51565b602082019050919050565b60006020820190508181036000830152611ab681611a7a565b9050919050565b7f4275796572207369676e20707269636520696e76616c69640000000000000000600082015250565b6000611af360188361164b565b9150611afe82611abd565b602082019050919050565b60006020820190508181036000830152611b2281611ae6565b9050919050565b7f657263546f6b656e20696e76616c696400000000000000000000000000000000600082015250565b6000611b5f60108361164b565b9150611b6a82611b29565b602082019050919050565b60006020820190508181036000830152611b8e81611b52565b9050919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b6000611bcf82611140565b9150611bda83611140565b9250827fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff03821115611c0f57611c0e611b95565b5b828201905092915050565b7f5072696365206973206578706972656400000000000000000000000000000000600082015250565b6000611c5060108361164b565b9150611c5b82611c1a565b602082019050919050565b60006020820190508181036000830152611c7f81611c43565b9050919050565b600060e082019050611c9b600083018a61181b565b611ca860208301896111e0565b611cb5604083018861182a565b611cc2606083018761182a565b611ccf608083018661181b565b611cdc60a08301856111e0565b611ce960c0830184611839565b98975050505050505050565b7f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160008201527f6464726573730000000000000000000000000000000000000000000000000000602082015250565b6000611d5160268361164b565b9150611d5c82611cf5565b604082019050919050565b60006020820190508181036000830152611d8081611d44565b9050919050565b7f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572600082015250565b6000611dbd60208361164b565b9150611dc882611d87565b602082019050919050565b60006020820190508181036000830152611dec81611db0565b9050919050565b600081905092915050565b7f1901000000000000000000000000000000000000000000000000000000000000600082015250565b6000611e34600283611df3565b9150611e3f82611dfe565b600282019050919050565b6000819050919050565b611e65611e6082611811565b611e4a565b82525050565b6000611e7682611e27565b9150611e828285611e54565b602082019150611e928284611e54565b6020820191508190509392505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052602160045260246000fd5b7f45434453413a20696e76616c6964207369676e61747572650000000000000000600082015250565b6000611f0760188361164b565b9150611f1282611ed1565b602082019050919050565b60006020820190508181036000830152611f3681611efa565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265206c656e67746800600082015250565b6000611f73601f8361164b565b9150611f7e82611f3d565b602082019050919050565b60006020820190508181036000830152611fa281611f66565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202773272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b600061200560228361164b565b915061201082611fa9565b604082019050919050565b6000602082019050818103600083015261203481611ff8565b9050919050565b7f45434453413a20696e76616c6964207369676e6174757265202776272076616c60008201527f7565000000000000000000000000000000000000000000000000000000000000602082015250565b600061209760228361164b565b91506120a28261203b565b604082019050919050565b600060208201905081810360008301526120c68161208a565b9050919050565b600060a0820190506120e2600083018861181b565b6120ef602083018761181b565b6120fc604083018661181b565b612109606083018561182a565b61211660808301846111e0565b9695505050505050565b600060ff82169050919050565b61213681612120565b82525050565b6000608082019050612151600083018761181b565b61215e602083018661212d565b61216b604083018561181b565b612178606083018461181b565b9594505050505056fea26469706673582212203a24a3566302c766cb67980fa62a5e07c49b1c85a08c1d0e082a08f07900acce64736f6c63430008090033