ETH Price: $2,397.56 (-0.82%)

Transaction Decoder

Block:
18333956 at Oct-12-2023 11:11:59 AM +UTC
Transaction Fee:
0.000477873115385776 ETH $1.15
Gas Used:
87,109 Gas / 5.485921264 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x243a8B73...04eC0dB97
0.031480824703045523 Eth
Nonce: 175
0.011002951587659747 Eth
Nonce: 176
0.020477873115385776
(Titan Builder)
7.648908100621130923 Eth7.648916811521130923 Eth0.0000087109
0x869fb8A3...159A20010 1.704 Eth1.724 Eth0.02

Execution Trace

ETH 0.02 LazyButts.mintManyButts( lionIds=[8812] )
  • LazyLions.ownerOf( tokenId=8812 ) => ( 0x243a8B738f682B888bD0C4FBCb42F3704eC0dB97 )
    File 1 of 2: LazyButts
    // File: @openzeppelin/contracts/token/ERC20/extensions/IERC20Permit.sol
    
    
    // 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: @openzeppelin/contracts/token/ERC20/IERC20.sol
    
    
    // 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: @openzeppelin/contracts/utils/math/SignedMath.sol
    
    
    // OpenZeppelin Contracts (last updated v4.8.0) (utils/math/SignedMath.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Standard signed math utilities missing in the Solidity language.
     */
    library SignedMath {
        /**
         * @dev Returns the largest of two signed numbers.
         */
        function max(int256 a, int256 b) internal pure returns (int256) {
            return a > b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two signed numbers.
         */
        function min(int256 a, int256 b) internal pure returns (int256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two signed numbers without overflow.
         * The result is rounded towards zero.
         */
        function average(int256 a, int256 b) internal pure returns (int256) {
            // Formula from the book "Hacker's Delight"
            int256 x = (a & b) + ((a ^ b) >> 1);
            return x + (int256(uint256(x) >> 255) & (a ^ b));
        }
    
        /**
         * @dev Returns the absolute unsigned value of a signed value.
         */
        function abs(int256 n) internal pure returns (uint256) {
            unchecked {
                // must be unchecked in order to support `n = type(int256).min`
                return uint256(n >= 0 ? n : -n);
            }
        }
    }
    
    // File: @openzeppelin/contracts/utils/math/Math.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/math/Math.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Standard math utilities missing in the Solidity language.
     */
    library Math {
        enum Rounding {
            Down, // Toward negative infinity
            Up, // Toward infinity
            Zero // Toward zero
        }
    
        /**
         * @dev Returns the largest of two numbers.
         */
        function max(uint256 a, uint256 b) internal pure returns (uint256) {
            return a > b ? a : b;
        }
    
        /**
         * @dev Returns the smallest of two numbers.
         */
        function min(uint256 a, uint256 b) internal pure returns (uint256) {
            return a < b ? a : b;
        }
    
        /**
         * @dev Returns the average of two numbers. The result is rounded towards
         * zero.
         */
        function average(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b) / 2 can overflow.
            return (a & b) + (a ^ b) / 2;
        }
    
        /**
         * @dev Returns the ceiling of the division of two numbers.
         *
         * This differs from standard division with `/` in that it rounds up instead
         * of rounding down.
         */
        function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
            // (a + b - 1) / b can overflow on addition, so we distribute.
            return a == 0 ? 0 : (a - 1) / b + 1;
        }
    
        /**
         * @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or denominator == 0
         * @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv)
         * with further edits by Uniswap Labs also under MIT license.
         */
        function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
            unchecked {
                // 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
                // use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
                // variables such that product = prod1 * 2^256 + prod0.
                uint256 prod0; // Least significant 256 bits of the product
                uint256 prod1; // Most significant 256 bits of the product
                assembly {
                    let mm := mulmod(x, y, not(0))
                    prod0 := mul(x, y)
                    prod1 := sub(sub(mm, prod0), lt(mm, prod0))
                }
    
                // Handle non-overflow cases, 256 by 256 division.
                if (prod1 == 0) {
                    // Solidity will revert if denominator == 0, unlike the div opcode on its own.
                    // The surrounding unchecked block does not change this fact.
                    // See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
                    return prod0 / denominator;
                }
    
                // Make sure the result is less than 2^256. Also prevents denominator == 0.
                require(denominator > prod1, "Math: mulDiv overflow");
    
                ///////////////////////////////////////////////
                // 512 by 256 division.
                ///////////////////////////////////////////////
    
                // Make division exact by subtracting the remainder from [prod1 prod0].
                uint256 remainder;
                assembly {
                    // Compute remainder using mulmod.
                    remainder := mulmod(x, y, denominator)
    
                    // Subtract 256 bit number from 512 bit number.
                    prod1 := sub(prod1, gt(remainder, prod0))
                    prod0 := sub(prod0, remainder)
                }
    
                // Factor powers of two out of denominator and compute largest power of two divisor of denominator. Always >= 1.
                // See https://cs.stackexchange.com/q/138556/92363.
    
                // Does not overflow because the denominator cannot be zero at this stage in the function.
                uint256 twos = denominator & (~denominator + 1);
                assembly {
                    // Divide denominator by twos.
                    denominator := div(denominator, twos)
    
                    // Divide [prod1 prod0] by twos.
                    prod0 := div(prod0, twos)
    
                    // Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
                    twos := add(div(sub(0, twos), twos), 1)
                }
    
                // Shift in bits from prod1 into prod0.
                prod0 |= prod1 * twos;
    
                // Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
                // that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
                // four bits. That is, denominator * inv = 1 mod 2^4.
                uint256 inverse = (3 * denominator) ^ 2;
    
                // Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also works
                // in modular arithmetic, doubling the correct bits in each step.
                inverse *= 2 - denominator * inverse; // inverse mod 2^8
                inverse *= 2 - denominator * inverse; // inverse mod 2^16
                inverse *= 2 - denominator * inverse; // inverse mod 2^32
                inverse *= 2 - denominator * inverse; // inverse mod 2^64
                inverse *= 2 - denominator * inverse; // inverse mod 2^128
                inverse *= 2 - denominator * inverse; // inverse mod 2^256
    
                // Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
                // This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
                // less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
                // is no longer required.
                result = prod0 * inverse;
                return result;
            }
        }
    
        /**
         * @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
         */
        function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
            uint256 result = mulDiv(x, y, denominator);
            if (rounding == Rounding.Up && mulmod(x, y, denominator) > 0) {
                result += 1;
            }
            return result;
        }
    
        /**
         * @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded down.
         *
         * Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
         */
        function sqrt(uint256 a) internal pure returns (uint256) {
            if (a == 0) {
                return 0;
            }
    
            // For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
            //
            // We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
            // `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
            //
            // This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
            // → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
            // → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
            //
            // Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
            uint256 result = 1 << (log2(a) >> 1);
    
            // At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
            // since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
            // every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
            // into the expected uint128 result.
            unchecked {
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                result = (result + a / result) >> 1;
                return min(result, a / result);
            }
        }
    
        /**
         * @notice Calculates sqrt(a), following the selected rounding direction.
         */
        function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = sqrt(a);
                return result + (rounding == Rounding.Up && result * result < a ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 2, rounded down, of a positive value.
         * Returns 0 if given 0.
         */
        function log2(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 128;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 64;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 32;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 16;
                }
                if (value >> 8 > 0) {
                    value >>= 8;
                    result += 8;
                }
                if (value >> 4 > 0) {
                    value >>= 4;
                    result += 4;
                }
                if (value >> 2 > 0) {
                    value >>= 2;
                    result += 2;
                }
                if (value >> 1 > 0) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 2, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log2(value);
                return result + (rounding == Rounding.Up && 1 << result < value ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 10, rounded down, of a positive value.
         * Returns 0 if given 0.
         */
        function log10(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >= 10 ** 64) {
                    value /= 10 ** 64;
                    result += 64;
                }
                if (value >= 10 ** 32) {
                    value /= 10 ** 32;
                    result += 32;
                }
                if (value >= 10 ** 16) {
                    value /= 10 ** 16;
                    result += 16;
                }
                if (value >= 10 ** 8) {
                    value /= 10 ** 8;
                    result += 8;
                }
                if (value >= 10 ** 4) {
                    value /= 10 ** 4;
                    result += 4;
                }
                if (value >= 10 ** 2) {
                    value /= 10 ** 2;
                    result += 2;
                }
                if (value >= 10 ** 1) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 10, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log10(value);
                return result + (rounding == Rounding.Up && 10 ** result < value ? 1 : 0);
            }
        }
    
        /**
         * @dev Return the log in base 256, rounded down, of a positive value.
         * Returns 0 if given 0.
         *
         * Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
         */
        function log256(uint256 value) internal pure returns (uint256) {
            uint256 result = 0;
            unchecked {
                if (value >> 128 > 0) {
                    value >>= 128;
                    result += 16;
                }
                if (value >> 64 > 0) {
                    value >>= 64;
                    result += 8;
                }
                if (value >> 32 > 0) {
                    value >>= 32;
                    result += 4;
                }
                if (value >> 16 > 0) {
                    value >>= 16;
                    result += 2;
                }
                if (value >> 8 > 0) {
                    result += 1;
                }
            }
            return result;
        }
    
        /**
         * @dev Return the log in base 256, following the selected rounding direction, of a positive value.
         * Returns 0 if given 0.
         */
        function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
            unchecked {
                uint256 result = log256(value);
                return result + (rounding == Rounding.Up && 1 << (result << 3) < value ? 1 : 0);
            }
        }
    }
    
    // File: @openzeppelin/contracts/utils/Strings.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (utils/Strings.sol)
    
    pragma solidity ^0.8.0;
    
    
    
    /**
     * @dev String operations.
     */
    library Strings {
        bytes16 private constant _SYMBOLS = "0123456789abcdef";
        uint8 private constant _ADDRESS_LENGTH = 20;
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` decimal representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            unchecked {
                uint256 length = Math.log10(value) + 1;
                string memory buffer = new string(length);
                uint256 ptr;
                /// @solidity memory-safe-assembly
                assembly {
                    ptr := add(buffer, add(32, length))
                }
                while (true) {
                    ptr--;
                    /// @solidity memory-safe-assembly
                    assembly {
                        mstore8(ptr, byte(mod(value, 10), _SYMBOLS))
                    }
                    value /= 10;
                    if (value == 0) break;
                }
                return buffer;
            }
        }
    
        /**
         * @dev Converts a `int256` to its ASCII `string` decimal representation.
         */
        function toString(int256 value) internal pure returns (string memory) {
            return string(abi.encodePacked(value < 0 ? "-" : "", toString(SignedMath.abs(value))));
        }
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
         */
        function toHexString(uint256 value) internal pure returns (string memory) {
            unchecked {
                return toHexString(value, Math.log256(value) + 1);
            }
        }
    
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
         */
        function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = "0";
            buffer[1] = "x";
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = _SYMBOLS[value & 0xf];
                value >>= 4;
            }
            require(value == 0, "Strings: hex length insufficient");
            return string(buffer);
        }
    
        /**
         * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
         */
        function toHexString(address addr) internal pure returns (string memory) {
            return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
        }
    
        /**
         * @dev Returns true if the two strings are equal.
         */
        function equal(string memory a, string memory b) internal pure returns (bool) {
            return keccak256(bytes(a)) == keccak256(bytes(b));
        }
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    
    // 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: @openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/utils/SafeERC20.sol)
    
    pragma solidity ^0.8.0;
    
    
    
    
    /**
     * @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. Compatible with tokens that require the approval to be set to
         * 0 before setting it to a non-zero value.
         */
        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: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
    
    
    // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    interface IERC721Receiver {
        /**
         * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
         * by `operator` from `from`, this function is called.
         *
         * It must return its Solidity selector to confirm the token transfer.
         * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
         *
         * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
         */
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes calldata data
        ) external returns (bytes4);
    }
    
    // File: @openzeppelin/contracts/utils/introspection/IERC165.sol
    
    
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: @openzeppelin/contracts/utils/introspection/ERC165.sol
    
    
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
    
    pragma solidity ^0.8.0;
    
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
     * for the additional interface id that will be supported. For example:
     *
     * ```solidity
     * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
     *     return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
     * }
     * ```
     *
     * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
     */
    abstract contract ERC165 is IERC165 {
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return interfaceId == type(IERC165).interfaceId;
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/IERC721.sol)
    
    pragma solidity ^0.8.0;
    
    
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
    
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
    
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
    
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
    
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes calldata data) external;
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) external;
    
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
         * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
         * understand this adds an external call which potentially creates a reentrancy vulnerability.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 tokenId) external;
    
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
    
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool approved) external;
    
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
    
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/extensions/IERC721Metadata.sol
    
    
    // OpenZeppelin Contracts v4.4.1 (token/ERC721/extensions/IERC721Metadata.sol)
    
    pragma solidity ^0.8.0;
    
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Metadata is IERC721 {
        /**
         * @dev Returns the token collection name.
         */
        function name() external view returns (string memory);
    
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() external view returns (string memory);
    
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) external view returns (string memory);
    }
    
    // File: @openzeppelin/contracts/utils/Context.sol
    
    
    // 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: @openzeppelin/contracts/finance/PaymentSplitter.sol
    
    
    // OpenZeppelin Contracts (last updated v4.8.0) (finance/PaymentSplitter.sol)
    
    pragma solidity ^0.8.0;
    
    
    
    
    /**
     * @title PaymentSplitter
     * @dev This contract allows to split Ether payments among a group of accounts. The sender does not need to be aware
     * that the Ether will be split in this way, since it is handled transparently by the contract.
     *
     * The split can be in equal parts or in any other arbitrary proportion. The way this is specified is by assigning each
     * account to a number of shares. Of all the Ether that this contract receives, each account will then be able to claim
     * an amount proportional to the percentage of total shares they were assigned. The distribution of shares is set at the
     * time of contract deployment and can't be updated thereafter.
     *
     * `PaymentSplitter` follows a _pull payment_ model. This means that payments are not automatically forwarded to the
     * accounts but kept in this contract, and the actual transfer is triggered as a separate step by calling the {release}
     * function.
     *
     * NOTE: This contract assumes that ERC20 tokens will behave similarly to native tokens (Ether). Rebasing tokens, and
     * tokens that apply fees during transfers, are likely to not be supported as expected. If in doubt, we encourage you
     * to run tests before sending real value to this contract.
     */
    contract PaymentSplitter is Context {
        event PayeeAdded(address account, uint256 shares);
        event PaymentReleased(address to, uint256 amount);
        event ERC20PaymentReleased(IERC20 indexed token, address to, uint256 amount);
        event PaymentReceived(address from, uint256 amount);
    
        uint256 private _totalShares;
        uint256 private _totalReleased;
    
        mapping(address => uint256) private _shares;
        mapping(address => uint256) private _released;
        address[] private _payees;
    
        mapping(IERC20 => uint256) private _erc20TotalReleased;
        mapping(IERC20 => mapping(address => uint256)) private _erc20Released;
    
        /**
         * @dev Creates an instance of `PaymentSplitter` where each account in `payees` is assigned the number of shares at
         * the matching position in the `shares` array.
         *
         * All addresses in `payees` must be non-zero. Both arrays must have the same non-zero length, and there must be no
         * duplicates in `payees`.
         */
        constructor(address[] memory payees, uint256[] memory shares_) payable {
            require(payees.length == shares_.length, "PaymentSplitter: payees and shares length mismatch");
            require(payees.length > 0, "PaymentSplitter: no payees");
    
            for (uint256 i = 0; i < payees.length; i++) {
                _addPayee(payees[i], shares_[i]);
            }
        }
    
        /**
         * @dev The Ether received will be logged with {PaymentReceived} events. Note that these events are not fully
         * reliable: it's possible for a contract to receive Ether without triggering this function. This only affects the
         * reliability of the events, and not the actual splitting of Ether.
         *
         * To learn more about this see the Solidity documentation for
         * https://solidity.readthedocs.io/en/latest/contracts.html#fallback-function[fallback
         * functions].
         */
        receive() external payable virtual {
            emit PaymentReceived(_msgSender(), msg.value);
        }
    
        /**
         * @dev Getter for the total shares held by payees.
         */
        function totalShares() public view returns (uint256) {
            return _totalShares;
        }
    
        /**
         * @dev Getter for the total amount of Ether already released.
         */
        function totalReleased() public view returns (uint256) {
            return _totalReleased;
        }
    
        /**
         * @dev Getter for the total amount of `token` already released. `token` should be the address of an IERC20
         * contract.
         */
        function totalReleased(IERC20 token) public view returns (uint256) {
            return _erc20TotalReleased[token];
        }
    
        /**
         * @dev Getter for the amount of shares held by an account.
         */
        function shares(address account) public view returns (uint256) {
            return _shares[account];
        }
    
        /**
         * @dev Getter for the amount of Ether already released to a payee.
         */
        function released(address account) public view returns (uint256) {
            return _released[account];
        }
    
        /**
         * @dev Getter for the amount of `token` tokens already released to a payee. `token` should be the address of an
         * IERC20 contract.
         */
        function released(IERC20 token, address account) public view returns (uint256) {
            return _erc20Released[token][account];
        }
    
        /**
         * @dev Getter for the address of the payee number `index`.
         */
        function payee(uint256 index) public view returns (address) {
            return _payees[index];
        }
    
        /**
         * @dev Getter for the amount of payee's releasable Ether.
         */
        function releasable(address account) public view returns (uint256) {
            uint256 totalReceived = address(this).balance + totalReleased();
            return _pendingPayment(account, totalReceived, released(account));
        }
    
        /**
         * @dev Getter for the amount of payee's releasable `token` tokens. `token` should be the address of an
         * IERC20 contract.
         */
        function releasable(IERC20 token, address account) public view returns (uint256) {
            uint256 totalReceived = token.balanceOf(address(this)) + totalReleased(token);
            return _pendingPayment(account, totalReceived, released(token, account));
        }
    
        /**
         * @dev Triggers a transfer to `account` of the amount of Ether they are owed, according to their percentage of the
         * total shares and their previous withdrawals.
         */
        function release(address payable account) public virtual {
            require(_shares[account] > 0, "PaymentSplitter: account has no shares");
    
            uint256 payment = releasable(account);
    
            require(payment != 0, "PaymentSplitter: account is not due payment");
    
            // _totalReleased is the sum of all values in _released.
            // If "_totalReleased += payment" does not overflow, then "_released[account] += payment" cannot overflow.
            _totalReleased += payment;
            unchecked {
                _released[account] += payment;
            }
    
            Address.sendValue(account, payment);
            emit PaymentReleased(account, payment);
        }
    
        /**
         * @dev Triggers a transfer to `account` of the amount of `token` tokens they are owed, according to their
         * percentage of the total shares and their previous withdrawals. `token` must be the address of an IERC20
         * contract.
         */
        function release(IERC20 token, address account) public virtual {
            require(_shares[account] > 0, "PaymentSplitter: account has no shares");
    
            uint256 payment = releasable(token, account);
    
            require(payment != 0, "PaymentSplitter: account is not due payment");
    
            // _erc20TotalReleased[token] is the sum of all values in _erc20Released[token].
            // If "_erc20TotalReleased[token] += payment" does not overflow, then "_erc20Released[token][account] += payment"
            // cannot overflow.
            _erc20TotalReleased[token] += payment;
            unchecked {
                _erc20Released[token][account] += payment;
            }
    
            SafeERC20.safeTransfer(token, account, payment);
            emit ERC20PaymentReleased(token, account, payment);
        }
    
        /**
         * @dev internal logic for computing the pending payment of an `account` given the token historical balances and
         * already released amounts.
         */
        function _pendingPayment(
            address account,
            uint256 totalReceived,
            uint256 alreadyReleased
        ) private view returns (uint256) {
            return (totalReceived * _shares[account]) / _totalShares - alreadyReleased;
        }
    
        /**
         * @dev Add a new payee to the contract.
         * @param account The address of the payee to add.
         * @param shares_ The number of shares owned by the payee.
         */
        function _addPayee(address account, uint256 shares_) private {
            require(account != address(0), "PaymentSplitter: account is the zero address");
            require(shares_ > 0, "PaymentSplitter: shares are 0");
            require(_shares[account] == 0, "PaymentSplitter: account already has shares");
    
            _payees.push(account);
            _shares[account] = shares_;
            _totalShares = _totalShares + shares_;
            emit PayeeAdded(account, shares_);
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC721/ERC721.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC721/ERC721.sol)
    
    pragma solidity ^0.8.0;
    
    
    
    
    
    
    
    
    /**
     * @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
     * the Metadata extension, but not including the Enumerable extension, which is available separately as
     * {ERC721Enumerable}.
     */
    contract ERC721 is Context, ERC165, IERC721, IERC721Metadata {
        using Address for address;
        using Strings for uint256;
    
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // Mapping from token ID to owner address
        mapping(uint256 => address) private _owners;
    
        // Mapping owner address to token count
        mapping(address => uint256) private _balances;
    
        // Mapping from token ID to approved address
        mapping(uint256 => address) private _tokenApprovals;
    
        // Mapping from owner to operator approvals
        mapping(address => mapping(address => bool)) private _operatorApprovals;
    
        /**
         * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
         */
        constructor(string memory name_, string memory symbol_) {
            _name = name_;
            _symbol = symbol_;
        }
    
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
            return
                interfaceId == type(IERC721).interfaceId ||
                interfaceId == type(IERC721Metadata).interfaceId ||
                super.supportsInterface(interfaceId);
        }
    
        /**
         * @dev See {IERC721-balanceOf}.
         */
        function balanceOf(address owner) public view virtual override returns (uint256) {
            require(owner != address(0), "ERC721: address zero is not a valid owner");
            return _balances[owner];
        }
    
        /**
         * @dev See {IERC721-ownerOf}.
         */
        function ownerOf(uint256 tokenId) public view virtual override returns (address) {
            address owner = _ownerOf(tokenId);
            require(owner != address(0), "ERC721: invalid token ID");
            return owner;
        }
    
        /**
         * @dev See {IERC721Metadata-name}.
         */
        function name() public view virtual override returns (string memory) {
            return _name;
        }
    
        /**
         * @dev See {IERC721Metadata-symbol}.
         */
        function symbol() public view virtual override returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev See {IERC721Metadata-tokenURI}.
         */
        function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
            _requireMinted(tokenId);
    
            string memory baseURI = _baseURI();
            return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenId.toString())) : "";
        }
    
        /**
         * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
         * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
         * by default, can be overridden in child contracts.
         */
        function _baseURI() internal view virtual returns (string memory) {
            return "";
        }
    
        /**
         * @dev See {IERC721-approve}.
         */
        function approve(address to, uint256 tokenId) public virtual override {
            address owner = ERC721.ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
    
            require(
                _msgSender() == owner || isApprovedForAll(owner, _msgSender()),
                "ERC721: approve caller is not token owner or approved for all"
            );
    
            _approve(to, tokenId);
        }
    
        /**
         * @dev See {IERC721-getApproved}.
         */
        function getApproved(uint256 tokenId) public view virtual override returns (address) {
            _requireMinted(tokenId);
    
            return _tokenApprovals[tokenId];
        }
    
        /**
         * @dev See {IERC721-setApprovalForAll}.
         */
        function setApprovalForAll(address operator, bool approved) public virtual override {
            _setApprovalForAll(_msgSender(), operator, approved);
        }
    
        /**
         * @dev See {IERC721-isApprovedForAll}.
         */
        function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
            return _operatorApprovals[owner][operator];
        }
    
        /**
         * @dev See {IERC721-transferFrom}.
         */
        function transferFrom(address from, address to, uint256 tokenId) public virtual override {
            //solhint-disable-next-line max-line-length
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
    
            _transfer(from, to, tokenId);
        }
    
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId) public virtual override {
            safeTransferFrom(from, to, tokenId, "");
        }
    
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual override {
            require(_isApprovedOrOwner(_msgSender(), tokenId), "ERC721: caller is not token owner or approved");
            _safeTransfer(from, to, tokenId, data);
        }
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * `data` is additional data, it has no specified format and it is sent in call to `to`.
         *
         * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
         * implement alternative mechanisms to perform token transfer, such as signature-based.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
            _transfer(from, to, tokenId);
            require(_checkOnERC721Received(from, to, tokenId, data), "ERC721: transfer to non ERC721Receiver implementer");
        }
    
        /**
         * @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
         */
        function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
            return _owners[tokenId];
        }
    
        /**
         * @dev Returns whether `tokenId` exists.
         *
         * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
         *
         * Tokens start existing when they are minted (`_mint`),
         * and stop existing when they are burned (`_burn`).
         */
        function _exists(uint256 tokenId) internal view virtual returns (bool) {
            return _ownerOf(tokenId) != address(0);
        }
    
        /**
         * @dev Returns whether `spender` is allowed to manage `tokenId`.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function _isApprovedOrOwner(address spender, uint256 tokenId) internal view virtual returns (bool) {
            address owner = ERC721.ownerOf(tokenId);
            return (spender == owner || isApprovedForAll(owner, spender) || getApproved(tokenId) == spender);
        }
    
        /**
         * @dev Safely mints `tokenId` and transfers it to `to`.
         *
         * Requirements:
         *
         * - `tokenId` must not exist.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeMint(address to, uint256 tokenId) internal virtual {
            _safeMint(to, tokenId, "");
        }
    
        /**
         * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
         * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
         */
        function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
            _mint(to, tokenId);
            require(
                _checkOnERC721Received(address(0), to, tokenId, data),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    
        /**
         * @dev Mints `tokenId` and transfers it to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
         *
         * Requirements:
         *
         * - `tokenId` must not exist.
         * - `to` cannot be the zero address.
         *
         * Emits a {Transfer} event.
         */
        function _mint(address to, uint256 tokenId) internal virtual {
            require(to != address(0), "ERC721: mint to the zero address");
            require(!_exists(tokenId), "ERC721: token already minted");
    
            _beforeTokenTransfer(address(0), to, tokenId, 1);
    
            // Check that tokenId was not minted by `_beforeTokenTransfer` hook
            require(!_exists(tokenId), "ERC721: token already minted");
    
            unchecked {
                // Will not overflow unless all 2**256 token ids are minted to the same owner.
                // Given that tokens are minted one by one, it is impossible in practice that
                // this ever happens. Might change if we allow batch minting.
                // The ERC fails to describe this case.
                _balances[to] += 1;
            }
    
            _owners[tokenId] = to;
    
            emit Transfer(address(0), to, tokenId);
    
            _afterTokenTransfer(address(0), to, tokenId, 1);
        }
    
        /**
         * @dev Destroys `tokenId`.
         * The approval is cleared when the token is burned.
         * This is an internal function that does not check if the sender is authorized to operate on the token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         *
         * Emits a {Transfer} event.
         */
        function _burn(uint256 tokenId) internal virtual {
            address owner = ERC721.ownerOf(tokenId);
    
            _beforeTokenTransfer(owner, address(0), tokenId, 1);
    
            // Update ownership in case tokenId was transferred by `_beforeTokenTransfer` hook
            owner = ERC721.ownerOf(tokenId);
    
            // Clear approvals
            delete _tokenApprovals[tokenId];
    
            unchecked {
                // Cannot overflow, as that would require more tokens to be burned/transferred
                // out than the owner initially received through minting and transferring in.
                _balances[owner] -= 1;
            }
            delete _owners[tokenId];
    
            emit Transfer(owner, address(0), tokenId);
    
            _afterTokenTransfer(owner, address(0), tokenId, 1);
        }
    
        /**
         * @dev Transfers `tokenId` from `from` to `to`.
         *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         *
         * Emits a {Transfer} event.
         */
        function _transfer(address from, address to, uint256 tokenId) internal virtual {
            require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
            require(to != address(0), "ERC721: transfer to the zero address");
    
            _beforeTokenTransfer(from, to, tokenId, 1);
    
            // Check that tokenId was not transferred by `_beforeTokenTransfer` hook
            require(ERC721.ownerOf(tokenId) == from, "ERC721: transfer from incorrect owner");
    
            // Clear approvals from the previous owner
            delete _tokenApprovals[tokenId];
    
            unchecked {
                // `_balances[from]` cannot overflow for the same reason as described in `_burn`:
                // `from`'s balance is the number of token held, which is at least one before the current
                // transfer.
                // `_balances[to]` could overflow in the conditions described in `_mint`. That would require
                // all 2**256 token ids to be minted, which in practice is impossible.
                _balances[from] -= 1;
                _balances[to] += 1;
            }
            _owners[tokenId] = to;
    
            emit Transfer(from, to, tokenId);
    
            _afterTokenTransfer(from, to, tokenId, 1);
        }
    
        /**
         * @dev Approve `to` to operate on `tokenId`
         *
         * Emits an {Approval} event.
         */
        function _approve(address to, uint256 tokenId) internal virtual {
            _tokenApprovals[tokenId] = to;
            emit Approval(ERC721.ownerOf(tokenId), to, tokenId);
        }
    
        /**
         * @dev Approve `operator` to operate on all of `owner` tokens
         *
         * Emits an {ApprovalForAll} event.
         */
        function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
            require(owner != operator, "ERC721: approve to caller");
            _operatorApprovals[owner][operator] = approved;
            emit ApprovalForAll(owner, operator, approved);
        }
    
        /**
         * @dev Reverts if the `tokenId` has not been minted yet.
         */
        function _requireMinted(uint256 tokenId) internal view virtual {
            require(_exists(tokenId), "ERC721: invalid token ID");
        }
    
        /**
         * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * @param from address representing the previous owner of the given token ID
         * @param to target address that will receive the tokens
         * @param tokenId uint256 ID of the token to be transferred
         * @param data bytes optional data to send along with the call
         * @return bool whether the call correctly returned the expected magic value
         */
        function _checkOnERC721Received(
            address from,
            address to,
            uint256 tokenId,
            bytes memory data
        ) private returns (bool) {
            if (to.isContract()) {
                try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
                    return retval == IERC721Receiver.onERC721Received.selector;
                } catch (bytes memory reason) {
                    if (reason.length == 0) {
                        revert("ERC721: transfer to non ERC721Receiver implementer");
                    } else {
                        /// @solidity memory-safe-assembly
                        assembly {
                            revert(add(32, reason), mload(reason))
                        }
                    }
                }
            } else {
                return true;
            }
        }
    
        /**
         * @dev Hook that is called before any token transfer. This includes minting and burning. If {ERC721Consecutive} is
         * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, ``from``'s tokens will be transferred to `to`.
         * - When `from` is zero, the tokens will be minted for `to`.
         * - When `to` is zero, ``from``'s tokens will be burned.
         * - `from` and `to` are never both zero.
         * - `batchSize` is non-zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}
    
        /**
         * @dev Hook that is called after any token transfer. This includes minting and burning. If {ERC721Consecutive} is
         * used, the hook may be called as part of a consecutive (batch) mint, as indicated by `batchSize` greater than 1.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, ``from``'s tokens were transferred to `to`.
         * - When `from` is zero, the tokens were minted for `to`.
         * - When `to` is zero, ``from``'s tokens were burned.
         * - `from` and `to` are never both zero.
         * - `batchSize` is non-zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _afterTokenTransfer(address from, address to, uint256 firstTokenId, uint256 batchSize) internal virtual {}
    
        /**
         * @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
         *
         * WARNING: Anyone calling this MUST ensure that the balances remain consistent with the ownership. The invariant
         * being that for any address `a` the value returned by `balanceOf(a)` must be equal to the number of tokens such
         * that `ownerOf(tokenId)` is `a`.
         */
        // solhint-disable-next-line func-name-mixedcase
        function __unsafe_increaseBalance(address account, uint256 amount) internal {
            _balances[account] += amount;
        }
    }
    
    // File: @openzeppelin/contracts/access/Ownable.sol
    
    
    // OpenZeppelin Contracts (last updated v4.9.0) (access/Ownable.sol)
    
    pragma solidity ^0.8.0;
    
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() {
            _transferOwnership(_msgSender());
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby disabling any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            _transferOwnership(address(0));
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(newOwner != address(0), "Ownable: new owner is the zero address");
            _transferOwnership(newOwner);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Internal function without access restriction.
         */
        function _transferOwnership(address newOwner) internal virtual {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    
    // File: utils/Delegated.sol
    
    
    
    pragma solidity ^0.8.0;
    
    
    contract Delegated is Ownable{
      mapping(address => bool) internal _delegates;
    
      constructor(){
        _delegates[owner()] = true;
      }
    
      modifier onlyDelegates {
        require(_delegates[msg.sender], "Invalid delegate" );
        _;
      }
    
      //onlyOwner
      function isDelegate( address addr ) external view onlyOwner returns ( bool ){
        return _delegates[addr];
      }
    
      function setDelegate( address addr, bool isDelegate_ ) external onlyOwner{
        _delegates[addr] = isDelegate_;
      }
    
      function transferOwnership(address newOwner) public virtual override onlyOwner {
        _delegates[newOwner] = true;
        super.transferOwnership( newOwner );
      }
    }
    
    // File: lazybutts.sol
    
    
    
    /* 
        Lazy Butts is not affiliated with Lazy Lions.
        It is an unofficial extension brought to you by the 3D Kings.
    */
    
    pragma solidity ^0.8.21;
    
    
    
    
    
    
    contract LazyButts is
        Delegated,
        PaymentSplitter,
        ERC721
    {
        using Strings for uint;
    
        uint256 public price = 0.02 ether;
        
        string private _tokenURIPrefix = "https://api.the3dkings.io/api/metadata/";
        string private _tokenURISuffix = ".json";
    
        bytes32 public merkleRoot = 0x5bbc1ee9865f275b8666093c9096f0525756bc427e2437047cef9396ff53e069;
        bool public isAllowListActive = false;
        bool public isMintActive = false;
    
        IERC721 private LazyLions =
            IERC721(0x8943C7bAC1914C9A7ABa750Bf2B6B09Fd21037E0);
    
        event Mint(address indexed to, uint indexed tokenId);
        
        mapping (address => bool) public allowListMinted;
    
        address[] private _payees = [
            0x49CAE18B5B796e993Cce4A43cAdA316B8c7388eC, // Community Wallet
            0x616188ADB7928954B922FBc672e2f3e82f4db578, // Operational Wallet
            0x626cdB47a91810EDb2Bde1d69e60C1B17071CF25, // Team Member Wallet
            0x6628FC01ae06E134e08E4E8A01Ed1075C77c87A1, // Team Member Wallet
            0x7Cf39e8D6F6f9F25E925Dad7EB371276231780d7, // Team Member Wallet
            0xC02Dd50b25364e747410730A1df9B72A92C3C68B  // Team Member Wallet
        ];
    
        uint256[] private _shares = [5000, 1000, 1000, 1000, 1000, 1000];
    
        constructor()
            Delegated()
            ERC721("Lazy Butts", "BUTTS")
            PaymentSplitter(_payees, _shares)
        {}
    
        /**
         * @param tokenId Id of token to check
         * @dev Checks if token exists and returns metadata URI
         */
        function tokenURI(
            uint tokenId
        ) public view override returns (string memory) {
            require(_exists(tokenId), "Token does not exist");
            return
                string(
                    abi.encodePacked(
                        _tokenURIPrefix,
                        tokenId.toString(),
                        _tokenURISuffix
                    )
                );
        }
    
        /**
         * @dev Checks if sender is tx.origin
         */
        modifier onlySender {
            require(msg.sender == tx.origin, "Only sender allowed");
            _;
        }
    
        /**
         * @dev Checks if mint is active
         */
        modifier mintActive {
            require(isMintActive, "Mint is not active");
            _;
        }
    
        /**
         * @param lionId Id of token to mint
         * @dev Mints token to owner
         */
        function mintButt(uint lionId) external payable onlySender mintActive {
            require(!_exists(lionId), "Token already minted");
            require(msg.value == price, "Not enough ether sent");
            address lion = LazyLions.ownerOf(lionId);
            _mint(lion, lionId);
            emit Mint(lion, lionId);
        }
    
        /**
         * @param lionIds Array of tokenIds to mint
         * @dev Mints tokens to owners
         */
        function mintManyButts(uint[] calldata lionIds) external payable onlySender mintActive {
            require(lionIds.length > 0, "No tokens to mint");
            require(msg.value == price * lionIds.length, "Not enough ether sent");
            address[] memory owners = new address[](lionIds.length);
            owners = _getLionOwners(lionIds);
            _mintMany(owners, lionIds);
        }
    
        /**
         * @param tokenIds Array of tokenIds to mint
         * @dev Mints tokens to owners
         * @dev Only callable by delegates
         */
        function buttDrop(uint[] calldata tokenIds) public payable onlyDelegates {
            require(tokenIds.length > 0, "No tokens to mint");
            address[] memory owners = new address[](tokenIds.length);
            owners = _getLionOwners(tokenIds);
            _mintMany(owners, tokenIds);
        }
    
        /**
         * @param tokenIds Array of tokenIds to check
         * @dev Gets owners of tokens
         */
        function _getLionOwners(
            uint[] memory tokenIds
        ) internal view returns (address[] memory owners) {
            owners = new address[](tokenIds.length);
            for (uint i; i < tokenIds.length; ++i) {
                require(!_exists(tokenIds[i]), "Token already minted");
                address lion = LazyLions.ownerOf(tokenIds[i]);
                owners[i] = lion;
            }
            return owners;
        }
    
        /**
         * @param owners Array of addresses to mint tokens to
         * @param lionIds Array of tokenIds to mint
         * @dev Mints tokens to owners
         */
        function _mintMany(
            address[] memory owners,
            uint[] memory lionIds
        ) internal {
            for (uint i; i < lionIds.length; ++i) {
                _mint(owners[i], lionIds[i]);
                emit Mint(owners[i], lionIds[i]);
            }
        }
    
        /**
         * @param prefix New prefix to append to tokenURI
         * @dev Only callable by delegates
         */
        function setTokenURIPrefix(string calldata prefix) external onlyDelegates {
            require(
                keccak256(abi.encodePacked(prefix)) !=
                    keccak256(abi.encodePacked(_tokenURIPrefix)),
                "Prefix already set"
            );
            _tokenURIPrefix = prefix;
        }
    
        /**
         * @param suffix New suffix to append to tokenURI
         * @dev Only callable by delegates
         */
        function setTokenURISuffix(string calldata suffix) external onlyDelegates {
            require(
                keccak256(abi.encodePacked(suffix)) !=
                    keccak256(abi.encodePacked(_tokenURISuffix)),
                "Suffix already set"
            );
            _tokenURISuffix = suffix;
        }
    
        /**
         * @param lazyLions Address of Lazy Lions contract
         * @dev Only callable by delegates
         */
        function setLazyLions(address lazyLions) external onlyDelegates {
            require(lazyLions != address(LazyLions), "Lazy Lions already set");
            LazyLions = IERC721(lazyLions);
        }
    
        /**
         * @param newPrice New price in wei
         * @dev Only callable by delegates
         */
        function updatePrice(uint256 newPrice) external onlyDelegates {
            require(newPrice != price, "Price already set");
            price = newPrice;
        }
    
        // Access List Functions
    
        /**
         * @param address_ Address to check
         * @param proof_ Merkle proof
         * @dev Checks merkle proof to determine if address is allowlisted.
         * @dev Merkle proof is generated off-chain.
         */
        function isAllowListed(address address_, bytes32[] memory proof_) public view returns (bool) {
            bytes32 _leaf = keccak256(abi.encodePacked(address_));
    
            for (uint i = 0; i < proof_.length; i++) {
                _leaf = _leaf < proof_[i] ? keccak256(abi.encodePacked(_leaf, proof_[i])) : keccak256(abi.encodePacked(proof_[i], _leaf));
            }
            return _leaf == merkleRoot;
        }
    
        /**
         * @param proof_ Merkle proof
         * @param lionIds Array of tokenIds to mint
         * @dev Public mint function for allowlist. Follows same rules as public mint, but requires merkle proof.
         */
        function mintAllowList(bytes32[] memory proof_, uint[] calldata lionIds) external payable {
            address _minter = msg.sender;
            require(isAllowListActive, "Allowlist is not active!");
            require(isAllowListed(_minter, proof_), "Address is not allowlisted!");
            require(lionIds.length > 0, "No tokens to mint");
            uint256 _totalPrice = allowListMinted[_minter] ? price * lionIds.length : lionIds.length > 1 ? price / 2 + price * (lionIds.length - 1) : price / 2;
            require(msg.value == _totalPrice, "Not enough ether sent");
            if (!allowListMinted[_minter]) allowListMinted[_minter] = true;
            address[] memory owners = new address[](lionIds.length);
            owners = _getLionOwners(lionIds);
            _mintMany(owners, lionIds);
        }
    
        /**
         * @notice Sets the merkle root for the allowlist. Can only be called by delegates.
         */ 
        function setMerkleRoot(bytes32 merkleRoot_) external onlyDelegates {
            merkleRoot = merkleRoot_;
        }
    
        /**
         * @notice Toggle the allowlist active state. Can only be called by delegates.
         */
        function setAllowListActive(bool isAllowListActive_) external onlyDelegates {
            require(isAllowListActive != isAllowListActive_, "Allowlist already set");
            isAllowListActive = isAllowListActive_;
        }
    
        /**
         * @notice Toggle the mint active state. Can only be called by delegates.
         */
        function setMintActive(bool isMintActive_) external onlyDelegates {
            require(isMintActive != isMintActive_, "Mint already set");
            isMintActive = isMintActive_;
        }
    
    }

    File 2 of 2: LazyLions
    /**
     *Ashur was here
     */
    
    // SPDX-License-Identifier: MIT
    
    // File: @openzeppelin/contracts/utils/Context.sol
    
    pragma solidity >=0.6.0 <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 GSN 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 payable) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes memory) {
            this; // silence state mutability warning without generating bytecode - see https://github.com/ethereum/solidity/issues/2691
            return msg.data;
        }
    }
    
    // File: @openzeppelin/contracts/introspection/IERC165.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721.sol
    
    pragma solidity >=0.6.2 <0.8.0;
    
    /**
     * @dev Required interface of an ERC721 compliant contract.
     */
    interface IERC721 is IERC165 {
        /**
         * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
         */
        event Transfer(
            address indexed from,
            address indexed to,
            uint256 indexed tokenId
        );
    
        /**
         * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
         */
        event Approval(
            address indexed owner,
            address indexed approved,
            uint256 indexed tokenId
        );
    
        /**
         * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
         */
        event ApprovalForAll(
            address indexed owner,
            address indexed operator,
            bool approved
        );
    
        /**
         * @dev Returns the number of tokens in ``owner``'s account.
         */
        function balanceOf(address owner) external view returns (uint256 balance);
    
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) external view returns (address owner);
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be have been allowed to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
    
        /**
         * @dev Transfers `tokenId` token from `from` to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external;
    
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account.
         * The approval is cleared when the token is transferred.
         *
         * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function approve(address to, uint256 tokenId) external;
    
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId)
            external
            view
            returns (address operator);
    
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
    
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}
         */
        function isApprovedForAll(address owner, address operator)
            external
            view
            returns (bool);
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes calldata data
        ) external;
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721Metadata.sol
    
    pragma solidity >=0.6.2 <0.8.0;
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional metadata extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Metadata is IERC721 {
        /**
         * @dev Returns the token collection name.
         */
        function name() external view returns (string memory);
    
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() external view returns (string memory);
    
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) external view returns (string memory);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721Enumerable.sol
    
    pragma solidity >=0.6.2 <0.8.0;
    
    /**
     * @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
     * @dev See https://eips.ethereum.org/EIPS/eip-721
     */
    interface IERC721Enumerable is IERC721 {
        /**
         * @dev Returns the total amount of tokens stored by the contract.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns a token ID owned by `owner` at a given `index` of its token list.
         * Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
         */
        function tokenOfOwnerByIndex(address owner, uint256 index)
            external
            view
            returns (uint256 tokenId);
    
        /**
         * @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
         * Use along with {totalSupply} to enumerate all tokens.
         */
        function tokenByIndex(uint256 index) external view returns (uint256);
    }
    
    // File: @openzeppelin/contracts/token/ERC721/IERC721Receiver.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @title ERC721 token receiver interface
     * @dev Interface for any contract that wants to support safeTransfers
     * from ERC721 asset contracts.
     */
    interface IERC721Receiver {
        /**
         * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
         * by `operator` from `from`, this function is called.
         *
         * It must return its Solidity selector to confirm the token transfer.
         * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
         *
         * The selector can be obtained in Solidity with `IERC721.onERC721Received.selector`.
         */
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes calldata data
        ) external returns (bytes4);
    }
    
    // File: @openzeppelin/contracts/introspection/ERC165.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Implementation of the {IERC165} interface.
     *
     * Contracts may inherit from this and call {_registerInterface} to declare
     * their support of an interface.
     */
    abstract contract ERC165 is IERC165 {
        /*
         * bytes4(keccak256('supportsInterface(bytes4)')) == 0x01ffc9a7
         */
        bytes4 private constant _INTERFACE_ID_ERC165 = 0x01ffc9a7;
    
        /**
         * @dev Mapping of interface ids to whether or not it's supported.
         */
        mapping(bytes4 => bool) private _supportedInterfaces;
    
        constructor() internal {
            // Derived contracts need only register support for their own interfaces,
            // we register support for ERC165 itself here
            _registerInterface(_INTERFACE_ID_ERC165);
        }
    
        /**
         * @dev See {IERC165-supportsInterface}.
         *
         * Time complexity O(1), guaranteed to always use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId)
            public
            view
            virtual
            override
            returns (bool)
        {
            return _supportedInterfaces[interfaceId];
        }
    
        /**
         * @dev Registers the contract as an implementer of the interface defined by
         * `interfaceId`. Support of the actual ERC165 interface is automatic and
         * registering its interface id is not required.
         *
         * See {IERC165-supportsInterface}.
         *
         * Requirements:
         *
         * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`).
         */
        function _registerInterface(bytes4 interfaceId) internal virtual {
            require(interfaceId != 0xffffffff, "ERC165: invalid interface id");
            _supportedInterfaces[interfaceId] = true;
        }
    }
    
    // File: @openzeppelin/contracts/math/SafeMath.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Wrappers over Solidity's arithmetic operations with added overflow
     * checks.
     *
     * Arithmetic operations in Solidity wrap on overflow. This can easily result
     * in bugs, because programmers usually assume that an overflow raises an
     * error, which is the standard behavior in high level programming languages.
     * `SafeMath` restores this intuition by reverting the transaction when an
     * operation overflows.
     *
     * Using this library instead of the unchecked operations eliminates an entire
     * class of bugs, so it's recommended to use it always.
     */
    library SafeMath {
        /**
         * @dev Returns the addition of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryAdd(uint256 a, uint256 b)
            internal
            pure
            returns (bool, uint256)
        {
            uint256 c = a + b;
            if (c < a) return (false, 0);
            return (true, c);
        }
    
        /**
         * @dev Returns the substraction of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function trySub(uint256 a, uint256 b)
            internal
            pure
            returns (bool, uint256)
        {
            if (b > a) return (false, 0);
            return (true, a - b);
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, with an overflow flag.
         *
         * _Available since v3.4._
         */
        function tryMul(uint256 a, uint256 b)
            internal
            pure
            returns (bool, uint256)
        {
            // Gas optimization: this is cheaper than requiring 'a' not being zero, but the
            // benefit is lost if 'b' is also tested.
            // See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
            if (a == 0) return (true, 0);
            uint256 c = a * b;
            if (c / a != b) return (false, 0);
            return (true, c);
        }
    
        /**
         * @dev Returns the division of two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryDiv(uint256 a, uint256 b)
            internal
            pure
            returns (bool, uint256)
        {
            if (b == 0) return (false, 0);
            return (true, a / b);
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
         *
         * _Available since v3.4._
         */
        function tryMod(uint256 a, uint256 b)
            internal
            pure
            returns (bool, uint256)
        {
            if (b == 0) return (false, 0);
            return (true, a % b);
        }
    
        /**
         * @dev Returns the addition of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `+` operator.
         *
         * Requirements:
         *
         * - Addition cannot overflow.
         */
        function add(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 c = a + b;
            require(c >= a, "SafeMath: addition overflow");
            return c;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting on
         * overflow (when the result is negative).
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b <= a, "SafeMath: subtraction overflow");
            return a - b;
        }
    
        /**
         * @dev Returns the multiplication of two unsigned integers, reverting on
         * overflow.
         *
         * Counterpart to Solidity's `*` operator.
         *
         * Requirements:
         *
         * - Multiplication cannot overflow.
         */
        function mul(uint256 a, uint256 b) internal pure returns (uint256) {
            if (a == 0) return 0;
            uint256 c = a * b;
            require(c / a == b, "SafeMath: multiplication overflow");
            return c;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers, reverting on
         * division by zero. The result is rounded towards zero.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: division by zero");
            return a / b;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting when dividing by zero.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(uint256 a, uint256 b) internal pure returns (uint256) {
            require(b > 0, "SafeMath: modulo by zero");
            return a % b;
        }
    
        /**
         * @dev Returns the subtraction of two unsigned integers, reverting with custom message on
         * overflow (when the result is negative).
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {trySub}.
         *
         * Counterpart to Solidity's `-` operator.
         *
         * Requirements:
         *
         * - Subtraction cannot overflow.
         */
        function sub(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b <= a, errorMessage);
            return a - b;
        }
    
        /**
         * @dev Returns the integer division of two unsigned integers, reverting with custom message on
         * division by zero. The result is rounded towards zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryDiv}.
         *
         * Counterpart to Solidity's `/` operator. Note: this function uses a
         * `revert` opcode (which leaves remaining gas untouched) while Solidity
         * uses an invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function div(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a / b;
        }
    
        /**
         * @dev Returns the remainder of dividing two unsigned integers. (unsigned integer modulo),
         * reverting with custom message when dividing by zero.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryMod}.
         *
         * Counterpart to Solidity's `%` operator. This function uses a `revert`
         * opcode (which leaves remaining gas untouched) while Solidity uses an
         * invalid opcode to revert (consuming all remaining gas).
         *
         * Requirements:
         *
         * - The divisor cannot be zero.
         */
        function mod(
            uint256 a,
            uint256 b,
            string memory errorMessage
        ) internal pure returns (uint256) {
            require(b > 0, errorMessage);
            return a % b;
        }
    }
    
    // File: @openzeppelin/contracts/utils/Address.sol
    
    pragma solidity >=0.6.2 <0.8.0;
    
    /**
     * @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
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize, which returns 0 for contracts in
            // construction, since the code is only stored at the end of the
            // constructor execution.
    
            uint256 size;
            // solhint-disable-next-line no-inline-assembly
            assembly {
                size := extcodesize(account)
            }
            return size > 0;
        }
    
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
         */
        function sendValue(address payable recipient, uint256 amount) internal {
            require(
                address(this).balance >= amount,
                "Address: insufficient balance"
            );
    
            // solhint-disable-next-line avoid-low-level-calls, avoid-call-value
            (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 functionCall(target, data, "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"
            );
            require(isContract(target), "Address: call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.call{value: value}(
                data
            );
            return _verifyCallResult(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) {
            require(isContract(target), "Address: static call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.staticcall(data);
            return _verifyCallResult(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) {
            require(isContract(target), "Address: delegate call to non-contract");
    
            // solhint-disable-next-line avoid-low-level-calls
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return _verifyCallResult(success, returndata, errorMessage);
        }
    
        function _verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) private pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                // 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
    
                    // solhint-disable-next-line no-inline-assembly
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    // File: @openzeppelin/contracts/utils/EnumerableSet.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Library for managing
     * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
     * types.
     *
     * Sets have the following properties:
     *
     * - Elements are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Elements are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```
     * contract Example {
     *     // Add the library methods
     *     using EnumerableSet for EnumerableSet.AddressSet;
     *
     *     // Declare a set state variable
     *     EnumerableSet.AddressSet private mySet;
     * }
     * ```
     *
     * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
     * and `uint256` (`UintSet`) are supported.
     */
    library EnumerableSet {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Set type with
        // bytes32 values.
        // The Set implementation uses private functions, and user-facing
        // implementations (such as AddressSet) are just wrappers around the
        // underlying Set.
        // This means that we can only create new EnumerableSets for types that fit
        // in bytes32.
    
        struct Set {
            // Storage of set values
            bytes32[] _values;
            // Position of the value in the `values` array, plus 1 because index 0
            // means a value is not in the set.
            mapping(bytes32 => uint256) _indexes;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function _add(Set storage set, bytes32 value) private returns (bool) {
            if (!_contains(set, value)) {
                set._values.push(value);
                // The value is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                set._indexes[value] = set._values.length;
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function _remove(Set storage set, bytes32 value) private returns (bool) {
            // We read and store the value's index to prevent multiple reads from the same storage slot
            uint256 valueIndex = set._indexes[value];
    
            if (valueIndex != 0) {
                // Equivalent to contains(set, value)
                // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
                // the array, and then remove the last element (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
    
                uint256 toDeleteIndex = valueIndex - 1;
                uint256 lastIndex = set._values.length - 1;
    
                // When the value to delete is the last one, the swap operation is unnecessary. However, since this occurs
                // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
    
                bytes32 lastvalue = set._values[lastIndex];
    
                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastvalue;
                // Update the index for the moved value
                set._indexes[lastvalue] = toDeleteIndex + 1; // All indexes are 1-based
    
                // Delete the slot where the moved value was stored
                set._values.pop();
    
                // Delete the index for the deleted slot
                delete set._indexes[value];
    
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function _contains(Set storage set, bytes32 value)
            private
            view
            returns (bool)
        {
            return set._indexes[value] != 0;
        }
    
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function _length(Set storage set) private view returns (uint256) {
            return set._values.length;
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(Set storage set, uint256 index)
            private
            view
            returns (bytes32)
        {
            require(
                set._values.length > index,
                "EnumerableSet: index out of bounds"
            );
            return set._values[index];
        }
    
        // Bytes32Set
    
        struct Bytes32Set {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(Bytes32Set storage set, bytes32 value)
            internal
            returns (bool)
        {
            return _add(set._inner, value);
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(Bytes32Set storage set, bytes32 value)
            internal
            returns (bool)
        {
            return _remove(set._inner, value);
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(Bytes32Set storage set, bytes32 value)
            internal
            view
            returns (bool)
        {
            return _contains(set._inner, value);
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(Bytes32Set storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(Bytes32Set storage set, uint256 index)
            internal
            view
            returns (bytes32)
        {
            return _at(set._inner, index);
        }
    
        // AddressSet
    
        struct AddressSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(AddressSet storage set, address value)
            internal
            returns (bool)
        {
            return _add(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(AddressSet storage set, address value)
            internal
            returns (bool)
        {
            return _remove(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(AddressSet storage set, address value)
            internal
            view
            returns (bool)
        {
            return _contains(set._inner, bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Returns the number of values in the set. O(1).
         */
        function length(AddressSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(AddressSet storage set, uint256 index)
            internal
            view
            returns (address)
        {
            return address(uint160(uint256(_at(set._inner, index))));
        }
    
        // UintSet
    
        struct UintSet {
            Set _inner;
        }
    
        /**
         * @dev Add a value to a set. O(1).
         *
         * Returns true if the value was added to the set, that is if it was not
         * already present.
         */
        function add(UintSet storage set, uint256 value) internal returns (bool) {
            return _add(set._inner, bytes32(value));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the value was removed from the set, that is if it was
         * present.
         */
        function remove(UintSet storage set, uint256 value)
            internal
            returns (bool)
        {
            return _remove(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns true if the value is in the set. O(1).
         */
        function contains(UintSet storage set, uint256 value)
            internal
            view
            returns (bool)
        {
            return _contains(set._inner, bytes32(value));
        }
    
        /**
         * @dev Returns the number of values on the set. O(1).
         */
        function length(UintSet storage set) internal view returns (uint256) {
            return _length(set._inner);
        }
    
        /**
         * @dev Returns the value stored at position `index` in the set. O(1).
         *
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(UintSet storage set, uint256 index)
            internal
            view
            returns (uint256)
        {
            return uint256(_at(set._inner, index));
        }
    }
    
    // File: @openzeppelin/contracts/utils/EnumerableMap.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Library for managing an enumerable variant of Solidity's
     * https://solidity.readthedocs.io/en/latest/types.html#mapping-types[`mapping`]
     * type.
     *
     * Maps have the following properties:
     *
     * - Entries are added, removed, and checked for existence in constant time
     * (O(1)).
     * - Entries are enumerated in O(n). No guarantees are made on the ordering.
     *
     * ```
     * contract Example {
     *     // Add the library methods
     *     using EnumerableMap for EnumerableMap.UintToAddressMap;
     *
     *     // Declare a set state variable
     *     EnumerableMap.UintToAddressMap private myMap;
     * }
     * ```
     *
     * As of v3.0.0, only maps of type `uint256 -> address` (`UintToAddressMap`) are
     * supported.
     */
    library EnumerableMap {
        // To implement this library for multiple types with as little code
        // repetition as possible, we write it in terms of a generic Map type with
        // bytes32 keys and values.
        // The Map implementation uses private functions, and user-facing
        // implementations (such as Uint256ToAddressMap) are just wrappers around
        // the underlying Map.
        // This means that we can only create new EnumerableMaps for types that fit
        // in bytes32.
    
        struct MapEntry {
            bytes32 _key;
            bytes32 _value;
        }
    
        struct Map {
            // Storage of map keys and values
            MapEntry[] _entries;
            // Position of the entry defined by a key in the `entries` array, plus 1
            // because index 0 means a key is not in the map.
            mapping(bytes32 => uint256) _indexes;
        }
    
        /**
         * @dev Adds a key-value pair to a map, or updates the value for an existing
         * key. O(1).
         *
         * Returns true if the key was added to the map, that is if it was not
         * already present.
         */
        function _set(
            Map storage map,
            bytes32 key,
            bytes32 value
        ) private returns (bool) {
            // We read and store the key's index to prevent multiple reads from the same storage slot
            uint256 keyIndex = map._indexes[key];
    
            if (keyIndex == 0) {
                // Equivalent to !contains(map, key)
                map._entries.push(MapEntry({_key: key, _value: value}));
                // The entry is stored at length-1, but we add 1 to all indexes
                // and use 0 as a sentinel value
                map._indexes[key] = map._entries.length;
                return true;
            } else {
                map._entries[keyIndex - 1]._value = value;
                return false;
            }
        }
    
        /**
         * @dev Removes a key-value pair from a map. O(1).
         *
         * Returns true if the key was removed from the map, that is if it was present.
         */
        function _remove(Map storage map, bytes32 key) private returns (bool) {
            // We read and store the key's index to prevent multiple reads from the same storage slot
            uint256 keyIndex = map._indexes[key];
    
            if (keyIndex != 0) {
                // Equivalent to contains(map, key)
                // To delete a key-value pair from the _entries array in O(1), we swap the entry to delete with the last one
                // in the array, and then remove the last entry (sometimes called as 'swap and pop').
                // This modifies the order of the array, as noted in {at}.
    
                uint256 toDeleteIndex = keyIndex - 1;
                uint256 lastIndex = map._entries.length - 1;
    
                // When the entry to delete is the last one, the swap operation is unnecessary. However, since this occurs
                // so rarely, we still do the swap anyway to avoid the gas cost of adding an 'if' statement.
    
                MapEntry storage lastEntry = map._entries[lastIndex];
    
                // Move the last entry to the index where the entry to delete is
                map._entries[toDeleteIndex] = lastEntry;
                // Update the index for the moved entry
                map._indexes[lastEntry._key] = toDeleteIndex + 1; // All indexes are 1-based
    
                // Delete the slot where the moved entry was stored
                map._entries.pop();
    
                // Delete the index for the deleted slot
                delete map._indexes[key];
    
                return true;
            } else {
                return false;
            }
        }
    
        /**
         * @dev Returns true if the key is in the map. O(1).
         */
        function _contains(Map storage map, bytes32 key)
            private
            view
            returns (bool)
        {
            return map._indexes[key] != 0;
        }
    
        /**
         * @dev Returns the number of key-value pairs in the map. O(1).
         */
        function _length(Map storage map) private view returns (uint256) {
            return map._entries.length;
        }
    
        /**
         * @dev Returns the key-value pair stored at position `index` in the map. O(1).
         *
         * Note that there are no guarantees on the ordering of entries inside the
         * array, and it may change when more entries are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function _at(Map storage map, uint256 index)
            private
            view
            returns (bytes32, bytes32)
        {
            require(
                map._entries.length > index,
                "EnumerableMap: index out of bounds"
            );
    
            MapEntry storage entry = map._entries[index];
            return (entry._key, entry._value);
        }
    
        /**
         * @dev Tries to returns the value associated with `key`.  O(1).
         * Does not revert if `key` is not in the map.
         */
        function _tryGet(Map storage map, bytes32 key)
            private
            view
            returns (bool, bytes32)
        {
            uint256 keyIndex = map._indexes[key];
            if (keyIndex == 0) return (false, 0); // Equivalent to contains(map, key)
            return (true, map._entries[keyIndex - 1]._value); // All indexes are 1-based
        }
    
        /**
         * @dev Returns the value associated with `key`.  O(1).
         *
         * Requirements:
         *
         * - `key` must be in the map.
         */
        function _get(Map storage map, bytes32 key) private view returns (bytes32) {
            uint256 keyIndex = map._indexes[key];
            require(keyIndex != 0, "EnumerableMap: nonexistent key"); // Equivalent to contains(map, key)
            return map._entries[keyIndex - 1]._value; // All indexes are 1-based
        }
    
        /**
         * @dev Same as {_get}, with a custom error message when `key` is not in the map.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {_tryGet}.
         */
        function _get(
            Map storage map,
            bytes32 key,
            string memory errorMessage
        ) private view returns (bytes32) {
            uint256 keyIndex = map._indexes[key];
            require(keyIndex != 0, errorMessage); // Equivalent to contains(map, key)
            return map._entries[keyIndex - 1]._value; // All indexes are 1-based
        }
    
        // UintToAddressMap
    
        struct UintToAddressMap {
            Map _inner;
        }
    
        /**
         * @dev Adds a key-value pair to a map, or updates the value for an existing
         * key. O(1).
         *
         * Returns true if the key was added to the map, that is if it was not
         * already present.
         */
        function set(
            UintToAddressMap storage map,
            uint256 key,
            address value
        ) internal returns (bool) {
            return _set(map._inner, bytes32(key), bytes32(uint256(uint160(value))));
        }
    
        /**
         * @dev Removes a value from a set. O(1).
         *
         * Returns true if the key was removed from the map, that is if it was present.
         */
        function remove(UintToAddressMap storage map, uint256 key)
            internal
            returns (bool)
        {
            return _remove(map._inner, bytes32(key));
        }
    
        /**
         * @dev Returns true if the key is in the map. O(1).
         */
        function contains(UintToAddressMap storage map, uint256 key)
            internal
            view
            returns (bool)
        {
            return _contains(map._inner, bytes32(key));
        }
    
        /**
         * @dev Returns the number of elements in the map. O(1).
         */
        function length(UintToAddressMap storage map)
            internal
            view
            returns (uint256)
        {
            return _length(map._inner);
        }
    
        /**
         * @dev Returns the element stored at position `index` in the set. O(1).
         * Note that there are no guarantees on the ordering of values inside the
         * array, and it may change when more values are added or removed.
         *
         * Requirements:
         *
         * - `index` must be strictly less than {length}.
         */
        function at(UintToAddressMap storage map, uint256 index)
            internal
            view
            returns (uint256, address)
        {
            (bytes32 key, bytes32 value) = _at(map._inner, index);
            return (uint256(key), address(uint160(uint256(value))));
        }
    
        /**
         * @dev Tries to returns the value associated with `key`.  O(1).
         * Does not revert if `key` is not in the map.
         *
         * _Available since v3.4._
         */
        function tryGet(UintToAddressMap storage map, uint256 key)
            internal
            view
            returns (bool, address)
        {
            (bool success, bytes32 value) = _tryGet(map._inner, bytes32(key));
            return (success, address(uint160(uint256(value))));
        }
    
        /**
         * @dev Returns the value associated with `key`.  O(1).
         *
         * Requirements:
         *
         * - `key` must be in the map.
         */
        function get(UintToAddressMap storage map, uint256 key)
            internal
            view
            returns (address)
        {
            return address(uint160(uint256(_get(map._inner, bytes32(key)))));
        }
    
        /**
         * @dev Same as {get}, with a custom error message when `key` is not in the map.
         *
         * CAUTION: This function is deprecated because it requires allocating memory for the error
         * message unnecessarily. For custom revert reasons use {tryGet}.
         */
        function get(
            UintToAddressMap storage map,
            uint256 key,
            string memory errorMessage
        ) internal view returns (address) {
            return
                address(
                    uint160(uint256(_get(map._inner, bytes32(key), errorMessage)))
                );
        }
    }
    
    // File: @openzeppelin/contracts/utils/Strings.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev String operations.
     */
    library Strings {
        /**
         * @dev Converts a `uint256` to its ASCII `string` representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
    
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            uint256 index = digits - 1;
            temp = value;
            while (temp != 0) {
                buffer[index--] = bytes1(uint8(48 + (temp % 10)));
                temp /= 10;
            }
            return string(buffer);
        }
    }
    
    // File: @openzeppelin/contracts/token/ERC721/ERC721.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @title ERC721 Non-Fungible Token Standard basic implementation
     * @dev see https://eips.ethereum.org/EIPS/eip-721
     */
    
    contract ERC721 is
        Context,
        ERC165,
        IERC721,
        IERC721Metadata,
        IERC721Enumerable
    {
        using SafeMath for uint256;
        using Address for address;
        using EnumerableSet for EnumerableSet.UintSet;
        using EnumerableMap for EnumerableMap.UintToAddressMap;
        using Strings for uint256;
    
        // Equals to `bytes4(keccak256("onERC721Received(address,address,uint256,bytes)"))`
        // which can be also obtained as `IERC721Receiver(0).onERC721Received.selector`
        bytes4 private constant _ERC721_RECEIVED = 0x150b7a02;
    
        // Mapping from holder address to their (enumerable) set of owned tokens
        mapping(address => EnumerableSet.UintSet) private _holderTokens;
    
        // Enumerable mapping from token ids to their owners
        EnumerableMap.UintToAddressMap private _tokenOwners;
    
        // Mapping from token ID to approved address
        mapping(uint256 => address) private _tokenApprovals;
    
        // Mapping from owner to operator approvals
        mapping(address => mapping(address => bool)) private _operatorApprovals;
    
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // Optional mapping for token URIs
        mapping(uint256 => string) private _tokenURIs;
    
        // Base URI
        string private _baseURI;
    
        /*
         *     bytes4(keccak256('balanceOf(address)')) == 0x70a08231
         *     bytes4(keccak256('ownerOf(uint256)')) == 0x6352211e
         *     bytes4(keccak256('approve(address,uint256)')) == 0x095ea7b3
         *     bytes4(keccak256('getApproved(uint256)')) == 0x081812fc
         *     bytes4(keccak256('setApprovalForAll(address,bool)')) == 0xa22cb465
         *     bytes4(keccak256('isApprovedForAll(address,address)')) == 0xe985e9c5
         *     bytes4(keccak256('transferFrom(address,address,uint256)')) == 0x23b872dd
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256)')) == 0x42842e0e
         *     bytes4(keccak256('safeTransferFrom(address,address,uint256,bytes)')) == 0xb88d4fde
         *
         *     => 0x70a08231 ^ 0x6352211e ^ 0x095ea7b3 ^ 0x081812fc ^
         *        0xa22cb465 ^ 0xe985e9c5 ^ 0x23b872dd ^ 0x42842e0e ^ 0xb88d4fde == 0x80ac58cd
         */
        bytes4 private constant _INTERFACE_ID_ERC721 = 0x80ac58cd;
    
        /*
         *     bytes4(keccak256('name()')) == 0x06fdde03
         *     bytes4(keccak256('symbol()')) == 0x95d89b41
         *     bytes4(keccak256('tokenURI(uint256)')) == 0xc87b56dd
         *
         *     => 0x06fdde03 ^ 0x95d89b41 ^ 0xc87b56dd == 0x5b5e139f
         */
        bytes4 private constant _INTERFACE_ID_ERC721_METADATA = 0x5b5e139f;
    
        /*
         *     bytes4(keccak256('totalSupply()')) == 0x18160ddd
         *     bytes4(keccak256('tokenOfOwnerByIndex(address,uint256)')) == 0x2f745c59
         *     bytes4(keccak256('tokenByIndex(uint256)')) == 0x4f6ccce7
         *
         *     => 0x18160ddd ^ 0x2f745c59 ^ 0x4f6ccce7 == 0x780e9d63
         */
        bytes4 private constant _INTERFACE_ID_ERC721_ENUMERABLE = 0x780e9d63;
    
        /**
         * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
         */
        constructor(string memory name_, string memory symbol_) public {
            _name = name_;
            _symbol = symbol_;
    
            // register the supported interfaces to conform to ERC721 via ERC165
            _registerInterface(_INTERFACE_ID_ERC721);
            _registerInterface(_INTERFACE_ID_ERC721_METADATA);
            _registerInterface(_INTERFACE_ID_ERC721_ENUMERABLE);
        }
    
        /**
         * @dev See {IERC721-balanceOf}.
         */
        function balanceOf(address owner)
            public
            view
            virtual
            override
            returns (uint256)
        {
            require(
                owner != address(0),
                "ERC721: balance query for the zero address"
            );
            return _holderTokens[owner].length();
        }
    
        /**
         * @dev See {IERC721-ownerOf}.
         */
        function ownerOf(uint256 tokenId)
            public
            view
            virtual
            override
            returns (address)
        {
            return
                _tokenOwners.get(
                    tokenId,
                    "ERC721: owner query for nonexistent token"
                );
        }
    
        /**
         * @dev See {IERC721Metadata-name}.
         */
        function name() public view virtual override returns (string memory) {
            return _name;
        }
    
        /**
         * @dev See {IERC721Metadata-symbol}.
         */
        function symbol() public view virtual override returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev See {IERC721Metadata-tokenURI}.
         */
        function tokenURI(uint256 tokenId)
            public
            view
            virtual
            override
            returns (string memory)
        {
            require(
                _exists(tokenId),
                "ERC721Metadata: URI query for nonexistent token"
            );
    
            string memory _tokenURI = _tokenURIs[tokenId];
            string memory base = baseURI();
    
            // If there is no base URI, return the token URI.
            if (bytes(base).length == 0) {
                return _tokenURI;
            }
            // If both are set, concatenate the baseURI and tokenURI (via abi.encodePacked).
            if (bytes(_tokenURI).length > 0) {
                return string(abi.encodePacked(base, _tokenURI));
            }
            // If there is a baseURI but no tokenURI, concatenate the tokenID to the baseURI.
            return string(abi.encodePacked(base, tokenId.toString()));
        }
    
        /**
         * @dev Returns the base URI set via {_setBaseURI}. This will be
         * automatically added as a prefix in {tokenURI} to each token's URI, or
         * to the token ID if no specific URI is set for that token ID.
         */
        function baseURI() public view virtual returns (string memory) {
            return _baseURI;
        }
    
        /**
         * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
         */
        function tokenOfOwnerByIndex(address owner, uint256 index)
            public
            view
            virtual
            override
            returns (uint256)
        {
            return _holderTokens[owner].at(index);
        }
    
        /**
         * @dev See {IERC721Enumerable-totalSupply}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            // _tokenOwners are indexed by tokenIds, so .length() returns the number of tokenIds
            return _tokenOwners.length();
        }
    
        /**
         * @dev See {IERC721Enumerable-tokenByIndex}.
         */
        function tokenByIndex(uint256 index)
            public
            view
            virtual
            override
            returns (uint256)
        {
            (uint256 tokenId, ) = _tokenOwners.at(index);
            return tokenId;
        }
    
        /**
         * @dev See {IERC721-approve}.
         */
        function approve(address to, uint256 tokenId) public virtual override {
            address owner = ERC721.ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
    
            require(
                _msgSender() == owner ||
                    ERC721.isApprovedForAll(owner, _msgSender()),
                "ERC721: approve caller is not owner nor approved for all"
            );
    
            _approve(to, tokenId);
        }
    
        /**
         * @dev See {IERC721-getApproved}.
         */
        function getApproved(uint256 tokenId)
            public
            view
            virtual
            override
            returns (address)
        {
            require(
                _exists(tokenId),
                "ERC721: approved query for nonexistent token"
            );
    
            return _tokenApprovals[tokenId];
        }
    
        /**
         * @dev See {IERC721-setApprovalForAll}.
         */
        function setApprovalForAll(address operator, bool approved)
            public
            virtual
            override
        {
            require(operator != _msgSender(), "ERC721: approve to caller");
    
            _operatorApprovals[_msgSender()][operator] = approved;
            emit ApprovalForAll(_msgSender(), operator, approved);
        }
    
        /**
         * @dev See {IERC721-isApprovedForAll}.
         */
        function isApprovedForAll(address owner, address operator)
            public
            view
            virtual
            override
            returns (bool)
        {
            return _operatorApprovals[owner][operator];
        }
    
        /**
         * @dev See {IERC721-transferFrom}.
         */
        function transferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public virtual override {
            //solhint-disable-next-line max-line-length
            require(
                _isApprovedOrOwner(_msgSender(), tokenId),
                "ERC721: transfer caller is not owner nor approved"
            );
    
            _transfer(from, to, tokenId);
        }
    
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public virtual override {
            safeTransferFrom(from, to, tokenId, "");
        }
    
        /**
         * @dev See {IERC721-safeTransferFrom}.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) public virtual override {
            require(
                _isApprovedOrOwner(_msgSender(), tokenId),
                "ERC721: transfer caller is not owner nor approved"
            );
            _safeTransfer(from, to, tokenId, _data);
        }
    
        /**
         * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
         * are aware of the ERC721 protocol to prevent tokens from being forever locked.
         *
         * `_data` is additional data, it has no specified format and it is sent in call to `to`.
         *
         * This internal function is equivalent to {safeTransferFrom}, and can be used to e.g.
         * implement alternative mechanisms to perform token transfer, such as signature-based.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `tokenId` token must exist and be owned by `from`.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeTransfer(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) internal virtual {
            _transfer(from, to, tokenId);
            require(
                _checkOnERC721Received(from, to, tokenId, _data),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    
        /**
         * @dev Returns whether `tokenId` exists.
         *
         * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
         *
         * Tokens start existing when they are minted (`_mint`),
         * and stop existing when they are burned (`_burn`).
         */
        function _exists(uint256 tokenId) internal view virtual returns (bool) {
            return _tokenOwners.contains(tokenId);
        }
    
        /**
         * @dev Returns whether `spender` is allowed to manage `tokenId`.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function _isApprovedOrOwner(address spender, uint256 tokenId)
            internal
            view
            virtual
            returns (bool)
        {
            require(
                _exists(tokenId),
                "ERC721: operator query for nonexistent token"
            );
            address owner = ERC721.ownerOf(tokenId);
            return (spender == owner ||
                getApproved(tokenId) == spender ||
                ERC721.isApprovedForAll(owner, spender));
        }
    
        /**
         * @dev Safely mints `tokenId` and transfers it to `to`.
         *
         * Requirements:
         d*
         * - `tokenId` must not exist.
         * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
         *
         * Emits a {Transfer} event.
         */
        function _safeMint(address to, uint256 tokenId) internal virtual {
            _safeMint(to, tokenId, "");
        }
    
        /**
         * @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
         * forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
         */
        function _safeMint(
            address to,
            uint256 tokenId,
            bytes memory _data
        ) internal virtual {
            _mint(to, tokenId);
            require(
                _checkOnERC721Received(address(0), to, tokenId, _data),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
        }
    
        /**
         * @dev Mints `tokenId` and transfers it to `to`.
         *
         * WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
         *
         * Requirements:
         *
         * - `tokenId` must not exist.
         * - `to` cannot be the zero address.
         *
         * Emits a {Transfer} event.
         */
        function _mint(address to, uint256 tokenId) internal virtual {
            require(to != address(0), "ERC721: mint to the zero address");
            require(!_exists(tokenId), "ERC721: token already minted");
    
            _beforeTokenTransfer(address(0), to, tokenId);
    
            _holderTokens[to].add(tokenId);
    
            _tokenOwners.set(tokenId, to);
    
            emit Transfer(address(0), to, tokenId);
        }
    
        /**
         * @dev Destroys `tokenId`.
         * The approval is cleared when the token is burned.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         *
         * Emits a {Transfer} event.
         */
        function _burn(uint256 tokenId) internal virtual {
            address owner = ERC721.ownerOf(tokenId); // internal owner
    
            _beforeTokenTransfer(owner, address(0), tokenId);
    
            // Clear approvals
            _approve(address(0), tokenId);
    
            // Clear metadata (if any)
            if (bytes(_tokenURIs[tokenId]).length != 0) {
                delete _tokenURIs[tokenId];
            }
    
            _holderTokens[owner].remove(tokenId);
    
            _tokenOwners.remove(tokenId);
    
            emit Transfer(owner, address(0), tokenId);
        }
    
        /**
         * @dev Transfers `tokenId` from `from` to `to`.
         *  As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `tokenId` token must be owned by `from`.
         *
         * Emits a {Transfer} event.
         */
        function _transfer(
            address from,
            address to,
            uint256 tokenId
        ) internal virtual {
            require(
                ERC721.ownerOf(tokenId) == from,
                "ERC721: transfer of token that is not own"
            ); // internal owner
            require(to != address(0), "ERC721: transfer to the zero address");
    
            _beforeTokenTransfer(from, to, tokenId);
    
            // Clear approvals from the previous owner
            _approve(address(0), tokenId);
    
            _holderTokens[from].remove(tokenId);
            _holderTokens[to].add(tokenId);
    
            _tokenOwners.set(tokenId, to);
    
            emit Transfer(from, to, tokenId);
        }
    
        /**
         * @dev Sets `_tokenURI` as the tokenURI of `tokenId`.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function _setTokenURI(uint256 tokenId, string memory _tokenURI)
            internal
            virtual
        {
            require(
                _exists(tokenId),
                "ERC721Metadata: URI set of nonexistent token"
            );
            _tokenURIs[tokenId] = _tokenURI;
        }
    
        /**
         * @dev Internal function to set the base URI for all token IDs. It is
         * automatically added as a prefix to the value returned in {tokenURI},
         * or to the token ID if {tokenURI} is empty.
         */
        function _setBaseURI(string memory baseURI_) internal virtual {
            _baseURI = baseURI_;
        }
    
        /**
         * @dev Internal function to invoke {IERC721Receiver-onERC721Received} on a target address.
         * The call is not executed if the target address is not a contract.
         *
         * @param from address representing the previous owner of the given token ID
         * @param to target address that will receive the tokens
         * @param tokenId uint256 ID of the token to be transferred
         * @param _data bytes optional data to send along with the call
         * @return bool whether the call correctly returned the expected magic value
         */
        function _checkOnERC721Received(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) private returns (bool) {
            if (!to.isContract()) {
                return true;
            }
            bytes memory returndata = to.functionCall(
                abi.encodeWithSelector(
                    IERC721Receiver(to).onERC721Received.selector,
                    _msgSender(),
                    from,
                    tokenId,
                    _data
                ),
                "ERC721: transfer to non ERC721Receiver implementer"
            );
            bytes4 retval = abi.decode(returndata, (bytes4));
            return (retval == _ERC721_RECEIVED);
        }
    
        /**
         * @dev Approve `to` to operate on `tokenId`
         *
         * Emits an {Approval} event.
         */
        function _approve(address to, uint256 tokenId) internal virtual {
            _tokenApprovals[tokenId] = to;
            emit Approval(ERC721.ownerOf(tokenId), to, tokenId); // internal owner
        }
    
        /**
         * @dev Hook that is called before any token transfer. This includes minting
         * and burning.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, ``from``'s `tokenId` will be
         * transferred to `to`.
         * - When `from` is zero, `tokenId` will be minted for `to`.
         * - When `to` is zero, ``from``'s `tokenId` will be burned.
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(
            address from,
            address to,
            uint256 tokenId
        ) internal virtual {}
    }
    
    // File: @openzeppelin/contracts/access/Ownable.sol
    
    pragma solidity >=0.6.0 <0.8.0;
    
    /**
     * @dev Contract module which provides a basic access control mechanism, where
     * there is an account (an owner) that can be granted exclusive access to
     * specific functions.
     *
     * By default, the owner account will be the one that deploys the contract. This
     * can later be changed with {transferOwnership}.
     *
     * This module is used through inheritance. It will make available the modifier
     * `onlyOwner`, which can be applied to your functions to restrict their use to
     * the owner.
     */
    abstract contract Ownable is Context {
        address private _owner;
    
        event OwnershipTransferred(
            address indexed previousOwner,
            address indexed newOwner
        );
    
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        constructor() internal {
            address msgSender = _msgSender();
            _owner = msgSender;
            emit OwnershipTransferred(address(0), msgSender);
        }
    
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
    
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
            _;
        }
    
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions anymore. Can only be called by the current owner.
         *
         * NOTE: Renouncing ownership will leave the contract without an owner,
         * thereby removing any functionality that is only available to the owner.
         */
        function renounceOwnership() public virtual onlyOwner {
            emit OwnershipTransferred(_owner, address(0));
            _owner = address(0);
        }
    
        /**
         * @dev Transfers ownership of the contract to a new account (`newOwner`).
         * Can only be called by the current owner.
         */
        function transferOwnership(address newOwner) public virtual onlyOwner {
            require(
                newOwner != address(0),
                "Ownable: new owner is the zero address"
            );
            emit OwnershipTransferred(_owner, newOwner);
            _owner = newOwner;
        }
    }
    
    /** 
    .-.     .--.  .---..-.  .-.   .-.   .-. .----. .-. .-. .----.
    | |    / {} \{_   / \ \/ /    | |   | |/  {}  \|  `| |{ {__  
    | `--./  /\  \/    } }  {     | `--.| |\      /| |\  |.-._} }
    `----'`-'  `-'`---'  `--'     `----'`-' `----' `-' `-'`----' 
    */
    
    pragma solidity ^0.7.0;
    pragma abicoder v2;
    
    contract LazyLions is ERC721, Ownable {
        using SafeMath for uint256;
    
        string public LION_PROVENANCE = ""; // IPFS PROVENANCE TO BE ADDED WHEN SOLD OUT
    
        string public LICENSE_TEXT = "";
    
        bool licenseLocked = false;
    
        uint256 public lionPrice = 50000000000000000; // 0.050 ETH
    
        uint256 public constant maxLionPurchase = 20;
    
        uint256 public constant MAX_LIONS = 10000;
    
        bool public saleIsActive = false;
    
        uint256 public lionReserve = 250; // Reserve 250 Lions for team & community (Used in giveaways, events etc...)
    
        event licenseisLocked(string _licenseText);
    
        constructor() ERC721("Lazy Lions", "LION") {}
    
        function withdraw() public onlyOwner {
            uint256 balance = address(this).balance;
            msg.sender.transfer(balance);
        }
    
        function reserveLions(address _to, uint256 _reserveAmount)
            public
            onlyOwner
        {
            uint256 supply = totalSupply();
            require(
                _reserveAmount > 0 && _reserveAmount <= lionReserve,
                "Not enough reserve left for team"
            );
            for (uint256 i = 0; i < _reserveAmount; i++) {
                _safeMint(_to, supply + i);
            }
            lionReserve = lionReserve.sub(_reserveAmount);
        }
    
        function setProvenanceHash(string memory provenanceHash) public onlyOwner {
            LION_PROVENANCE = provenanceHash;
        }
    
        function setBaseURI(string memory baseURI) public onlyOwner {
            _setBaseURI(baseURI);
        }
    
        function flipSaleState() public onlyOwner {
            saleIsActive = !saleIsActive;
        }
    
        function tokensOfOwner(address _owner)
            external
            view
            returns (uint256[] memory)
        {
            uint256 tokenCount = balanceOf(_owner);
            if (tokenCount == 0) {
                // Return an empty array
                return new uint256[](0);
            } else {
                uint256[] memory result = new uint256[](tokenCount);
                uint256 index;
                for (index = 0; index < tokenCount; index++) {
                    result[index] = tokenOfOwnerByIndex(_owner, index);
                }
                return result;
            }
        }
    
        // Returns the license for tokens
        function tokenLicense(uint256 _id) public view returns (string memory) {
            require(_id < totalSupply(), "CHOOSE A LION WITHIN RANGE");
            return LICENSE_TEXT;
        }
    
        // Locks the license to prevent further changes
        function lockLicense() public onlyOwner {
            licenseLocked = true;
            emit licenseisLocked(LICENSE_TEXT);
        }
    
        // Change the license
        function changeLicense(string memory _license) public onlyOwner {
            require(licenseLocked == false, "License already locked");
            LICENSE_TEXT = _license;
        }
    
        function mintLion(uint256 numberOfTokens) public payable {
            require(saleIsActive, "Sale must be active to mint Lion");
            require(
                numberOfTokens > 0 && numberOfTokens <= maxLionPurchase,
                "Can only mint 20 tokens at a time"
            );
            require(
                totalSupply().add(numberOfTokens) <= MAX_LIONS,
                "Purchase would exceed max supply of Lions"
            );
            require(
                msg.value >= lionPrice.mul(numberOfTokens),
                "Ether value sent is not correct"
            );
    
            for (uint256 i = 0; i < numberOfTokens; i++) {
                uint256 mintIndex = totalSupply();
                if (totalSupply() < MAX_LIONS) {
                    _safeMint(msg.sender, mintIndex);
                }
            }
        }
    
        function setLionPrice(uint256 newPrice) public onlyOwner {
            lionPrice = newPrice;
        }
    }