MATIC Price: $0.534256 (+2.37%)
Gas: 30.9 GWei
 

Sponsored

Transaction Hash
Method
Block
From
To
Safe Transfer Fr...595938252024-07-20 14:21:1646 mins ago1721485276IN
0x10Db7f08...79879500B
0 MATIC0.0025648230.00000003
Safe Transfer Fr...595935142024-07-20 14:10:0857 mins ago1721484608IN
0x10Db7f08...79879500B
0 MATIC0.0025645830.00000009
Safe Transfer Fr...595934882024-07-20 14:09:1458 mins ago1721484554IN
0x10Db7f08...79879500B
0 MATIC0.002907434
Safe Transfer Fr...595934002024-07-20 14:06:041 hr ago1721484364IN
0x10Db7f08...79879500B
0 MATIC0.00256530.0000001
Safe Transfer Fr...595932902024-07-20 14:01:061 hr ago1721484066IN
0x10Db7f08...79879500B
0 MATIC0.0025645230.00000004
Safe Transfer Fr...595931502024-07-20 13:56:081 hr ago1721483768IN
0x10Db7f08...79879500B
0 MATIC0.0025653630.00000003
Safe Transfer Fr...595928662024-07-20 13:45:561 hr ago1721483156IN
0x10Db7f08...79879500B
0 MATIC0.0025651230.00000007
Safe Transfer Fr...595927892024-07-20 13:43:121 hr ago1721482992IN
0x10Db7f08...79879500B
0 MATIC0.0018145230.00000016
Safe Transfer Fr...595927532024-07-20 13:41:561 hr ago1721482916IN
0x10Db7f08...79879500B
0 MATIC0.0025653630.00000018
Safe Transfer Fr...595925002024-07-20 13:31:521 hr ago1721482312IN
0x10Db7f08...79879500B
0 MATIC0.0025660230.00000007
Safe Transfer Fr...595923972024-07-20 13:28:121 hr ago1721482092IN
0x10Db7f08...79879500B
0 MATIC0.0025668330.00000005
Safe Transfer Fr...595923832024-07-20 13:27:421 hr ago1721482062IN
0x10Db7f08...79879500B
0 MATIC0.002565330.00000006
Safe Transfer Fr...595923702024-07-20 13:27:161 hr ago1721482036IN
0x10Db7f08...79879500B
0 MATIC0.0026096130.00000005
Safe Transfer Fr...595922592024-07-20 13:23:201 hr ago1721481800IN
0x10Db7f08...79879500B
0 MATIC0.0025658430.00000008
Safe Transfer Fr...595922552024-07-20 13:23:101 hr ago1721481790IN
0x10Db7f08...79879500B
0 MATIC0.0025668330.00000008
Safe Transfer Fr...595921452024-07-20 13:19:151 hr ago1721481555IN
0x10Db7f08...79879500B
0 MATIC0.0025670730.0000001
Safe Transfer Fr...595918362024-07-20 13:08:161 hr ago1721480896IN
0x10Db7f08...79879500B
0 MATIC0.002566530.0000001
Safe Transfer Fr...595917282024-07-20 13:03:242 hrs ago1721480604IN
0x10Db7f08...79879500B
0 MATIC0.0025652130.00000003
Safe Transfer Fr...595916162024-07-20 12:59:262 hrs ago1721480366IN
0x10Db7f08...79879500B
0 MATIC0.0025665930.00000003
Safe Transfer Fr...595915442024-07-20 12:56:522 hrs ago1721480212IN
0x10Db7f08...79879500B
0 MATIC0.0025654830.00000002
Safe Transfer Fr...595915042024-07-20 12:55:282 hrs ago1721480128IN
0x10Db7f08...79879500B
0 MATIC0.0025661130.00000004
Safe Transfer Fr...595914022024-07-20 12:51:502 hrs ago1721479910IN
0x10Db7f08...79879500B
0 MATIC0.002908834
Safe Transfer Fr...595913732024-07-20 12:50:482 hrs ago1721479848IN
0x10Db7f08...79879500B
0 MATIC0.0025652130.00000002
Safe Transfer Fr...595913052024-07-20 12:48:242 hrs ago1721479704IN
0x10Db7f08...79879500B
0 MATIC0.0025654830.00000005
Safe Transfer Fr...595912142024-07-20 12:45:102 hrs ago1721479510IN
0x10Db7f08...79879500B
0 MATIC0.0025647330.00000004
View all transactions

Parent Transaction Hash Block From To
View All Internal Transactions
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC1155FullBurn

Compiler Version
v0.8.22+commit.4fc1097e

Optimization Enabled:
Yes with 99999 runs

Other Settings:
paris EvmVersion, MIT license
File 1 of 70 : ERC1155FullBurn.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.22;

import {IForwarderRegistry} from "./../../../metatx/interfaces/IForwarderRegistry.sol";
import {ITokenMetadataResolver} from "./../../metadata/interfaces/ITokenMetadataResolver.sol";
import {IOperatorFilterRegistry} from "./../../royalty/interfaces/IOperatorFilterRegistry.sol";
import {ERC1155WithOperatorFilterer} from "./../ERC1155WithOperatorFilterer.sol";
import {ERC1155Metadata} from "./../ERC1155Metadata.sol";
import {ERC1155Mintable} from "./../ERC1155Mintable.sol";
import {ERC1155Deliverable} from "./../ERC1155Deliverable.sol";
import {ERC1155Burnable} from "./../ERC1155Burnable.sol";
import {ERC2981} from "./../../royalty/ERC2981.sol";
import {ContractOwnership} from "./../../../access/ContractOwnership.sol";
import {TokenRecovery} from "./../../../security/TokenRecovery.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {ForwarderRegistryContextBase} from "./../../../metatx/base/ForwarderRegistryContextBase.sol";
import {ForwarderRegistryContext} from "./../../../metatx/ForwarderRegistryContext.sol";

contract ERC1155FullBurn is
    ERC1155WithOperatorFilterer,
    ERC1155Metadata,
    ERC1155Mintable,
    ERC1155Deliverable,
    ERC1155Burnable,
    ERC2981,
    TokenRecovery,
    ForwarderRegistryContext
{
    constructor(
        string memory tokenName,
        string memory tokenSymbol,
        ITokenMetadataResolver metadataResolver,
        IOperatorFilterRegistry filterRegistry,
        IForwarderRegistry forwarderRegistry
    )
        ContractOwnership(msg.sender)
        ERC1155Metadata(tokenName, tokenSymbol, metadataResolver)
        ERC1155WithOperatorFilterer(filterRegistry)
        ForwarderRegistryContext(forwarderRegistry)
    {}

    /// @inheritdoc ForwarderRegistryContextBase
    function _msgSender() internal view virtual override(Context, ForwarderRegistryContextBase) returns (address) {
        return ForwarderRegistryContextBase._msgSender();
    }

    /// @inheritdoc ForwarderRegistryContextBase
    function _msgData() internal view virtual override(Context, ForwarderRegistryContextBase) returns (bytes calldata) {
        return ForwarderRegistryContextBase._msgData();
    }
}

File 2 of 70 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (interfaces/IERC20.sol)

pragma solidity ^0.8.0;

import "../token/ERC20/IERC20.sol";

File 3 of 70 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

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

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(address from, address to, uint256 amount) external returns (bool);
}

File 4 of 70 : IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/extensions/IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 5 of 70 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.3) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    /**
     * @dev Transfer `value` amount of `token` from the calling contract to `to`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeTransfer(IERC20 token, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    /**
     * @dev Transfer `value` amount of `token` from `from` to `to`, spending the approval given by `from` to the
     * calling contract. If `token` returns no value, non-reverting calls are assumed to be successful.
     */
    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(IERC20 token, address spender, uint256 value) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    /**
     * @dev Increase the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        uint256 oldAllowance = token.allowance(address(this), spender);
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance + value));
    }

    /**
     * @dev Decrease the calling contract's allowance toward `spender` by `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful.
     */
    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, oldAllowance - value));
        }
    }

    /**
     * @dev Set the calling contract's allowance toward `spender` to `value`. If `token` returns no value,
     * non-reverting calls are assumed to be successful. Meant to be used with tokens that require the approval
     * to be set to zero before setting it to a non-zero value, such as USDT.
     */
    function forceApprove(IERC20 token, address spender, uint256 value) internal {
        bytes memory approvalCall = abi.encodeWithSelector(token.approve.selector, spender, value);

        if (!_callOptionalReturnBool(token, approvalCall)) {
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, 0));
            _callOptionalReturn(token, approvalCall);
        }
    }

    /**
     * @dev Use a ERC-2612 signature to set the `owner` approval toward `spender` on `token`.
     * Revert on invalid signature.
     */
    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address-functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        require(returndata.length == 0 || abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     *
     * This is a variant of {_callOptionalReturn} that silents catches all reverts and returns a bool instead.
     */
    function _callOptionalReturnBool(IERC20 token, bytes memory data) private returns (bool) {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We cannot use {Address-functionCall} here since this should return false
        // and not revert is the subcall reverts.

        (bool success, bytes memory returndata) = address(token).call(data);
        return
            success && (returndata.length == 0 || abi.decode(returndata, (bool))) && Address.isContract(address(token));
    }
}

File 6 of 70 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/Address.sol)

pragma solidity ^0.8.1;

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

        return account.code.length > 0;
    }

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

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

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

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

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

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

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

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

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

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

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

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

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

File 7 of 70 : 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 8 of 70 : StorageSlot.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.9.0) (utils/StorageSlot.sol)
// This file was procedurally generated from scripts/generate/templates/StorageSlot.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for reading and writing primitive types to specific storage slots.
 *
 * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts.
 * This library helps with reading and writing to such slots without the need for inline assembly.
 *
 * The functions in this library return Slot structs that contain a `value` member that can be used to read or write.
 *
 * Example usage to set ERC1967 implementation slot:
 * ```solidity
 * contract ERC1967 {
 *     bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc;
 *
 *     function _getImplementation() internal view returns (address) {
 *         return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value;
 *     }
 *
 *     function _setImplementation(address newImplementation) internal {
 *         require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract");
 *         StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation;
 *     }
 * }
 * ```
 *
 * _Available since v4.1 for `address`, `bool`, `bytes32`, `uint256`._
 * _Available since v4.9 for `string`, `bytes`._
 */
library StorageSlot {
    struct AddressSlot {
        address value;
    }

    struct BooleanSlot {
        bool value;
    }

    struct Bytes32Slot {
        bytes32 value;
    }

    struct Uint256Slot {
        uint256 value;
    }

    struct StringSlot {
        string value;
    }

    struct BytesSlot {
        bytes value;
    }

    /**
     * @dev Returns an `AddressSlot` with member `value` located at `slot`.
     */
    function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BooleanSlot` with member `value` located at `slot`.
     */
    function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Bytes32Slot` with member `value` located at `slot`.
     */
    function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `Uint256Slot` with member `value` located at `slot`.
     */
    function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` with member `value` located at `slot`.
     */
    function getStringSlot(bytes32 slot) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `StringSlot` representation of the string storage pointer `store`.
     */
    function getStringSlot(string storage store) internal pure returns (StringSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` with member `value` located at `slot`.
     */
    function getBytesSlot(bytes32 slot) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := slot
        }
    }

    /**
     * @dev Returns an `BytesSlot` representation of the bytes storage pointer `store`.
     */
    function getBytesSlot(bytes storage store) internal pure returns (BytesSlot storage r) {
        /// @solidity memory-safe-assembly
        assembly {
            r.slot := store.slot
        }
    }
}

File 9 of 70 : CommonErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when trying to transfer tokens without calldata to the contract.
error EtherReceptionDisabled();

/// @notice Thrown when the multiple related arrays have different lengths.
error InconsistentArrayLengths();

/// @notice Thrown when an ETH transfer has failed.
error TransferFailed();

File 10 of 70 : AccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {AccessControlBase} from "./base/AccessControlBase.sol";
import {ContractOwnership} from "./ContractOwnership.sol";

/// @title Access control via roles management (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract AccessControl is AccessControlBase, ContractOwnership {

}

File 11 of 70 : ContractOwnership.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ContractOwnershipStorage} from "./libraries/ContractOwnershipStorage.sol";
import {ContractOwnershipBase} from "./base/ContractOwnershipBase.sol";
import {InterfaceDetection} from "./../introspection/InterfaceDetection.sol";

/// @title ERC173 Contract Ownership Standard (immutable version).
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ContractOwnership is ContractOwnershipBase, InterfaceDetection {
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;

    /// @notice Initializes the storage with an initial contract owner.
    /// @notice Marks the following ERC165 interface(s) as supported: ERC173.
    /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
    /// @param initialOwner the initial contract owner.
    constructor(address initialOwner) {
        ContractOwnershipStorage.layout().constructorInit(initialOwner);
    }
}

File 12 of 70 : AccessControlBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IAccessControl} from "./../../access/interfaces/IAccessControl.sol";
import {AccessControlStorage} from "./../libraries/AccessControlStorage.sol";
import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title Access control via roles management (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract AccessControlBase is IAccessControl, Context {
    using AccessControlStorage for AccessControlStorage.Layout;
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;

    /// @notice Grants a role to an account.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Emits a {RoleGranted} event if the account did not previously have the role.
    /// @param role The role to grant.
    /// @param account The account to grant the role to.
    function grantRole(bytes32 role, address account) external {
        address operator = _msgSender();
        ContractOwnershipStorage.layout().enforceIsContractOwner(operator);
        AccessControlStorage.layout().grantRole(role, account, operator);
    }

    /// @notice Revokes a role from an account.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Emits a {RoleRevoked} event if the account previously had the role.
    /// @param role The role to revoke.
    /// @param account The account to revoke the role from.
    function revokeRole(bytes32 role, address account) external {
        address operator = _msgSender();
        ContractOwnershipStorage.layout().enforceIsContractOwner(operator);
        AccessControlStorage.layout().revokeRole(role, account, operator);
    }

    /// @inheritdoc IAccessControl
    function renounceRole(bytes32 role) external {
        AccessControlStorage.layout().renounceRole(_msgSender(), role);
    }

    /// @inheritdoc IAccessControl
    function hasRole(bytes32 role, address account) external view returns (bool hasRole_) {
        return AccessControlStorage.layout().hasRole(role, account);
    }
}

File 13 of 70 : ContractOwnershipBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC173} from "./../interfaces/IERC173.sol";
import {ContractOwnershipStorage} from "./../libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC173 Contract Ownership Standard (proxiable version).
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
abstract contract ContractOwnershipBase is IERC173, Context {
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;

    /// @inheritdoc IERC173
    function owner() public view virtual returns (address) {
        return ContractOwnershipStorage.layout().owner();
    }

    /// @inheritdoc IERC173
    function transferOwnership(address newOwner) public virtual {
        ContractOwnershipStorage.layout().transferOwnership(_msgSender(), newOwner);
    }
}

File 14 of 70 : AccessControlErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when an account does not have the required role.
/// @param role The role the caller is missing.
/// @param account The account that was checked.
error NotRoleHolder(bytes32 role, address account);

/// @notice Thrown when an account does not have the required role on a target contract.
/// @param targetContract The contract that was checked.
/// @param role The role that was checked.
/// @param account The account that was checked.
error NotTargetContractRoleHolder(address targetContract, bytes32 role, address account);

File 15 of 70 : Common.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when the target contract is actually not a contract.
/// @param targetContract The contract that was checked
error TargetIsNotAContract(address targetContract);

File 16 of 70 : ContractOwnershipErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when an account is not the contract owner but is required to.
/// @param account The account that was checked.
error NotContractOwner(address account);

/// @notice Thrown when an account is not the target contract owner but is required to.
/// @param targetContract The contract that was checked.
/// @param account The account that was checked.
error NotTargetContractOwner(address targetContract, address account);

File 17 of 70 : AccessControlEvents.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Emitted when `role` is granted to `account`.
/// @param role The role that has been granted.
/// @param account The account that has been granted the role.
/// @param operator The account that granted the role.
event RoleGranted(bytes32 role, address account, address operator);

/// @notice Emitted when `role` is revoked from `account`.
/// @param role The role that has been revoked.
/// @param account The account that has been revoked the role.
/// @param operator The account that revoked the role.
event RoleRevoked(bytes32 role, address account, address operator);

File 18 of 70 : ERC173Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Emitted when the contract ownership changes.
/// @param previousOwner the previous contract owner.
/// @param newOwner the new contract owner.
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

File 19 of 70 : IAccessControl.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title Access control via roles management (functions)
interface IAccessControl {
    /// @notice Renounces a role by the sender.
    /// @dev Reverts if `sender` does not have `role`.
    /// @dev Emits a {RoleRevoked} event.
    /// @param role The role to renounce.
    function renounceRole(bytes32 role) external;

    /// @notice Retrieves whether an account has a role.
    /// @param role The role.
    /// @param account The account.
    /// @return hasRole_ Whether `account` has `role`.
    function hasRole(bytes32 role, address account) external view returns (bool hasRole_);
}

File 20 of 70 : IERC173.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC-173 Contract Ownership Standard (functions)
/// @dev See https://eips.ethereum.org/EIPS/eip-173
/// @dev Note: the ERC-165 identifier for this interface is 0x7f5828d0
interface IERC173 {
    /// @notice Sets the address of the new contract owner.
    /// @dev Reverts if the sender is not the contract owner.
    /// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner.
    /// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership.
    function transferOwnership(address newOwner) external;

    /// @notice Gets the address of the contract owner.
    /// @return contractOwner The address of the contract owner.
    function owner() external view returns (address contractOwner);
}

File 21 of 70 : AccessControlStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {NotRoleHolder, NotTargetContractRoleHolder} from "./../errors/AccessControlErrors.sol";
import {TargetIsNotAContract} from "./../errors/Common.sol";
import {RoleGranted, RoleRevoked} from "./../events/AccessControlEvents.sol";
import {IAccessControl} from "./../interfaces/IAccessControl.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

library AccessControlStorage {
    using Address for address;
    using AccessControlStorage for AccessControlStorage.Layout;

    struct Layout {
        mapping(bytes32 => mapping(address => bool)) roles;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.AccessControl.storage")) - 1);

    /// @notice Grants a role to an account.
    /// @dev Note: Call to this function should be properly access controlled.
    /// @dev Emits a {RoleGranted} event if the account did not previously have the role.
    /// @param role The role to grant.
    /// @param account The account to grant the role to.
    /// @param operator The account requesting the role change.
    function grantRole(Layout storage s, bytes32 role, address account, address operator) internal {
        if (!s.hasRole(role, account)) {
            s.roles[role][account] = true;
            emit RoleGranted(role, account, operator);
        }
    }

    /// @notice Revokes a role from an account.
    /// @dev Note: Call to this function should be properly access controlled.
    /// @dev Emits a {RoleRevoked} event if the account previously had the role.
    /// @param role The role to revoke.
    /// @param account The account to revoke the role from.
    /// @param operator The account requesting the role change.
    function revokeRole(Layout storage s, bytes32 role, address account, address operator) internal {
        if (s.hasRole(role, account)) {
            s.roles[role][account] = false;
            emit RoleRevoked(role, account, operator);
        }
    }

    /// @notice Renounces a role by the sender.
    /// @dev Reverts with {NotRoleHolder} if `sender` does not have `role`.
    /// @dev Emits a {RoleRevoked} event.
    /// @param sender The message sender.
    /// @param role The role to renounce.
    function renounceRole(Layout storage s, address sender, bytes32 role) internal {
        s.enforceHasRole(role, sender);
        s.roles[role][sender] = false;
        emit RoleRevoked(role, sender, sender);
    }

    /// @notice Retrieves whether an account has a role.
    /// @param role The role.
    /// @param account The account.
    /// @return hasRole_ Whether `account` has `role`.
    function hasRole(Layout storage s, bytes32 role, address account) internal view returns (bool hasRole_) {
        return s.roles[role][account];
    }

    /// @notice Checks whether an account has a role in a target contract.
    /// @param targetContract The contract to check.
    /// @param role The role to check.
    /// @param account The account to check.
    /// @return hasTargetContractRole_ Whether `account` has `role` in `targetContract`.
    function hasTargetContractRole(address targetContract, bytes32 role, address account) internal view returns (bool hasTargetContractRole_) {
        if (!targetContract.isContract()) revert TargetIsNotAContract(targetContract);
        return IAccessControl(targetContract).hasRole(role, account);
    }

    /// @notice Ensures that an account has a role.
    /// @dev Reverts with {NotRoleHolder} if `account` does not have `role`.
    /// @param role The role.
    /// @param account The account.
    function enforceHasRole(Layout storage s, bytes32 role, address account) internal view {
        if (!s.hasRole(role, account)) revert NotRoleHolder(role, account);
    }

    /// @notice Enforces that an account has a role in a target contract.
    /// @dev Reverts with {NotTargetContractRoleHolder} if the account does not have the role.
    /// @param targetContract The contract to check.
    /// @param role The role to check.
    /// @param account The account to check.
    function enforceHasTargetContractRole(address targetContract, bytes32 role, address account) internal view {
        if (!hasTargetContractRole(targetContract, role, account)) revert NotTargetContractRoleHolder(targetContract, role, account);
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }
}

File 22 of 70 : ContractOwnershipStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {NotContractOwner, NotTargetContractOwner} from "./../errors/ContractOwnershipErrors.sol";
import {TargetIsNotAContract} from "./../errors/Common.sol";
import {OwnershipTransferred} from "./../events/ERC173Events.sol";
import {IERC173} from "./../interfaces/IERC173.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {ProxyInitialization} from "./../../proxy/libraries/ProxyInitialization.sol";
import {InterfaceDetectionStorage} from "./../../introspection/libraries/InterfaceDetectionStorage.sol";

library ContractOwnershipStorage {
    using Address for address;
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
    using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;

    struct Layout {
        address contractOwner;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.storage")) - 1);
    bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.core.access.ContractOwnership.phase")) - 1);

    /// @notice Initializes the storage with an initial contract owner (immutable version).
    /// @notice Marks the following ERC165 interface(s) as supported: ERC173.
    /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract.
    /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
    /// @param initialOwner The initial contract owner.
    function constructorInit(Layout storage s, address initialOwner) internal {
        if (initialOwner != address(0)) {
            s.contractOwner = initialOwner;
            emit OwnershipTransferred(address(0), initialOwner);
        }
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC173).interfaceId, true);
    }

    /// @notice Initializes the storage with an initial contract owner (proxied version).
    /// @notice Sets the proxy initialization phase to `1`.
    /// @notice Marks the following ERC165 interface(s) as supported: ERC173.
    /// @dev Note: This function should be called ONLY in the init function of a proxied contract.
    /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above.
    /// @dev Emits an {OwnershipTransferred} if `initialOwner` is not the zero address.
    /// @param initialOwner The initial contract owner.
    function proxyInit(Layout storage s, address initialOwner) internal {
        ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1);
        s.constructorInit(initialOwner);
    }

    /// @notice Sets the address of the new contract owner.
    /// @dev Reverts with {NotContractOwner} if `sender` is not the contract owner.
    /// @dev Emits an {OwnershipTransferred} event if `newOwner` is different from the current contract owner.
    /// @param newOwner The address of the new contract owner. Using the zero address means renouncing ownership.
    function transferOwnership(Layout storage s, address sender, address newOwner) internal {
        address previousOwner = s.contractOwner;
        if (sender != previousOwner) revert NotContractOwner(sender);
        if (previousOwner != newOwner) {
            s.contractOwner = newOwner;
            emit OwnershipTransferred(previousOwner, newOwner);
        }
    }

    /// @notice Gets the address of the contract owner.
    /// @return contractOwner The address of the contract owner.
    function owner(Layout storage s) internal view returns (address contractOwner) {
        return s.contractOwner;
    }

    /// @notice Checks whether an account is the owner of a target contract.
    /// @param targetContract The contract to check.
    /// @param account The account to check.
    /// @return isTargetContractOwner_ Whether `account` is the owner of `targetContract`.
    function isTargetContractOwner(address targetContract, address account) internal view returns (bool isTargetContractOwner_) {
        if (!targetContract.isContract()) revert TargetIsNotAContract(targetContract);
        return IERC173(targetContract).owner() == account;
    }

    /// @notice Ensures that an account is the contract owner.
    /// @dev Reverts with {NotContractOwner} if `account` is not the contract owner.
    /// @param account The account.
    function enforceIsContractOwner(Layout storage s, address account) internal view {
        if (account != s.contractOwner) revert NotContractOwner(account);
    }

    /// @notice Enforces that an account is the owner of a target contract.
    /// @dev Reverts with {NotTheTargetContractOwner} if the account is not the owner.
    /// @param targetContract The contract to check.
    /// @param account The account to check.
    function enforceIsTargetContractOwner(address targetContract, address account) internal view {
        if (!isTargetContractOwner(targetContract, account)) revert NotTargetContractOwner(targetContract, account);
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }
}

File 23 of 70 : InterfaceDetection.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC165} from "./interfaces/IERC165.sol";
import {InterfaceDetectionStorage} from "./libraries/InterfaceDetectionStorage.sol";

/// @title ERC165 Interface Detection Standard (immutable or proxiable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) or proxied implementation.
abstract contract InterfaceDetection is IERC165 {
    using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;

    /// @inheritdoc IERC165
    function supportsInterface(bytes4 interfaceId) external view returns (bool) {
        return InterfaceDetectionStorage.layout().supportsInterface(interfaceId);
    }
}

File 24 of 70 : InterfaceDetectionErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when setting the illegal interfaceId 0xffffffff.
error IllegalInterfaceId();

File 25 of 70 : IERC165.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC165 Interface Detection Standard.
/// @dev See https://eips.ethereum.org/EIPS/eip-165.
/// @dev Note: The ERC-165 identifier for this interface is 0x01ffc9a7.
interface IERC165 {
    /// @notice Returns whether this contract implements a given interface.
    /// @dev Note: This function call must use less than 30 000 gas.
    /// @param interfaceId the interface identifier to test.
    /// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported.
    function supportsInterface(bytes4 interfaceId) external view returns (bool supported);
}

File 26 of 70 : InterfaceDetectionStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IllegalInterfaceId} from "./../errors/InterfaceDetectionErrors.sol";
import {IERC165} from "./../interfaces/IERC165.sol";

library InterfaceDetectionStorage {
    struct Layout {
        mapping(bytes4 => bool) supportedInterfaces;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.core.introspection.InterfaceDetection.storage")) - 1);

    bytes4 internal constant ILLEGAL_INTERFACE_ID = 0xffffffff;

    /// @notice Sets or unsets an ERC165 interface.
    /// @dev Revertswith {IllegalInterfaceId} if `interfaceId` is `0xffffffff`.
    /// @param interfaceId the interface identifier.
    /// @param supported True to set the interface, false to unset it.
    function setSupportedInterface(Layout storage s, bytes4 interfaceId, bool supported) internal {
        if (interfaceId == ILLEGAL_INTERFACE_ID) revert IllegalInterfaceId();
        s.supportedInterfaces[interfaceId] = supported;
    }

    /// @notice Returns whether this contract implements a given interface.
    /// @dev Note: This function call must use less than 30 000 gas.
    /// @param interfaceId The interface identifier to test.
    /// @return supported True if the interface is supported, false if `interfaceId` is `0xffffffff` or if the interface is not supported.
    function supportsInterface(Layout storage s, bytes4 interfaceId) internal view returns (bool supported) {
        if (interfaceId == ILLEGAL_INTERFACE_ID) {
            return false;
        }
        if (interfaceId == type(IERC165).interfaceId) {
            return true;
        }
        return s.supportedInterfaces[interfaceId];
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }
}

File 27 of 70 : ForwarderRegistryContext.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IForwarderRegistry} from "./interfaces/IForwarderRegistry.sol";
import {IERC2771} from "./interfaces/IERC2771.sol";
import {ForwarderRegistryContextBase} from "./base/ForwarderRegistryContextBase.sol";

/// @title Meta-Transactions Forwarder Registry Context (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
/// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence)
abstract contract ForwarderRegistryContext is ForwarderRegistryContextBase, IERC2771 {
    constructor(IForwarderRegistry forwarderRegistry_) ForwarderRegistryContextBase(forwarderRegistry_) {}

    function forwarderRegistry() external view returns (IForwarderRegistry) {
        return _FORWARDER_REGISTRY;
    }

    /// @inheritdoc IERC2771
    function isTrustedForwarder(address forwarder) external view virtual returns (bool) {
        return forwarder == address(_FORWARDER_REGISTRY);
    }
}

File 28 of 70 : ForwarderRegistryContextBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IForwarderRegistry} from "./../interfaces/IForwarderRegistry.sol";
import {ERC2771Calldata} from "./../libraries/ERC2771Calldata.sol";

/// @title Meta-Transactions Forwarder Registry Context (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence)
abstract contract ForwarderRegistryContextBase {
    IForwarderRegistry internal immutable _FORWARDER_REGISTRY;

    constructor(IForwarderRegistry forwarderRegistry) {
        _FORWARDER_REGISTRY = forwarderRegistry;
    }

    /// @notice Returns the message sender depending on the ForwarderRegistry-based meta-transaction context.
    function _msgSender() internal view virtual returns (address) {
        // Optimised path in case of an EOA-initiated direct tx to the contract or a call from a contract not complying with EIP-2771
        // solhint-disable-next-line avoid-tx-origin
        if (msg.sender == tx.origin || msg.data.length < 24) {
            return msg.sender;
        }

        address sender = ERC2771Calldata.msgSender();

        // Return the EIP-2771 calldata-appended sender address if the message was forwarded by the ForwarderRegistry or an approved forwarder
        if (msg.sender == address(_FORWARDER_REGISTRY) || _FORWARDER_REGISTRY.isApprovedForwarder(sender, msg.sender)) {
            return sender;
        }

        return msg.sender;
    }

    /// @notice Returns the message data depending on the ForwarderRegistry-based meta-transaction context.
    function _msgData() internal view virtual returns (bytes calldata) {
        // Optimised path in case of an EOA-initiated direct tx to the contract or a call from a contract not complying with EIP-2771
        // solhint-disable-next-line avoid-tx-origin
        if (msg.sender == tx.origin || msg.data.length < 24) {
            return msg.data;
        }

        // Return the EIP-2771 calldata (minus the appended sender) if the message was forwarded by the ForwarderRegistry or an approved forwarder
        if (msg.sender == address(_FORWARDER_REGISTRY) || _FORWARDER_REGISTRY.isApprovedForwarder(ERC2771Calldata.msgSender(), msg.sender)) {
            return ERC2771Calldata.msgData();
        }

        return msg.data;
    }
}

File 29 of 70 : IERC2771.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title Secure Protocol for Native Meta Transactions.
/// @dev See https://eips.ethereum.org/EIPS/eip-2771
interface IERC2771 {
    /// @notice Checks whether a forwarder is trusted.
    /// @param forwarder The forwarder to check.
    /// @return isTrusted True if `forwarder` is trusted, false if not.
    function isTrustedForwarder(address forwarder) external view returns (bool isTrusted);
}

File 30 of 70 : IForwarderRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title Universal Meta-Transactions Forwarder Registry.
/// @dev Derived from https://github.com/wighawag/universal-forwarder (MIT licence)
interface IForwarderRegistry {
    /// @notice Checks whether an account is as an approved meta-transaction forwarder for a sender account.
    /// @param sender The sender account.
    /// @param forwarder The forwarder account.
    /// @return isApproved True if `forwarder` is an approved meta-transaction forwarder for `sender`, false otherwise.
    function isApprovedForwarder(address sender, address forwarder) external view returns (bool isApproved);
}

File 31 of 70 : ERC2771Calldata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @dev Derived from https://github.com/OpenZeppelin/openzeppelin-contracts (MIT licence)
/// @dev See https://eips.ethereum.org/EIPS/eip-2771
library ERC2771Calldata {
    /// @notice Returns the sender address appended at the end of the calldata, as specified in EIP-2771.
    function msgSender() internal pure returns (address sender) {
        assembly {
            sender := shr(96, calldataload(sub(calldatasize(), 20)))
        }
    }

    /// @notice Returns the calldata while omitting the appended sender address, as specified in EIP-2771.
    function msgData() internal pure returns (bytes calldata data) {
        unchecked {
            return msg.data[:msg.data.length - 20];
        }
    }
}

File 32 of 70 : ProxyInitializationErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Emitted when trying to set a phase value that has already been reached.
/// @param currentPhase The current phase.
/// @param newPhase The new phase trying to be set.
error InitializationPhaseAlreadyReached(uint256 currentPhase, uint256 newPhase);

File 33 of 70 : ProxyInitialization.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {InitializationPhaseAlreadyReached} from "./../errors/ProxyInitializationErrors.sol";
import {StorageSlot} from "@openzeppelin/contracts/utils/StorageSlot.sol";

/// @notice Multiple calls protection for storage-modifying proxy initialization functions.
library ProxyInitialization {
    /// @notice Sets the initialization phase during a storage-modifying proxy initialization function.
    /// @dev Reverts with {InitializationPhaseAlreadyReached} if `phase` has been reached already.
    /// @param storageSlot the storage slot where `phase` is stored.
    /// @param phase the initialization phase.
    function setPhase(bytes32 storageSlot, uint256 phase) internal {
        StorageSlot.Uint256Slot storage currentVersion = StorageSlot.getUint256Slot(storageSlot);
        uint256 currentPhase = currentVersion.value;
        if (currentPhase >= phase) revert InitializationPhaseAlreadyReached(currentPhase, phase);
        currentVersion.value = phase;
    }
}

File 34 of 70 : TokenRecovery.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {TokenRecoveryBase} from "./base/TokenRecoveryBase.sol";
import {ContractOwnership} from "./../access/ContractOwnership.sol";

/// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract TokenRecovery is TokenRecoveryBase, ContractOwnership {

}

File 35 of 70 : TokenRecoveryBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {InconsistentArrayLengths} from "./../../CommonErrors.sol";
import {IERC20} from "@openzeppelin/contracts/interfaces/IERC20.sol";
import {IERC721} from "./../../token/ERC721/interfaces/IERC721.sol";
import {ContractOwnershipStorage} from "./../../access/libraries/ContractOwnershipStorage.sol";
import {SafeERC20} from "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";

/// @title Recovery mechanism for ETH/ERC20/ERC721 tokens accidentally sent to this contract (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract TokenRecoveryBase is Context {
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;
    using SafeERC20 for IERC20;
    using Address for address payable;

    /// @notice Extract ETH tokens which were accidentally sent to the contract to a list of accounts.
    /// @dev Note: While contracts can generally prevent accidental ETH transfer by implementating a reverting
    ///  `receive()` function, this can still be bypassed in a `selfdestruct(address)` scenario.
    /// @dev Warning: this function should be overriden for contracts which are supposed to hold ETH tokens
    ///  so that the extraction is limited to only amounts sent accidentally.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Reverts with {InconsistentArrayLengths} `accounts` and `amounts` do not have the same length.
    /// @dev Reverts if one of the ETH transfers fails for any reason.
    /// @param accounts the list of accounts to transfer the tokens to.
    /// @param amounts the list of token amounts to transfer.
    function recoverETH(address payable[] calldata accounts, uint256[] calldata amounts) public virtual {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        uint256 length = accounts.length;
        if (length != amounts.length) revert InconsistentArrayLengths();
        for (uint256 i; i < length; ++i) {
            accounts[i].sendValue(amounts[i]);
        }
    }

    /// @notice Extract ERC20 tokens which were accidentally sent to the contract to a list of accounts.
    /// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC20 tokens
    ///  so that the extraction is limited to only amounts sent accidentally.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `tokens` and `amounts` do not have the same length.
    /// @dev Reverts if one of the ERC20 transfers fails for any reason.
    /// @param accounts the list of accounts to transfer the tokens to.
    /// @param tokens the list of ERC20 token addresses.
    /// @param amounts the list of token amounts to transfer.
    function recoverERC20s(address[] calldata accounts, IERC20[] calldata tokens, uint256[] calldata amounts) public virtual {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        uint256 length = accounts.length;
        if (length != tokens.length || length != amounts.length) revert InconsistentArrayLengths();
        for (uint256 i; i < length; ++i) {
            tokens[i].safeTransfer(accounts[i], amounts[i]);
        }
    }

    /// @notice Extract ERC721 tokens which were accidentally sent to the contract to a list of accounts.
    /// @dev Warning: this function should be overriden for contracts which are supposed to hold ERC721 tokens
    ///  so that the extraction is limited to only tokens sent accidentally.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Reverts with {InconsistentArrayLengths} if `accounts`, `contracts` and `amounts` do not have the same length.
    /// @dev Reverts if one of the ERC721 transfers fails for any reason.
    /// @param accounts the list of accounts to transfer the tokens to.
    /// @param contracts the list of ERC721 contract addresses.
    /// @param tokenIds the list of token ids to transfer.
    function recoverERC721s(address[] calldata accounts, IERC721[] calldata contracts, uint256[] calldata tokenIds) public virtual {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        uint256 length = accounts.length;
        if (length != contracts.length || length != tokenIds.length) revert InconsistentArrayLengths();
        for (uint256 i; i < length; ++i) {
            contracts[i].transferFrom(address(this), accounts[i], tokenIds[i]);
        }
    }
}

File 36 of 70 : ERC1155Burnable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC1155Storage} from "./libraries/ERC1155Storage.sol";
import {ERC1155BurnableBase} from "./base/ERC1155BurnableBase.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Burnable (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC1155Burnable is ERC1155BurnableBase {
    /// @notice Marks the fllowing ERC165 interface(s) as supported: ERC1155Burnable
    constructor() {
        ERC1155Storage.initERC1155Burnable();
    }
}

File 37 of 70 : ERC1155Deliverable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC1155Storage} from "./libraries/ERC1155Storage.sol";
import {ERC1155DeliverableBase} from "./base/ERC1155DeliverableBase.sol";
import {AccessControl} from "./../../access/AccessControl.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Deliverable (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC1155Deliverable is ERC1155DeliverableBase, AccessControl {
    /// @notice Marks the fllowing ERC165 interface(s) as supported: ERC1155Deliverable
    constructor() {
        ERC1155Storage.initERC1155Deliverable();
    }
}

File 38 of 70 : ERC1155Metadata.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ITokenMetadataResolver} from "./../metadata/interfaces/ITokenMetadataResolver.sol";
import {TokenMetadataStorage} from "./../metadata/libraries/TokenMetadataStorage.sol";
import {ERC1155Storage} from "./libraries/ERC1155Storage.sol";
import {ERC1155MetadataBase} from "./base/ERC1155MetadataBase.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Metadata (immutable version).
/// @notice This contracts uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC1155Metadata is ERC1155MetadataBase {
    using TokenMetadataStorage for TokenMetadataStorage.Layout;

    /// @notice Marks the following ERC165 interfaces as supported: ERC1155MetadataURI.
    /// @param name The name of the token.
    /// @param symbol The symbol of the token.
    /// @param metadataResolver The address of the metadata resolver contract.
    constructor(string memory name, string memory symbol, ITokenMetadataResolver metadataResolver) {
        TokenMetadataStorage.layout().constructorInit(name, symbol, metadataResolver);
        ERC1155Storage.initERC1155MetadataURI();
    }
}

File 39 of 70 : ERC1155Mintable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC1155Storage} from "./libraries/ERC1155Storage.sol";
import {ERC1155MintableBase} from "./base/ERC1155MintableBase.sol";
import {AccessControl} from "./../../access/AccessControl.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Mintable (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC1155Mintable is ERC1155MintableBase, AccessControl {
    /// @notice Marks the fllowing ERC165 interface(s) as supported: ERC1155Mintable
    constructor() {
        ERC1155Storage.initERC1155Mintable();
    }
}

File 40 of 70 : ERC1155WithOperatorFilterer.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IOperatorFilterRegistry} from "./../royalty/interfaces/IOperatorFilterRegistry.sol";
import {ERC1155Storage} from "./libraries/ERC1155Storage.sol";
import {OperatorFiltererStorage} from "./../royalty/libraries/OperatorFiltererStorage.sol";
import {ERC1155WithOperatorFiltererBase} from "./base/ERC1155WithOperatorFiltererBase.sol";
import {OperatorFiltererBase} from "./../royalty/base/OperatorFiltererBase.sol";
import {ContractOwnership} from "./../../access/ContractOwnership.sol";

/// @title ERC1155 Multi Token Standard with Operator Filterer (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC1155WithOperatorFilterer is ERC1155WithOperatorFiltererBase, OperatorFiltererBase, ContractOwnership {
    using OperatorFiltererStorage for OperatorFiltererStorage.Layout;

    /// @notice Marks the following ERC165 interfaces as supported: ERC1155.
    /// @notice Sets the address that the contract will make OperatorFilter checks against.
    /// @param operatorFilterRegistry The operator filter registry address. When set to the zero address, checks will be bypassed.
    constructor(IOperatorFilterRegistry operatorFilterRegistry) {
        ERC1155Storage.init();
        OperatorFiltererStorage.layout().constructorInit(operatorFilterRegistry);
    }
}

File 41 of 70 : ERC1155BurnableBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC1155Burnable} from "./../interfaces/IERC1155Burnable.sol";
import {ERC1155Storage} from "./../libraries/ERC1155Storage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Burnable (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC1155 (Multi Token Standard).
abstract contract ERC1155BurnableBase is IERC1155Burnable, Context {
    using ERC1155Storage for ERC1155Storage.Layout;

    /// @inheritdoc IERC1155Burnable
    function burnFrom(address from, uint256 id, uint256 value) external virtual {
        ERC1155Storage.layout().burnFrom(_msgSender(), from, id, value);
    }

    /// @inheritdoc IERC1155Burnable
    function batchBurnFrom(address from, uint256[] calldata ids, uint256[] calldata values) external virtual {
        ERC1155Storage.layout().batchBurnFrom(_msgSender(), from, ids, values);
    }
}

File 42 of 70 : ERC1155DeliverableBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC1155Deliverable} from "./../interfaces/IERC1155Deliverable.sol";
import {ERC1155Storage} from "./../libraries/ERC1155Storage.sol";
import {AccessControlStorage} from "./../../../access/libraries/AccessControlStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Deliverable (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC1155 (Multi Token Standard).
/// @dev Note: This contract requires AccessControl.
abstract contract ERC1155DeliverableBase is IERC1155Deliverable, Context {
    using ERC1155Storage for ERC1155Storage.Layout;
    using AccessControlStorage for AccessControlStorage.Layout;

    // prevent variable name clash with public ERC1155MintableBase.MINTER_ROLE
    bytes32 private constant _MINTER_ROLE = "minter";

    /// @inheritdoc IERC1155Deliverable
    /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role.
    function safeDeliver(address[] calldata recipients, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external virtual {
        address sender = _msgSender();
        AccessControlStorage.layout().enforceHasRole(_MINTER_ROLE, sender);
        ERC1155Storage.layout().safeDeliver(sender, recipients, ids, values, data);
    }
}

File 43 of 70 : ERC1155MetadataBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {InconsistentArrayLengths} from "./../../../CommonErrors.sol";
import {NotMetadataResolver} from "./../../metadata/errors/TokenMetadataErrors.sol";
import {URI} from "./../events/ERC1155Events.sol";
import {IERC1155MetadataURI} from "./../interfaces/IERC1155MetadataURI.sol";
import {IERC1155MetadataSetter} from "./../interfaces/IERC1155MetadataSetter.sol";
import {TokenMetadataStorage} from "./../../metadata/libraries/TokenMetadataStorage.sol";
import {TokenMetadataBase} from "./../../metadata/base/TokenMetadataBase.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Metadata (proxiable version).
/// @notice This contracts uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC1155 (Multi Token Standard).
abstract contract ERC1155MetadataBase is TokenMetadataBase, IERC1155MetadataURI, IERC1155MetadataSetter {
    using TokenMetadataStorage for TokenMetadataStorage.Layout;

    /// @inheritdoc IERC1155MetadataURI
    function uri(uint256 tokenId) external view virtual returns (string memory metadataURI) {
        return TokenMetadataStorage.layout().tokenMetadataURI(address(this), tokenId);
    }

    /// @notice Emits the URI event when a token metadata URI is set by the metadata resolver.
    /// @dev Reverts if the caller is not the metadata resolver.
    /// @dev Emits a {URI} event.
    /// @param tokenId The token identifier.
    /// @param tokenURI The token metadata URI.
    function setTokenURI(uint256 tokenId, string calldata tokenURI) external virtual {
        if (msg.sender != address(TokenMetadataStorage.layout().metadataResolver())) revert NotMetadataResolver(msg.sender);
        emit URI(tokenURI, tokenId);
    }

    /// @notice Emits URI events when a batch of token metadata URIs is set by the metadata resolver.
    /// @dev Reverts if `tokenIds` and `tokenURIs` have different lengths.
    /// @dev Reverts if the caller is not the metadata resolver.
    /// @dev Emits a {URI} event for each token.
    /// @param tokenIds The token identifiers.
    /// @param tokenURIs The token metadata URIs.
    function batchSetTokenURI(uint256[] calldata tokenIds, string[] calldata tokenURIs) external virtual {
        if (tokenIds.length != tokenURIs.length) revert InconsistentArrayLengths();
        if (msg.sender != address(TokenMetadataStorage.layout().metadataResolver())) revert NotMetadataResolver(msg.sender);

        for (uint256 i; i < tokenIds.length; ++i) {
            emit URI(tokenURIs[i], tokenIds[i]);
        }
    }
}

File 44 of 70 : ERC1155MintableBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC1155Mintable} from "./../interfaces/IERC1155Mintable.sol";
import {ERC1155Storage} from "./../libraries/ERC1155Storage.sol";
import {AccessControlStorage} from "./../../../access/libraries/AccessControlStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC1155 Multi Token Standard, optional extension: Mintable (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC1155 (Multi Token Standard).
/// @dev Note: This contract requires AccessControl.
abstract contract ERC1155MintableBase is IERC1155Mintable, Context {
    using ERC1155Storage for ERC1155Storage.Layout;
    using AccessControlStorage for AccessControlStorage.Layout;

    bytes32 public constant MINTER_ROLE = "minter";

    /// @inheritdoc IERC1155Mintable
    /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role.
    function safeMint(address to, uint256 id, uint256 value, bytes calldata data) external virtual {
        address sender = _msgSender();
        AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, sender);
        ERC1155Storage.layout().safeMint(sender, to, id, value, data);
    }

    /// @inheritdoc IERC1155Mintable
    /// @dev Reverts with {NotRoleHolder} if the sender does not have the 'minter' role.
    function safeBatchMint(address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external virtual {
        address sender = _msgSender();
        AccessControlStorage.layout().enforceHasRole(MINTER_ROLE, sender);
        ERC1155Storage.layout().safeBatchMint(sender, to, ids, values, data);
    }
}

File 45 of 70 : ERC1155WithOperatorFiltererBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC1155} from "./../interfaces/IERC1155.sol";
import {ERC1155Storage} from "./../libraries/ERC1155Storage.sol";
import {OperatorFiltererStorage} from "./../../royalty/libraries/OperatorFiltererStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC1155 Multi Token Standard with Operator Filterer (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
abstract contract ERC1155WithOperatorFiltererBase is IERC1155, Context {
    using ERC1155Storage for ERC1155Storage.Layout;
    using OperatorFiltererStorage for OperatorFiltererStorage.Layout;

    /// @inheritdoc IERC1155
    /// @dev Reverts with {OperatorNotAllowed} if the sender is not `from` and is not allowed by the operator registry.
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external virtual {
        address sender = _msgSender();
        OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from);
        ERC1155Storage.layout().safeTransferFrom(sender, from, to, id, value, data);
    }

    /// @inheritdoc IERC1155
    /// @dev Reverts with {OperatorNotAllowed} if the sender is not `from` and is not allowed by the operator registry.
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external virtual {
        address sender = _msgSender();
        OperatorFiltererStorage.layout().requireAllowedOperatorForTransfer(sender, from);
        ERC1155Storage.layout().safeBatchTransferFrom(sender, from, to, ids, values, data);
    }

    /// @inheritdoc IERC1155
    /// @dev Reverts with {OperatorNotAllowed} if `operator` is not allowed by the operator registry.
    function setApprovalForAll(address operator, bool approved) external virtual {
        if (approved) {
            OperatorFiltererStorage.layout().requireAllowedOperatorForApproval(operator);
        }
        ERC1155Storage.layout().setApprovalForAll(_msgSender(), operator, approved);
    }

    /// @inheritdoc IERC1155
    function isApprovedForAll(address owner, address operator) external view returns (bool approvedForAll) {
        return ERC1155Storage.layout().isApprovedForAll(owner, operator);
    }

    /// @inheritdoc IERC1155
    function balanceOf(address owner, uint256 id) external view virtual returns (uint256 balance) {
        return ERC1155Storage.layout().balanceOf(owner, id);
    }

    /// @inheritdoc IERC1155
    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view virtual returns (uint256[] memory balances) {
        return ERC1155Storage.layout().balanceOfBatch(owners, ids);
    }
}

File 46 of 70 : ERC1155Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when trying to approveForAll oneself.
/// @param account The account trying to approveForAll itself.
error ERC1155SelfApprovalForAll(address account);

/// @notice Thrown when transferring tokens to the zero address.
error ERC1155TransferToAddressZero();

/// @notice Thrown when a sender tries to transfer tokens but is neither the owner nor approved by the owner.
/// @param sender The sender.
/// @param owner The owner.
error ERC1155NonApproved(address sender, address owner);

/// @notice Thrown when transferring an amount of tokens greater than the current balance.
/// @param owner The owner.
/// @param id The token identifier.
/// @param balance The current balance.
/// @param value The amount of tokens to transfer.
error ERC1155InsufficientBalance(address owner, uint256 id, uint256 balance, uint256 value);

/// @notice Thrown when minting or transferring an amount of tokens that would overflow the recipient's balance.
/// @param recipient The recipient.
/// @param id The token identifier.
/// @param balance The current balance.
/// @param value The amount of tokens to transfer.
error ERC1155BalanceOverflow(address recipient, uint256 id, uint256 balance, uint256 value);

/// @notice Thrown when a safe transfer is rejected by the recipient contract.
/// @param recipient The recipient contract.
/// @param id The token identifier.
/// @param value The amount of tokens to transfer.
error ERC1155SafeTransferRejected(address recipient, uint256 id, uint256 value);

/// @notice Thrown when a safe batch transfer is rejected by the recipient contract.
/// @param recipient The recipient contract.
/// @param ids The token identifiers.
/// @param values The amounts of tokens to transfer.
error ERC1155SafeBatchTransferRejected(address recipient, uint256[] ids, uint256[] values);

/// @notice Thrown when querying the balance of the zero address.
error ERC1155BalanceOfAddressZero();

File 47 of 70 : ERC1155MintableErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when minting tokens to the zero address.
error ERC1155MintToAddressZero();

File 48 of 70 : ERC1155Events.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Emitted when some token is transferred.
/// @param operator The initiator of the transfer.
/// @param from The previous token owner.
/// @param to The new token owner.
/// @param id The transferred token identifier.
/// @param value The amount of token.
event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

/// @notice Emitted when a batch of tokens is transferred.
/// @param operator The initiator of the transfer.
/// @param from The previous tokens owner.
/// @param to The new tokens owner.
/// @param ids The transferred tokens identifiers.
/// @param values The amounts of tokens.
event TransferBatch(address indexed operator, address indexed from, address indexed to, uint256[] ids, uint256[] values);

/// @notice Emitted when an approval for all tokens is set or unset.
/// @param owner The tokens owner.
/// @param operator The approved address.
/// @param approved True when then approval is set, false when it is unset.
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

/// @notice Emitted when a token metadata URI is set updated.
/// @param value The token metadata URI.
/// @param id The token identifier.
event URI(string value, uint256 indexed id);

File 49 of 70 : IERC1155.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, basic interface (functions).
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0xd9b67a26.
interface IERC1155 {
    /// @notice Safely transfers some token.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from`.
    /// @dev Reverts if `from` has an insufficient balance of `id`.
    /// @dev Reverts if `to` is a contract and the call to {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits a {TransferSingle} event.
    /// @param from Current token owner.
    /// @param to Address of the new token owner.
    /// @param id Identifier of the token to transfer.
    /// @param value Amount of token to transfer.
    /// @param data Optional data to send along to a receiver contract.
    function safeTransferFrom(address from, address to, uint256 id, uint256 value, bytes calldata data) external;

    /// @notice Safely transfers a batch of tokens.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `ids` and `values` have different lengths.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from`.
    /// @dev Reverts if `from` has an insufficient balance for any of `ids`.
    /// @dev Reverts if `to` is a contract and the call to {IERC1155TokenReceiver-onERC1155BatchReceived} fails, reverts or is rejected.
    /// @dev Emits a {TransferBatch} event.
    /// @param from Current tokens owner.
    /// @param to Address of the new tokens owner.
    /// @param ids Identifiers of the tokens to transfer.
    /// @param values Amounts of tokens to transfer.
    /// @param data Optional data to send along to a receiver contract.
    function safeBatchTransferFrom(address from, address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external;

    /// @notice Enables or disables an operator's approval.
    /// @dev Emits an {ApprovalForAll} event.
    /// @param operator Address of the operator.
    /// @param approved True to approve the operator, false to revoke its approval.
    function setApprovalForAll(address operator, bool approved) external;

    /// @notice Retrieves the approval status of an operator for a given owner.
    /// @param owner Address of the authorisation giver.
    /// @param operator Address of the operator.
    /// @return approved True if the operator is approved, false if not.
    function isApprovedForAll(address owner, address operator) external view returns (bool approved);

    /// @notice Retrieves the balance of `id` owned by account `owner`.
    /// @param owner The account to retrieve the balance of.
    /// @param id The identifier to retrieve the balance of.
    /// @return balance The balance of `id` owned by account `owner`.
    function balanceOf(address owner, uint256 id) external view returns (uint256 balance);

    /// @notice Retrieves the balances of `ids` owned by accounts `owners`.
    /// @dev Reverts if `owners` and `ids` have different lengths.
    /// @param owners The addresses of the token holders
    /// @param ids The identifiers to retrieve the balance of.
    /// @return balances The balances of `ids` owned by accounts `owners`.
    function balanceOfBatch(address[] calldata owners, uint256[] calldata ids) external view returns (uint256[] memory balances);
}

File 50 of 70 : IERC1155Burnable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, optional extension: Burnable.
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0x921ed8d1.
interface IERC1155Burnable {
    /// @notice Burns some token.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from`.
    /// @dev Reverts if `from` has an insufficient balance of `id`.
    /// @dev Emits an {IERC1155-TransferSingle} event.
    /// @param from Address of the current token owner.
    /// @param id Identifier of the token to burn.
    /// @param value Amount of token to burn.
    function burnFrom(address from, uint256 id, uint256 value) external;

    /// @notice Burns multiple tokens.
    /// @dev Reverts if `ids` and `values` have different lengths.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from`.
    /// @dev Reverts if `from` has an insufficient balance for any of `ids`.
    /// @dev Emits an {IERC1155-TransferBatch} event.
    /// @param from Address of the current tokens owner.
    /// @param ids Identifiers of the tokens to burn.
    /// @param values Amounts of tokens to burn.
    function batchBurnFrom(address from, uint256[] calldata ids, uint256[] calldata values) external;
}

File 51 of 70 : IERC1155Deliverable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, optional extension: Deliverable.
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0xe8ab9ccc.
interface IERC1155Deliverable {
    /// @notice Safely mints tokens to multiple recipients.
    /// @dev Reverts if `recipients`, `ids` and `values` have different lengths.
    /// @dev Reverts if one of `recipients` is the zero address.
    /// @dev Reverts if one of `recipients` balance overflows.
    /// @dev Reverts if one of `recipients` is a contract and the call to {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits an {IERC1155-TransferSingle} event from the zero address for each transfer.
    /// @param recipients Addresses of the new tokens owners.
    /// @param ids Identifiers of the tokens to mint.
    /// @param values Amounts of tokens to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeDeliver(address[] calldata recipients, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external;
}

File 52 of 70 : IERC1155MetadataSetter.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

interface IERC1155MetadataSetter {
    /// @notice Sets the metadata URI for a token.
    /// @dev Emits a {URI} event.
    /// @param tokenId The token identifier.
    /// @param tokenURI The token metadata URI.
    function setTokenURI(uint256 tokenId, string calldata tokenURI) external;

    /// @notice Sets the metadata URIs for a batch of tokens.
    /// @dev Reverts with {InconsistentArrayLengths} if the arrays are of inconsistent lengths.
    /// @dev Emits a {URI} event for each token.
    /// @param tokenIds The token identifiers.
    /// @param tokenURIs The token metadata URIs.
    function batchSetTokenURI(uint256[] calldata tokenIds, string[] calldata tokenURIs) external;
}

File 53 of 70 : IERC1155MetadataURI.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, optional extension: Metadata URI.
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0x0e89341c.
interface IERC1155MetadataURI {
    /// @notice Retrieves the URI for a given token.
    /// @dev URIs are defined in RFC 3986.
    /// @dev The URI MUST point to a JSON file that conforms to the "ERC1155 Metadata URI JSON Schema".
    /// @dev The uri function SHOULD be used to retrieve values if no event was emitted.
    /// @dev The uri function MUST return the same value as the latest event for an _id if it was emitted.
    /// @dev The uri function MUST NOT be used to check for the existence of a token as it is possible for
    ///  an implementation to return a valid string even if the token does not exist.
    /// @return metadataURI The URI associated to the token.
    function uri(uint256 id) external view returns (string memory metadataURI);
}

File 54 of 70 : IERC1155Mintable.sol
// SPDX-License-Identifier: MIT

pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, optional extension: Mintable.
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0x5190c92c.
interface IERC1155Mintable {
    /// @notice Safely mints some token.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `to`'s balance of `id` overflows.
    /// @dev Reverts if `to` is a contract and the call to {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits an {IERC1155-TransferSingle} event.
    /// @param to Address of the new token owner.
    /// @param id Identifier of the token to mint.
    /// @param value Amount of token to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeMint(address to, uint256 id, uint256 value, bytes calldata data) external;

    /// @notice Safely mints a batch of tokens.
    /// @dev Reverts if `ids` and `values` have different lengths.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `to`'s balance overflows for one of `ids`.
    /// @dev Reverts if `to` is a contract and the call to {IERC1155TokenReceiver-onERC1155batchReceived} fails, reverts or is rejected.
    /// @dev Emits an {IERC1155-TransferBatch} event.
    /// @param to Address of the new tokens owner.
    /// @param ids Identifiers of the tokens to mint.
    /// @param values Amounts of tokens to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeBatchMint(address to, uint256[] calldata ids, uint256[] calldata values, bytes calldata data) external;
}

File 55 of 70 : IERC1155TokenReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC1155 Multi Token Standard, Tokens Receiver.
/// @notice Interface for any contract that wants to support transfers from ERC1155 asset contracts.
/// @dev See https://eips.ethereum.org/EIPS/eip-1155
/// @dev Note: The ERC-165 identifier for this interface is 0x4e2312e0.
interface IERC1155TokenReceiver {
    /// @notice Handles the receipt of a single ERC1155 token type.
    /// @notice ERC1155 contracts MUST call this function on a recipient contract, at the end of a `safeTransferFrom` after the balance update.
    /// @dev Return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` (`0xf23a6e61`) to accept the transfer.
    /// @dev Return of any other value than the prescribed keccak256 generated value will result in the transaction being reverted by the caller.
    /// @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 magicValue `0xf23a6e61` to accept the transfer, or any other value to reject it.
    function onERC1155Received(address operator, address from, uint256 id, uint256 value, bytes calldata data) external returns (bytes4 magicValue);

    /// @notice Handles the receipt of multiple ERC1155 token types.
    /// @notice ERC1155 contracts MUST call this function on a recipient contract, at the end of a `safeBatchTransferFrom` after the balance updates.
    /// @dev Return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` (`0xbc197c81`) to accept the transfer.
    /// @dev Return of any other value than the prescribed keccak256 generated value will result in the transaction being reverted by the caller.
    /// @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 magicValue `0xbc197c81` to accept the transfer, or any other value to reject it.
    function onERC1155BatchReceived(
        address operator,
        address from,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) external returns (bytes4 magicValue);
}

File 56 of 70 : ERC1155Storage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

// solhint-disable-next-line max-line-length
import {ERC1155SelfApprovalForAll, ERC1155TransferToAddressZero, ERC1155NonApproved, ERC1155InsufficientBalance, ERC1155BalanceOverflow, ERC1155SafeTransferRejected, ERC1155SafeBatchTransferRejected, ERC1155BalanceOfAddressZero} from "./../errors/ERC1155Errors.sol";
import {ERC1155MintToAddressZero} from "./../errors/ERC1155MintableErrors.sol";
import {InconsistentArrayLengths} from "./../../../CommonErrors.sol";
import {TransferSingle, TransferBatch, ApprovalForAll} from "./../events/ERC1155Events.sol";
import {IERC1155} from "./../interfaces/IERC1155.sol";
import {IERC1155MetadataURI} from "./../interfaces/IERC1155MetadataURI.sol";
import {IERC1155Mintable} from "./../interfaces/IERC1155Mintable.sol";
import {IERC1155Deliverable} from "./../interfaces/IERC1155Deliverable.sol";
import {IERC1155Burnable} from "./../interfaces/IERC1155Burnable.sol";
import {IERC1155TokenReceiver} from "./../interfaces/IERC1155TokenReceiver.sol";
import {Address} from "@openzeppelin/contracts/utils/Address.sol";
import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol";

library ERC1155Storage {
    using Address for address;
    using ERC1155Storage for ERC1155Storage.Layout;
    using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;

    struct Layout {
        mapping(uint256 => mapping(address => uint256)) balances;
        mapping(address => mapping(address => bool)) operators;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.ERC1155.ERC1155.storage")) - 1);

    bytes4 internal constant ERC1155_SINGLE_RECEIVED = IERC1155TokenReceiver.onERC1155Received.selector;
    bytes4 internal constant ERC1155_BATCH_RECEIVED = IERC1155TokenReceiver.onERC1155BatchReceived.selector;

    /// @notice Marks the following ERC165 interface(s) as supported: ERC1155.
    function init() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC1155).interfaceId, true);
    }

    /// @notice Marks the following ERC165 interface(s) as supported: ERC1155MetadataURI.
    function initERC1155MetadataURI() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC1155MetadataURI).interfaceId, true);
    }

    /// @notice Marks the following ERC165 interface(s) as supported: ERC1155Mintable.
    function initERC1155Mintable() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC1155Mintable).interfaceId, true);
    }

    /// @notice Marks the following ERC165 interface(s) as supported: ERC1155Deliverable.
    function initERC1155Deliverable() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC1155Deliverable).interfaceId, true);
    }

    /// @notice Marks the following ERC165 interface(s) as supported: ERC1155Burnable.
    function initERC1155Burnable() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC1155Burnable).interfaceId, true);
    }

    /// @notice Safely transfers some token by a sender.
    /// @dev Note: This function implements {ERC1155-safeTransferFrom(address,address,uint256,uint256,bytes)}.
    /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
    /// @dev Reverts with {ERC1155TransferToAddressZero} if `to` is the zero address.
    /// @dev Reverts with {ERC1155NonApproved} if `sender` is not `from` and has not been approved by `from`.
    /// @dev Reverts with {ERC1155InsufficientBalance} if `from` has an insufficient balance of `id`.
    /// @dev Reverts with {ERC1155BalanceOverflow} if `to`'s balance of `id` overflows.
    /// @dev Reverts with {ERC1155SafeTransferRejected} if `to` is a contract and the call to
    ///  {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits a {TransferSingle} event.
    /// @param sender The message sender.
    /// @param from Current token owner.
    /// @param to Address of the new token owner.
    /// @param id Identifier of the token to transfer.
    /// @param value Amount of token to transfer.
    /// @param data Optional data to send along to a receiver contract.
    function safeTransferFrom(Layout storage s, address sender, address from, address to, uint256 id, uint256 value, bytes calldata data) internal {
        if (to == address(0)) revert ERC1155TransferToAddressZero();
        if (!_isOperatable(s, from, sender)) revert ERC1155NonApproved(sender, from);

        _transferToken(s, from, to, id, value);

        emit TransferSingle(sender, from, to, id, value);

        if (to.isContract()) {
            _callOnERC1155Received(sender, from, to, id, value, data);
        }
    }

    /// @notice Safely transfers a batch of tokens by a sender.
    /// @dev Note: This function implements {ERC1155-safeBatchTransferFrom(address,address,uint256[],uint256[],bytes)}.
    /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
    /// @dev Reverts with {ERC1155TransferToAddressZero} if `to` is the zero address.
    /// @dev Reverts with {InconsistentArrayLengths} if `ids` and `values` have different lengths.
    /// @dev Reverts with {ERC1155NonApproved} if `sender` is not `from` and has not been approved by `from`.
    /// @dev Reverts with {ERC1155InsufficientBalance} if `from` has an insufficient balance for any of `ids`.
    /// @dev Reverts with {ERC1155BalanceOverflow} if `to`'s balance of any of `ids` overflows.
    /// @dev Reverts with {ERC1155SafeBatchTransferRejected} if `to` is a contract and the call to
    ///  {IERC1155TokenReceiver-onERC1155BatchReceived} fails, reverts or is rejected.
    /// @dev Emits a {TransferBatch} event.
    /// @param sender The message sender.
    /// @param from Current tokens owner.
    /// @param to Address of the new tokens owner.
    /// @param ids Identifiers of the tokens to transfer.
    /// @param values Amounts of tokens to transfer.
    /// @param data Optional data to send along to a receiver contract.
    function safeBatchTransferFrom(
        Layout storage s,
        address sender,
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata values,
        bytes calldata data
    ) internal {
        if (to == address(0)) revert ERC1155TransferToAddressZero();
        uint256 length = ids.length;
        if (length != values.length) revert InconsistentArrayLengths();

        if (!_isOperatable(s, from, sender)) revert ERC1155NonApproved(sender, from);

        for (uint256 i; i < length; ++i) {
            _transferToken(s, from, to, ids[i], values[i]);
        }

        emit TransferBatch(sender, from, to, ids, values);

        if (to.isContract()) {
            _callOnERC1155BatchReceived(sender, from, to, ids, values, data);
        }
    }

    /// @notice Safely mints some token by a sender.
    /// @dev Note: This function implements {ERC1155Mintable-safeMint(address,uint256,uint256,bytes)}.
    /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
    /// @dev Reverts with {ERC1155MintToAddressZero} if `to` is the zero address.
    /// @dev Reverts with {ERC1155BalanceOverflow} if `to`'s balance of `id` overflows.
    /// @dev Reverts with {ERC1155SafeTransferRejected} if `to` is a contract and the call to
    ///  {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits a {TransferSingle} event.
    /// @param sender The message sender.
    /// @param to Address of the new token owner.
    /// @param id Identifier of the token to mint.
    /// @param value Amount of token to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeMint(Layout storage s, address sender, address to, uint256 id, uint256 value, bytes memory data) internal {
        if (to == address(0)) revert ERC1155MintToAddressZero();

        _mintToken(s, to, id, value);

        emit TransferSingle(sender, address(0), to, id, value);

        if (to.isContract()) {
            _callOnERC1155Received(sender, address(0), to, id, value, data);
        }
    }

    /// @notice Safely mints a batch of tokens by a sender.
    /// @dev Note: This function implements {ERC1155Mintable-safeBatchMint(address,uint256[],uint256[],bytes)}.
    /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
    /// @dev Reverts with {ERC1155MintToAddressZero} if `to` is the zero address.
    /// @dev Reverts with {InconsistentArrayLengths} if `ids` and `values` have different lengths.
    /// @dev Reverts with {ERC1155BalanceOverflow} if `to`'s balance overflows for one of `ids`.
    /// @dev Reverts with {ERC1155SafeBatchTransferRejected} if `to` is a contract and the call to
    ///  {IERC1155TokenReceiver-onERC1155batchReceived} fails, reverts or is rejected.
    /// @dev Emits a {TransferBatch} event.
    /// @param sender The message sender.
    /// @param to Address of the new tokens owner.
    /// @param ids Identifiers of the tokens to mint.
    /// @param values Amounts of tokens to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeBatchMint(Layout storage s, address sender, address to, uint256[] memory ids, uint256[] memory values, bytes memory data) internal {
        if (to == address(0)) revert ERC1155MintToAddressZero();
        uint256 length = ids.length;
        if (length != values.length) revert InconsistentArrayLengths();

        for (uint256 i; i < length; ++i) {
            _mintToken(s, to, ids[i], values[i]);
        }

        emit TransferBatch(sender, address(0), to, ids, values);

        if (to.isContract()) {
            _callOnERC1155BatchReceived(sender, address(0), to, ids, values, data);
        }
    }

    /// @notice Safely mints tokens to multiple recipients by a sender.
    /// @dev Note: This function implements {ERC1155Deliverable-safeDeliver(address[],uint256[],uint256[],bytes)}.
    /// @dev Warning: Since a `to` contract can run arbitrary code, developers should be aware of potential re-entrancy attacks.
    /// @dev Reverts with {InconsistentArrayLengths} if `recipients`, `ids` and `values` have different lengths.
    /// @dev Reverts with {ERC1155MintToAddressZero} if one of `recipients` is the zero address.
    /// @dev Reverts with {ERC1155BalanceOverflow} if one of the `recipients`' balance overflows for the associated `ids`.
    /// @dev Reverts with {ERC1155SafeTransferRejected} if one of `recipients` is a contract and the call to
    ///  {IERC1155TokenReceiver-onERC1155Received} fails, reverts or is rejected.
    /// @dev Emits a {TransferSingle} event from the zero address for each transfer.
    /// @param sender The message sender.
    /// @param recipients Addresses of the new tokens owners.
    /// @param ids Identifiers of the tokens to mint.
    /// @param values Amounts of tokens to mint.
    /// @param data Optional data to send along to a receiver contract.
    function safeDeliver(
        Layout storage s,
        address sender,
        address[] memory recipients,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) internal {
        uint256 length = recipients.length;
        if (length != ids.length || length != values.length) revert InconsistentArrayLengths();
        for (uint256 i; i < length; ++i) {
            s.safeMint(sender, recipients[i], ids[i], values[i], data);
        }
    }

    /// @notice Burns some token by a sender.
    /// @dev Reverts with {ERC1155NonApproved} if `sender` is not `from` and has not been approved by `from`.
    /// @dev Reverts with {ERC1155InsufficientBalance} if `from` has an insufficient balance of `id`.
    /// @dev Emits a {TransferSingle} event.
    /// @param sender The message sender.
    /// @param from Address of the current token owner.
    /// @param id Identifier of the token to burn.
    /// @param value Amount of token to burn.
    function burnFrom(Layout storage s, address sender, address from, uint256 id, uint256 value) internal {
        if (!_isOperatable(s, from, sender)) revert ERC1155NonApproved(sender, from);
        _burnToken(s, from, id, value);
        emit TransferSingle(sender, from, address(0), id, value);
    }

    /// @notice Burns multiple tokens by a sender.
    /// @dev Reverts with {InconsistentArrayLengths} if `ids` and `values` have different lengths.
    /// @dev Reverts with {ERC1155NonApproved} if `sender` is not `from` and has not been approved by `from`.
    /// @dev Reverts with {ERC1155InsufficientBalance} if `from` has an insufficient balance for any of `ids`.
    /// @dev Emits an {IERC1155-TransferBatch} event.
    /// @param sender The message sender.
    /// @param from Address of the current tokens owner.
    /// @param ids Identifiers of the tokens to burn.
    /// @param values Amounts of tokens to burn.
    function batchBurnFrom(Layout storage s, address sender, address from, uint256[] calldata ids, uint256[] calldata values) internal {
        uint256 length = ids.length;
        if (length != values.length) revert InconsistentArrayLengths();
        if (!_isOperatable(s, from, sender)) revert ERC1155NonApproved(sender, from);

        for (uint256 i; i < length; ++i) {
            _burnToken(s, from, ids[i], values[i]);
        }

        emit TransferBatch(sender, from, address(0), ids, values);
    }

    /// @notice Enables or disables an operator's approval by a sender.
    /// @dev Reverts with {ERC1155SelfApprovalForAll} if `sender` is `operator`.
    /// @dev Emits an {ApprovalForAll} event.
    /// @param sender The message sender.
    /// @param operator Address of the operator.
    /// @param approved True to approve the operator, false to revoke its approval.
    function setApprovalForAll(Layout storage s, address sender, address operator, bool approved) internal {
        if (operator == sender) revert ERC1155SelfApprovalForAll(sender);
        s.operators[sender][operator] = approved;
        emit ApprovalForAll(sender, operator, approved);
    }

    /// @notice Retrieves the approval status of an operator for a given owner.
    /// @param owner Address of the authorisation giver.
    /// @param operator Address of the operator.
    /// @return approved True if the operator is approved, false if not.
    function isApprovedForAll(Layout storage s, address owner, address operator) internal view returns (bool approved) {
        return s.operators[owner][operator];
    }

    /// @notice Retrieves the balance of `id` owned by account `owner`.
    /// @dev Reverts with {ERC1155BalanceOfAddressZero} if `owner` is the zero address.
    /// @param owner The account to retrieve the balance of.
    /// @param id The identifier to retrieve the balance of.
    /// @return balance The balance of `id` owned by account `owner`.
    function balanceOf(Layout storage s, address owner, uint256 id) internal view returns (uint256 balance) {
        if (owner == address(0)) revert ERC1155BalanceOfAddressZero();
        return s.balances[id][owner];
    }

    /// @notice Retrieves the balances of `ids` owned by accounts `owners`.
    /// @dev Reverts with {InconsistentArrayLengths} if `owners` and `ids` have different lengths.
    /// @dev Reverts with {ERC1155BalanceOfAddressZero} if one of `owners` is the zero address.
    /// @param owners The addresses of the token holders
    /// @param ids The identifiers to retrieve the balance of.
    /// @return balances The balances of `ids` owned by accounts `owners`.
    function balanceOfBatch(Layout storage s, address[] calldata owners, uint256[] calldata ids) internal view returns (uint256[] memory balances) {
        uint256 length = owners.length;
        if (length != ids.length) revert InconsistentArrayLengths();

        balances = new uint256[](owners.length);

        for (uint256 i; i < length; ++i) {
            balances[i] = s.balanceOf(owners[i], ids[i]);
        }
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }

    /// @notice Returns whether an account is authorised to make a transfer on behalf of an owner.
    /// @param owner The token owner.
    /// @param account The account to check the operatability of.
    /// @return operatable True if `account` is `owner` or is an operator for `owner`, false otherwise.
    function _isOperatable(Layout storage s, address owner, address account) private view returns (bool operatable) {
        return (owner == account) || s.operators[owner][account];
    }

    function _transferToken(Layout storage s, address from, address to, uint256 id, uint256 value) private {
        if (value != 0) {
            uint256 fromBalance = s.balances[id][from];
            unchecked {
                uint256 newFromBalance = fromBalance - value;
                if (newFromBalance >= fromBalance) revert ERC1155InsufficientBalance(from, id, fromBalance, value);
                if (from != to) {
                    uint256 toBalance = s.balances[id][to];
                    uint256 newToBalance = toBalance + value;
                    if (newToBalance <= toBalance) revert ERC1155BalanceOverflow(to, id, toBalance, value);

                    s.balances[id][from] = newFromBalance;
                    s.balances[id][to] = newToBalance;
                }
            }
        }
    }

    function _mintToken(Layout storage s, address to, uint256 id, uint256 value) private {
        if (value != 0) {
            unchecked {
                uint256 balance = s.balances[id][to];
                uint256 newBalance = balance + value;
                if (newBalance <= balance) revert ERC1155BalanceOverflow(to, id, balance, value);
                s.balances[id][to] = newBalance;
            }
        }
    }

    function _burnToken(Layout storage s, address from, uint256 id, uint256 value) private {
        if (value != 0) {
            uint256 balance = s.balances[id][from];
            unchecked {
                uint256 newBalance = balance - value;
                if (newBalance >= balance) revert ERC1155InsufficientBalance(from, id, balance, value);
                s.balances[id][from] = newBalance;
            }
        }
    }

    /// @notice Calls {IERC1155TokenReceiver-onERC1155Received} on a target contract.
    /// @dev Reverts with {ERC1155SafeTransferRejected} if the call to the target fails, reverts or is rejected.
    /// @param sender The message sender.
    /// @param from Previous token owner.
    /// @param to New token owner.
    /// @param id Identifier of the token transferred.
    /// @param value Value transferred.
    /// @param data Optional data to send along with the receiver contract call.
    function _callOnERC1155Received(address sender, address from, address to, uint256 id, uint256 value, bytes memory data) private {
        if (IERC1155TokenReceiver(to).onERC1155Received(sender, from, id, value, data) != ERC1155_SINGLE_RECEIVED)
            revert ERC1155SafeTransferRejected(to, id, value);
    }

    /// @notice Calls {IERC1155TokenReceiver-onERC1155BatchReceived} on a target contract.
    /// @dev Reverts with {ERC1155SafeBatchTransferRejected} if the call to the target fails, reverts or is rejected.
    /// @param sender The message sender.
    /// @param from Previous token owner.
    /// @param to New token owner.
    /// @param ids Identifiers of the tokens transferred.
    /// @param values Values transferred.
    /// @param data Optional data to send along with the receiver contract call.
    function _callOnERC1155BatchReceived(
        address sender,
        address from,
        address to,
        uint256[] memory ids,
        uint256[] memory values,
        bytes memory data
    ) private {
        if (IERC1155TokenReceiver(to).onERC1155BatchReceived(sender, from, ids, values, data) != ERC1155_BATCH_RECEIVED)
            revert ERC1155SafeBatchTransferRejected(to, ids, values);
    }
}

File 57 of 70 : IERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC721 Non-Fungible Token Standard, basic interface (functions).
/// @dev See https://eips.ethereum.org/EIPS/eip-721
/// @dev This interface only contains the standard functions. See IERC721Events for the events.
/// @dev Note: The ERC-165 identifier for this interface is 0x80ac58cd.
interface IERC721 {
    /// @notice Sets or unsets an approval to transfer a single token on behalf of its owner.
    /// @dev Note: There can only be one approved address per token at a given time.
    /// @dev Note: A token approval gets reset when this token is transferred, including a self-transfer.
    /// @dev Reverts if `tokenId` does not exist.
    /// @dev Reverts if `to` is the token owner.
    /// @dev Reverts if the sender is not the token owner and has not been approved by the token owner.
    /// @dev Emits an {Approval} event.
    /// @param to The address to approve, or the zero address to remove any existing approval.
    /// @param tokenId The token identifier to give approval for.
    function approve(address to, uint256 tokenId) external;

    /// @notice Sets or unsets an approval to transfer all tokens on behalf of their owner.
    /// @dev Reverts if the sender is the same as `operator`.
    /// @dev Emits an {ApprovalForAll} event.
    /// @param operator The address to approve for all tokens.
    /// @param approved True to set an approval for all tokens, false to unset it.
    function setApprovalForAll(address operator, bool approved) external;

    /// @notice Unsafely transfers the ownership of a token to a recipient.
    /// @dev Note: Usage of this method is discouraged, use `safeTransferFrom` whenever possible.
    /// @dev Resets the token approval for `tokenId`.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `from` is not the owner of `tokenId`.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
    /// @dev Emits a {Transfer} event.
    /// @param from The current token owner.
    /// @param to The recipient of the token transfer. Self-transfers are possible.
    /// @param tokenId The identifier of the token to transfer.
    function transferFrom(address from, address to, uint256 tokenId) external;

    /// @notice Safely transfers the ownership of a token to a recipient.
    /// @dev Resets the token approval for `tokenId`.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `from` is not the owner of `tokenId`.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
    /// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
    /// @dev Emits a {Transfer} event.
    /// @param from The current token owner.
    /// @param to The recipient of the token transfer.
    /// @param tokenId The identifier of the token to transfer.
    function safeTransferFrom(address from, address to, uint256 tokenId) external;

    /// @notice Safely transfers the ownership of a token to a recipient.
    /// @dev Resets the token approval for `tokenId`.
    /// @dev Reverts if `to` is the zero address.
    /// @dev Reverts if `from` is not the owner of `tokenId`.
    /// @dev Reverts if the sender is not `from` and has not been approved by `from` for `tokenId`.
    /// @dev Reverts if `to` is a contract and the call to {IERC721Receiver-onERC721Received} fails, reverts or is rejected.
    /// @dev Emits a {Transfer} event.
    /// @param from The current token owner.
    /// @param to The recipient of the token transfer.
    /// @param tokenId The identifier of the token to transfer.
    /// @param data Optional data to send along to a receiver contract.
    function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;

    /// @notice Gets the balance of an address.
    /// @dev Reverts if `owner` is the zero address.
    /// @param owner The address to query the balance of.
    /// @return balance The amount owned by the owner.
    function balanceOf(address owner) external view returns (uint256 balance);

    /// @notice Gets the owner of a token.
    /// @dev Reverts if `tokenId` does not exist.
    /// @param tokenId The token identifier to query the owner of.
    /// @return tokenOwner The owner of the token identifier.
    function ownerOf(uint256 tokenId) external view returns (address tokenOwner);

    /// @notice Gets the approved address for a token.
    /// @dev Reverts if `tokenId` does not exist.
    /// @param tokenId The token identifier to query the approval of.
    /// @return approved The approved address for the token identifier, or the zero address if no approval is set.
    function getApproved(uint256 tokenId) external view returns (address approved);

    /// @notice Gets whether an operator is approved for all tokens by an owner.
    /// @param owner The address which gives the approval for all tokens.
    /// @param operator The address which receives the approval for all tokens.
    /// @return approvedForAll Whether the operator is approved for all tokens by the owner.
    function isApprovedForAll(address owner, address operator) external view returns (bool approvedForAll);
}

File 58 of 70 : TokenMetadataBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol";
import {TokenMetadataStorage} from "./../libraries/TokenMetadataStorage.sol";

/// @title TokenMetadataBase (proxiable version).
/// @notice Provides metadata management for token contracts (ERC721/ERC1155) which uses an external resolver for managing individual tokens metadata.
/// @dev This contract is to be used via inheritance in a proxied implementation.
abstract contract TokenMetadataBase {
    using TokenMetadataStorage for TokenMetadataStorage.Layout;

    /// @notice Gets the token name. E.g. "My Token".
    /// @return tokenName The token name.
    function name() public view virtual returns (string memory tokenName) {
        return TokenMetadataStorage.layout().name();
    }

    /// @notice Gets the token symbol. E.g. "TOK".
    /// @return tokenSymbol The token symbol.
    function symbol() public view virtual returns (string memory tokenSymbol) {
        return TokenMetadataStorage.layout().symbol();
    }

    /// @notice Gets the token metadata resolver address.
    /// @return tokenMetadataResolver The token metadata resolver address.
    function metadataResolver() external view virtual returns (ITokenMetadataResolver tokenMetadataResolver) {
        return TokenMetadataStorage.layout().metadataResolver();
    }
}

File 59 of 70 : TokenMetadataErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when an account is not the metadata resolver but is required to.
/// @param account The account that was checked.
error NotMetadataResolver(address account);

File 60 of 70 : ITokenMetadataResolver.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ITokenMetadataResolver
/// @notice Interface for Token Metadata Resolvers.
interface ITokenMetadataResolver {
    /// @notice Gets the token metadata URI for a token.
    /// @param tokenContract The token contract for which to retrieve the token URI.
    /// @param tokenId The token identifier.
    /// @return tokenURI The token metadata URI.
    function tokenMetadataURI(address tokenContract, uint256 tokenId) external view returns (string memory tokenURI);
}

File 61 of 70 : TokenMetadataStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ITokenMetadataResolver} from "./../interfaces/ITokenMetadataResolver.sol";
import {ProxyInitialization} from "./../../../proxy/libraries/ProxyInitialization.sol";

library TokenMetadataStorage {
    struct Layout {
        string tokenName;
        string tokenSymbol;
        ITokenMetadataResolver tokenMetadataResolver;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.storage")) - 1);
    bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.token.metadata.TokenMetadata.phase")) - 1);

    /// @notice Initializes the metadata storage (immutable version).
    /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract.
    /// @param tokenName The token name.
    /// @param tokenSymbol The token symbol.
    /// @param tokenMetadataResolver The address of the metadata resolver contract.
    function constructorInit(
        Layout storage s,
        string memory tokenName,
        string memory tokenSymbol,
        ITokenMetadataResolver tokenMetadataResolver
    ) internal {
        s.tokenName = tokenName;
        s.tokenSymbol = tokenSymbol;
        s.tokenMetadataResolver = tokenMetadataResolver;
    }

    /// @notice Initializes the metadata storage (proxied version).
    /// @notice Sets the proxy initialization phase to `1`.
    /// @dev Note: This function should be called ONLY in the init function of a proxied contract.
    /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above.
    /// @param tokenName The token name.
    /// @param tokenSymbol The token symbol.
    /// @param tokenMetadataResolver The address of the metadata resolver contract.
    function proxyInit(
        Layout storage s,
        string calldata tokenName,
        string calldata tokenSymbol,
        ITokenMetadataResolver tokenMetadataResolver
    ) internal {
        ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1);
        s.tokenName = tokenName;
        s.tokenSymbol = tokenSymbol;
        s.tokenMetadataResolver = tokenMetadataResolver;
    }

    /// @notice Gets the name of the token.
    /// @return tokenName The name of the token contract.
    function name(Layout storage s) internal view returns (string memory tokenName) {
        return s.tokenName;
    }

    /// @notice Gets the symbol of the token.
    /// @return tokenSymbol The symbol of the token contract.
    function symbol(Layout storage s) internal view returns (string memory tokenSymbol) {
        return s.tokenSymbol;
    }

    /// @notice Gets the address of the token metadata resolver.
    /// @return tokenMetadataResolver The address of the token metadata resolver.
    function metadataResolver(Layout storage s) internal view returns (ITokenMetadataResolver tokenMetadataResolver) {
        return s.tokenMetadataResolver;
    }

    /// @notice Gets the token metadata URI retieved from the metadata resolver contract.
    /// @param tokenContract The address of the token contract.
    /// @param tokenId The ID of the token.
    function tokenMetadataURI(Layout storage s, address tokenContract, uint256 tokenId) internal view returns (string memory) {
        return s.tokenMetadataResolver.tokenMetadataURI(tokenContract, tokenId);
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }
}

File 62 of 70 : ERC2981.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC2981Storage} from "./libraries/ERC2981Storage.sol";
import {ERC2981Base} from "./base/ERC2981Base.sol";
import {ContractOwnership} from "./../../access/ContractOwnership.sol";

/// @title ERC2981 NFT Royalty Standard (immutable version).
/// @dev This contract is to be used via inheritance in an immutable (non-proxied) implementation.
abstract contract ERC2981 is ERC2981Base, ContractOwnership {
    /// @notice Marks the following ERC165 interface(s) as supported: ERC2981.
    constructor() {
        ERC2981Storage.init();
    }
}

File 63 of 70 : ERC2981Base.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IERC2981} from "./../interfaces/IERC2981.sol";
import {ERC2981Storage} from "./../libraries/ERC2981Storage.sol";
import {ContractOwnershipStorage} from "./../../../access/libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title ERC2981 NFT Royalty Standard (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC165 (Interface Detection Standard).
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract ERC2981Base is Context, IERC2981 {
    using ERC2981Storage for ERC2981Storage.Layout;
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;

    uint256 public constant ROYALTY_FEE_DENOMINATOR = ERC2981Storage.ROYALTY_FEE_DENOMINATOR;

    /// @notice Sets the royalty percentage.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Reverts with {IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR).
    /// @param percentage The new percentage to set. For example 50000 sets 50% royalty.
    function setRoyaltyPercentage(uint256 percentage) external {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        ERC2981Storage.layout().setRoyaltyPercentage(percentage);
    }

    /// @notice Sets the royalty receiver.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @dev Reverts with {IncorrectRoyaltyReceiver} if `receiver` is the zero address.
    /// @param receiver The new receiver to set.
    function setRoyaltyReceiver(address receiver) external {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        ERC2981Storage.layout().setRoyaltyReceiver(receiver);
    }

    /// @inheritdoc IERC2981
    function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount) {
        return ERC2981Storage.layout().royaltyInfo(tokenId, salePrice);
    }
}

File 64 of 70 : OperatorFiltererBase.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {IOperatorFilterRegistry} from "./../interfaces/IOperatorFilterRegistry.sol";
import {OperatorFiltererStorage} from "./../libraries/OperatorFiltererStorage.sol";
import {ContractOwnershipStorage} from "./../../../access/libraries/ContractOwnershipStorage.sol";
import {Context} from "@openzeppelin/contracts/utils/Context.sol";

/// @title Operator Filterer for token contracts (proxiable version).
/// @dev This contract is to be used via inheritance in a proxied implementation.
/// @dev Note: This contract requires ERC173 (Contract Ownership standard).
abstract contract OperatorFiltererBase is Context {
    using OperatorFiltererStorage for OperatorFiltererStorage.Layout;
    using ContractOwnershipStorage for ContractOwnershipStorage.Layout;

    /// @notice Updates the address that the contract will make OperatorFilter checks against.
    /// @dev Reverts with {NotContractOwner} if the sender is not the contract owner.
    /// @param registry The new operator filter registry address. When set to the zero address, checks will be bypassed.
    function updateOperatorFilterRegistry(IOperatorFilterRegistry registry) external {
        ContractOwnershipStorage.layout().enforceIsContractOwner(_msgSender());
        OperatorFiltererStorage.layout().updateOperatorFilterRegistry(registry);
    }

    /// @notice Gets the operator filter registry address.
    function operatorFilterRegistry() external view returns (IOperatorFilterRegistry) {
        return OperatorFiltererStorage.layout().operatorFilterRegistry();
    }
}

File 65 of 70 : ERC2981Errors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when setting a royalty percentage that is above 100% (> FEE_DENOMINATOR).
/// @param percentage The royalty percentage that was attempted to be set.
error ERC2981IncorrectRoyaltyPercentage(uint256 percentage);

/// @notice Thrown when setting a royalty receiver that is the zero address.
error ERC2981IncorrectRoyaltyReceiver();

File 66 of 70 : OperatorFiltererErrors.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @notice Thrown when transferring to or giving approval to a non-authorized operator.
/// @param operator The address that is not authorized.
error OperatorNotAllowed(address operator);

File 67 of 70 : IERC2981.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

/// @title ERC2981 NFT Royalty Standard.
/// @dev See https://eips.ethereum.org/EIPS/eip-2981
/// @dev Note: The ERC-165 identifier for this interface is 0x2a55205a.
interface IERC2981 {
    /// @notice Called with the sale price to determine how much royalty is owed and to whom.
    /// @param tokenId The NFT asset queried for royalty information
    /// @param salePrice The sale price of the NFT asset specified by `tokenId`
    /// @return receiver Address of who should be sent the royalty payment
    /// @return royaltyAmount The royalty payment amount for `salePrice`
    function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount);
}

File 68 of 70 : IOperatorFilterRegistry.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

interface IOperatorFilterRegistry {
    function isOperatorAllowed(address registrant, address operator) external view returns (bool);

    function register(address registrant) external;

    function registerAndSubscribe(address registrant, address subscription) external;

    function registerAndCopyEntries(address registrant, address registrantToCopy) external;

    function unregister(address addr) external;

    function updateOperator(address registrant, address operator, bool filtered) external;

    function updateOperators(address registrant, address[] calldata operators, bool filtered) external;

    function updateCodeHash(address registrant, bytes32 codehash, bool filtered) external;

    function updateCodeHashes(address registrant, bytes32[] calldata codeHashes, bool filtered) external;

    function subscribe(address registrant, address registrantToSubscribe) external;

    function unsubscribe(address registrant, bool copyExistingEntries) external;

    function subscriptionOf(address addr) external returns (address registrant);

    function subscribers(address registrant) external returns (address[] memory);

    function subscriberAt(address registrant, uint256 index) external returns (address);

    function copyEntriesOf(address registrant, address registrantToCopy) external;

    function isOperatorFiltered(address registrant, address operator) external returns (bool);

    function isCodeHashOfFiltered(address registrant, address operatorWithCode) external returns (bool);

    function isCodeHashFiltered(address registrant, bytes32 codeHash) external returns (bool);

    function filteredOperators(address addr) external returns (address[] memory);

    function filteredCodeHashes(address addr) external returns (bytes32[] memory);

    function filteredOperatorAt(address registrant, uint256 index) external returns (address);

    function filteredCodeHashAt(address registrant, uint256 index) external returns (bytes32);

    function isRegistered(address addr) external returns (bool);

    function codeHashOf(address addr) external returns (bytes32);
}

File 69 of 70 : ERC2981Storage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {ERC2981IncorrectRoyaltyReceiver, ERC2981IncorrectRoyaltyPercentage} from "./../errors/ERC2981Errors.sol";
import {IERC2981} from "./../interfaces/IERC2981.sol";
import {InterfaceDetectionStorage} from "./../../../introspection/libraries/InterfaceDetectionStorage.sol";

library ERC2981Storage {
    using InterfaceDetectionStorage for InterfaceDetectionStorage.Layout;

    struct Layout {
        address royaltyReceiver;
        uint96 royaltyPercentage;
    }

    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.ERC2981.storage")) - 1);

    uint256 internal constant ROYALTY_FEE_DENOMINATOR = 100000;

    /// @notice Marks the following ERC165 interface(s) as supported: ERC2981.
    function init() internal {
        InterfaceDetectionStorage.layout().setSupportedInterface(type(IERC2981).interfaceId, true);
    }

    /// @notice Sets the royalty percentage.
    /// @dev Reverts with {ERC2981IncorrectRoyaltyPercentage} if `percentage` is above 100% (> FEE_DENOMINATOR).
    /// @param percentage The new percentage to set. For example 50000 sets 50% royalty.
    function setRoyaltyPercentage(Layout storage s, uint256 percentage) internal {
        if (percentage > ROYALTY_FEE_DENOMINATOR) {
            revert ERC2981IncorrectRoyaltyPercentage(percentage);
        }
        s.royaltyPercentage = uint96(percentage);
    }

    /// @notice Sets the royalty receiver.
    /// @dev Reverts with {ERC2981IncorrectRoyaltyReceiver} if `receiver` is the zero address.
    /// @param receiver The new receiver to set.
    function setRoyaltyReceiver(Layout storage s, address receiver) internal {
        if (receiver == address(0)) {
            revert ERC2981IncorrectRoyaltyReceiver();
        }
        s.royaltyReceiver = receiver;
    }

    /// @notice Called with the sale price to determine how much royalty is owed and to whom.
    // / @param tokenId The NFT asset queried for royalty information
    /// @param salePrice The sale price of the NFT asset specified by `tokenId`
    /// @return receiver Address of who should be sent the royalty payment
    /// @return royaltyAmount The royalty payment amount for `salePrice`
    function royaltyInfo(Layout storage s, uint256, uint256 salePrice) internal view returns (address receiver, uint256 royaltyAmount) {
        receiver = s.royaltyReceiver;
        uint256 royaltyPercentage = s.royaltyPercentage;
        if (salePrice == 0 || royaltyPercentage == 0) {
            royaltyAmount = 0;
        } else {
            if (salePrice < ROYALTY_FEE_DENOMINATOR) {
                royaltyAmount = (salePrice * royaltyPercentage) / ROYALTY_FEE_DENOMINATOR;
            } else {
                royaltyAmount = (salePrice / ROYALTY_FEE_DENOMINATOR) * royaltyPercentage;
            }
        }
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }
}

File 70 of 70 : OperatorFiltererStorage.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.22;

import {OperatorNotAllowed} from "./../errors/OperatorFiltererErrors.sol";
import {IOperatorFilterRegistry} from "./../interfaces/IOperatorFilterRegistry.sol";
import {ProxyInitialization} from "./../../../proxy/libraries/ProxyInitialization.sol";

library OperatorFiltererStorage {
    using OperatorFiltererStorage for OperatorFiltererStorage.Layout;

    struct Layout {
        IOperatorFilterRegistry registry;
    }

    bytes32 internal constant PROXY_INIT_PHASE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.OperatorFilterer.phase")) - 1);
    bytes32 internal constant LAYOUT_STORAGE_SLOT = bytes32(uint256(keccak256("animoca.token.royalty.OperatorFilterer.storage")) - 1);

    /// @notice Sets the address that the contract will make OperatorFilter checks against.
    /// @dev Note: This function should be called ONLY in the constructor of an immutable (non-proxied) contract.
    /// @param registry The operator filter registry address. When set to the zero address, checks will be bypassed.
    function constructorInit(Layout storage s, IOperatorFilterRegistry registry) internal {
        s.registry = registry;
    }

    /// @notice Sets the address that the contract will make OperatorFilter checks against.
    /// @dev Note: This function should be called ONLY in the init function of a proxied contract.
    /// @dev Reverts with {InitializationPhaseAlreadyReached} if the proxy initialization phase is set to `1` or above.
    /// @param registry The operator filter registry address. When set to the zero address, checks will be bypassed.
    function proxyInit(Layout storage s, IOperatorFilterRegistry registry) internal {
        ProxyInitialization.setPhase(PROXY_INIT_PHASE_SLOT, 1);
        s.constructorInit(registry);
    }

    /// @notice Updates the address that the contract will make OperatorFilter checks against.
    /// @param registry The new operator filter registry address. When set to the zero address, checks will be bypassed.
    function updateOperatorFilterRegistry(Layout storage s, IOperatorFilterRegistry registry) internal {
        s.registry = registry;
    }

    /// @dev Reverts with {OperatorNotAllowed} if `sender` is not `from` and is not allowed by a valid operator registry.
    function requireAllowedOperatorForTransfer(Layout storage s, address sender, address from) internal view {
        // Allow spending tokens from addresses with balance
        // Note that this still allows listings and marketplaces with escrow to transfer tokens if transferred from an EOA.
        if (sender != from) {
            _checkFilterOperator(s, sender);
        }
    }

    /// @dev Reverts with {OperatorNotAllowed} if `sender` is not allowed by a valid operator registry.
    function requireAllowedOperatorForApproval(Layout storage s, address operator) internal view {
        _checkFilterOperator(s, operator);
    }

    function operatorFilterRegistry(Layout storage s) internal view returns (IOperatorFilterRegistry) {
        return s.registry;
    }

    function layout() internal pure returns (Layout storage s) {
        bytes32 position = LAYOUT_STORAGE_SLOT;
        assembly {
            s.slot := position
        }
    }

    function _checkFilterOperator(Layout storage s, address operator) private view {
        IOperatorFilterRegistry registry = s.registry;
        // Check registry code length to facilitate testing in environments without a deployed registry.
        if (address(registry) != address(0) && address(registry).code.length > 0) {
            if (!registry.isOperatorAllowed(address(this), operator)) {
                revert OperatorNotAllowed(operator);
            }
        }
    }
}

Settings
{
  "evmVersion": "paris",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 99999
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"contract ITokenMetadataResolver","name":"metadataResolver","type":"address"},{"internalType":"contract IOperatorFilterRegistry","name":"filterRegistry","type":"address"},{"internalType":"contract IForwarderRegistry","name":"forwarderRegistry","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ERC1155BalanceOfAddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC1155BalanceOverflow","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"balance","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC1155InsufficientBalance","type":"error"},{"inputs":[],"name":"ERC1155MintToAddressZero","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC1155NonApproved","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"ERC1155SafeBatchTransferRejected","type":"error"},{"inputs":[{"internalType":"address","name":"recipient","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"ERC1155SafeTransferRejected","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"ERC1155SelfApprovalForAll","type":"error"},{"inputs":[],"name":"ERC1155TransferToAddressZero","type":"error"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"ERC2981IncorrectRoyaltyPercentage","type":"error"},{"inputs":[],"name":"ERC2981IncorrectRoyaltyReceiver","type":"error"},{"inputs":[],"name":"IllegalInterfaceId","type":"error"},{"inputs":[],"name":"InconsistentArrayLengths","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotContractOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"NotMetadataResolver","type":"error"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"NotRoleHolder","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"OperatorNotAllowed","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","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":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleGranted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"role","type":"bytes32"},{"indexed":false,"internalType":"address","name":"account","type":"address"},{"indexed":false,"internalType":"address","name":"operator","type":"address"}],"name":"RoleRevoked","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":[],"name":"MINTER_ROLE","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_FEE_DENOMINATOR","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"owners","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"balanceOfBatch","outputs":[{"internalType":"uint256[]","name":"balances","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"}],"name":"batchBurnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"string[]","name":"tokenURIs","type":"string[]"}],"name":"batchSetTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"}],"name":"burnFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"forwarderRegistry","outputs":[{"internalType":"contract IForwarderRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"grantRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"hasRole","outputs":[{"internalType":"bool","name":"hasRole_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"approvedForAll","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"forwarder","type":"address"}],"name":"isTrustedForwarder","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataResolver","outputs":[{"internalType":"contract ITokenMetadataResolver","name":"tokenMetadataResolver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"tokenName","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"operatorFilterRegistry","outputs":[{"internalType":"contract IOperatorFilterRegistry","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC20[]","name":"tokens","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverERC20s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"accounts","type":"address[]"},{"internalType":"contract IERC721[]","name":"contracts","type":"address[]"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"recoverERC721s","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable[]","name":"accounts","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"recoverETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"}],"name":"renounceRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"role","type":"bytes32"},{"internalType":"address","name":"account","type":"address"}],"name":"revokeRole","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"recipients","type":"address[]"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"},{"internalType":"uint256[]","name":"values","type":"uint256[]"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeDeliver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeMint","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":"value","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"percentage","type":"uint256"}],"name":"setRoyaltyPercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"setRoyaltyReceiver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"string","name":"tokenURI","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"tokenSymbol","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IOperatorFilterRegistry","name":"registry","type":"address"}],"name":"updateOperatorFilterRegistry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"uri","outputs":[{"internalType":"string","name":"metadataURI","type":"string"}],"stateMutability":"view","type":"function"}]

60a06040523480156200001157600080fd5b506040516200473c3803806200473c833981016040819052620000349162000446565b8080868686863362000051816200004a620000f3565b9062000129565b506200005c620001a4565b62000089816200006b620001be565b9081546001600160a01b0319166001600160a01b0391909116179055565b50620000a48383836200009b620001ee565b9291906200021e565b620000ae62000265565b50620000bc9150506200027d565b620000c662000295565b620000d0620002ad565b620000da620002c5565b6001600160a01b03166080525062000671945050505050565b6000806200012360017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd620004f2565b92915050565b6001600160a01b03811615620001805781546001600160a01b0319166001600160a01b03821690811783556040516000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a35b620001a06307f5828d60e41b600162000198620002d8565b919062000308565b5050565b620001bc636cdb3d1360e11b600162000198620002d8565b565b6000806200012360017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd31620004f2565b6000806200012360017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a5620004f2565b836200022b8482620005a5565b50600184016200023c8382620005a5565b5060029390930180546001600160a01b0319166001600160a01b03909416939093179092555050565b620001bc6303a24d0760e21b600162000198620002d8565b620001bc631464324b60e21b600162000198620002d8565b620001bc633a2ae73360e21b600162000198620002d8565b620001bc63921ed8d160e01b600162000198620002d8565b620001bc63152a902d60e11b6001620001985b6000806200012360017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e620004f2565b600160e01b6001600160e01b031983160162000337576040516372c683bb60e01b815260040160405180910390fd5b6001600160e01b03199190911660009081526020929092526040909120805460ff1916911515919091179055565b634e487b7160e01b600052604160045260246000fd5b600082601f8301126200038d57600080fd5b81516001600160401b0380821115620003aa57620003aa62000365565b604051601f8301601f19908116603f01168101908282118183101715620003d557620003d562000365565b8160405283815260209250866020858801011115620003f357600080fd5b600091505b83821015620004175785820183015181830184015290820190620003f8565b6000602085830101528094505050505092915050565b6001600160a01b03811681146200044357600080fd5b50565b600080600080600060a086880312156200045f57600080fd5b85516001600160401b03808211156200047757600080fd5b6200048589838a016200037b565b965060208801519150808211156200049c57600080fd5b50620004ab888289016200037b565b9450506040860151620004be816200042d565b6060870151909350620004d1816200042d565b6080870151909250620004e4816200042d565b809150509295509295909350565b818103818111156200012357634e487b7160e01b600052601160045260246000fd5b600181811c908216806200052957607f821691505b6020821081036200054a57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620005a0576000816000526020600020601f850160051c810160208610156200057b5750805b601f850160051c820191505b818110156200059c5782815560010162000587565b5050505b505050565b81516001600160401b03811115620005c157620005c162000365565b620005d981620005d2845462000514565b8462000550565b602080601f831160018114620006115760008415620005f85750858301515b600019600386901b1c1916600185901b1785556200059c565b600085815260208120601f198616915b82811015620006425788860151825594840194600190910190840162000621565b5085821015620006615787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b60805161409a620006a260003960008181610360015281816103fb015281816129a00152612a28015261409a6000f3fe608060405234801561001057600080fd5b506004361061025b5760003560e01c80638053493411610145578063c3666c36116100bd578063e8ab9ccc1161008c578063f242432a11610071578063f242432a14610580578063f2fde38b14610593578063f7ba94bd146105a657600080fd5b8063e8ab9ccc1461055a578063e985e9c51461056d57600080fd5b8063c3666c3614610503578063d539139314610516578063d547741f1461053d578063e1a8bf2c1461055057600080fd5b806391d1485411610114578063a0c76f62116100f9578063a0c76f62146104e0578063a22cb465146104e8578063b0ccc31e146104fb57600080fd5b806391d14854146104c557806395d89b41146104d857600080fd5b806380534934146104845780638bb9c5bf146104975780638da5cb5b146104aa5780638dc251e3146104b257600080fd5b80632b4c9f16116101d8578063572b6c05116101a757806361ba27da1161018c57806361ba27da1461044b5780636706467b1461045e57806373c8a9581461047157600080fd5b8063572b6c05146103eb5780635cfa92971461043857600080fd5b80632b4c9f161461035e5780632eb2c2d6146103a55780632f2ff15d146103b85780634e1273f4146103cb57600080fd5b80630e89341c1161022f578063124d91e511610214578063124d91e5146102f9578063162094c41461030c5780632a55205a1461031f57600080fd5b80630e89341c146102d3578063114ba8ee146102e657600080fd5b8062fdd58e1461026057806301ffc9a71461028657806306fdde03146102a95780630d6a5bbb146102be575b600080fd5b61027361026e366004613419565b6105b9565b6040519081526020015b60405180910390f35b610299610294366004613473565b6105d8565b604051901515815260200161027d565b6102b16105ec565b60405161027d9190613505565b6102d16102cc36600461359f565b610603565b005b6102b16102e136600461364c565b6106fe565b6102d16102f4366004613665565b610714565b6102d1610307366004613682565b61077f565b6102d161031a3660046136b7565b6107a3565b61033261032d366004613703565b610875565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161027d565b7f00000000000000000000000000000000000000000000000000000000000000005b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161027d565b6102d16103b3366004613725565b610898565b6102d16103c63660046137e4565b6108e5565b6103de6103d9366004613814565b610913565b60405161027d91906138bc565b6102996103f9366004613665565b7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102d16104463660046138cf565b610938565b6102d161045936600461364c565b6109ca565b6102d161046c366004613814565b6109e7565b6102d161047f366004613939565b610b1f565b6102d16104923660046139d3565b610c0b565b6102d16104a536600461364c565b610c2e565b610380610c49565b6102d16104c0366004613665565b610c70565b6102996104d33660046137e4565b610c8d565b6102b1610cd1565b610380610ce3565b6102d16104f6366004613a53565b610cf0565b610380610d29565b6102d1610511366004613939565b610d36565b6102737f6d696e746572000000000000000000000000000000000000000000000000000081565b6102d161054b3660046137e4565b610eae565b610273620186a081565b6102d1610568366004613a81565b610edc565b61029961057b366004613b24565b610ff6565b6102d161058e366004613b52565b611044565b6102d16105a1366004613665565b611084565b6102d16105b4366004613814565b61109f565b60006105cf83836105c8611156565b9190611184565b90505b92915050565b60006105d2826105e6611208565b90611236565b60606105fe6105f9611310565b61133e565b905090565b600061060d6113d4565b90506106437f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b919061140c565b6106f4818989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152506106ea9250611156915050565b9493929190611492565b5050505050505050565b60606105d2308361070d611310565b9190611618565b61072d61071f6113d4565b6107276116d8565b90611706565b61077c81610739611771565b9081547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b50565b61079e61078a6113d4565b848484610795611156565b939291906117e1565b505050565b6107cb6107ae611310565b6002015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610836576040517f220606710000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b8383604051610868929190613bbc565b60405180910390a2505050565b60008061088c84846108856118ae565b91906118dc565b915091505b9250929050565b60006108a26113d4565b90506108b8818a6108b1611771565b9190611986565b6108da818a8a8a8a8a8a8a8a6108cc611156565b9897969594939291906119c3565b505050505050505050565b60006108ef6113d4565b90506108fd816107276116d8565b61079e83838361090b6113de565b929190611c4c565b606061092d85858585610924611156565b93929190611d23565b90505b949350505050565b60006109426113d4565b90506109717f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b6109c28187878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109b89250611156915050565b9493929190611e32565b505050505050565b6109d561071f6113d4565b61077c816109e16118ae565b90611f10565b828114610a20576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a2b6107ae611310565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a91576040517f2206067100000000000000000000000000000000000000000000000000000000815233600482015260240161082d565b60005b83811015610b1857848482818110610aae57610aae613c09565b905060200201357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b848484818110610ae857610ae8613c09565b9050602002810190610afa9190613c38565b604051610b08929190613bbc565b60405180910390a2600101610a94565b5050505050565b610b2a61071f6113d4565b848381141580610b3a5750808214155b15610b71576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457610c03888883818110610b9157610b91613c09565b9050602002016020810190610ba69190613665565b858584818110610bb857610bb8613c09565b90506020020135888885818110610bd157610bd1613c09565b9050602002016020810190610be69190613665565b73ffffffffffffffffffffffffffffffffffffffff169190611f96565b600101610b74565b610b18610c166113d4565b8686868686610c23611156565b959493929190612023565b61077c610c396113d4565b82610c426113de565b919061219b565b60006105fe610c566116d8565b5473ffffffffffffffffffffffffffffffffffffffff1690565b610c7b61071f6113d4565b61077c81610c876118ae565b9061223f565b60006105cf8383610c9c6113de565b60009283526020908152604080842073ffffffffffffffffffffffffffffffffffffffff909316845291905290205460ff1690565b60606105fe610cde611310565b61228c565b60006105fe6107ae611310565b8015610d0857610d0882610d02611771565b9061229d565b610d25610d136113d4565b8383610d1d611156565b9291906122a7565b5050565b60006105fe610c56611771565b610d4161071f6113d4565b848381141580610d515750808214155b15610d88576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457858582818110610da557610da5613c09565b9050602002016020810190610dba9190613665565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd308a8a85818110610de857610de8613c09565b9050602002016020810190610dfd9190613665565b878786818110610e0f57610e0f613c09565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610e8b57600080fd5b505af1158015610e9f573d6000803e3d6000fd5b50505050806001019050610d8b565b6000610eb86113d4565b9050610ec6816107276116d8565b61079e838383610ed46113de565b9291906123bf565b6000610ee66113d4565b9050610f157f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b6108da818a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a9150899081908401838280828437600092019190915250610fec9250611156915050565b9493929190612489565b60006105cf8383611005611156565b919073ffffffffffffffffffffffffffffffffffffffff9182166000908152600193909301602090815260408085209290931684525290205460ff1690565b600061104e6113d4565b905061105d81886108b1611771565b61107b8188888888888861106f611156565b9695949392919061254c565b50505050505050565b61077c61108f6113d4565b826110986116d8565b91906126ef565b6110aa61071f6113d4565b828181146110e4576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156109c25761114e84848381811061110457611104613c09565b9050602002013587878481811061111d5761111d613c09565b90506020020160208101906111329190613665565b73ffffffffffffffffffffffffffffffffffffffff1690612803565b6001016110e7565b6000806105d260017f5ccf5846fa27a68fafc8e588671a68f5e67c2f9b56af4263806a4d71735e8613613ccc565b600073ffffffffffffffffffffffffffffffffffffffff83166111d3576040517fca2434a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526020928352604080822073ffffffffffffffffffffffffffffffffffffffff9390931682529190925290205490565b6000806105d260017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e613ccc565b60007c01000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611286575060006105d2565b7ffe003659000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316016112d7575060016105d2565b507fffffffff00000000000000000000000000000000000000000000000000000000166000908152602091909152604090205460ff1690565b6000806105d260017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a5613ccc565b606081600001805461134f90613cdf565b80601f016020809104026020016040519081016040528092919081815260200182805461137b90613cdf565b80156113c85780601f1061139d576101008083540402835291602001916113c8565b820191906000526020600020905b8154815290600101906020018083116113ab57829003601f168201915b50505050509050919050565b60006105fe61295d565b6000806105d260017fc8827d3282af6f37b64c3e9e6f3ac9df286ab0bb0fccd6f8661bf19adb368b23613ccc565b60008281526020848152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661079e576040517f7aa728820000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161082d565b73ffffffffffffffffffffffffffffffffffffffff84166114df576040517f021149bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82518251811461151b576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561156c57611564888787848151811061153d5761153d613c09565b602002602001015187858151811061155757611557613c09565b6020026020010151612aa4565b60010161151e565b508473ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516115e4929190613d32565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff85163b1561107b5761107b86600087878787612b75565b60028301546040517ff724dad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260248201849052606092169063f724dad790604401600060405180830381865afa158015611692573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526109309190810190613d8f565b6000806105d260017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd613ccc565b815473ffffffffffffffffffffffffffffffffffffffff828116911614610d25576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161082d565b6000806105d260017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd31613ccc565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b6117ec858486612c73565b611842576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80861660048301528416602482015260440161082d565b61184e85848484612ce8565b604080518381526020810183905260009173ffffffffffffffffffffffffffffffffffffffff86811692908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050505050565b6000806105d260017f2c0cf10337caabbd02dcf226f05f5fd19a0919a41a8df8958c39b80007826858613ccc565b825473ffffffffffffffffffffffffffffffffffffffff8116906000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1683158061192a575080155b15611938576000915061197d565b620186a084101561196257620186a06119518286613e4f565b61195b9190613e66565b915061197d565b80611970620186a086613e66565b61197a9190613e4f565b91505b50935093915050565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161461079e5761079e8383612d85565b73ffffffffffffffffffffffffffffffffffffffff8716611a10576040517fb5e8901500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84838114611a4a576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a558b8a8c612c73565b611aab576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c1660048301528a16602482015260440161082d565b60005b81811015611afb57611af38c8b8b8b8b86818110611ace57611ace613c09565b905060200201358a8a87818110611ae757611ae7613c09565b90506020020135612eac565b600101611aae565b508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8a8a8a8a604051611b769493929190613eec565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff88163b15611c3f57611c3f8a8a8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a9081908401838280828437600092019190915250612b7592505050565b5050505050505050505050565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16611d1d5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815187815292830152918316918101919091527f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d906060015b60405180910390a15b50505050565b606083828114611d5f576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8467ffffffffffffffff811115611d7857611d78613d60565b604051908082528060200260200182016040528015611da1578160200160208202803683370190505b50915060005b81811015611e2757611e02878783818110611dc457611dc4613c09565b9050602002016020810190611dd99190613665565b868684818110611deb57611deb613c09565b905060200201358a6111849092919063ffffffff16565b838281518110611e1457611e14613c09565b6020908102919091010152600101611da7565b505095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416611e7f576040517f021149bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e8b86858585612aa4565b604080518481526020810184905273ffffffffffffffffffffffffffffffffffffffff80871692600092918916917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a473ffffffffffffffffffffffffffffffffffffffff84163b156109c2576109c285600086868686613059565b620186a0811115611f50576040517fac0404080000000000000000000000000000000000000000000000000000000081526004810182905260240161082d565b81546bffffffffffffffffffffffff909116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff909116179055565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261079e908490613177565b8281811461205d576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612068888789612c73565b6120be576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80891660048301528716602482015260440161082d565b60005b8181101561210d5761210589888888858181106120e0576120e0613c09565b905060200201358787868181106120f9576120f9613c09565b90506020020135612ce8565b6001016120c1565b50600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb888888886040516121899493929190613eec565b60405180910390a45050505050505050565b6121a683828461140c565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518481529182018390528101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9060600160405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff811661179f576040517f16de0c8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081600101805461134f90613cdf565b610d258282612d85565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612324576040517ffb0fdf6100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082d565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260018701602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff1615611d1d5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815187815292830152918316918101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b90606001611d14565b835183518114158061249c575082518114155b156124d3576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457612544878783815181106124f4576124f4613c09565b602002602001015187848151811061250e5761250e613c09565b602002602001015187858151811061252857612528613c09565b6020026020010151878d611e329095949392919063ffffffff16565b6001016124d6565b73ffffffffffffffffffffffffffffffffffffffff8516612599576040517fb5e8901500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125a4888789612c73565b6125fa576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80891660048301528716602482015260440161082d565b6126078887878787612eac565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628787604051612686929190918252602082015260400190565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff85163b156106f4576106f4878787878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061305992505050565b825473ffffffffffffffffffffffffffffffffffffffff908116908316811461275c576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082d565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611d1d5783547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178655604051908316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350505050565b8047101561286d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161082d565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146128c7576040519150601f19603f3d011682016040523d82523d6000602084013e6128cc565b606091505b505090508061079e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161082d565b60003332148061296d5750601836105b1561297757503390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c7f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16331480612a9357506040517f8929a8ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301527f00000000000000000000000000000000000000000000000000000000000000001690638929a8ca90604401602060405180830381865afa158015612a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a939190613f13565b15612a9d57919050565b3391505090565b8015611d1d5760008281526020858152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902054818101818111612b41576040517f42fb00bc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260248101859052604481018390526064810184905260840161082d565b60009384526020958652604080852073ffffffffffffffffffffffffffffffffffffffff9690961685529490955250502055565b6040517fbc197c81000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063bc197c8190612bd1908a908a90899089908990600401613f30565b6020604051808303816000875af1158015612bf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c149190613f9b565b7fffffffff0000000000000000000000000000000000000000000000000000000016146109c2578383836040517fc287817e00000000000000000000000000000000000000000000000000000000815260040161082d93929190613fb8565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16148061093057505073ffffffffffffffffffffffffffffffffffffffff9182166000908152600193909301602090815260408085209290931684525290205460ff1690565b8015611d1d5760008281526020858152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902054818103818110612b41576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260248101859052604481018390526064810184905260840161082d565b815473ffffffffffffffffffffffffffffffffffffffff168015801590612dc3575060008173ffffffffffffffffffffffffffffffffffffffff163b115b1561079e576040517fc617113400000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282169063c617113490604401602060405180830381865afa158015612e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5e9190613f13565b61079e576040517fede71dcc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161082d565b8015610b185760008281526020868152604080832073ffffffffffffffffffffffffffffffffffffffff88168452909152902054818103818110612f49576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8716600482015260248101859052604481018390526064810184905260840161082d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461107b5760008481526020888152604080832073ffffffffffffffffffffffffffffffffffffffff89168452909152902054838101818111613013576040517f42fb00bc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8816600482015260248101879052604481018390526064810186905260840161082d565b600086815260208a8152604080832073ffffffffffffffffffffffffffffffffffffffff808d1685528184528285208890558b1684529091529020555050505050505050565b6040517ff23a6e61000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063f23a6e61906130b5908a908a90899089908990600401614003565b6020604051808303816000875af11580156130d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f89190613f9b565b7fffffffff0000000000000000000000000000000000000000000000000000000016146109c2576040517f40f39d3800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602481018490526044810183905260640161082d565b60006131d9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166132869092919063ffffffff16565b90508051600014806131fa5750808060200190518101906131fa9190613f13565b61079e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161082d565b60606109308484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516132ba9190614048565b60006040518083038185875af1925050503d80600081146132f7576040519150601f19603f3d011682016040523d82523d6000602084013e6132fc565b606091505b509150915061330d87838387613318565b979650505050505050565b606083156133ae5782516000036133a75773ffffffffffffffffffffffffffffffffffffffff85163b6133a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161082d565b5081610930565b61093083838151156133c35781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161082d9190613505565b73ffffffffffffffffffffffffffffffffffffffff8116811461077c57600080fd5b6000806040838503121561342c57600080fd5b8235613437816133f7565b946020939093013593505050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461077c57600080fd5b60006020828403121561348557600080fd5b813561349081613445565b9392505050565b60005b838110156134b257818101518382015260200161349a565b50506000910152565b600081518084526134d3816020860160208601613497565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006105cf60208301846134bb565b60008083601f84011261352a57600080fd5b50813567ffffffffffffffff81111561354257600080fd5b6020830191508360208260051b850101111561089157600080fd5b60008083601f84011261356f57600080fd5b50813567ffffffffffffffff81111561358757600080fd5b60208301915083602082850101111561089157600080fd5b60008060008060008060006080888a0312156135ba57600080fd5b87356135c5816133f7565b9650602088013567ffffffffffffffff808211156135e257600080fd5b6135ee8b838c01613518565b909850965060408a013591508082111561360757600080fd5b6136138b838c01613518565b909650945060608a013591508082111561362c57600080fd5b506136398a828b0161355d565b989b979a50959850939692959293505050565b60006020828403121561365e57600080fd5b5035919050565b60006020828403121561367757600080fd5b8135613490816133f7565b60008060006060848603121561369757600080fd5b83356136a2816133f7565b95602085013595506040909401359392505050565b6000806000604084860312156136cc57600080fd5b83359250602084013567ffffffffffffffff8111156136ea57600080fd5b6136f68682870161355d565b9497909650939450505050565b6000806040838503121561371657600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b03121561374157600080fd5b883561374c816133f7565b9750602089013561375c816133f7565b9650604089013567ffffffffffffffff8082111561377957600080fd5b6137858c838d01613518565b909850965060608b013591508082111561379e57600080fd5b6137aa8c838d01613518565b909650945060808b01359150808211156137c357600080fd5b506137d08b828c0161355d565b999c989b5096995094979396929594505050565b600080604083850312156137f757600080fd5b823591506020830135613809816133f7565b809150509250929050565b6000806000806040858703121561382a57600080fd5b843567ffffffffffffffff8082111561384257600080fd5b61384e88838901613518565b9096509450602087013591508082111561386757600080fd5b5061387487828801613518565b95989497509550505050565b60008151808452602080850194506020840160005b838110156138b157815187529582019590820190600101613895565b509495945050505050565b6020815260006105cf6020830184613880565b6000806000806000608086880312156138e757600080fd5b85356138f2816133f7565b94506020860135935060408601359250606086013567ffffffffffffffff81111561391c57600080fd5b6139288882890161355d565b969995985093965092949392505050565b6000806000806000806060878903121561395257600080fd5b863567ffffffffffffffff8082111561396a57600080fd5b6139768a838b01613518565b9098509650602089013591508082111561398f57600080fd5b61399b8a838b01613518565b909650945060408901359150808211156139b457600080fd5b506139c189828a01613518565b979a9699509497509295939492505050565b6000806000806000606086880312156139eb57600080fd5b85356139f6816133f7565b9450602086013567ffffffffffffffff80821115613a1357600080fd5b613a1f89838a01613518565b90965094506040880135915080821115613a3857600080fd5b5061392888828901613518565b801515811461077c57600080fd5b60008060408385031215613a6657600080fd5b8235613a71816133f7565b9150602083013561380981613a45565b6000806000806000806000806080898b031215613a9d57600080fd5b883567ffffffffffffffff80821115613ab557600080fd5b613ac18c838d01613518565b909a50985060208b0135915080821115613ada57600080fd5b613ae68c838d01613518565b909850965060408b0135915080821115613aff57600080fd5b613b0b8c838d01613518565b909650945060608b01359150808211156137c357600080fd5b60008060408385031215613b3757600080fd5b8235613b42816133f7565b91506020830135613809816133f7565b60008060008060008060a08789031215613b6b57600080fd5b8635613b76816133f7565b95506020870135613b86816133f7565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bb057600080fd5b6139c189828a0161355d565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613c6d57600080fd5b83018035915067ffffffffffffffff821115613c8857600080fd5b60200191503681900382131561089157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105d2576105d2613c9d565b600181811c90821680613cf357607f821691505b602082108103613d2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b604081526000613d456040830185613880565b8281036020840152613d578185613880565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215613da157600080fd5b815167ffffffffffffffff80821115613db957600080fd5b818401915084601f830112613dcd57600080fd5b815181811115613ddf57613ddf613d60565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715613e2557613e25613d60565b81604052828152876020848701011115613e3e57600080fd5b61330d836020830160208801613497565b80820281158282048414176105d2576105d2613c9d565b600082613e9c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ed357600080fd5b8260051b80836020870137939093016020019392505050565b604081526000613f00604083018688613ea1565b828103602084015261330d818587613ea1565b600060208284031215613f2557600080fd5b815161349081613a45565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a06040830152613f6960a0830186613880565b8281036060840152613f7b8186613880565b90508281036080840152613f8f81856134bb565b98975050505050505050565b600060208284031215613fad57600080fd5b815161349081613445565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000613fe76060830185613880565b8281036040840152613ff98185613880565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a0608083015261330d60a08301846134bb565b6000825161405a818460208701613497565b919091019291505056fea2646970667358221220e9680e560ccf9b231c3045d8bb0d991ca6013fac9803a3900b0ade6e46854f8064736f6c6343000816003300000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000faf5d68fc49f647b7bb61b9fd02c3a96f97aedf9000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e0000000000000000000000003f547f87251710f70109ae0409d461b2707096930000000000000000000000000000000000000000000000000000000000000018416e69636865737320546865204d697373696e67204f7262000000000000000000000000000000000000000000000000000000000000000000000000000000044d4f524200000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b506004361061025b5760003560e01c80638053493411610145578063c3666c36116100bd578063e8ab9ccc1161008c578063f242432a11610071578063f242432a14610580578063f2fde38b14610593578063f7ba94bd146105a657600080fd5b8063e8ab9ccc1461055a578063e985e9c51461056d57600080fd5b8063c3666c3614610503578063d539139314610516578063d547741f1461053d578063e1a8bf2c1461055057600080fd5b806391d1485411610114578063a0c76f62116100f9578063a0c76f62146104e0578063a22cb465146104e8578063b0ccc31e146104fb57600080fd5b806391d14854146104c557806395d89b41146104d857600080fd5b806380534934146104845780638bb9c5bf146104975780638da5cb5b146104aa5780638dc251e3146104b257600080fd5b80632b4c9f16116101d8578063572b6c05116101a757806361ba27da1161018c57806361ba27da1461044b5780636706467b1461045e57806373c8a9581461047157600080fd5b8063572b6c05146103eb5780635cfa92971461043857600080fd5b80632b4c9f161461035e5780632eb2c2d6146103a55780632f2ff15d146103b85780634e1273f4146103cb57600080fd5b80630e89341c1161022f578063124d91e511610214578063124d91e5146102f9578063162094c41461030c5780632a55205a1461031f57600080fd5b80630e89341c146102d3578063114ba8ee146102e657600080fd5b8062fdd58e1461026057806301ffc9a71461028657806306fdde03146102a95780630d6a5bbb146102be575b600080fd5b61027361026e366004613419565b6105b9565b6040519081526020015b60405180910390f35b610299610294366004613473565b6105d8565b604051901515815260200161027d565b6102b16105ec565b60405161027d9190613505565b6102d16102cc36600461359f565b610603565b005b6102b16102e136600461364c565b6106fe565b6102d16102f4366004613665565b610714565b6102d1610307366004613682565b61077f565b6102d161031a3660046136b7565b6107a3565b61033261032d366004613703565b610875565b6040805173ffffffffffffffffffffffffffffffffffffffff909316835260208301919091520161027d565b7f0000000000000000000000003f547f87251710f70109ae0409d461b2707096935b60405173ffffffffffffffffffffffffffffffffffffffff909116815260200161027d565b6102d16103b3366004613725565b610898565b6102d16103c63660046137e4565b6108e5565b6103de6103d9366004613814565b610913565b60405161027d91906138bc565b6102996103f9366004613665565b7f0000000000000000000000003f547f87251710f70109ae0409d461b27070969373ffffffffffffffffffffffffffffffffffffffff90811691161490565b6102d16104463660046138cf565b610938565b6102d161045936600461364c565b6109ca565b6102d161046c366004613814565b6109e7565b6102d161047f366004613939565b610b1f565b6102d16104923660046139d3565b610c0b565b6102d16104a536600461364c565b610c2e565b610380610c49565b6102d16104c0366004613665565b610c70565b6102996104d33660046137e4565b610c8d565b6102b1610cd1565b610380610ce3565b6102d16104f6366004613a53565b610cf0565b610380610d29565b6102d1610511366004613939565b610d36565b6102737f6d696e746572000000000000000000000000000000000000000000000000000081565b6102d161054b3660046137e4565b610eae565b610273620186a081565b6102d1610568366004613a81565b610edc565b61029961057b366004613b24565b610ff6565b6102d161058e366004613b52565b611044565b6102d16105a1366004613665565b611084565b6102d16105b4366004613814565b61109f565b60006105cf83836105c8611156565b9190611184565b90505b92915050565b60006105d2826105e6611208565b90611236565b60606105fe6105f9611310565b61133e565b905090565b600061060d6113d4565b90506106437f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b919061140c565b6106f4818989898080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a91508990819084018382808284376000920191909152506106ea9250611156915050565b9493929190611492565b5050505050505050565b60606105d2308361070d611310565b9190611618565b61072d61071f6113d4565b6107276116d8565b90611706565b61077c81610739611771565b9081547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b50565b61079e61078a6113d4565b848484610795611156565b939291906117e1565b505050565b6107cb6107ae611310565b6002015473ffffffffffffffffffffffffffffffffffffffff1690565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610836576040517f220606710000000000000000000000000000000000000000000000000000000081523360048201526024015b60405180910390fd5b827f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b8383604051610868929190613bbc565b60405180910390a2505050565b60008061088c84846108856118ae565b91906118dc565b915091505b9250929050565b60006108a26113d4565b90506108b8818a6108b1611771565b9190611986565b6108da818a8a8a8a8a8a8a8a6108cc611156565b9897969594939291906119c3565b505050505050505050565b60006108ef6113d4565b90506108fd816107276116d8565b61079e83838361090b6113de565b929190611c4c565b606061092d85858585610924611156565b93929190611d23565b90505b949350505050565b60006109426113d4565b90506109717f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b6109c28187878787878080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152506109b89250611156915050565b9493929190611e32565b505050505050565b6109d561071f6113d4565b61077c816109e16118ae565b90611f10565b828114610a20576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610a2b6107ae611310565b73ffffffffffffffffffffffffffffffffffffffff163373ffffffffffffffffffffffffffffffffffffffff1614610a91576040517f2206067100000000000000000000000000000000000000000000000000000000815233600482015260240161082d565b60005b83811015610b1857848482818110610aae57610aae613c09565b905060200201357f6bb7ff708619ba0610cba295a58592e0451dee2622938c8755667688daf3529b848484818110610ae857610ae8613c09565b9050602002810190610afa9190613c38565b604051610b08929190613bbc565b60405180910390a2600101610a94565b5050505050565b610b2a61071f6113d4565b848381141580610b3a5750808214155b15610b71576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457610c03888883818110610b9157610b91613c09565b9050602002016020810190610ba69190613665565b858584818110610bb857610bb8613c09565b90506020020135888885818110610bd157610bd1613c09565b9050602002016020810190610be69190613665565b73ffffffffffffffffffffffffffffffffffffffff169190611f96565b600101610b74565b610b18610c166113d4565b8686868686610c23611156565b959493929190612023565b61077c610c396113d4565b82610c426113de565b919061219b565b60006105fe610c566116d8565b5473ffffffffffffffffffffffffffffffffffffffff1690565b610c7b61071f6113d4565b61077c81610c876118ae565b9061223f565b60006105cf8383610c9c6113de565b60009283526020908152604080842073ffffffffffffffffffffffffffffffffffffffff909316845291905290205460ff1690565b60606105fe610cde611310565b61228c565b60006105fe6107ae611310565b8015610d0857610d0882610d02611771565b9061229d565b610d25610d136113d4565b8383610d1d611156565b9291906122a7565b5050565b60006105fe610c56611771565b610d4161071f6113d4565b848381141580610d515750808214155b15610d88576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457858582818110610da557610da5613c09565b9050602002016020810190610dba9190613665565b73ffffffffffffffffffffffffffffffffffffffff166323b872dd308a8a85818110610de857610de8613c09565b9050602002016020810190610dfd9190613665565b878786818110610e0f57610e0f613c09565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e088901b16815273ffffffffffffffffffffffffffffffffffffffff958616600482015294909316602485015250602090910201356044820152606401600060405180830381600087803b158015610e8b57600080fd5b505af1158015610e9f573d6000803e3d6000fd5b50505050806001019050610d8b565b6000610eb86113d4565b9050610ec6816107276116d8565b61079e838383610ed46113de565b9291906123bf565b6000610ee66113d4565b9050610f157f6d696e74657200000000000000000000000000000000000000000000000000008261063c6113de565b6108da818a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020808d0282810182019093528c82529093508c92508b91829185019084908082843760009201919091525050604080516020601f8c018190048102820181019092528a815292508a9150899081908401838280828437600092019190915250610fec9250611156915050565b9493929190612489565b60006105cf8383611005611156565b919073ffffffffffffffffffffffffffffffffffffffff9182166000908152600193909301602090815260408085209290931684525290205460ff1690565b600061104e6113d4565b905061105d81886108b1611771565b61107b8188888888888861106f611156565b9695949392919061254c565b50505050505050565b61077c61108f6113d4565b826110986116d8565b91906126ef565b6110aa61071f6113d4565b828181146110e4576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156109c25761114e84848381811061110457611104613c09565b9050602002013587878481811061111d5761111d613c09565b90506020020160208101906111329190613665565b73ffffffffffffffffffffffffffffffffffffffff1690612803565b6001016110e7565b6000806105d260017f5ccf5846fa27a68fafc8e588671a68f5e67c2f9b56af4263806a4d71735e8613613ccc565b600073ffffffffffffffffffffffffffffffffffffffff83166111d3576040517fca2434a500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b5060009081526020928352604080822073ffffffffffffffffffffffffffffffffffffffff9390931682529190925290205490565b6000806105d260017fca9d3e17f264b0f3984e2634e94adb37fa3e6a8103f06aeae6fa59e21c769f5e613ccc565b60007c01000000000000000000000000000000000000000000000000000000007fffffffff00000000000000000000000000000000000000000000000000000000831601611286575060006105d2565b7ffe003659000000000000000000000000000000000000000000000000000000007fffffffff000000000000000000000000000000000000000000000000000000008316016112d7575060016105d2565b507fffffffff00000000000000000000000000000000000000000000000000000000166000908152602091909152604090205460ff1690565b6000806105d260017f7ea68fd2dcf1c056b94db6a0a537aa80d26fa9ab1eacd85da1ba0b61b7e7a8a5613ccc565b606081600001805461134f90613cdf565b80601f016020809104026020016040519081016040528092919081815260200182805461137b90613cdf565b80156113c85780601f1061139d576101008083540402835291602001916113c8565b820191906000526020600020905b8154815290600101906020018083116113ab57829003601f168201915b50505050509050919050565b60006105fe61295d565b6000806105d260017fc8827d3282af6f37b64c3e9e6f3ac9df286ab0bb0fccd6f8661bf19adb368b23613ccc565b60008281526020848152604080832073ffffffffffffffffffffffffffffffffffffffff8516845290915290205460ff1661079e576040517f7aa728820000000000000000000000000000000000000000000000000000000081526004810183905273ffffffffffffffffffffffffffffffffffffffff8216602482015260440161082d565b73ffffffffffffffffffffffffffffffffffffffff84166114df576040517f021149bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b82518251811461151b576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b8181101561156c57611564888787848151811061153d5761153d613c09565b602002602001015187858151811061155757611557613c09565b6020026020010151612aa4565b60010161151e565b508473ffffffffffffffffffffffffffffffffffffffff16600073ffffffffffffffffffffffffffffffffffffffff168773ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb87876040516115e4929190613d32565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff85163b1561107b5761107b86600087878787612b75565b60028301546040517ff724dad700000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff848116600483015260248201849052606092169063f724dad790604401600060405180830381865afa158015611692573d6000803e3d6000fd5b505050506040513d6000823e601f3d9081017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe01682016040526109309190810190613d8f565b6000806105d260017fc9ed16f33ab3a66c84bfd83099ccb2a8845871e2e1c1928f63797152f0fd54cd613ccc565b815473ffffffffffffffffffffffffffffffffffffffff828116911614610d25576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8216600482015260240161082d565b6000806105d260017f609b85bcafa81ecfaf3ff62cdde2c6c9082a68dbe4922f07399c706bdeb7cd31613ccc565b81547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff91909116179055565b6117ec858486612c73565b611842576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80861660048301528416602482015260440161082d565b61184e85848484612ce8565b604080518381526020810183905260009173ffffffffffffffffffffffffffffffffffffffff86811692908816917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a45050505050565b6000806105d260017f2c0cf10337caabbd02dcf226f05f5fd19a0919a41a8df8958c39b80007826858613ccc565b825473ffffffffffffffffffffffffffffffffffffffff8116906000907401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1683158061192a575080155b15611938576000915061197d565b620186a084101561196257620186a06119518286613e4f565b61195b9190613e66565b915061197d565b80611970620186a086613e66565b61197a9190613e4f565b91505b50935093915050565b8073ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff161461079e5761079e8383612d85565b73ffffffffffffffffffffffffffffffffffffffff8716611a10576040517fb5e8901500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b84838114611a4a576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611a558b8a8c612c73565b611aab576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff808c1660048301528a16602482015260440161082d565b60005b81811015611afb57611af38c8b8b8b8b86818110611ace57611ace613c09565b905060200201358a8a87818110611ae757611ae7613c09565b90506020020135612eac565b600101611aae565b508773ffffffffffffffffffffffffffffffffffffffff168973ffffffffffffffffffffffffffffffffffffffff168b73ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb8a8a8a8a604051611b769493929190613eec565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff88163b15611c3f57611c3f8a8a8a8a8a8080602002602001604051908101604052809392919081815260200183836020028082843760009201919091525050604080516020808e0282810182019093528d82529093508d92508c91829185019084908082843760009201919091525050604080516020601f8d018190048102820181019092528b815292508b91508a9081908401838280828437600092019190915250612b7592505050565b5050505050505050505050565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff16611d1d5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055815187815292830152918316918101919091527f2f8788117e7eff1d82e926ec794901d17c78024a50270940304540a733656f0d906060015b60405180910390a15b50505050565b606083828114611d5f576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8467ffffffffffffffff811115611d7857611d78613d60565b604051908082528060200260200182016040528015611da1578160200160208202803683370190505b50915060005b81811015611e2757611e02878783818110611dc457611dc4613c09565b9050602002016020810190611dd99190613665565b868684818110611deb57611deb613c09565b905060200201358a6111849092919063ffffffff16565b838281518110611e1457611e14613c09565b6020908102919091010152600101611da7565b505095945050505050565b73ffffffffffffffffffffffffffffffffffffffff8416611e7f576040517f021149bd00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611e8b86858585612aa4565b604080518481526020810184905273ffffffffffffffffffffffffffffffffffffffff80871692600092918916917fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f62910160405180910390a473ffffffffffffffffffffffffffffffffffffffff84163b156109c2576109c285600086868686613059565b620186a0811115611f50576040517fac0404080000000000000000000000000000000000000000000000000000000081526004810182905260240161082d565b81546bffffffffffffffffffffffff909116740100000000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff909116179055565b6040805173ffffffffffffffffffffffffffffffffffffffff8416602482015260448082018490528251808303909101815260649091019091526020810180517bffffffffffffffffffffffffffffffffffffffffffffffffffffffff167fa9059cbb0000000000000000000000000000000000000000000000000000000017905261079e908490613177565b8281811461205d576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b612068888789612c73565b6120be576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80891660048301528716602482015260440161082d565b60005b8181101561210d5761210589888888858181106120e0576120e0613c09565b905060200201358787868181106120f9576120f9613c09565b90506020020135612ce8565b6001016120c1565b50600073ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167f4a39dc06d4c0dbc64b70af90fd698a233a518aa5d07e595d983b8c0526c8f7fb888888886040516121899493929190613eec565b60405180910390a45050505050505050565b6121a683828461140c565b60008181526020848152604080832073ffffffffffffffffffffffffffffffffffffffff86168085529083529281902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0016905580518481529182018390528101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b9060600160405180910390a1505050565b73ffffffffffffffffffffffffffffffffffffffff811661179f576040517f16de0c8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b606081600101805461134f90613cdf565b610d258282612d85565b8273ffffffffffffffffffffffffffffffffffffffff168273ffffffffffffffffffffffffffffffffffffffff1603612324576040517ffb0fdf6100000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082d565b73ffffffffffffffffffffffffffffffffffffffff838116600081815260018701602090815260408083209487168084529482529182902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff001686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a350505050565b60008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8616845290915290205460ff1615611d1d5760008381526020858152604080832073ffffffffffffffffffffffffffffffffffffffff8681168086529184529382902080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055815187815292830152918316918101919091527ff6391f5c32d9c69d2a47ea670b442974b53935d1edc7fd64eb21e047a839171b90606001611d14565b835183518114158061249c575082518114155b156124d3576040517f6582533600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b818110156106f457612544878783815181106124f4576124f4613c09565b602002602001015187848151811061250e5761250e613c09565b602002602001015187858151811061252857612528613c09565b6020026020010151878d611e329095949392919063ffffffff16565b6001016124d6565b73ffffffffffffffffffffffffffffffffffffffff8516612599576040517fb5e8901500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6125a4888789612c73565b6125fa576040517f05bbb9c400000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff80891660048301528716602482015260440161082d565b6126078887878787612eac565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff168873ffffffffffffffffffffffffffffffffffffffff167fc3d58168c5ae7397731d063d5bbf3d657854427343f4c083240f7aacaa2d0f628787604051612686929190918252602082015260400190565b60405180910390a473ffffffffffffffffffffffffffffffffffffffff85163b156106f4576106f4878787878787878080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061305992505050565b825473ffffffffffffffffffffffffffffffffffffffff908116908316811461275c576040517f2ef4875e00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8416600482015260240161082d565b8173ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614611d1d5783547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff8381169182178655604051908316907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350505050565b8047101561286d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a20696e73756666696369656e742062616c616e6365000000604482015260640161082d565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d80600081146128c7576040519150601f19603f3d011682016040523d82523d6000602084013e6128cc565b606091505b505090508061079e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152603a60248201527f416464726573733a20756e61626c6520746f2073656e642076616c75652c207260448201527f6563697069656e74206d61792068617665207265766572746564000000000000606482015260840161082d565b60003332148061296d5750601836105b1561297757503390565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffec36013560601c7f0000000000000000000000003f547f87251710f70109ae0409d461b27070969373ffffffffffffffffffffffffffffffffffffffff16331480612a9357506040517f8929a8ca00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff82811660048301523360248301527f0000000000000000000000003f547f87251710f70109ae0409d461b2707096931690638929a8ca90604401602060405180830381865afa158015612a6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612a939190613f13565b15612a9d57919050565b3391505090565b8015611d1d5760008281526020858152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902054818101818111612b41576040517f42fb00bc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260248101859052604481018390526064810184905260840161082d565b60009384526020958652604080852073ffffffffffffffffffffffffffffffffffffffff9690961685529490955250502055565b6040517fbc197c81000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063bc197c8190612bd1908a908a90899089908990600401613f30565b6020604051808303816000875af1158015612bf0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612c149190613f9b565b7fffffffff0000000000000000000000000000000000000000000000000000000016146109c2578383836040517fc287817e00000000000000000000000000000000000000000000000000000000815260040161082d93929190613fb8565b60008173ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16148061093057505073ffffffffffffffffffffffffffffffffffffffff9182166000908152600193909301602090815260408085209290931684525290205460ff1690565b8015611d1d5760008281526020858152604080832073ffffffffffffffffffffffffffffffffffffffff87168452909152902054818103818110612b41576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8616600482015260248101859052604481018390526064810184905260840161082d565b815473ffffffffffffffffffffffffffffffffffffffff168015801590612dc3575060008173ffffffffffffffffffffffffffffffffffffffff163b115b1561079e576040517fc617113400000000000000000000000000000000000000000000000000000000815230600482015273ffffffffffffffffffffffffffffffffffffffff838116602483015282169063c617113490604401602060405180830381865afa158015612e3a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5e9190613f13565b61079e576040517fede71dcc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8316600482015260240161082d565b8015610b185760008281526020868152604080832073ffffffffffffffffffffffffffffffffffffffff88168452909152902054818103818110612f49576040517f03dee4c500000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8716600482015260248101859052604481018390526064810184905260840161082d565b8473ffffffffffffffffffffffffffffffffffffffff168673ffffffffffffffffffffffffffffffffffffffff161461107b5760008481526020888152604080832073ffffffffffffffffffffffffffffffffffffffff89168452909152902054838101818111613013576040517f42fb00bc00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8816600482015260248101879052604481018390526064810186905260840161082d565b600086815260208a8152604080832073ffffffffffffffffffffffffffffffffffffffff808d1685528184528285208890558b1684529091529020555050505050505050565b6040517ff23a6e61000000000000000000000000000000000000000000000000000000008082529073ffffffffffffffffffffffffffffffffffffffff86169063f23a6e61906130b5908a908a90899089908990600401614003565b6020604051808303816000875af11580156130d4573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906130f89190613f9b565b7fffffffff0000000000000000000000000000000000000000000000000000000016146109c2576040517f40f39d3800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff85166004820152602481018490526044810183905260640161082d565b60006131d9826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c65648152508573ffffffffffffffffffffffffffffffffffffffff166132869092919063ffffffff16565b90508051600014806131fa5750808060200190518101906131fa9190613f13565b61079e576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e60448201527f6f74207375636365656400000000000000000000000000000000000000000000606482015260840161082d565b60606109308484600085856000808673ffffffffffffffffffffffffffffffffffffffff1685876040516132ba9190614048565b60006040518083038185875af1925050503d80600081146132f7576040519150601f19603f3d011682016040523d82523d6000602084013e6132fc565b606091505b509150915061330d87838387613318565b979650505050505050565b606083156133ae5782516000036133a75773ffffffffffffffffffffffffffffffffffffffff85163b6133a7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e7472616374000000604482015260640161082d565b5081610930565b61093083838151156133c35781518083602001fd5b806040517f08c379a000000000000000000000000000000000000000000000000000000000815260040161082d9190613505565b73ffffffffffffffffffffffffffffffffffffffff8116811461077c57600080fd5b6000806040838503121561342c57600080fd5b8235613437816133f7565b946020939093013593505050565b7fffffffff000000000000000000000000000000000000000000000000000000008116811461077c57600080fd5b60006020828403121561348557600080fd5b813561349081613445565b9392505050565b60005b838110156134b257818101518382015260200161349a565b50506000910152565b600081518084526134d3816020860160208601613497565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006105cf60208301846134bb565b60008083601f84011261352a57600080fd5b50813567ffffffffffffffff81111561354257600080fd5b6020830191508360208260051b850101111561089157600080fd5b60008083601f84011261356f57600080fd5b50813567ffffffffffffffff81111561358757600080fd5b60208301915083602082850101111561089157600080fd5b60008060008060008060006080888a0312156135ba57600080fd5b87356135c5816133f7565b9650602088013567ffffffffffffffff808211156135e257600080fd5b6135ee8b838c01613518565b909850965060408a013591508082111561360757600080fd5b6136138b838c01613518565b909650945060608a013591508082111561362c57600080fd5b506136398a828b0161355d565b989b979a50959850939692959293505050565b60006020828403121561365e57600080fd5b5035919050565b60006020828403121561367757600080fd5b8135613490816133f7565b60008060006060848603121561369757600080fd5b83356136a2816133f7565b95602085013595506040909401359392505050565b6000806000604084860312156136cc57600080fd5b83359250602084013567ffffffffffffffff8111156136ea57600080fd5b6136f68682870161355d565b9497909650939450505050565b6000806040838503121561371657600080fd5b50508035926020909101359150565b60008060008060008060008060a0898b03121561374157600080fd5b883561374c816133f7565b9750602089013561375c816133f7565b9650604089013567ffffffffffffffff8082111561377957600080fd5b6137858c838d01613518565b909850965060608b013591508082111561379e57600080fd5b6137aa8c838d01613518565b909650945060808b01359150808211156137c357600080fd5b506137d08b828c0161355d565b999c989b5096995094979396929594505050565b600080604083850312156137f757600080fd5b823591506020830135613809816133f7565b809150509250929050565b6000806000806040858703121561382a57600080fd5b843567ffffffffffffffff8082111561384257600080fd5b61384e88838901613518565b9096509450602087013591508082111561386757600080fd5b5061387487828801613518565b95989497509550505050565b60008151808452602080850194506020840160005b838110156138b157815187529582019590820190600101613895565b509495945050505050565b6020815260006105cf6020830184613880565b6000806000806000608086880312156138e757600080fd5b85356138f2816133f7565b94506020860135935060408601359250606086013567ffffffffffffffff81111561391c57600080fd5b6139288882890161355d565b969995985093965092949392505050565b6000806000806000806060878903121561395257600080fd5b863567ffffffffffffffff8082111561396a57600080fd5b6139768a838b01613518565b9098509650602089013591508082111561398f57600080fd5b61399b8a838b01613518565b909650945060408901359150808211156139b457600080fd5b506139c189828a01613518565b979a9699509497509295939492505050565b6000806000806000606086880312156139eb57600080fd5b85356139f6816133f7565b9450602086013567ffffffffffffffff80821115613a1357600080fd5b613a1f89838a01613518565b90965094506040880135915080821115613a3857600080fd5b5061392888828901613518565b801515811461077c57600080fd5b60008060408385031215613a6657600080fd5b8235613a71816133f7565b9150602083013561380981613a45565b6000806000806000806000806080898b031215613a9d57600080fd5b883567ffffffffffffffff80821115613ab557600080fd5b613ac18c838d01613518565b909a50985060208b0135915080821115613ada57600080fd5b613ae68c838d01613518565b909850965060408b0135915080821115613aff57600080fd5b613b0b8c838d01613518565b909650945060608b01359150808211156137c357600080fd5b60008060408385031215613b3757600080fd5b8235613b42816133f7565b91506020830135613809816133f7565b60008060008060008060a08789031215613b6b57600080fd5b8635613b76816133f7565b95506020870135613b86816133f7565b94506040870135935060608701359250608087013567ffffffffffffffff811115613bb057600080fd5b6139c189828a0161355d565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b60008083357fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe1843603018112613c6d57600080fd5b83018035915067ffffffffffffffff821115613c8857600080fd5b60200191503681900382131561089157600080fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b818103818111156105d2576105d2613c9d565b600181811c90821680613cf357607f821691505b602082108103613d2c577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b604081526000613d456040830185613880565b8281036020840152613d578185613880565b95945050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600060208284031215613da157600080fd5b815167ffffffffffffffff80821115613db957600080fd5b818401915084601f830112613dcd57600080fd5b815181811115613ddf57613ddf613d60565b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0908116603f01168101908382118183101715613e2557613e25613d60565b81604052828152876020848701011115613e3e57600080fd5b61330d836020830160208801613497565b80820281158282048414176105d2576105d2613c9d565b600082613e9c577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b81835260007f07ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff831115613ed357600080fd5b8260051b80836020870137939093016020019392505050565b604081526000613f00604083018688613ea1565b828103602084015261330d818587613ea1565b600060208284031215613f2557600080fd5b815161349081613a45565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525060a06040830152613f6960a0830186613880565b8281036060840152613f7b8186613880565b90508281036080840152613f8f81856134bb565b98975050505050505050565b600060208284031215613fad57600080fd5b815161349081613445565b73ffffffffffffffffffffffffffffffffffffffff84168152606060208201526000613fe76060830185613880565b8281036040840152613ff98185613880565b9695505050505050565b600073ffffffffffffffffffffffffffffffffffffffff808816835280871660208401525084604083015283606083015260a0608083015261330d60a08301846134bb565b6000825161405a818460208701613497565b919091019291505056fea2646970667358221220e9680e560ccf9b231c3045d8bb0d991ca6013fac9803a3900b0ade6e46854f8064736f6c63430008160033

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

00000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000faf5d68fc49f647b7bb61b9fd02c3a96f97aedf9000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e0000000000000000000000003f547f87251710f70109ae0409d461b2707096930000000000000000000000000000000000000000000000000000000000000018416e69636865737320546865204d697373696e67204f7262000000000000000000000000000000000000000000000000000000000000000000000000000000044d4f524200000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : tokenName (string): Anichess The Missing Orb
Arg [1] : tokenSymbol (string): MORB
Arg [2] : metadataResolver (address): 0xfaF5d68FC49f647B7BB61B9FD02c3a96f97AEdF9
Arg [3] : filterRegistry (address): 0x000000000000AAeB6D7670E522A718067333cd4E
Arg [4] : forwarderRegistry (address): 0x3f547F87251710F70109Ae0409d461b270709693

-----Encoded View---------------
9 Constructor Arguments found :
Arg [0] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000e0
Arg [2] : 000000000000000000000000faf5d68fc49f647b7bb61b9fd02c3a96f97aedf9
Arg [3] : 000000000000000000000000000000000000aaeb6d7670e522a718067333cd4e
Arg [4] : 0000000000000000000000003f547f87251710f70109ae0409d461b270709693
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000018
Arg [6] : 416e69636865737320546865204d697373696e67204f72620000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [8] : 4d4f524200000000000000000000000000000000000000000000000000000000


Block Transaction Gas Used Reward
view all blocks produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading
Loading...
Loading

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.