ETH Price: $3,396.34 (-1.07%)

Token

Infinity (∞)
 

Overview

Max Total Supply

115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639,935

Holders

1,442

Total Transfers

-

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW



# Exchange Pair Price  24H Volume % Volume
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.

Contract Source Code Verified (Exact Match)

Contract Name:
Infinity

Compiler Version
v0.8.20+commit.a1b79de6

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion
File 1 of 14 : Infinity.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./libraries/InfiniteArt.sol";
import "./libraries/InfiniteBags.sol";
import "./libraries/InfiniteGenerator.sol";
import "./libraries/InfiniteMetadata.sol";

import "./standards/ERC1155.sol";

/// @title Infinity token contract.
/// @notice Imo notable.
/// @author Visualize Value
contract Infinity is ERC1155 {

    /// @notice The name of the collection.
    string public name = "Infinity";

    /// @notice The symbol of the collection.
    string public symbol = unicode"∞";

    /// @notice The price of an infinity token.
    uint public price = 0.008 ether;

    /// @dev VV creator account.
    address private constant VV = 0xc8f8e2F59Dd95fF67c3d39109ecA2e2A017D4c8a;

    /// @dev Instanciate the contract...
    constructor(address[] memory genesisRecipients) ERC1155() payable {
        _checkDeposit(genesisRecipients.length);

        uint count = genesisRecipients.length;
        for (uint i = 0; i < count;) {
            _mint(genesisRecipients[i], 0, 1, "");

            unchecked { ++i; }
        }
    }

    /// @notice Deposit ether, receive random infinities
    receive() external payable {
        _generateViaDeposit(msg.sender, _randomId());
    }

    /// @notice Create a new infinity check and deposit 0.008 ETH for each token.
    /// @param recipient The address that should receive the token.
    /// @param message Mint the token with an optional message.
    function generate(
        address recipient,
        string calldata message
    ) public payable {
        uint tokenId = _randomId();

        _generateViaDeposit(recipient, tokenId);

        _message(recipient, tokenId, message);
    }

    /// @notice Copy an existing infinity check owned by someone and deposit 0.008 ETH for each token.
    /// @param source The address of an existing owner of the token.
    /// @param recipient The address that should receive the token.
    /// @param tokenId The token ID to mint.
    /// @param message Mint the token with an optional message.
    function generateExisting(
        address source,
        address recipient,
        uint tokenId,
        string calldata message
    ) public payable {
        _validateId(tokenId, source);

        _generateViaDeposit(recipient, tokenId);

        _message(recipient, tokenId, message);
    }

    /// @notice Swap an inifinity token for a new one.
    /// @param id The token ID to burn.
    /// @param amount The token amount to burn / recreate.
    function regenerate(uint id, uint amount) public {
        // Execute burn
        _burn(msg.sender, id, amount);

        // Mint a new token
        _mint(msg.sender, _randomId(), amount, "");
    }

    /// @notice Destroy the token to withdraw its desposited ETH.
    /// @param id The token ID to destroy.
    /// @param amount The amount to degenerate (withdraws 0.008 ETH per item).
    function degenerate(
        uint id,
        uint amount
    ) public {
        // Execute burn
        _burn(msg.sender, id, amount);

        // Withdraw funds
        _send(msg.sender, amount * price);
    }

    /// @notice Create multiple infinity check tokens and deposit 0.008 ETH in each.
    /// @param recipients The addresses that should receive the token.
    /// @param amounts The number of tokens to send to each recipient.
    function generateMany(
        address[] calldata recipients,
        uint[] calldata amounts
    ) public payable {
        _checkDeposit(_totalAmount(amounts));

        uint count = recipients.length;
        for (uint i = 0; i < count;) {
            _mint(recipients[i], _randomId(), amounts[i], "");

            unchecked { ++i; }
        }
    }

    /// @notice Copy multiple infinity check tokens and deposit 0.008 ETH in each.
    /// @param sources The addresses of existing owners of each token.
    /// @param recipients The addresses that should receive the token.
    /// @param tokenIds The tokenIDs to mint.
    /// @param amounts The number of tokens to send for each token.
    function generateManyExisting(
        address[] calldata sources,
        address[] calldata recipients,
        uint[] calldata tokenIds,
        uint[] calldata amounts
    ) public payable {
        _checkDeposit(_totalAmount(amounts));

        uint count = sources.length;
        for (uint i = 0; i < count;) {
            _validateId(tokenIds[i], sources[i]);

            _mint(recipients[i], tokenIds[i], amounts[i], "");

            unchecked { ++i; }
        }
    }

    /// @notice Create multiple new infinity check tokens and deposit 0.008 ETH in each.
    /// @param ids The existing token IDs that should be destroyed in the process.
    /// @param degenerateAmounts The number of tokens per id to burn.
    /// @param amounts The number of tokens per id recreate.
    function regenerateMany(
        uint[] calldata ids,
        uint[] calldata degenerateAmounts,
        uint[] calldata amounts
    ) public payable {
        if (_totalAmount(degenerateAmounts) != _totalAmount(amounts)) revert InvalidInput();

        uint count = ids.length;
        for (uint i = 0; i < count;) {
            _burn(msg.sender, ids[i], degenerateAmounts[i]);
            _mint(msg.sender, _randomId(), amounts[i], "");

            unchecked { ++i; }
        }
    }

    /// @notice Degenerate multiple tokens at once.
    /// @param ids The tokenIDs to destroy.
    /// @param amounts The amounts to degenerate (withdraws 0.008 ETH per item).
    function degenerateMany(
        uint[] memory ids,
        uint[] memory amounts
    ) public {
        if (ids.length != amounts.length) revert InvalidInput();

        // Execute burn
        _burnBatch(msg.sender, ids, amounts);

        // Withdraw funds
        _send(msg.sender, _totalAmount(amounts) * price);
    }

    /// @notice Render SVG of the token.
    /// @param tokenId The token ID to render.
    function svg(uint tokenId) public pure returns (string memory) {
        return InfiniteArt.renderSVG(InfiniteGenerator.tokenData(tokenId));
    }

    /// @notice Render the encoded token metadata-URI.
    /// @param tokenId The token ID to get metadata for.
    function uri(uint tokenId) public pure override returns (string memory) {
        return InfiniteMetadata.tokenURI(InfiniteGenerator.tokenData(tokenId));
    }

    /// @notice Supply is (in)finite: (2^256 - 1)^2.
    function totalSupply() public pure returns (uint) { return type(uint).max; }
    function totalSupply(uint) public pure returns (uint) { return type(uint).max; }

    /// @dev Mint a token n times, based on the amount of ETH sent.
    function _generateViaDeposit(address recipient, uint tokenId) internal {
        uint amount  = msg.value / price;
        uint surplus = msg.value % price;

        if (amount == 0) revert InvalidDesposit();

        _mint(recipient, tokenId, amount, "");
        _send(recipient, surplus);
    }

    /// @dev Validate IDs to minted tokens or randomize for initial mints. Exception for VV mints.
    function _validateId(uint id, address source) internal view {
        bool minted = balanceOf(source, id) > 0;

        // If it's not already minted piece, or we are not VV, revert.
        if(! minted && msg.sender != VV) revert InvalidToken();
    }

    /// @dev Make a random generative token ID.
    function _randomId() internal view returns (uint) {
        return uint(keccak256(abi.encodePacked(block.prevrandao, msg.sender, gasleft())));
    }

    /// @dev Check whether the deposited Ether is a correct {price} multipe of the token {amount}
    function _checkDeposit(uint amount) internal {
        if (msg.value != amount * price) revert InvalidDesposit();
    }

    /// @dev Get the sum of all given amounts
    function _totalAmount(uint[] memory amounts) internal pure returns (uint amount) {
        for (uint i = 0; i < amounts.length; i++) {
            amount += amounts[i];
        }
    }

    /// @dev Send ETH to an address
    function _send(address to, uint value) internal {
        (bool success, ) = payable(to).call{value: value}("");
        require(success, "Unable to send value, recipient may have reverted");
    }

    /// @dev Emit a mint message, if provided
    function _message(address recipient, uint tokenId, string calldata message) internal {
        if (bytes(message).length > 0) {
            emit Message(msg.sender, recipient, tokenId, message);
        }
    }
}

File 2 of 14 : IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC1155/extensions/IERC1155MetadataURI.sol)

pragma solidity ^0.8.0;

import "../IERC1155.sol";

/**
 * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
 * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155MetadataURI is IERC1155 {
    /**
     * @dev Returns the URI for token type `id`.
     *
     * If the `\{id\}` substring is present in the URI, it must be replaced by
     * clients with the actual token type ID.
     */
    function uri(uint256 id) external view returns (string memory);
}

File 3 of 14 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 4 of 14 : IERC1155Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.5.0) (token/ERC1155/IERC1155Receiver.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev _Available since v3.1._
 */
interface IERC1155Receiver is IERC165 {
    /**
     * @dev Handles the receipt of a single ERC1155 token type. This function is
     * called at the end of a `safeTransferFrom` after the balance has been updated.
     *
     * NOTE: To accept the transfer, this must return
     * `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
     * (i.e. 0xf23a6e61, or its own function selector).
     *
     * @param operator The address which initiated the transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param id The ID of the token being transferred
     * @param value The amount of tokens being transferred
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
     */
    function onERC1155Received(
        address operator,
        address from,
        uint256 id,
        uint256 value,
        bytes calldata data
    ) external returns (bytes4);

    /**
     * @dev Handles the receipt of a multiple ERC1155 token types. This function
     * is called at the end of a `safeBatchTransferFrom` after the balances have
     * been updated.
     *
     * NOTE: To accept the transfer(s), this must return
     * `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
     * (i.e. 0xbc197c81, or its own function selector).
     *
     * @param operator The address which initiated the batch transfer (i.e. msg.sender)
     * @param from The address which previously owned the token
     * @param ids An array containing ids of each token being transferred (order and length must match values array)
     * @param values An array containing amounts of each token being transferred (order and length must match ids array)
     * @param data Additional data with no specified format
     * @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
     */
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4);
}

File 5 of 14 : Base64.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Base64.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides a set of functions to operate with Base64 strings.
 *
 * _Available since v4.5._
 */
library Base64 {
    /**
     * @dev Base64 Encoding/Decoding Table
     */
    string internal constant _TABLE = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";

    /**
     * @dev Converts a `bytes` to its Bytes64 `string` representation.
     */
    function encode(bytes memory data) internal pure returns (string memory) {
        /**
         * Inspired by Brecht Devos (Brechtpd) implementation - MIT licence
         * https://github.com/Brechtpd/base64/blob/e78d9fd951e7b0977ddca77d92dc85183770daf4/base64.sol
         */
        if (data.length == 0) return "";

        // Loads the table into memory
        string memory table = _TABLE;

        // Encoding takes 3 bytes chunks of binary data from `bytes` data parameter
        // and split into 4 numbers of 6 bits.
        // The final Base64 length should be `bytes` data length multiplied by 4/3 rounded up
        // - `data.length + 2`  -> Round up
        // - `/ 3`              -> Number of 3-bytes chunks
        // - `4 *`              -> 4 characters for each chunk
        string memory result = new string(4 * ((data.length + 2) / 3));

        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the lookup table (skip the first "length" byte)
            let tablePtr := add(table, 1)

            // Prepare result pointer, jump over length
            let resultPtr := add(result, 32)

            // Run over the input, 3 bytes at a time
            for {
                let dataPtr := data
                let endPtr := add(data, mload(data))
            } lt(dataPtr, endPtr) {

            } {
                // Advance 3 bytes
                dataPtr := add(dataPtr, 3)
                let input := mload(dataPtr)

                // To write each character, shift the 3 bytes (18 bits) chunk
                // 4 times in blocks of 6 bits for each character (18, 12, 6, 0)
                // and apply logical AND with 0x3F which is the number of
                // the previous character in the ASCII table prior to the Base64 Table
                // The result is then added to the table to get the character to write,
                // and finally write it in the result pointer but with a left shift
                // of 256 (1 byte) - 8 (1 ASCII char) = 248 bits

                mstore8(resultPtr, mload(add(tablePtr, and(shr(18, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(12, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(shr(6, input), 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance

                mstore8(resultPtr, mload(add(tablePtr, and(input, 0x3F))))
                resultPtr := add(resultPtr, 1) // Advance
            }

            // When data `bytes` is not exactly 3 bytes long
            // it is padded with `=` characters at the end
            switch mod(mload(data), 3)
            case 1 {
                mstore8(sub(resultPtr, 1), 0x3d)
                mstore8(sub(resultPtr, 2), 0x3d)
            }
            case 2 {
                mstore8(sub(resultPtr, 1), 0x3d)
            }
        }

        return result;
    }
}

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

pragma solidity ^0.8.0;

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

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

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

pragma solidity ^0.8.0;

import "./IERC165.sol";

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

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

pragma solidity ^0.8.0;

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

File 9 of 14 : InfiniteArt.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./InfiniteBags.sol";
import "./Utilities.sol";

/**
@title  InfiniteArt
@author VisualizeValue
@notice Renders the Infinity visuals.
*/
library InfiniteArt {

    /// @dev Generate the SVG code for an Infinity token.
    function renderSVG(Token memory data) public pure returns (string memory) {
        return string.concat(
            '<svg viewBox="0 0 800 800" fill="none" xmlns="http://www.w3.org/2000/svg">',
                renderStyle(data),
                renderDefs(),
                '<rect width="800" height="800" fill="var(--bg)" />',
                '<g transform="scale(0.95)" transform-origin="center">',
                    renderGrid(),
                '</g>',
                renderNoise(data),
                '<g transform="scale(0.95)" transform-origin="center">',
                    renderSymbols(data),
                '</g>',
            '</svg>'
        );
    }

    /// @dev Render CSS variables.
    function renderStyle(Token memory data) public pure returns (string memory) {
        return string.concat(
            '<style>',
                ':root {',
                    '--bg: ', data.background, ';',
                    '--gr: ', data.gridColor, ';',
                '}',
            '</style>'
        );
    }

    /// @dev Render SVG meta defenitions.
    function renderDefs() public pure returns (string memory) {
        return string.concat(
            '<defs>',
                '<rect id="box" width="100" height="100" stroke="var(--gr)" stroke-width="3" style="paint-order: stroke;" />'
                '<g id="row">', renderGridRow(), '</g>',
                '<mask id="mask"><rect width="800" height="800" fill="white"/></mask>',
                '<path id="loop" d="M 100 0 A 100 100, 0, 1, 1, 0 100 L 0 0 Z"/>',
                '<g id="infinity">',
                    '<use href="#loop" />',
                    '<use href="#loop" transform="scale(-1,-1)" />',
                '</g>',
                '<filter id="noise">',
                    '<feTurbulence type="fractalNoise" baseFrequency="0.8" stitchTiles="stitch" numOctaves="1" seed="8"/>',
                    '<feColorMatrix type="saturate" values="0"/>',
                '</filter>',
            '</defs>'
        );
    }

    /// @dev Generate the SVG code for the entire 8x8 grid.
    function renderGrid() public pure returns (string memory) {
        string memory grid;
        for (uint256 i; i < 8; i++) {
            grid = string.concat(
                grid,
                '<use href="#row" transform="translate(0,', str(i*100), ')" />'
            );
        }

        return grid;
    }

    /// @dev Generate the SVG code for rows in the 8x8 grid.
    function renderGridRow() public pure returns (string memory) {
        string memory row;
        for (uint256 i; i < 8; i++) {
            row = string.concat(
                row,
                '<use transform="translate(', str(i*100), ')" href="#box" />'
            );
        }
        return row;
    }

    /// @dev Render the noise layer.
    function renderNoise(Token memory data) public pure returns (string memory) {
        return string.concat(
            '<rect mask="url(#mask)" width="800" height="800" fill="black" filter="url(#noise)" ',
                'style="mix-blend-mode: multiply;" opacity="', data.light ? '0.248"' : '0.8"',
            '/>'
        );
    }

    /// @dev Generate SVG code for the symbols.
    function renderSymbols(Token memory data) public pure returns (string memory) {
        uint space  = 800 / data.grid;
        uint center = space / 4;
        uint width  = space / 2;

        string memory symbols;
        for (uint i = 0; i < data.count; i++) {
            Symbol memory symbol = data.symbols[i];

            uint baseStroke = symbol.isInfinity ? 8 : 4;
            uint stroke = (data.grid < 8 ? baseStroke : baseStroke * 3 / 4) * data.grid / 2;
            uint scale  = width * 1000 / symbol.formWidth;

            symbol.x      = str(i % data.grid * space + center);
            symbol.y      = str(i / data.grid * space + center);
            symbol.stroke = str(stroke);
            symbol.center = str(center);
            symbol.width  = str(width);
            symbol.scale  = scale < 1000
                ? string.concat('0.', str(scale))
                : str(scale / 1000);

            symbols = string.concat(symbols, renderSymbol(symbol));
        }
        return symbols;
    }

    /// @dev Generate SVG code for the symbols.
    function renderSymbol(Symbol memory symbol) public pure returns (string memory) {
        symbol.color.rendered = renderColor(symbol.color);

        string memory rendered = symbol.form == 1 ? renderLoop(symbol)
                               : symbol.form == 2 ? renderInfinitySingle(symbol)
                               : symbol.form == 3 ? render90Loop(symbol)
                               : symbol.form == 4 ? renderInfinityPair(symbol)
                               : symbol.form == 5 ? render180Loop(symbol)
                               : symbol.form == 8 ? renderInfinityCheck(symbol)
                                                  : render360Loop(symbol);

        return string.concat(
            '<g transform="translate(',symbol.x,',',symbol.y,') rotate(',symbol.rotation,')" ',
                'transform-origin="',symbol.center,' ',symbol.center,'" ',
                'stroke-width="', symbol.stroke,
            '">',
                rendered,
            '</g>'
        );
    }

    /// @dev Helper to render a color to its SVG compliant HSL string.
    function renderColor(Color memory color) public pure returns (string memory) {
        if (bytes(color.rendered).length > 0) return color.rendered;

        return string.concat('hsl(', str(color.h), ' ', str(color.s), '% ', str(color.l), '%)');
    }

    /// @dev Render a single loop symbol.
    function renderLoop(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<use href="#loop" transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '" />'
        );
    }

    /// @dev Render two loop symbols, one rotated by 90 degrees.
    function render90Loop(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<use href="#loop" />',
                '<use href="#loop" transform="translate(200,0) scale(-1,1)" />',
            '</g>'
        );
    }

    /// @dev Render two loop symbols, one rotated by 180 degrees.
    function render180Loop(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<use href="#loop" />',
                '<use href="#loop" transform="translate(200,200) scale(-1,-1)" />',
            '</g>'
        );
    }

    /// @dev Render four loop symbols to form a square.
    function render360Loop(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<use href="#loop" />',
                '<use href="#loop" transform="translate(200,0) scale(-1,1)" />',
                '<use href="#loop" transform="translate(0,200) scale(1,-1)" />',
                '<use href="#loop" transform="translate(200,200) scale(-1,-1)" />',
            '</g>'
        );
    }

    /// @dev Check: Render a single infinity.
    function renderInfinitySingle(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<g transform="translate(200,200)">'
                    '<use href="#infinity" />',
                '</g>'
            '</g>'
        );
    }

    /// @dev Double check: Render an infinity pair.
    function renderInfinityPair(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<g transform="translate(200,200)">'
                    '<use href="#infinity" />',
                    '<use href="#infinity" transform="rotate(90)" />',
                '</g>'
            '</g>'
        );
    }

    /// @dev Quadruple check: Render an infinity check.
    function renderInfinityCheck(Symbol memory symbol) public pure returns (string memory) {
        return string.concat(
            '<g transform="scale(', symbol.scale, ')" stroke="', symbol.color.rendered, '">',
                '<g transform="translate(200,200)">'
                    '<use href="#infinity" />',
                    '<use href="#infinity" transform="rotate(45)" />',
                    '<use href="#infinity" transform="rotate(90)" />',
                    '<use href="#infinity" transform="rotate(135)" />',
                '</g>'
            '</g>'
        );
    }

    /// @dev Uint to string helper.
    function str(uint n) public pure returns (string memory) {
        return Utilities.uint2str(n);
    }
}

File 10 of 14 : InfiniteBags.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

/**
@title  InfiniteBags
@author VisualizeValue
@notice Bags to hold infinity token data. Imo pretty funny...
*/

/// @dev Bag holding computed token data.
struct Token {
    uint seed;
    string background;
    string gridColor;
    uint8 alloy;
    uint8 grid;
    uint8 count;
    uint8 band;
    uint8 gradient;
    bool continuous;
    bool mapColors;
    bool light;
    Symbol[64] symbols;
}

/// @dev Bag holding computed symbol data.
struct Symbol {
    uint form;
    uint16 formWidth;
    bool isInfinity;
    string rotation;
    string stroke;
    string center;
    string scale;
    string width;
    string x;
    string y;
    uint colorIdx;
    Color color;
}

/// @dev Bag holding color data.
struct Color {
    uint16 h;
    uint16 s;
    uint16 l;
    string rendered;
}

File 11 of 14 : InfiniteGenerator.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "./InfiniteBags.sol";
import "./Utilities.sol";

/**
@title  InfiniteGenerator
@author VisualizeValue
@notice Gathers the data to render Infinity visuals.
*/
library InfiniteGenerator {

    /// @dev 16 distinct colors + void.
    uint8 public constant ELEMENTS = 17;

    /// @dev Number of shades for each color.
    uint8 public constant SHADES = 4;

    /// @dev Collect relevant rendering data for easy access across functions.
    function tokenData(uint tokenId) public pure returns (Token memory data) {
        data.seed        = tokenId;
        data.light       = tokenId % 4096 == 0 ? true : false;
        data.background  = data.light == true ? '#FFFFFF' : '#111111';
        data.gridColor   = data.light == true ? '#F5F5F5' : '#19181B';
        data.grid        = getGrid(data);
        data.count       = data.grid ** 2;
        data.alloy       = getAlloy(data);
        data.band        = getBand(data);
        data.continuous  = getContinuous(data);
        data.gradient    = getGradient(data);
        data.mapColors   = getColorMap(data);
        data.symbols     = getSymbols(data);
    }

    /// @dev Define the grid for a token.
    function getGrid(Token memory data) public pure returns (uint8) {
        if (data.seed == 0) return 1; // Genesis token override.

        uint n = Utilities.random(data.seed, 'grid', 160);

        return n <  1 ? 1
             : n <  8 ? 2
             : n < 32 ? 4
                      : 8;
    }

    /// @dev Define the color band size for a token.
    function getBand(Token memory data) public pure returns (uint8) {
        // Four times the number of used elements, min 1.
        return Utilities.max(data.alloy * SHADES, 1);
    }

    /// @dev Whether to map symbols to colors.
    function getColorMap(Token memory data) public pure returns (bool) {
        // 20% for gradients; 8% for skittles.
        return data.gradient > 0
            ? Utilities.random(data.seed, 'color_map', 100) < 20
            : Utilities.random(data.seed, 'color_map', 100) < 8;
    }

    /// @dev Whether color banding is continuous or random. 50/50.
    function getContinuous(Token memory data) public pure returns (bool) {
        return Utilities.random(data.seed, 'continuous', 2) < 1;
    }

    /// @dev Get the number of distinct elements used. 0 for Isolates.
    function getAlloy(Token memory data) public pure returns (uint8) {
        if (data.grid == 1) return 0;

        uint8 n = uint8(Utilities.random(data.seed, 'alloy', 100));

        return n >= 56 ? 4 + n % (ELEMENTS - 4) // Complete
             : n >= 24 ? 2                     // Compound
             : n >=  4 ? 1                    // Composite
                       : 0;                  // Isolate
    }

    /// @dev Choose a gradient for the token.
    function getGradient(Token memory data) public pure returns (uint8) {
        if (data.grid == 1 || data.alloy == 0) return 0; // No gradients for 1x1 or isolate tokens
        if (Utilities.random(data.seed, 'gradient', 10) < 8) return 0; // 80% have no gradient

        uint8 options = data.grid == 2 ? 2 : 7;
        uint8[7] memory GRADIENTS = data.grid == 2 ? [1, 2, 0, 0, 0, 0, 0]
                                  : data.grid == 4 ? [1, 2, 3, 4, 5, 8, 10]
                                                   : [1, 2, 4, 7, 8, 9, 16];

        return GRADIENTS[Utilities.random(data.seed, 'select_gradient', options)];
    }

    /// @dev Get the symbols for all slots on the grid.
    function getSymbols(Token memory data) public pure returns (Symbol[64] memory symbols) {
        uint8[7] memory forms          = [1, 2, 3, 4, 5, 8, 9]; // Seven distinct symbols.
        uint8[7] memory rotationCounts = [2, 4, 4, 2, 2, 0, 0]; // How often we rotate.

        (uint[64] memory colorIndexes, Color[64] memory colors) = getColors(data);
        uint[64] memory formColorMap;

        for (uint i = 0; i < data.count; i++) {
            symbols[i].colorIdx = colorIndexes[i];
            symbols[i].color = colors[i];

            uint formIdx = getFormIdx(data, i);
            uint form = forms[formIdx];
            if (data.mapColors) {
                (formColorMap, form) = setGetMap(formColorMap, symbols[i].colorIdx, form);
            }
            symbols[i].form = form;

            symbols[i].isInfinity = symbols[i].form % 2 == 0;
            symbols[i].formWidth = symbols[i].isInfinity ? 400 : 200;

            uint rotationIncrement = symbols[i].isInfinity ? 45 : 90;
            uint rotations = rotationCounts[formIdx] > 0
                ? Utilities.random(
                    data.seed,
                    string.concat('rotation', str(i)),
                    rotationCounts[formIdx]
                )
                : 0;
            symbols[i].rotation = str(rotations * rotationIncrement);
        }
    }

    /// @dev Get shape of a given symbol of a token.
    function getFormIdx(Token memory data, uint i) public pure returns (uint) {
        if (data.seed == 0) return 5; // Genesis token is an infinity flower.

        uint random = Utilities.random(data.seed, string.concat('form', str(i)), 10);
        if (random == 0) return 0; // 10% Single Loops

        uint8[3] memory common = [1, 3, 5]; // Infinities
        uint8[3] memory uncommon = [2, 4, 6]; // Loops

        uint idx = Utilities.random(data.seed, string.concat('form-idx', str(i)), 3);
        return random < 8 ? common[idx] : uncommon[idx];
    }

    /// @dev Get all colors available to choose from.
    function allColors() public pure returns (Color[68] memory colors) {
        // One "Void" color with 4 shades.
        uint8[4] memory voidLums = [16, 32, 80, 96];
        for (uint i = 0; i < SHADES; i++) {
            colors[i].h = 270;
            colors[i].s = 8;
            colors[i].l = voidLums[i];
        }

        // 16 distinct colors with 4 shades each.
        uint8 count = 4*4;
        uint16 startHue = 256;
        uint8[4] memory lums = [56, 60, 64, 72];
        for (uint8 i = 0; i < 16; i++) {
            uint16 hue = (startHue + 360 * i / count) % 360;

            for(uint8 e = 0; e < 4; e++) {
                uint8 idx = 4+i*4+e;
                colors[idx].h = hue;
                colors[idx].s = 88;
                colors[idx].l = lums[e];
            }
        }
    }

    /// @dev Get the color variations for a specific token. Compute gradients / skittles.
    function getColors(Token memory data) public pure returns (
        uint[64] memory colorIndexes,
        Color[64] memory colors
    ) {
        Color[68] memory all = allColors();
        uint[68] memory options = getColorOptions(data);
        bool reverse = Utilities.random(data.seed, 'reverse', 2) > 0;

        for (uint i = 0; i < data.count; i++) {
            colorIndexes[i] = (
                data.gradient > 0
                    ? getGradientColor(data, i)
                    : getRandomColor(data, i)
            ) % 68;

            uint idx = reverse ? data.count - 1 - i : i;

            colors[idx] = all[options[colorIndexes[i]]];

            // Paradoxical, i know. Opepen your eyes. All one. Common fate.
            if (data.light) colors[idx].rendered = '#080808';
        }
    }

    /// @dev Get the colors to choose from for a given token.
    function getColorOptions(Token memory data) public pure returns (uint[68] memory options) {
        uint count = Utilities.max(1, data.alloy);
        for (uint element = 0; element < count; element++) {
            uint idx = element * SHADES;

            uint chosen = data.continuous && element > 0
                // Increment previous by one for a continuous band.
                ? (options[idx - 1] / SHADES + 1) % ELEMENTS
                // Random selection for hard shifts in color.
                : Utilities.random(data.seed, string.concat('element', str(element)), ELEMENTS);

            uint chosenIdx = chosen * SHADES;

            for (uint shade = 0; shade < SHADES; shade++) {
                options[idx + shade] = chosenIdx + shade;
            }
        }
    }

    /// @dev Compute the gradient colors for a gradient token.
    function getGradientColor(Token memory data, uint i) public pure returns (uint) {
        uint offset;
        if (data.gradient == 3 || data.gradient == 7) {
            // Fix angled gradient y-shift.
            offset = data.grid + 1;
        }

        return ((offset + i) * data.gradient * data.band / data.count) % data.band;
    }

    /// @dev Compute colors for a skittle tokens.
    function getRandomColor(Token memory data, uint i) public pure returns (uint) {
        uint8 max = Utilities.max(SHADES, data.band);
        string memory key = data.alloy == 0 ? '0' : str(i);
        return Utilities.random(data.seed, string.concat('random_color_', key), max);
    }

    /// @dev Helper to keep track of a key value store in memory.
    function setGetMap(
        uint[64] memory map, uint key, uint value
    ) public pure returns (uint[64] memory, uint) {
        uint k = key % 64;

        if (map[k] == 0) {
            map[k] = value;
        }

        return (map, map[k]);
    }

    /// @dev Uint to string helper.
    function str(uint n) public pure returns (string memory) {
        return Utilities.uint2str(n);
    }
}

File 12 of 14 : InfiniteMetadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

import "@openzeppelin/contracts/utils/Base64.sol";

import "./InfiniteBags.sol";
import "./InfiniteArt.sol";
import "./Utilities.sol";

/**
@title  InfiniteMetadata
@author VisualizeValue
@notice Renders ERC1155 compatible metadata for Infinity tokens.
*/
library InfiniteMetadata {

    /// @dev Render the JSON Metadata for a given Infinity token.
    /// @param data The render data for our token
    function tokenURI(
        Token memory data
    ) public pure returns (string memory) {
        bytes memory metadata = abi.encodePacked(
            '{',
                '"name": "Infinity",',
                unicode'"description": "∞",',
                '"image": ',
                    '"data:image/svg+xml;base64,',
                    Base64.encode(abi.encodePacked(InfiniteArt.renderSVG(data))),
                    '",',
                '"attributes": [', attributes(data), ']',
            '}'
        );

        return string.concat(
            "data:application/json;base64,",
            Base64.encode(metadata)
        );
    }

    /// @dev Render the JSON atributes for a given Infinity token.
    /// @param data The check to render.
    function attributes(Token memory data) public pure returns (string memory) {
        return string.concat(
            trait('Light', light(data.light), ','),
            trait('Grid', grid(data), ','),
            data.light  ? '' : trait('Elements',  elements(data), ','),
            data.light  ? '' : trait('Gradient',  gradient(data), ','),
            data.light  ? '' : trait('Band',      band(data), ','),
            trait('Symbols',   symbols(data), '')
        );
    }

    /// @dev Get the value for the 'Light' attribute.
    function light(bool on) public pure returns (string memory) {
        return on ? 'On' : 'Off';
    }

    /// @dev Get the value for the 'Grid' attribute.
    function grid(Token memory data) public pure returns (string memory) {
        string memory g = Utilities.uint2str(data.grid);

        return string.concat(g, 'x', g);
    }

    /// @dev Get the value for the 'Elements' attribute.
    function elements(Token memory data) public pure returns (string memory) {
        return data.alloy == 0 ? 'Isolate'
             : data.alloy == 1 ? 'Composite'
             : data.alloy == 2 ? 'Compound'
                               : 'Complete';
    }

    /// @dev Get the value for the 'Band' attribute.
    function band(Token memory data) public pure returns (string memory) {
        return (data.continuous || data.alloy < 2) ? 'Continuous' : 'Cut';
    }

    /// @dev Get the value for the 'Gradient' attribute.
    function gradient(Token memory data) public pure returns (string memory) {
        return [
            // [0, 1, 2, 3, 4, 5, _, 7, 8, 9, 10, _, _, _, _, _, 16]
            'None', 'Linear', 'Double Linear', 'Angled Down', 'Ordered', 'Angled Up', '', 'Angled Down', 'Linear Z',
            'Angled', 'Angled Up', '', '', '', '', '', 'Double Linear Z'
        ][data.gradient];
    }

    /// @dev Get the value for the 'Symbols' attribute.
    function symbols(Token memory data) public pure returns (string memory) {
        return data.mapColors ? 'Mapped' : 'Random';
    }

    /// @dev Generate the SVG snipped for a single attribute.
    /// @param traitType The `trait_type` for this trait.
    /// @param traitValue The `value` for this trait.
    /// @param append Helper to append a comma.
    function trait(
        string memory traitType, string memory traitValue, string memory append
    ) public pure returns (string memory) {
        return string(abi.encodePacked(
            '{',
                '"trait_type": "', traitType, '",'
                '"value": "', traitValue, '"'
            '}',
            append
        ));
    }

}

File 13 of 14 : Utilities.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.17;

library Utilities {
    /// @dev Zero-index based pseudorandom number based on one input and max bound
    function random(uint256 input, uint256 _max) public pure returns (uint256) {
        return (uint256(keccak256(abi.encodePacked(input))) % _max);
    }

    /// @dev Zero-index based salted pseudorandom number based on two inputs and max bound
    function random(uint256 input, string memory salt, uint256 _max) public pure returns (uint256) {
        return (uint256(keccak256(abi.encodePacked(input, salt))) % _max);
    }

    /// @dev Convert an integer to a string
    function uint2str(uint256 _i) public pure returns (string memory _uintAsString) {
        if (_i == 0) {
            return "0";
        }
        uint256 j = _i;
        uint256 len;
        while (j != 0) {
            ++len;
            j /= 10;
        }
        bytes memory bstr = new bytes(len);
        uint256 k = len;
        while (_i != 0) {
            k = k - 1;
            uint8 temp = (48 + uint8(_i - (_i / 10) * 10));
            bytes1 b1 = bytes1(temp);
            bstr[k] = b1;
            _i /= 10;
        }
        return string(bstr);
    }

    /// @dev Get the smallest non zero number
    function minGt0(uint8 one, uint8 two) public pure returns (uint8) {
        return one > two
            ? two > 0
                ? two
                : one
            : one;
    }

    /// @dev Get the smaller number
    function min(uint8 one, uint8 two) public pure returns (uint8) {
        return one < two ? one : two;
    }

    /// @dev Get the larger number
    function max(uint8 one, uint8 two) public pure returns (uint8) {
        return one > two ? one : two;
    }

    /// @dev Get the average between two numbers
    function avg(uint8 one, uint8 two) public pure returns (uint8 result) {
        unchecked {
            result = (one >> 1) + (two >> 1) + (one & two & 1);
        }
    }

    /// @dev Get the days since another date (input is seconds)
    function day(uint256 from, uint256 to) public pure returns (uint24) {
        return uint24((to - from) / 24 hours + 1);
    }
}

File 14 of 14 : ERC1155.sol
// SPDX-License-Identifier: MIT
// Derived from OpenZeppelin Contracts (last updated v4.8.0) (token/ERC1155/ERC1155.sol)

pragma solidity ^0.8.0;

import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155Receiver.sol";
import "@openzeppelin/contracts/token/ERC1155/extensions/IERC1155MetadataURI.sol";
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/introspection/ERC165.sol";

/**
 * @dev Simplified implementation of the basic standard multi-token.
 * See https://eips.ethereum.org/EIPS/eip-1155
 * Originally based on code by Enjin: https://github.com/enjin/erc-1155
 */
contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
    // Mapping from token ID to account balances
    mapping(uint256 => mapping(address => uint256)) private _balances;

    /**
     * @dev Emitted when minting a token with a message.
     */
    event Message(address indexed from, address indexed to, uint256 indexed id, string message);

    /**
     * @dev Custom revert errors.
     */
    error InvalidToken();
    error InvalidInput();
    error InvalidDesposit();

    /**
     * @dev See {IERC165-supportsInterface}.
     */
    function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
        return
            interfaceId == type(IERC1155).interfaceId ||
            interfaceId == type(IERC1155MetadataURI).interfaceId ||
            super.supportsInterface(interfaceId);
    }

    /**
     * @dev See {IERC1155MetadataURI-uri}.
     *
     * This implementation returns the same URI for *all* token types. It relies
     * on the token type ID substitution mechanism
     * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
     *
     * Clients calling this function must replace the `\{id\}` substring with the
     * actual token type ID.
     */
    function uri(uint256) public view virtual override returns (string memory) {}

    /**
     * @dev See {IERC1155-balanceOf}.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
        if (account == address(0)) return 0;
        return _balances[id][account];
    }

    /**
     * @dev See {IERC1155-balanceOfBatch}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
        public
        view
        virtual
        override
        returns (uint256[] memory)
    {
        require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");

        uint256[] memory batchBalances = new uint256[](accounts.length);

        for (uint256 i = 0; i < accounts.length; ++i) {
            batchBalances[i] = balanceOf(accounts[i], ids[i]);
        }

        return batchBalances;
    }

    /**
     * @notice Infinities are never approved.
     * @dev See {IERC1155-setApprovalForAll}.
     */
    function setApprovalForAll(address, bool) public virtual override {
        revert("No approvals on infinities");
    }

    /**
     * @notice Infinities are never approved.
     * @dev See {IERC1155-isApprovedForAll}.
     */
    function isApprovedForAll(address, address) public view virtual override returns (bool) {
        return false;
    }

    /**
     * @dev See {IERC1155-safeTransferFrom}.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender(),
            "ERC1155: caller is not token owner"
        );
        _safeTransferFrom(from, to, id, amount, data);
    }

    /**
     * @dev See {IERC1155-safeBatchTransferFrom}.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) public virtual override {
        require(
            from == _msgSender(),
            "ERC1155: caller is not token owner"
        );
        _safeBatchTransferFrom(from, to, ids, amounts, data);
    }

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: transfer to the zero address");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }
        _balances[id][to] += amount;

        emit TransferSingle(from, from, to, id, amount);

        _doSafeTransferAcceptanceCheck(from, from, to, id, amount, data);
    }

    /**
     * @dev Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function _safeBatchTransferFrom(
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) internal virtual {
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
        require(to != address(0), "ERC1155: transfer to the zero address");

        for (uint256 i = 0; i < ids.length; ++i) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
            _balances[id][to] += amount;
        }

        emit TransferBatch(from, from, to, ids, amounts);

        _doSafeBatchTransferAcceptanceCheck(from, from, to, ids, amounts, data);
    }

    /**
     * @dev Creates `amount` tokens of token type `id`, and assigns them to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function _mint(
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) internal virtual {
        require(to != address(0), "ERC1155: mint to the zero address");

        address operator = _msgSender();

        _balances[id][to] += amount;
        emit TransferSingle(operator, address(0), to, id, amount);

        _doSafeTransferAcceptanceCheck(operator, address(0), to, id, amount, data);
    }

    /**
     * @dev Destroys `amount` tokens of token type `id` from `from`
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `from` must have at least `amount` tokens of token type `id`.
     */
    function _burn(
        address from,
        uint256 id,
        uint256 amount
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");

        uint256 fromBalance = _balances[id][from];
        require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
        unchecked {
            _balances[id][from] = fromBalance - amount;
        }

        emit TransferSingle(_msgSender(), from, address(0), id, amount);
    }

    /**
     * @dev Batched version of {_burn}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     */
    function _burnBatch(
        address from,
        uint256[] memory ids,
        uint256[] memory amounts
    ) internal virtual {
        require(from != address(0), "ERC1155: burn from the zero address");
        require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");

        address operator = _msgSender();

        for (uint256 i = 0; i < ids.length; i++) {
            uint256 id = ids[i];
            uint256 amount = amounts[i];

            uint256 fromBalance = _balances[id][from];
            require(fromBalance >= amount, "ERC1155: burn amount exceeds balance");
            unchecked {
                _balances[id][from] = fromBalance - amount;
            }
        }

        emit TransferBatch(operator, from, address(0), ids, amounts);
    }

    function _doSafeTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes memory data
    ) private {
        if (_isContract(to)) {
            try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                if (response != IERC1155Receiver.onERC1155Received.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _doSafeBatchTransferAcceptanceCheck(
        address operator,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory amounts,
        bytes memory data
    ) private {
        if (_isContract(to)) {
            try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                bytes4 response
            ) {
                if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                    revert("ERC1155: ERC1155Receiver rejected tokens");
                }
            } catch Error(string memory reason) {
                revert(reason);
            } catch {
                revert("ERC1155: transfer to non-ERC1155Receiver implementer");
            }
        }
    }

    function _isContract(address account) internal view returns (bool) {
        return account.code.length > 0;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 1000
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  },
  "metadata": {
    "useLiteralContent": true
  },
  "libraries": {
    "contracts/libraries/InfiniteArt.sol": {
      "InfiniteArt": "0xc6b17cafcc2439ef4833fe6a073ba71438112f87"
    },
    "contracts/libraries/InfiniteGenerator.sol": {
      "InfiniteGenerator": "0xb0047233de84066b491f093380b8ca3cff4f7333"
    },
    "contracts/libraries/InfiniteMetadata.sol": {
      "InfiniteMetadata": "0x12b7f0e2f3d562b0cd012bd58e2d620bfdfe542f"
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"address[]","name":"genesisRecipients","type":"address[]"}],"stateMutability":"payable","type":"constructor"},{"inputs":[],"name":"InvalidDesposit","type":"error"},{"inputs":[],"name":"InvalidInput","type":"error"},{"inputs":[],"name":"InvalidToken","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"string","name":"message","type":"string"}],"name":"Message","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"indexed":false,"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"TransferBatch","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"TransferSingle","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"value","type":"string"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"URI","type":"event"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"degenerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"degenerateMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"string","name":"message","type":"string"}],"name":"generate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"source","type":"address"},{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"message","type":"string"}],"name":"generateExisting","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"generateMany","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address[]","name":"sources","type":"address[]"},{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"generateManyExisting","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"regenerate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"degenerateAmounts","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"regenerateMany","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"svg","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","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":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"stateMutability":"payable","type":"receive"}]

60c06040526008608090815267496e66696e69747960c01b60a0526001906200002990826200047b565b5060408051808201909152600381526271444f60e91b60208201526002906200005390826200047b565b50661c6bf526340000600355604051620034bf380380620034bf833981016040819052620000819162000572565b80516200008e90620000ec565b80515f5b81811015620000e357620000da838281518110620000b457620000b462000637565b60200260200101515f600160405180602001604052805f8152506200011e60201b60201c565b60010162000092565b5050506200080c565b600354620000fb90826200065f565b34146200011b576040516328df225d60e01b815260040160405180910390fd5b50565b6001600160a01b038416620001845760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f206164647265736044820152607360f81b60648201526084015b60405180910390fd5b5f838152602081815260408083206001600160a01b0388168452909152812080543392859291620001b79084906200067f565b909155505060408051858152602081018590526001600160a01b03808816925f92918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a462000217815f878787876200021e565b5050505050565b6001600160a01b0384163b15620003d75760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e6190620002659089908990889088908890600401620006da565b6020604051808303815f875af1925050508015620002a2575060408051601f3d908101601f191682019092526200029f9181019062000720565b60015b6200036257620002b162000750565b806308c379a003620002f15750620002c86200076a565b80620002d55750620002f3565b8060405162461bcd60e51b81526004016200017b9190620007f8565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560448201527f526563656976657220696d706c656d656e74657200000000000000000000000060648201526084016200017b565b6001600160e01b0319811663f23a6e6160e01b14620003d55760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b60648201526084016200017b565b505b505050505050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806200040857607f821691505b6020821081036200042757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111562000476575f81815260208120601f850160051c81016020861015620004555750805b601f850160051c820191505b81811015620003d75782815560010162000461565b505050565b81516001600160401b03811115620004975762000497620003df565b620004af81620004a88454620003f3565b846200042d565b602080601f831160018114620004e5575f8415620004cd5750858301515b5f19600386901b1c1916600185901b178555620003d7565b5f85815260208120601f198616915b828110156200051557888601518255948401946001909101908401620004f4565b50858210156200053357878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b601f8201601f191681016001600160401b03811182821017156200056b576200056b620003df565b6040525050565b5f602080838503121562000584575f80fd5b82516001600160401b03808211156200059b575f80fd5b818501915085601f830112620005af575f80fd5b815181811115620005c457620005c4620003df565b8060051b9150604051620005db8584018262000543565b81815291830184019184810188841115620005f4575f80fd5b938501935b838510156200062b57845192506001600160a01b03831683146200061c575f8081fd5b828152938501938501620005f9565b50979650505050505050565b634e487b7160e01b5f52603260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b80820281158282048414176200067957620006796200064b565b92915050565b808201808211156200067957620006796200064b565b5f81518084525f5b81811015620006bb576020818501810151868301820152016200069d565b505f602082860101526020601f19601f83011685010191505092915050565b6001600160a01b03868116825285166020820152604081018490526060810183905260a0608082018190525f90620007159083018462000695565b979650505050505050565b5f6020828403121562000731575f80fd5b81516001600160e01b03198116811462000749575f80fd5b9392505050565b5f60033d1115620007675760045f803e505f5160e01c5b90565b5f60443d1015620007785790565b6040516003193d81016004833e81513d6001600160401b038083116024840183101715620007a857505050505090565b8285019150815181811115620007c15750505050505090565b843d8701016020828501011115620007dc5750505050505090565b620007ed6020828601018762000543565b509095945050505050565b602081525f62000749602083018462000695565b612ca5806200081a5f395ff3fe60806040526004361061016f575f3560e01c806344b285db116100c65780639c095f561161007c578063bd85b03911610057578063bd85b039146103ad578063e985e9c5146103cd578063f242432a146103ee575f80fd5b80639c095f561461035a578063a035b1fe14610379578063a22cb4651461038e575f80fd5b80634e840992116100ac5780634e8409921461031457806368987a831461033357806395d89b4114610346575f80fd5b806344b285db146102c95780634e1273f4146102e8575f80fd5b806318160ddd116101265780632bfc3052116101015780632bfc3052146102845780632eb2c2d6146102975780633f6b5fde146102b6575f80fd5b806318160ddd1461024b57806325431b181461025e578063262fb60814610271575f80fd5b806306fdde031161015657806306fdde03146101ec5780630e89341c1461020d57806310981eb31461022c575f80fd5b8062fdd58e1461018b57806301ffc9a7146101bd575f80fd5b36610187576101853361018061040d565b610463565b005b5f80fd5b348015610196575f80fd5b506101aa6101a5366004611a68565b6104cf565b6040519081526020015b60405180910390f35b3480156101c8575f80fd5b506101dc6101d7366004611aa5565b61050d565b60405190151581526020016101b4565b3480156101f7575f80fd5b506102006105a7565b6040516101b49190611b14565b348015610218575f80fd5b50610200610227366004611b26565b610633565b348015610237575f80fd5b50610185610246366004611b3d565b610726565b348015610256575f80fd5b505f196101aa565b61018561026c366004611ba2565b61074c565b61018561027f366004611c4d565b610773565b610185610292366004611ce0565b610898565b3480156102a2575f80fd5b506101856102b1366004611ee9565b610928565b6101856102c4366004611f8c565b61099d565b3480156102d4575f80fd5b506102006102e3366004611b26565b6109be565b3480156102f3575f80fd5b50610307610302366004611fdb565b610a13565b6040516101b491906120d9565b34801561031f575f80fd5b5061018561032e3660046120eb565b610b4f565b610185610341366004612134565b610b96565b348015610351575f80fd5b50610200610c90565b348015610365575f80fd5b50610185610374366004611b3d565b610c9d565b348015610384575f80fd5b506101aa60035481565b348015610399575f80fd5b506101856103a83660046121fc565b610cc9565b3480156103b8575f80fd5b506101aa6103c7366004611b26565b505f1990565b3480156103d8575f80fd5b506101dc6103e7366004612231565b5f92915050565b3480156103f9575f80fd5b50610185610408366004612262565b610d11565b5f44335a6040516020016104469392919092835260609190911b6bffffffffffffffffffffffff19166020830152603482015260540190565b604051602081830303815290604052805190602001205f1c905090565b5f6003543461047291906122ea565b90505f6003543461048391906122fd565b9050815f036104a5576040516328df225d60e01b815260040160405180910390fd5b6104bf84848460405180602001604052805f815250610d81565b6104c98482610e8c565b50505050565b5f6001600160a01b0383166104e557505f610507565b505f818152602081815260408083206001600160a01b03861684529091529020545b92915050565b5f6001600160e01b031982167fd9b67a2600000000000000000000000000000000000000000000000000000000148061056f57506001600160e01b031982167f0e89341c00000000000000000000000000000000000000000000000000000000145b8061050757507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610507565b600180546105b490612310565b80601f01602080910402602001604051908101604052809291908181526020018280546105e090612310565b801561062b5780601f106106025761010080835404028352916020019161062b565b820191905f5260205f20905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b60607312b7f0e2f3d562b0cd012bd58e2d620bfdfe542f634afd561b73b0047233de84066b491f093380b8ca3cff4f733363b4b5b48f856040518263ffffffff1660e01b815260040161068891815260200190565b5f60405180830381865af41580156106a2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106c9919081019061263f565b6040518263ffffffff1660e01b81526004016106e59190612923565b5f60405180830381865af41580156106ff573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526105079190810190612a2b565b610731338383610f56565b61074833600354836107439190612a5d565b610e8c565b5050565b610756838661109a565b6107608484610463565b61076c84848484611101565b5050505050565b6107ae8282808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b6107e98585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b146108075760405163b4fa3fb360e01b815260040160405180910390fd5b845f5b8181101561088e5761084d3389898481811061082857610828612a74565b9050602002013588888581811061084157610841612a74565b90506020020135610f56565b6108863361085961040d565b86868581811061086b5761086b612a74565b9050602002013560405180602001604052805f815250610d81565b60010161080a565b5050505050505050565b6108db6108d68383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b611198565b825f5b81811015610920576109188686838181106108fb576108fb612a74565b90506020020160208101906109109190612a88565b61085961040d565b6001016108de565b505050505050565b6001600160a01b03851633146109905760405162461bcd60e51b815260206004820152602260248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526132b960f11b60648201526084015b60405180910390fd5b61076c85858585856111c7565b5f6109a661040d565b90506109b28482610463565b6104c984828585611101565b606073c6b17cafcc2439ef4833fe6a073ba71438112f8763929ecd9d73b0047233de84066b491f093380b8ca3cff4f733363b4b5b48f856040518263ffffffff1660e01b815260040161068891815260200190565b60608151835114610a8c5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152608401610987565b5f835167ffffffffffffffff811115610aa757610aa7611d47565b604051908082528060200260200182016040528015610ad0578160200160208202803683370190505b5090505f5b8451811015610b4757610b1a858281518110610af357610af3612a74565b6020026020010151858381518110610b0d57610b0d612a74565b60200260200101516104cf565b828281518110610b2c57610b2c612a74565b6020908102919091010152610b4081612aa1565b9050610ad5565b509392505050565b8051825114610b715760405163b4fa3fb360e01b815260040160405180910390fd5b610b7c338383611417565b61074833600354610b8c8461114d565b6107439190612a5d565b610bd46108d68383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b865f5b81811015610c8457610c27868683818110610bf457610bf4612a74565b905060200201358b8b84818110610c0d57610c0d612a74565b9050602002016020810190610c229190612a88565b61109a565b610c7c888883818110610c3c57610c3c612a74565b9050602002016020810190610c519190612a88565b878784818110610c6357610c63612a74565b9050602002013586868581811061086b5761086b612a74565b600101610bd7565b50505050505050505050565b600280546105b490612310565b610ca8338383610f56565b61074833610cb461040d565b8360405180602001604052805f815250610d81565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f20617070726f76616c73206f6e20696e66696e69746965730000000000006044820152606401610987565b6001600160a01b0385163314610d745760405162461bcd60e51b815260206004820152602260248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526132b960f11b6064820152608401610987565b61076c8585858585611628565b6001600160a01b038416610dfd5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610987565b5f838152602081815260408083206001600160a01b0388168452909152812080543392859291610e2e908490612ab9565b909155505060408051858152602081018590526001600160a01b03808816925f92918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a461076c815f878787876117a5565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610ed5576040519150601f19603f3d011682016040523d82523d5f602084013e610eda565b606091505b5050905080610f515760405162461bcd60e51b815260206004820152603160248201527f556e61626c6520746f2073656e642076616c75652c20726563697069656e742060448201527f6d617920686176652072657665727465640000000000000000000000000000006064820152608401610987565b505050565b6001600160a01b038316610fb85760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610987565b5f828152602081815260408083206001600160a01b0387168452909152902054818110156110345760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610987565b5f838152602081815260408083206001600160a01b038816808552908352818420868603905581518781529283018690529133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6291015b60405180910390a450505050565b5f806110a683856104cf565b1190508015816110ca57503373c8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a14155b15610f51576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156104c95782846001600160a01b0316336001600160a01b03167fdd99aef5e4fdfad84059320be40f5dc0f015dc4025f56bd4010608c6743bc22e858560405161108c929190612acc565b5f805b82518110156111925782818151811061116b5761116b612a74565b60200260200101518261117e9190612ab9565b91508061118a81612aa1565b915050611150565b50919050565b6003546111a59082612a5d565b34146111c4576040516328df225d60e01b815260040160405180910390fd5b50565b81518351146112295760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610987565b6001600160a01b03841661128d5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610987565b5f5b83518110156113b1575f8482815181106112ab576112ab612a74565b602002602001015190505f8483815181106112c8576112c8612a74565b6020908102919091018101515f84815280835260408082206001600160a01b038d16835290935291909120549091508181101561135a5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610987565b5f838152602081815260408083206001600160a01b038d8116855292528083208585039055908a16825281208054849290611396908490612ab9565b92505081905550505050806113aa90612aa1565b905061128f565b50836001600160a01b0316856001600160a01b0316866001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051611401929190612afa565b60405180910390a461076c858686868686611952565b6001600160a01b0383166114795760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610987565b80518251146114db5760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610987565b335f5b83518110156115d8575f8482815181106114fa576114fa612a74565b602002602001015190505f84838151811061151757611517612a74565b6020908102919091018101515f84815280835260408082206001600160a01b038c1683529093529190912054909150818110156115a25760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610987565b5f928352602083815260408085206001600160a01b038b16865290915290922091039055806115d081612aa1565b9150506114de565b505f6001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb868660405161108c929190612afa565b6001600160a01b03841661168c5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610987565b5f838152602081815260408083206001600160a01b03891684529091529020548281101561170f5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610987565b5f848152602081815260408083206001600160a01b038a811685529252808320868503905590871682528120805485929061174b908490612ab9565b909155505060408051858152602081018590526001600160a01b03808816929089169182917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46109208687878787875b6001600160a01b0384163b156109205760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906117e99089908990889088908890600401612b1e565b6020604051808303815f875af1925050508015611823575060408051601f3d908101601f1916820190925261182091810190612b60565b60015b6118d85761182f612b7b565b806308c379a0036118685750611843612b94565b8061184e575061186a565b8060405162461bcd60e51b81526004016109879190611b14565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560448201527f526563656976657220696d706c656d656e7465720000000000000000000000006064820152608401610987565b6001600160e01b0319811663f23a6e6160e01b146119495760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610987565b50505050505050565b6001600160a01b0384163b156109205760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906119969089908990889088908890600401612c12565b6020604051808303815f875af19250505080156119d0575060408051601f3d908101601f191682019092526119cd91810190612b60565b60015b6119dc5761182f612b7b565b6001600160e01b0319811663bc197c8160e01b146119495760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610987565b80356001600160a01b0381168114611a63575f80fd5b919050565b5f8060408385031215611a79575f80fd5b611a8283611a4d565b946020939093013593505050565b6001600160e01b0319811681146111c4575f80fd5b5f60208284031215611ab5575f80fd5b8135611ac081611a90565b9392505050565b5f5b83811015611ae1578181015183820152602001611ac9565b50505f910152565b5f8151808452611b00816020860160208601611ac7565b601f01601f19169290920160200192915050565b602081525f611ac06020830184611ae9565b5f60208284031215611b36575f80fd5b5035919050565b5f8060408385031215611b4e575f80fd5b50508035926020909101359150565b5f8083601f840112611b6d575f80fd5b50813567ffffffffffffffff811115611b84575f80fd5b602083019150836020828501011115611b9b575f80fd5b9250929050565b5f805f805f60808688031215611bb6575f80fd5b611bbf86611a4d565b9450611bcd60208701611a4d565b935060408601359250606086013567ffffffffffffffff811115611bef575f80fd5b611bfb88828901611b5d565b969995985093965092949392505050565b5f8083601f840112611c1c575f80fd5b50813567ffffffffffffffff811115611c33575f80fd5b6020830191508360208260051b8501011115611b9b575f80fd5b5f805f805f8060608789031215611c62575f80fd5b863567ffffffffffffffff80821115611c79575f80fd5b611c858a838b01611c0c565b90985096506020890135915080821115611c9d575f80fd5b611ca98a838b01611c0c565b90965094506040890135915080821115611cc1575f80fd5b50611cce89828a01611c0c565b979a9699509497509295939492505050565b5f805f8060408587031215611cf3575f80fd5b843567ffffffffffffffff80821115611d0a575f80fd5b611d1688838901611c0c565b90965094506020870135915080821115611d2e575f80fd5b50611d3b87828801611c0c565b95989497509550505050565b634e487b7160e01b5f52604160045260245ffd5b610800810181811067ffffffffffffffff82111715611d7c57611d7c611d47565b60405250565b601f8201601f1916810167ffffffffffffffff81118282101715611da857611da8611d47565b6040525050565b604051610180810167ffffffffffffffff81118282101715611dd357611dd3611d47565b60405290565b5f67ffffffffffffffff821115611df257611df2611d47565b5060051b60200190565b5f82601f830112611e0b575f80fd5b81356020611e1882611dd9565b604051611e258282611d82565b83815260059390931b8501820192828101915086841115611e44575f80fd5b8286015b84811015611e5f5780358352918301918301611e48565b509695505050505050565b5f67ffffffffffffffff821115611e8357611e83611d47565b50601f01601f191660200190565b5f82601f830112611ea0575f80fd5b8135611eab81611e6a565b604051611eb88282611d82565b828152856020848701011115611ecc575f80fd5b826020860160208301375f92810160200192909252509392505050565b5f805f805f60a08688031215611efd575f80fd5b611f0686611a4d565b9450611f1460208701611a4d565b9350604086013567ffffffffffffffff80821115611f30575f80fd5b611f3c89838a01611dfc565b94506060880135915080821115611f51575f80fd5b611f5d89838a01611dfc565b93506080880135915080821115611f72575f80fd5b50611f7f88828901611e91565b9150509295509295909350565b5f805f60408486031215611f9e575f80fd5b611fa784611a4d565b9250602084013567ffffffffffffffff811115611fc2575f80fd5b611fce86828701611b5d565b9497909650939450505050565b5f8060408385031215611fec575f80fd5b823567ffffffffffffffff80821115612003575f80fd5b818501915085601f830112612016575f80fd5b8135602061202382611dd9565b6040516120308282611d82565b83815260059390931b850182019282810191508984111561204f575f80fd5b948201945b838610156120745761206586611a4d565b82529482019490820190612054565b96505086013592505080821115612089575f80fd5b5061209685828601611dfc565b9150509250929050565b5f8151808452602080850194508084015f5b838110156120ce578151875295820195908201906001016120b2565b509495945050505050565b602081525f611ac060208301846120a0565b5f80604083850312156120fc575f80fd5b823567ffffffffffffffff80821115612113575f80fd5b61211f86838701611dfc565b93506020850135915080821115612089575f80fd5b5f805f805f805f806080898b03121561214b575f80fd5b883567ffffffffffffffff80821115612162575f80fd5b61216e8c838d01611c0c565b909a50985060208b0135915080821115612186575f80fd5b6121928c838d01611c0c565b909850965060408b01359150808211156121aa575f80fd5b6121b68c838d01611c0c565b909650945060608b01359150808211156121ce575f80fd5b506121db8b828c01611c0c565b999c989b5096995094979396929594505050565b80151581146111c4575f80fd5b5f806040838503121561220d575f80fd5b61221683611a4d565b91506020830135612226816121ef565b809150509250929050565b5f8060408385031215612242575f80fd5b61224b83611a4d565b915061225960208401611a4d565b90509250929050565b5f805f805f60a08688031215612276575f80fd5b61227f86611a4d565b945061228d60208701611a4d565b93506040860135925060608601359150608086013567ffffffffffffffff8111156122b6575f80fd5b611f7f88828901611e91565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f826122f8576122f86122c2565b500490565b5f8261230b5761230b6122c2565b500690565b600181811c9082168061232457607f821691505b60208210810361119257634e487b7160e01b5f52602260045260245ffd5b5f82601f830112612351575f80fd5b815161235c81611e6a565b6040516123698282611d82565b82815285602084870101111561237d575f80fd5b61238e836020830160208801611ac7565b95945050505050565b805160ff81168114611a63575f80fd5b8051611a63816121ef565b805161ffff81168114611a63575f80fd5b5f608082840312156123d3575f80fd5b6040516080810167ffffffffffffffff82821081831117156123f7576123f7611d47565b81604052829350612407856123b2565b8352612415602086016123b2565b6020840152612426604086016123b2565b6040840152606085015191508082111561243e575f80fd5b5061244b85828601612342565b6060830152505092915050565b5f82601f830112612467575f80fd5b6040805161247481611d5b565b80610800850186811115612486575f80fd5b855b8181101561263357805167ffffffffffffffff808211156124a8575f8081fd5b90880190610180828b0312156124bd575f8081fd5b6124c5611daf565b8251815260206124d68185016123b2565b818301526124e58985016123a7565b89830152606080850151848111156124fc575f8081fd5b6125088e828801612342565b82850152505060808085015184811115612521575f8081fd5b61252d8e828801612342565b82850152505060a08085015184811115612546575f8081fd5b6125528e828801612342565b82850152505060c0808501518481111561256b575f8081fd5b6125778e828801612342565b82850152505060e08085015184811115612590575f8081fd5b61259c8e828801612342565b82850152505061010080850151848111156125b6575f8081fd5b6125c28e828801612342565b82850152505061012080850151848111156125dc575f8081fd5b6125e88e828801612342565b828501525050610140808501518184015250610160808501518481111561260e575f8081fd5b61261a8e8288016123c3565b9184019190915250908652909401935050602001612488565b50919695505050505050565b5f6020828403121561264f575f80fd5b815167ffffffffffffffff80821115612666575f80fd5b90830190610180828603121561267a575f80fd5b612682611daf565b82518152602083015182811115612697575f80fd5b6126a387828601612342565b6020830152506040830151828111156126ba575f80fd5b6126c687828601612342565b6040830152506126d860608401612397565b60608201526126e960808401612397565b60808201526126fa60a08401612397565b60a082015261270b60c08401612397565b60c082015261271c60e08401612397565b60e082015261010061272f8185016123a7565b908201526101206127418482016123a7565b908201526101406127538482016123a7565b90820152610160838101518381111561276a575f80fd5b61277688828701612458565b918301919091525095945050505050565b5f61ffff808351168452806020840151166020850152806040840151166040850152506060820151608060608501526127c36080850182611ae9565b949350505050565b5f826108008101835f5b60408082106127e45750612918565b84840388528251610180815186526020808301516128078289018261ffff169052565b508284015180151588860152506060935083830151828589015261282d83890182611ae9565b9450506080915081830151878503838901526128498582611ae9565b94505060a0915081830151878503838901526128658582611ae9565b94505060c0915081830151878503838901526128818582611ae9565b94505060e09150818301518785038389015261289d8582611ae9565b945050610100915081830151878503838901526128ba8582611ae9565b945050610120915081830151878503838901526128d78582611ae9565b61014085810151908a015261016094850151898203868b015290955093925061290290508484612787565b9a81019a965094909401935050506001016127d5565b509095945050505050565b60208152815160208201525f602083015161018080604085015261294b6101a0850183611ae9565b91506040850151601f19808685030160608701526129698483611ae9565b935060608701519150612981608087018360ff169052565b608087015160ff811660a0880152915060a087015160ff811660c0880152915060c087015160ff811660e0880152915060e087015191506101006129c98188018460ff169052565b87015191506101206129de8782018415159052565b87015191506101406129f38782018415159052565b8701519150610160612a088782018415159052565b870151868503909101838701529050612a2183826127cb565b9695505050505050565b5f60208284031215612a3b575f80fd5b815167ffffffffffffffff811115612a51575f80fd5b6127c384828501612342565b8082028115828204841417610507576105076122d6565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612a98575f80fd5b611ac082611a4d565b5f60018201612ab257612ab26122d6565b5060010190565b80820180821115610507576105076122d6565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b604081525f612b0c60408301856120a0565b828103602084015261238e81856120a0565b5f6001600160a01b03808816835280871660208401525084604083015283606083015260a06080830152612b5560a0830184611ae9565b979650505050505050565b5f60208284031215612b70575f80fd5b8151611ac081611a90565b5f60033d1115612b915760045f803e505f5160e01c5b90565b5f60443d1015612ba15790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715612bd157505050505090565b8285019150815181811115612be95750505050505090565b843d8701016020828501011115612c035750505050505090565b61291860208286010187611d82565b5f6001600160a01b03808816835280871660208401525060a06040830152612c3d60a08301866120a0565b8281036060840152612c4f81866120a0565b90508281036080840152612c638185611ae9565b9897505050505050505056fea26469706673582212208f1dec0001dd30a4328452be58dc810cbf520c3cd7e3a40477f8707b3dc8445e64736f6c634300081400330000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005000000000000000000000000044a3ccddccae339d05200a8f4347f83a58847e52000000000000000000000000c31328e68ba9770d4c3375fd2b7c79c9904c711f000000000000000000000000c3c7ea560b5533da8eee31212a9595a419e6d63100000000000000000000000097b439db483bb0e02c709b2e948a32ee72daa82d000000000000000000000000b3b5102aee1557135449ec0d514f2b7334769af2000000000000000000000000184a973a0ed40b7c4ee187b844bd1455f2191a1d0000000000000000000000007637dcb54a019a027175964ad845763d3fc3b5cd00000000000000000000000078b05cc4f278662416083dfe211f7496abc3851800000000000000000000000069e68074f1aada957edd39c5eae0069973343f300000000000000000000000004b5fe817488d86f55ab1a4e40598a3cfbde95b6a0000000000000000000000001a1427a73b7cb0f4ea3f71c6c8090c4366c8ebe10000000000000000000000002177da04f9479496c2292d6344d306aa49beb34a000000000000000000000000f0d6999725115e3ead3d927eb3329d63afaec09b000000000000000000000000e11da9560b51f8918295edc5ab9c0a90e9ada20b000000000000000000000000047d0cb513a2ccb1ed44d4af271410a9c8d5248f00000000000000000000000012c29df62b1b254e1311bef777a37bf8c575b58d00000000000000000000000016a2ebd556af2a39eba349be7d6eba7a57c477110000000000000000000000001da5331994e781ab0e2af9f85bfce2037a5141700000000000000000000000001f8615a2caa4c8ab08bf1312e022341022c90e37000000000000000000000000243db4aaa62b3785df27c364090749b96e45f3ec000000000000000000000000324111baf9886e0456d74cef0ecbd49ed0779ee1000000000000000000000000343e73d33639d9c354fa215ca23ffcd0f5604ac1000000000000000000000000367dc97068ab54ba1dfbfc0fad12fbcb7b3a0d090000000000000000000000003c1bee74ff0d159ab06b6113417fc536499057c6000000000000000000000000461a5b8326ba0e2dfd133651a3b559dc8d3b04000000000000000000000000004f55fd3b7ec169a364e34eb7f523ca5ceb12c88800000000000000000000000051787a2c56d710c68140bdadefd3a98bff96feb400000000000000000000000059590178e9eddb027ed87bed9c1da8cd5129fed90000000000000000000000005efdb6d8c798c2c2bea5b1961982a5944f92a5c10000000000000000000000005f45c7ea2e094fea813a8a8813620ffcc4a19d0f000000000000000000000000626ffae9f5537d4fadb6065585213f095b106bfc00000000000000000000000065a4c69f4ea3fea89a0d4156c3d91c787472b67000000000000000000000000067164d8853d3dc9ab5d11cb6744e6f04401cf772000000000000000000000000679d5162bad71990abca0f18095948c12a2756b000000000000000000000000072915ad3110eb31768a562f540ac1ebcd51d3dc800000000000000000000000075432062a9bcc6bc5c294f44a8e3aa65bec8a64d0000000000000000000000007a3cf7122eb2e3f3820f0afaaac4206cdc50bd7e00000000000000000000000081eef2d7c4033c3224660b6a5d4b4a4727f1c762000000000000000000000000881475210e75b814d5b711090a064942b6f30605000000000000000000000000a3e0f18fec11b027bc23fd8a1cac729cffab11d9000000000000000000000000b69cd25391df0b18e6cafe9dd61b966388d6beec000000000000000000000000c0dcce9d4f0e5dbf20dc2631786550dbdeebf756000000000000000000000000c3d1b0445c7d62fdb86e02c467f4239478b37f20000000000000000000000000c8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a000000000000000000000000d52fba65a52214a65c78dc7f95c9fee1f13a5955000000000000000000000000e2601273be4c89a729a3fe0af4bd6503bb20c27c000000000000000000000000e3603cf313dcd49cc3061c9850a474d40aa81159000000000000000000000000e5b0a257f0420ed4860d5d431e6ad6744da08405000000000000000000000000f035af8a3dff1f90aeb21f9623589ae1330e9e09000000000000000000000000fc8f57a04f4df6f167599162bf5fdaa098ac18cc000000000000000000000000962a7d642178c87eeec92240669ec98f868dc54e000000000000000000000000a5af072b89525ef22b60bb1aa2107a48f35d0cfe0000000000000000000000005d802e2fe48392c104ce0401c7eca8a4456f1f16000000000000000000000000aec4075e4fc8ce829bc4f0cfd5e2fa10dd2b12d1000000000000000000000000463fc06d16e146ec9e4cb2ab8c3077732c75f38b00000000000000000000000081590c16b9d1495d133cf881acf5cc0b56730b740000000000000000000000001aae1bc09e1785c8cb00650db0c6015bd73b0c7e000000000000000000000000c3f1d077fa590018d3924ce8da1a085b4eae506d0000000000000000000000008715ed9bbd4f8cfbed14f045556f19f39f11c75b000000000000000000000000d5a06056701c7cfba12b1a384294148b9d2d8bca0000000000000000000000009027bd5b0d32b0cb51dce93e8add64aca3a2491200000000000000000000000099b8226ec774c957ffe2747fdfbae8f22741e8990000000000000000000000009c81559aac49da60ff1e7755436dc2924d1a4c4f00000000000000000000000036ed861a319278e5b6c39028884b0ca93df105d0000000000000000000000000b2d2ecc7d94cfb8e70f60aeb97bf7f4c4cb8ef28000000000000000000000000c2322d5e0cb1dc57695ecae84e5f6868c17f1cb7000000000000000000000000b379b56bcacdd58ae0768654763881849bfaad94000000000000000000000000d2dea18d040152c580f29195b29670633b0c979600000000000000000000000036041d9f21901599b9825bf4ecdf03aee81be0a600000000000000000000000092890034a3dcb1c38c1184775788ba0f95c23f03000000000000000000000000cd64a3e77335b652f8582e081f02bf9c90f908a40000000000000000000000003348de5cc020eefa5d3b8212aefbc0c19d315f24000000000000000000000000d8208bbf403a5de65a61e45321580fd0e31d4432000000000000000000000000f6e9ccea1f646fee85e13ab3361c75959a94d5b000000000000000000000000097a6d7365e64d56b8a9aede0096a0fa2ace4eebc0000000000000000000000009adccfd429a7ba40e7945841164ea2cffa7611fd0000000000000000000000003689c216f8f6ce7e2ce2a27c81a23096a787f532000000000000000000000000d2498b4dc8402789736f7c94caf969ea65badfa20000000000000000000000000d0e328b8fbc4a148eeae9e7b4791d7a6a0d2d07000000000000000000000000f56345338cb4cddaf915ebef3bfde63e70fe3053

Deployed Bytecode

0x60806040526004361061016f575f3560e01c806344b285db116100c65780639c095f561161007c578063bd85b03911610057578063bd85b039146103ad578063e985e9c5146103cd578063f242432a146103ee575f80fd5b80639c095f561461035a578063a035b1fe14610379578063a22cb4651461038e575f80fd5b80634e840992116100ac5780634e8409921461031457806368987a831461033357806395d89b4114610346575f80fd5b806344b285db146102c95780634e1273f4146102e8575f80fd5b806318160ddd116101265780632bfc3052116101015780632bfc3052146102845780632eb2c2d6146102975780633f6b5fde146102b6575f80fd5b806318160ddd1461024b57806325431b181461025e578063262fb60814610271575f80fd5b806306fdde031161015657806306fdde03146101ec5780630e89341c1461020d57806310981eb31461022c575f80fd5b8062fdd58e1461018b57806301ffc9a7146101bd575f80fd5b36610187576101853361018061040d565b610463565b005b5f80fd5b348015610196575f80fd5b506101aa6101a5366004611a68565b6104cf565b6040519081526020015b60405180910390f35b3480156101c8575f80fd5b506101dc6101d7366004611aa5565b61050d565b60405190151581526020016101b4565b3480156101f7575f80fd5b506102006105a7565b6040516101b49190611b14565b348015610218575f80fd5b50610200610227366004611b26565b610633565b348015610237575f80fd5b50610185610246366004611b3d565b610726565b348015610256575f80fd5b505f196101aa565b61018561026c366004611ba2565b61074c565b61018561027f366004611c4d565b610773565b610185610292366004611ce0565b610898565b3480156102a2575f80fd5b506101856102b1366004611ee9565b610928565b6101856102c4366004611f8c565b61099d565b3480156102d4575f80fd5b506102006102e3366004611b26565b6109be565b3480156102f3575f80fd5b50610307610302366004611fdb565b610a13565b6040516101b491906120d9565b34801561031f575f80fd5b5061018561032e3660046120eb565b610b4f565b610185610341366004612134565b610b96565b348015610351575f80fd5b50610200610c90565b348015610365575f80fd5b50610185610374366004611b3d565b610c9d565b348015610384575f80fd5b506101aa60035481565b348015610399575f80fd5b506101856103a83660046121fc565b610cc9565b3480156103b8575f80fd5b506101aa6103c7366004611b26565b505f1990565b3480156103d8575f80fd5b506101dc6103e7366004612231565b5f92915050565b3480156103f9575f80fd5b50610185610408366004612262565b610d11565b5f44335a6040516020016104469392919092835260609190911b6bffffffffffffffffffffffff19166020830152603482015260540190565b604051602081830303815290604052805190602001205f1c905090565b5f6003543461047291906122ea565b90505f6003543461048391906122fd565b9050815f036104a5576040516328df225d60e01b815260040160405180910390fd5b6104bf84848460405180602001604052805f815250610d81565b6104c98482610e8c565b50505050565b5f6001600160a01b0383166104e557505f610507565b505f818152602081815260408083206001600160a01b03861684529091529020545b92915050565b5f6001600160e01b031982167fd9b67a2600000000000000000000000000000000000000000000000000000000148061056f57506001600160e01b031982167f0e89341c00000000000000000000000000000000000000000000000000000000145b8061050757507f01ffc9a7000000000000000000000000000000000000000000000000000000006001600160e01b0319831614610507565b600180546105b490612310565b80601f01602080910402602001604051908101604052809291908181526020018280546105e090612310565b801561062b5780601f106106025761010080835404028352916020019161062b565b820191905f5260205f20905b81548152906001019060200180831161060e57829003601f168201915b505050505081565b60607312b7f0e2f3d562b0cd012bd58e2d620bfdfe542f634afd561b73b0047233de84066b491f093380b8ca3cff4f733363b4b5b48f856040518263ffffffff1660e01b815260040161068891815260200190565b5f60405180830381865af41580156106a2573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526106c9919081019061263f565b6040518263ffffffff1660e01b81526004016106e59190612923565b5f60405180830381865af41580156106ff573d5f803e3d5ffd5b505050506040513d5f823e601f3d908101601f191682016040526105079190810190612a2b565b610731338383610f56565b61074833600354836107439190612a5d565b610e8c565b5050565b610756838661109a565b6107608484610463565b61076c84848484611101565b5050505050565b6107ae8282808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b6107e98585808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b146108075760405163b4fa3fb360e01b815260040160405180910390fd5b845f5b8181101561088e5761084d3389898481811061082857610828612a74565b9050602002013588888581811061084157610841612a74565b90506020020135610f56565b6108863361085961040d565b86868581811061086b5761086b612a74565b9050602002013560405180602001604052805f815250610d81565b60010161080a565b5050505050505050565b6108db6108d68383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b611198565b825f5b81811015610920576109188686838181106108fb576108fb612a74565b90506020020160208101906109109190612a88565b61085961040d565b6001016108de565b505050505050565b6001600160a01b03851633146109905760405162461bcd60e51b815260206004820152602260248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526132b960f11b60648201526084015b60405180910390fd5b61076c85858585856111c7565b5f6109a661040d565b90506109b28482610463565b6104c984828585611101565b606073c6b17cafcc2439ef4833fe6a073ba71438112f8763929ecd9d73b0047233de84066b491f093380b8ca3cff4f733363b4b5b48f856040518263ffffffff1660e01b815260040161068891815260200190565b60608151835114610a8c5760405162461bcd60e51b815260206004820152602960248201527f455243313135353a206163636f756e747320616e6420696473206c656e67746860448201527f206d69736d6174636800000000000000000000000000000000000000000000006064820152608401610987565b5f835167ffffffffffffffff811115610aa757610aa7611d47565b604051908082528060200260200182016040528015610ad0578160200160208202803683370190505b5090505f5b8451811015610b4757610b1a858281518110610af357610af3612a74565b6020026020010151858381518110610b0d57610b0d612a74565b60200260200101516104cf565b828281518110610b2c57610b2c612a74565b6020908102919091010152610b4081612aa1565b9050610ad5565b509392505050565b8051825114610b715760405163b4fa3fb360e01b815260040160405180910390fd5b610b7c338383611417565b61074833600354610b8c8461114d565b6107439190612a5d565b610bd46108d68383808060200260200160405190810160405280939291908181526020018383602002808284375f9201919091525061114d92505050565b865f5b81811015610c8457610c27868683818110610bf457610bf4612a74565b905060200201358b8b84818110610c0d57610c0d612a74565b9050602002016020810190610c229190612a88565b61109a565b610c7c888883818110610c3c57610c3c612a74565b9050602002016020810190610c519190612a88565b878784818110610c6357610c63612a74565b9050602002013586868581811061086b5761086b612a74565b600101610bd7565b50505050505050505050565b600280546105b490612310565b610ca8338383610f56565b61074833610cb461040d565b8360405180602001604052805f815250610d81565b60405162461bcd60e51b815260206004820152601a60248201527f4e6f20617070726f76616c73206f6e20696e66696e69746965730000000000006044820152606401610987565b6001600160a01b0385163314610d745760405162461bcd60e51b815260206004820152602260248201527f455243313135353a2063616c6c6572206973206e6f7420746f6b656e206f776e60448201526132b960f11b6064820152608401610987565b61076c8585858585611628565b6001600160a01b038416610dfd5760405162461bcd60e51b815260206004820152602160248201527f455243313135353a206d696e7420746f20746865207a65726f2061646472657360448201527f73000000000000000000000000000000000000000000000000000000000000006064820152608401610987565b5f838152602081815260408083206001600160a01b0388168452909152812080543392859291610e2e908490612ab9565b909155505060408051858152602081018590526001600160a01b03808816925f92918516917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a461076c815f878787876117a5565b5f826001600160a01b0316826040515f6040518083038185875af1925050503d805f8114610ed5576040519150601f19603f3d011682016040523d82523d5f602084013e610eda565b606091505b5050905080610f515760405162461bcd60e51b815260206004820152603160248201527f556e61626c6520746f2073656e642076616c75652c20726563697069656e742060448201527f6d617920686176652072657665727465640000000000000000000000000000006064820152608401610987565b505050565b6001600160a01b038316610fb85760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610987565b5f828152602081815260408083206001600160a01b0387168452909152902054818110156110345760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610987565b5f838152602081815260408083206001600160a01b038816808552908352818420868603905581518781529283018690529133917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f6291015b60405180910390a450505050565b5f806110a683856104cf565b1190508015816110ca57503373c8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a14155b15610f51576040517fc1ab6dc100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b80156104c95782846001600160a01b0316336001600160a01b03167fdd99aef5e4fdfad84059320be40f5dc0f015dc4025f56bd4010608c6743bc22e858560405161108c929190612acc565b5f805b82518110156111925782818151811061116b5761116b612a74565b60200260200101518261117e9190612ab9565b91508061118a81612aa1565b915050611150565b50919050565b6003546111a59082612a5d565b34146111c4576040516328df225d60e01b815260040160405180910390fd5b50565b81518351146112295760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610987565b6001600160a01b03841661128d5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610987565b5f5b83518110156113b1575f8482815181106112ab576112ab612a74565b602002602001015190505f8483815181106112c8576112c8612a74565b6020908102919091018101515f84815280835260408082206001600160a01b038d16835290935291909120549091508181101561135a5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610987565b5f838152602081815260408083206001600160a01b038d8116855292528083208585039055908a16825281208054849290611396908490612ab9565b92505081905550505050806113aa90612aa1565b905061128f565b50836001600160a01b0316856001600160a01b0316866001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8686604051611401929190612afa565b60405180910390a461076c858686868686611952565b6001600160a01b0383166114795760405162461bcd60e51b815260206004820152602360248201527f455243313135353a206275726e2066726f6d20746865207a65726f206164647260448201526265737360e81b6064820152608401610987565b80518251146114db5760405162461bcd60e51b815260206004820152602860248201527f455243313135353a2069647320616e6420616d6f756e7473206c656e677468206044820152670dad2e6dac2e8c6d60c31b6064820152608401610987565b335f5b83518110156115d8575f8482815181106114fa576114fa612a74565b602002602001015190505f84838151811061151757611517612a74565b6020908102919091018101515f84815280835260408082206001600160a01b038c1683529093529190912054909150818110156115a25760405162461bcd60e51b8152602060048201526024808201527f455243313135353a206275726e20616d6f756e7420657863656564732062616c604482015263616e636560e01b6064820152608401610987565b5f928352602083815260408085206001600160a01b038b16865290915290922091039055806115d081612aa1565b9150506114de565b505f6001600160a01b0316846001600160a01b0316826001600160a01b03167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb868660405161108c929190612afa565b6001600160a01b03841661168c5760405162461bcd60e51b815260206004820152602560248201527f455243313135353a207472616e7366657220746f20746865207a65726f206164604482015264647265737360d81b6064820152608401610987565b5f838152602081815260408083206001600160a01b03891684529091529020548281101561170f5760405162461bcd60e51b815260206004820152602a60248201527f455243313135353a20696e73756666696369656e742062616c616e636520666f60448201526939103a3930b739b332b960b11b6064820152608401610987565b5f848152602081815260408083206001600160a01b038a811685529252808320868503905590871682528120805485929061174b908490612ab9565b909155505060408051858152602081018590526001600160a01b03808816929089169182917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a46109208687878787875b6001600160a01b0384163b156109205760405163f23a6e6160e01b81526001600160a01b0385169063f23a6e61906117e99089908990889088908890600401612b1e565b6020604051808303815f875af1925050508015611823575060408051601f3d908101601f1916820190925261182091810190612b60565b60015b6118d85761182f612b7b565b806308c379a0036118685750611843612b94565b8061184e575061186a565b8060405162461bcd60e51b81526004016109879190611b14565b505b60405162461bcd60e51b815260206004820152603460248201527f455243313135353a207472616e7366657220746f206e6f6e2d4552433131353560448201527f526563656976657220696d706c656d656e7465720000000000000000000000006064820152608401610987565b6001600160e01b0319811663f23a6e6160e01b146119495760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610987565b50505050505050565b6001600160a01b0384163b156109205760405163bc197c8160e01b81526001600160a01b0385169063bc197c81906119969089908990889088908890600401612c12565b6020604051808303815f875af19250505080156119d0575060408051601f3d908101601f191682019092526119cd91810190612b60565b60015b6119dc5761182f612b7b565b6001600160e01b0319811663bc197c8160e01b146119495760405162461bcd60e51b815260206004820152602860248201527f455243313135353a204552433131353552656365697665722072656a656374656044820152676420746f6b656e7360c01b6064820152608401610987565b80356001600160a01b0381168114611a63575f80fd5b919050565b5f8060408385031215611a79575f80fd5b611a8283611a4d565b946020939093013593505050565b6001600160e01b0319811681146111c4575f80fd5b5f60208284031215611ab5575f80fd5b8135611ac081611a90565b9392505050565b5f5b83811015611ae1578181015183820152602001611ac9565b50505f910152565b5f8151808452611b00816020860160208601611ac7565b601f01601f19169290920160200192915050565b602081525f611ac06020830184611ae9565b5f60208284031215611b36575f80fd5b5035919050565b5f8060408385031215611b4e575f80fd5b50508035926020909101359150565b5f8083601f840112611b6d575f80fd5b50813567ffffffffffffffff811115611b84575f80fd5b602083019150836020828501011115611b9b575f80fd5b9250929050565b5f805f805f60808688031215611bb6575f80fd5b611bbf86611a4d565b9450611bcd60208701611a4d565b935060408601359250606086013567ffffffffffffffff811115611bef575f80fd5b611bfb88828901611b5d565b969995985093965092949392505050565b5f8083601f840112611c1c575f80fd5b50813567ffffffffffffffff811115611c33575f80fd5b6020830191508360208260051b8501011115611b9b575f80fd5b5f805f805f8060608789031215611c62575f80fd5b863567ffffffffffffffff80821115611c79575f80fd5b611c858a838b01611c0c565b90985096506020890135915080821115611c9d575f80fd5b611ca98a838b01611c0c565b90965094506040890135915080821115611cc1575f80fd5b50611cce89828a01611c0c565b979a9699509497509295939492505050565b5f805f8060408587031215611cf3575f80fd5b843567ffffffffffffffff80821115611d0a575f80fd5b611d1688838901611c0c565b90965094506020870135915080821115611d2e575f80fd5b50611d3b87828801611c0c565b95989497509550505050565b634e487b7160e01b5f52604160045260245ffd5b610800810181811067ffffffffffffffff82111715611d7c57611d7c611d47565b60405250565b601f8201601f1916810167ffffffffffffffff81118282101715611da857611da8611d47565b6040525050565b604051610180810167ffffffffffffffff81118282101715611dd357611dd3611d47565b60405290565b5f67ffffffffffffffff821115611df257611df2611d47565b5060051b60200190565b5f82601f830112611e0b575f80fd5b81356020611e1882611dd9565b604051611e258282611d82565b83815260059390931b8501820192828101915086841115611e44575f80fd5b8286015b84811015611e5f5780358352918301918301611e48565b509695505050505050565b5f67ffffffffffffffff821115611e8357611e83611d47565b50601f01601f191660200190565b5f82601f830112611ea0575f80fd5b8135611eab81611e6a565b604051611eb88282611d82565b828152856020848701011115611ecc575f80fd5b826020860160208301375f92810160200192909252509392505050565b5f805f805f60a08688031215611efd575f80fd5b611f0686611a4d565b9450611f1460208701611a4d565b9350604086013567ffffffffffffffff80821115611f30575f80fd5b611f3c89838a01611dfc565b94506060880135915080821115611f51575f80fd5b611f5d89838a01611dfc565b93506080880135915080821115611f72575f80fd5b50611f7f88828901611e91565b9150509295509295909350565b5f805f60408486031215611f9e575f80fd5b611fa784611a4d565b9250602084013567ffffffffffffffff811115611fc2575f80fd5b611fce86828701611b5d565b9497909650939450505050565b5f8060408385031215611fec575f80fd5b823567ffffffffffffffff80821115612003575f80fd5b818501915085601f830112612016575f80fd5b8135602061202382611dd9565b6040516120308282611d82565b83815260059390931b850182019282810191508984111561204f575f80fd5b948201945b838610156120745761206586611a4d565b82529482019490820190612054565b96505086013592505080821115612089575f80fd5b5061209685828601611dfc565b9150509250929050565b5f8151808452602080850194508084015f5b838110156120ce578151875295820195908201906001016120b2565b509495945050505050565b602081525f611ac060208301846120a0565b5f80604083850312156120fc575f80fd5b823567ffffffffffffffff80821115612113575f80fd5b61211f86838701611dfc565b93506020850135915080821115612089575f80fd5b5f805f805f805f806080898b03121561214b575f80fd5b883567ffffffffffffffff80821115612162575f80fd5b61216e8c838d01611c0c565b909a50985060208b0135915080821115612186575f80fd5b6121928c838d01611c0c565b909850965060408b01359150808211156121aa575f80fd5b6121b68c838d01611c0c565b909650945060608b01359150808211156121ce575f80fd5b506121db8b828c01611c0c565b999c989b5096995094979396929594505050565b80151581146111c4575f80fd5b5f806040838503121561220d575f80fd5b61221683611a4d565b91506020830135612226816121ef565b809150509250929050565b5f8060408385031215612242575f80fd5b61224b83611a4d565b915061225960208401611a4d565b90509250929050565b5f805f805f60a08688031215612276575f80fd5b61227f86611a4d565b945061228d60208701611a4d565b93506040860135925060608601359150608086013567ffffffffffffffff8111156122b6575f80fd5b611f7f88828901611e91565b634e487b7160e01b5f52601260045260245ffd5b634e487b7160e01b5f52601160045260245ffd5b5f826122f8576122f86122c2565b500490565b5f8261230b5761230b6122c2565b500690565b600181811c9082168061232457607f821691505b60208210810361119257634e487b7160e01b5f52602260045260245ffd5b5f82601f830112612351575f80fd5b815161235c81611e6a565b6040516123698282611d82565b82815285602084870101111561237d575f80fd5b61238e836020830160208801611ac7565b95945050505050565b805160ff81168114611a63575f80fd5b8051611a63816121ef565b805161ffff81168114611a63575f80fd5b5f608082840312156123d3575f80fd5b6040516080810167ffffffffffffffff82821081831117156123f7576123f7611d47565b81604052829350612407856123b2565b8352612415602086016123b2565b6020840152612426604086016123b2565b6040840152606085015191508082111561243e575f80fd5b5061244b85828601612342565b6060830152505092915050565b5f82601f830112612467575f80fd5b6040805161247481611d5b565b80610800850186811115612486575f80fd5b855b8181101561263357805167ffffffffffffffff808211156124a8575f8081fd5b90880190610180828b0312156124bd575f8081fd5b6124c5611daf565b8251815260206124d68185016123b2565b818301526124e58985016123a7565b89830152606080850151848111156124fc575f8081fd5b6125088e828801612342565b82850152505060808085015184811115612521575f8081fd5b61252d8e828801612342565b82850152505060a08085015184811115612546575f8081fd5b6125528e828801612342565b82850152505060c0808501518481111561256b575f8081fd5b6125778e828801612342565b82850152505060e08085015184811115612590575f8081fd5b61259c8e828801612342565b82850152505061010080850151848111156125b6575f8081fd5b6125c28e828801612342565b82850152505061012080850151848111156125dc575f8081fd5b6125e88e828801612342565b828501525050610140808501518184015250610160808501518481111561260e575f8081fd5b61261a8e8288016123c3565b9184019190915250908652909401935050602001612488565b50919695505050505050565b5f6020828403121561264f575f80fd5b815167ffffffffffffffff80821115612666575f80fd5b90830190610180828603121561267a575f80fd5b612682611daf565b82518152602083015182811115612697575f80fd5b6126a387828601612342565b6020830152506040830151828111156126ba575f80fd5b6126c687828601612342565b6040830152506126d860608401612397565b60608201526126e960808401612397565b60808201526126fa60a08401612397565b60a082015261270b60c08401612397565b60c082015261271c60e08401612397565b60e082015261010061272f8185016123a7565b908201526101206127418482016123a7565b908201526101406127538482016123a7565b90820152610160838101518381111561276a575f80fd5b61277688828701612458565b918301919091525095945050505050565b5f61ffff808351168452806020840151166020850152806040840151166040850152506060820151608060608501526127c36080850182611ae9565b949350505050565b5f826108008101835f5b60408082106127e45750612918565b84840388528251610180815186526020808301516128078289018261ffff169052565b508284015180151588860152506060935083830151828589015261282d83890182611ae9565b9450506080915081830151878503838901526128498582611ae9565b94505060a0915081830151878503838901526128658582611ae9565b94505060c0915081830151878503838901526128818582611ae9565b94505060e09150818301518785038389015261289d8582611ae9565b945050610100915081830151878503838901526128ba8582611ae9565b945050610120915081830151878503838901526128d78582611ae9565b61014085810151908a015261016094850151898203868b015290955093925061290290508484612787565b9a81019a965094909401935050506001016127d5565b509095945050505050565b60208152815160208201525f602083015161018080604085015261294b6101a0850183611ae9565b91506040850151601f19808685030160608701526129698483611ae9565b935060608701519150612981608087018360ff169052565b608087015160ff811660a0880152915060a087015160ff811660c0880152915060c087015160ff811660e0880152915060e087015191506101006129c98188018460ff169052565b87015191506101206129de8782018415159052565b87015191506101406129f38782018415159052565b8701519150610160612a088782018415159052565b870151868503909101838701529050612a2183826127cb565b9695505050505050565b5f60208284031215612a3b575f80fd5b815167ffffffffffffffff811115612a51575f80fd5b6127c384828501612342565b8082028115828204841417610507576105076122d6565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612a98575f80fd5b611ac082611a4d565b5f60018201612ab257612ab26122d6565b5060010190565b80820180821115610507576105076122d6565b60208152816020820152818360408301375f818301604090810191909152601f909201601f19160101919050565b604081525f612b0c60408301856120a0565b828103602084015261238e81856120a0565b5f6001600160a01b03808816835280871660208401525084604083015283606083015260a06080830152612b5560a0830184611ae9565b979650505050505050565b5f60208284031215612b70575f80fd5b8151611ac081611a90565b5f60033d1115612b915760045f803e505f5160e01c5b90565b5f60443d1015612ba15790565b6040516003193d81016004833e81513d67ffffffffffffffff8160248401118184111715612bd157505050505090565b8285019150815181811115612be95750505050505090565b843d8701016020828501011115612c035750505050505090565b61291860208286010187611d82565b5f6001600160a01b03808816835280871660208401525060a06040830152612c3d60a08301866120a0565b8281036060840152612c4f81866120a0565b90508281036080840152612c638185611ae9565b9897505050505050505056fea26469706673582212208f1dec0001dd30a4328452be58dc810cbf520c3cd7e3a40477f8707b3dc8445e64736f6c63430008140033

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

0000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000005000000000000000000000000044a3ccddccae339d05200a8f4347f83a58847e52000000000000000000000000c31328e68ba9770d4c3375fd2b7c79c9904c711f000000000000000000000000c3c7ea560b5533da8eee31212a9595a419e6d63100000000000000000000000097b439db483bb0e02c709b2e948a32ee72daa82d000000000000000000000000b3b5102aee1557135449ec0d514f2b7334769af2000000000000000000000000184a973a0ed40b7c4ee187b844bd1455f2191a1d0000000000000000000000007637dcb54a019a027175964ad845763d3fc3b5cd00000000000000000000000078b05cc4f278662416083dfe211f7496abc3851800000000000000000000000069e68074f1aada957edd39c5eae0069973343f300000000000000000000000004b5fe817488d86f55ab1a4e40598a3cfbde95b6a0000000000000000000000001a1427a73b7cb0f4ea3f71c6c8090c4366c8ebe10000000000000000000000002177da04f9479496c2292d6344d306aa49beb34a000000000000000000000000f0d6999725115e3ead3d927eb3329d63afaec09b000000000000000000000000e11da9560b51f8918295edc5ab9c0a90e9ada20b000000000000000000000000047d0cb513a2ccb1ed44d4af271410a9c8d5248f00000000000000000000000012c29df62b1b254e1311bef777a37bf8c575b58d00000000000000000000000016a2ebd556af2a39eba349be7d6eba7a57c477110000000000000000000000001da5331994e781ab0e2af9f85bfce2037a5141700000000000000000000000001f8615a2caa4c8ab08bf1312e022341022c90e37000000000000000000000000243db4aaa62b3785df27c364090749b96e45f3ec000000000000000000000000324111baf9886e0456d74cef0ecbd49ed0779ee1000000000000000000000000343e73d33639d9c354fa215ca23ffcd0f5604ac1000000000000000000000000367dc97068ab54ba1dfbfc0fad12fbcb7b3a0d090000000000000000000000003c1bee74ff0d159ab06b6113417fc536499057c6000000000000000000000000461a5b8326ba0e2dfd133651a3b559dc8d3b04000000000000000000000000004f55fd3b7ec169a364e34eb7f523ca5ceb12c88800000000000000000000000051787a2c56d710c68140bdadefd3a98bff96feb400000000000000000000000059590178e9eddb027ed87bed9c1da8cd5129fed90000000000000000000000005efdb6d8c798c2c2bea5b1961982a5944f92a5c10000000000000000000000005f45c7ea2e094fea813a8a8813620ffcc4a19d0f000000000000000000000000626ffae9f5537d4fadb6065585213f095b106bfc00000000000000000000000065a4c69f4ea3fea89a0d4156c3d91c787472b67000000000000000000000000067164d8853d3dc9ab5d11cb6744e6f04401cf772000000000000000000000000679d5162bad71990abca0f18095948c12a2756b000000000000000000000000072915ad3110eb31768a562f540ac1ebcd51d3dc800000000000000000000000075432062a9bcc6bc5c294f44a8e3aa65bec8a64d0000000000000000000000007a3cf7122eb2e3f3820f0afaaac4206cdc50bd7e00000000000000000000000081eef2d7c4033c3224660b6a5d4b4a4727f1c762000000000000000000000000881475210e75b814d5b711090a064942b6f30605000000000000000000000000a3e0f18fec11b027bc23fd8a1cac729cffab11d9000000000000000000000000b69cd25391df0b18e6cafe9dd61b966388d6beec000000000000000000000000c0dcce9d4f0e5dbf20dc2631786550dbdeebf756000000000000000000000000c3d1b0445c7d62fdb86e02c467f4239478b37f20000000000000000000000000c8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a000000000000000000000000d52fba65a52214a65c78dc7f95c9fee1f13a5955000000000000000000000000e2601273be4c89a729a3fe0af4bd6503bb20c27c000000000000000000000000e3603cf313dcd49cc3061c9850a474d40aa81159000000000000000000000000e5b0a257f0420ed4860d5d431e6ad6744da08405000000000000000000000000f035af8a3dff1f90aeb21f9623589ae1330e9e09000000000000000000000000fc8f57a04f4df6f167599162bf5fdaa098ac18cc000000000000000000000000962a7d642178c87eeec92240669ec98f868dc54e000000000000000000000000a5af072b89525ef22b60bb1aa2107a48f35d0cfe0000000000000000000000005d802e2fe48392c104ce0401c7eca8a4456f1f16000000000000000000000000aec4075e4fc8ce829bc4f0cfd5e2fa10dd2b12d1000000000000000000000000463fc06d16e146ec9e4cb2ab8c3077732c75f38b00000000000000000000000081590c16b9d1495d133cf881acf5cc0b56730b740000000000000000000000001aae1bc09e1785c8cb00650db0c6015bd73b0c7e000000000000000000000000c3f1d077fa590018d3924ce8da1a085b4eae506d0000000000000000000000008715ed9bbd4f8cfbed14f045556f19f39f11c75b000000000000000000000000d5a06056701c7cfba12b1a384294148b9d2d8bca0000000000000000000000009027bd5b0d32b0cb51dce93e8add64aca3a2491200000000000000000000000099b8226ec774c957ffe2747fdfbae8f22741e8990000000000000000000000009c81559aac49da60ff1e7755436dc2924d1a4c4f00000000000000000000000036ed861a319278e5b6c39028884b0ca93df105d0000000000000000000000000b2d2ecc7d94cfb8e70f60aeb97bf7f4c4cb8ef28000000000000000000000000c2322d5e0cb1dc57695ecae84e5f6868c17f1cb7000000000000000000000000b379b56bcacdd58ae0768654763881849bfaad94000000000000000000000000d2dea18d040152c580f29195b29670633b0c979600000000000000000000000036041d9f21901599b9825bf4ecdf03aee81be0a600000000000000000000000092890034a3dcb1c38c1184775788ba0f95c23f03000000000000000000000000cd64a3e77335b652f8582e081f02bf9c90f908a40000000000000000000000003348de5cc020eefa5d3b8212aefbc0c19d315f24000000000000000000000000d8208bbf403a5de65a61e45321580fd0e31d4432000000000000000000000000f6e9ccea1f646fee85e13ab3361c75959a94d5b000000000000000000000000097a6d7365e64d56b8a9aede0096a0fa2ace4eebc0000000000000000000000009adccfd429a7ba40e7945841164ea2cffa7611fd0000000000000000000000003689c216f8f6ce7e2ce2a27c81a23096a787f532000000000000000000000000d2498b4dc8402789736f7c94caf969ea65badfa20000000000000000000000000d0e328b8fbc4a148eeae9e7b4791d7a6a0d2d07000000000000000000000000f56345338cb4cddaf915ebef3bfde63e70fe3053

-----Decoded View---------------
Arg [0] : genesisRecipients (address[]): 0x44a3CCddccae339D05200a8f4347F83A58847E52,0xc31328e68bA9770D4C3375FD2B7c79C9904c711f,0xc3c7Ea560b5533DA8EEE31212a9595A419e6D631,0x97B439DB483bB0E02c709b2E948a32Ee72dAa82D,0xB3b5102aee1557135449eC0D514f2b7334769af2,0x184A973A0Ed40b7C4EE187b844bd1455F2191a1d,0x7637DCB54a019A027175964aD845763d3fC3b5cd,0x78b05cC4f278662416083dfE211f7496ABc38518,0x69E68074f1aadA957eDd39c5EAE0069973343f30,0x4B5fE817488D86F55aB1A4e40598a3cFbDE95b6a,0x1a1427A73b7Cb0F4ea3F71C6c8090c4366c8eBe1,0x2177dA04f9479496c2292D6344d306aA49BeB34A,0xf0D6999725115E3EAd3D927Eb3329D63AFAEC09b,0xe11Da9560b51f8918295edC5ab9c0a90E9ADa20B,0x047d0cB513A2CcB1ED44d4aF271410A9C8D5248F,0x12C29df62b1b254e1311Bef777a37Bf8C575b58D,0x16a2EBd556Af2a39eBa349be7D6eba7A57c47711,0x1DA5331994e781AB0E2AF9f85bfce2037A514170,0x1f8615a2caa4c8ab08bf1312e022341022C90e37,0x243db4aAa62b3785DF27c364090749B96E45f3Ec,0x324111bAF9886E0456d74ceF0ECbd49Ed0779ee1,0x343e73D33639d9c354FA215cA23fFCd0F5604Ac1,0x367dC97068aB54bA1dFBFC0fad12FBCB7B3A0d09,0x3c1BEE74Ff0D159AB06B6113417fc536499057C6,0x461A5B8326bA0e2DFd133651A3b559Dc8d3B0400,0x4f55FD3B7EC169a364E34Eb7f523Ca5CEB12C888,0x51787a2C56d710c68140bdAdeFD3A98BfF96FeB4,0x59590178E9eddb027eD87bEd9c1da8Cd5129fEd9,0x5efdB6D8c798c2c2Bea5b1961982a5944F92a5C1,0x5f45C7EA2E094FeA813A8a8813620FFCC4A19d0f,0x626ffAe9f5537d4faDB6065585213f095b106bfC,0x65a4C69f4EA3fEA89a0D4156c3D91C787472b670,0x67164D8853D3dC9Ab5d11cB6744e6f04401cf772,0x679d5162BaD71990ABCA0f18095948c12a2756B0,0x72915ad3110Eb31768A562F540aC1ebcd51d3Dc8,0x75432062a9bCc6bc5C294F44a8E3aa65bec8a64d,0x7A3Cf7122EB2E3F3820f0aFaaaC4206CDc50Bd7e,0x81Eef2d7C4033C3224660B6a5D4B4A4727f1c762,0x881475210E75b814D5b711090a064942b6f30605,0xa3E0F18FeC11B027bC23Fd8a1cac729CffaB11D9,0xB69cD25391Df0b18E6cafe9dd61B966388d6BEec,0xc0dccE9D4F0e5dBF20DC2631786550dBDEEBF756,0xC3D1b0445C7D62FdB86e02C467f4239478b37F20,0xc8f8e2F59Dd95fF67c3d39109ecA2e2A017D4c8a,0xD52fbA65a52214A65C78Dc7f95c9FeE1F13a5955,0xe2601273Be4c89A729a3fe0Af4BD6503BB20c27C,0xe3603cf313Dcd49CC3061C9850a474d40aa81159,0xE5b0a257f0420eD4860D5D431e6aD6744dA08405,0xf035Af8a3dFf1f90aeb21F9623589AE1330E9e09,0xFc8f57A04F4dF6F167599162BF5FDAA098Ac18CC,0x962A7D642178C87EeeC92240669Ec98f868DC54e,0xa5AF072B89525ef22B60bB1aA2107a48f35D0Cfe,0x5D802e2Fe48392c104Ce0401C7ECa8a4456f1F16,0xAEC4075e4fc8cE829BC4f0cFD5e2fA10dd2b12D1,0x463fC06d16E146eC9E4Cb2aB8C3077732c75F38B,0x81590c16B9d1495D133CF881AcF5cc0B56730b74,0x1aaE1bC09E1785C8CB00650db0c6015BD73b0C7E,0xC3f1D077fa590018d3924ce8dA1a085b4eaE506D,0x8715Ed9BbD4F8cfbed14F045556f19F39f11C75b,0xd5A06056701c7CFba12B1a384294148b9D2D8bCa,0x9027Bd5B0D32b0CB51dCE93E8aDd64aCA3a24912,0x99B8226ec774c957Ffe2747fDFBAE8F22741e899,0x9c81559AAc49DA60fF1e7755436DC2924d1A4C4F,0x36eD861a319278e5B6C39028884b0ca93df105D0,0xB2D2ECC7d94CFb8e70F60AeB97Bf7F4C4cB8eF28,0xc2322d5E0cB1Dc57695ECAE84E5f6868C17F1CB7,0xb379B56bcACdD58Ae0768654763881849bFAAd94,0xd2dea18D040152c580F29195B29670633b0C9796,0x36041D9F21901599B9825bF4EcDf03aEe81be0a6,0x92890034a3dCB1c38C1184775788bA0f95C23f03,0xcD64A3e77335B652f8582e081F02bf9c90f908A4,0x3348de5CC020eEfA5D3b8212aEfbC0c19d315f24,0xd8208BBF403a5De65a61E45321580Fd0e31D4432,0xf6E9ccEA1f646FEE85e13Ab3361c75959A94D5b0,0x97a6d7365E64d56b8a9AEDe0096a0FA2aCe4eeBc,0x9aDccfD429A7Ba40E7945841164eA2Cffa7611Fd,0x3689c216f8f6ce7e2CE2a27c81a23096A787F532,0xd2498b4Dc8402789736F7C94CAf969eA65BadFa2,0x0D0E328B8fBc4a148Eeae9E7b4791D7A6A0D2d07,0xf56345338Cb4CddaF915ebeF3bfde63E70FE3053

-----Encoded View---------------
82 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000020
Arg [1] : 0000000000000000000000000000000000000000000000000000000000000050
Arg [2] : 00000000000000000000000044a3ccddccae339d05200a8f4347f83a58847e52
Arg [3] : 000000000000000000000000c31328e68ba9770d4c3375fd2b7c79c9904c711f
Arg [4] : 000000000000000000000000c3c7ea560b5533da8eee31212a9595a419e6d631
Arg [5] : 00000000000000000000000097b439db483bb0e02c709b2e948a32ee72daa82d
Arg [6] : 000000000000000000000000b3b5102aee1557135449ec0d514f2b7334769af2
Arg [7] : 000000000000000000000000184a973a0ed40b7c4ee187b844bd1455f2191a1d
Arg [8] : 0000000000000000000000007637dcb54a019a027175964ad845763d3fc3b5cd
Arg [9] : 00000000000000000000000078b05cc4f278662416083dfe211f7496abc38518
Arg [10] : 00000000000000000000000069e68074f1aada957edd39c5eae0069973343f30
Arg [11] : 0000000000000000000000004b5fe817488d86f55ab1a4e40598a3cfbde95b6a
Arg [12] : 0000000000000000000000001a1427a73b7cb0f4ea3f71c6c8090c4366c8ebe1
Arg [13] : 0000000000000000000000002177da04f9479496c2292d6344d306aa49beb34a
Arg [14] : 000000000000000000000000f0d6999725115e3ead3d927eb3329d63afaec09b
Arg [15] : 000000000000000000000000e11da9560b51f8918295edc5ab9c0a90e9ada20b
Arg [16] : 000000000000000000000000047d0cb513a2ccb1ed44d4af271410a9c8d5248f
Arg [17] : 00000000000000000000000012c29df62b1b254e1311bef777a37bf8c575b58d
Arg [18] : 00000000000000000000000016a2ebd556af2a39eba349be7d6eba7a57c47711
Arg [19] : 0000000000000000000000001da5331994e781ab0e2af9f85bfce2037a514170
Arg [20] : 0000000000000000000000001f8615a2caa4c8ab08bf1312e022341022c90e37
Arg [21] : 000000000000000000000000243db4aaa62b3785df27c364090749b96e45f3ec
Arg [22] : 000000000000000000000000324111baf9886e0456d74cef0ecbd49ed0779ee1
Arg [23] : 000000000000000000000000343e73d33639d9c354fa215ca23ffcd0f5604ac1
Arg [24] : 000000000000000000000000367dc97068ab54ba1dfbfc0fad12fbcb7b3a0d09
Arg [25] : 0000000000000000000000003c1bee74ff0d159ab06b6113417fc536499057c6
Arg [26] : 000000000000000000000000461a5b8326ba0e2dfd133651a3b559dc8d3b0400
Arg [27] : 0000000000000000000000004f55fd3b7ec169a364e34eb7f523ca5ceb12c888
Arg [28] : 00000000000000000000000051787a2c56d710c68140bdadefd3a98bff96feb4
Arg [29] : 00000000000000000000000059590178e9eddb027ed87bed9c1da8cd5129fed9
Arg [30] : 0000000000000000000000005efdb6d8c798c2c2bea5b1961982a5944f92a5c1
Arg [31] : 0000000000000000000000005f45c7ea2e094fea813a8a8813620ffcc4a19d0f
Arg [32] : 000000000000000000000000626ffae9f5537d4fadb6065585213f095b106bfc
Arg [33] : 00000000000000000000000065a4c69f4ea3fea89a0d4156c3d91c787472b670
Arg [34] : 00000000000000000000000067164d8853d3dc9ab5d11cb6744e6f04401cf772
Arg [35] : 000000000000000000000000679d5162bad71990abca0f18095948c12a2756b0
Arg [36] : 00000000000000000000000072915ad3110eb31768a562f540ac1ebcd51d3dc8
Arg [37] : 00000000000000000000000075432062a9bcc6bc5c294f44a8e3aa65bec8a64d
Arg [38] : 0000000000000000000000007a3cf7122eb2e3f3820f0afaaac4206cdc50bd7e
Arg [39] : 00000000000000000000000081eef2d7c4033c3224660b6a5d4b4a4727f1c762
Arg [40] : 000000000000000000000000881475210e75b814d5b711090a064942b6f30605
Arg [41] : 000000000000000000000000a3e0f18fec11b027bc23fd8a1cac729cffab11d9
Arg [42] : 000000000000000000000000b69cd25391df0b18e6cafe9dd61b966388d6beec
Arg [43] : 000000000000000000000000c0dcce9d4f0e5dbf20dc2631786550dbdeebf756
Arg [44] : 000000000000000000000000c3d1b0445c7d62fdb86e02c467f4239478b37f20
Arg [45] : 000000000000000000000000c8f8e2f59dd95ff67c3d39109eca2e2a017d4c8a
Arg [46] : 000000000000000000000000d52fba65a52214a65c78dc7f95c9fee1f13a5955
Arg [47] : 000000000000000000000000e2601273be4c89a729a3fe0af4bd6503bb20c27c
Arg [48] : 000000000000000000000000e3603cf313dcd49cc3061c9850a474d40aa81159
Arg [49] : 000000000000000000000000e5b0a257f0420ed4860d5d431e6ad6744da08405
Arg [50] : 000000000000000000000000f035af8a3dff1f90aeb21f9623589ae1330e9e09
Arg [51] : 000000000000000000000000fc8f57a04f4df6f167599162bf5fdaa098ac18cc
Arg [52] : 000000000000000000000000962a7d642178c87eeec92240669ec98f868dc54e
Arg [53] : 000000000000000000000000a5af072b89525ef22b60bb1aa2107a48f35d0cfe
Arg [54] : 0000000000000000000000005d802e2fe48392c104ce0401c7eca8a4456f1f16
Arg [55] : 000000000000000000000000aec4075e4fc8ce829bc4f0cfd5e2fa10dd2b12d1
Arg [56] : 000000000000000000000000463fc06d16e146ec9e4cb2ab8c3077732c75f38b
Arg [57] : 00000000000000000000000081590c16b9d1495d133cf881acf5cc0b56730b74
Arg [58] : 0000000000000000000000001aae1bc09e1785c8cb00650db0c6015bd73b0c7e
Arg [59] : 000000000000000000000000c3f1d077fa590018d3924ce8da1a085b4eae506d
Arg [60] : 0000000000000000000000008715ed9bbd4f8cfbed14f045556f19f39f11c75b
Arg [61] : 000000000000000000000000d5a06056701c7cfba12b1a384294148b9d2d8bca
Arg [62] : 0000000000000000000000009027bd5b0d32b0cb51dce93e8add64aca3a24912
Arg [63] : 00000000000000000000000099b8226ec774c957ffe2747fdfbae8f22741e899
Arg [64] : 0000000000000000000000009c81559aac49da60ff1e7755436dc2924d1a4c4f
Arg [65] : 00000000000000000000000036ed861a319278e5b6c39028884b0ca93df105d0
Arg [66] : 000000000000000000000000b2d2ecc7d94cfb8e70f60aeb97bf7f4c4cb8ef28
Arg [67] : 000000000000000000000000c2322d5e0cb1dc57695ecae84e5f6868c17f1cb7
Arg [68] : 000000000000000000000000b379b56bcacdd58ae0768654763881849bfaad94
Arg [69] : 000000000000000000000000d2dea18d040152c580f29195b29670633b0c9796
Arg [70] : 00000000000000000000000036041d9f21901599b9825bf4ecdf03aee81be0a6
Arg [71] : 00000000000000000000000092890034a3dcb1c38c1184775788ba0f95c23f03
Arg [72] : 000000000000000000000000cd64a3e77335b652f8582e081f02bf9c90f908a4
Arg [73] : 0000000000000000000000003348de5cc020eefa5d3b8212aefbc0c19d315f24
Arg [74] : 000000000000000000000000d8208bbf403a5de65a61e45321580fd0e31d4432
Arg [75] : 000000000000000000000000f6e9ccea1f646fee85e13ab3361c75959a94d5b0
Arg [76] : 00000000000000000000000097a6d7365e64d56b8a9aede0096a0fa2ace4eebc
Arg [77] : 0000000000000000000000009adccfd429a7ba40e7945841164ea2cffa7611fd
Arg [78] : 0000000000000000000000003689c216f8f6ce7e2ce2a27c81a23096a787f532
Arg [79] : 000000000000000000000000d2498b4dc8402789736f7c94caf969ea65badfa2
Arg [80] : 0000000000000000000000000d0e328b8fbc4a148eeae9e7b4791d7a6a0d2d07
Arg [81] : 000000000000000000000000f56345338cb4cddaf915ebef3bfde63e70fe3053


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

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