ETH Price: $2,113.47 (+1.29%)
Gas: 0.03 Gwei

Transaction Decoder

Block:
14356784 at Mar-10-2022 03:59:12 AM +UTC
Transaction Fee:
0.00445972051876112 ETH $9.43
Gas Used:
96,436 Gas / 46.24539092 Gwei

Emitted Events:

478 Cans.TransferBatch( operator=[Sender] 0x16feeddc44704b4773a37f2f9d329660a279f391, from=0x00000000...000000000, to=[Sender] 0x16feeddc44704b4773a37f2f9d329660a279f391, ids=[0, 1, 2, 3, 4, 5, 6], values=[1, 2, 2, 1, 6, 6, 3] )

Account State Difference:

  Address   Before After State Difference Code
0x16feEddc...0a279f391
0.314126861887458678 Eth
Nonce: 298
0.309667141368697558 Eth
Nonce: 299
0.00445972051876112
(F2Pool Old)
2,480.41704117000009459 Eth2,480.41718582400009459 Eth0.000144654
0xD386fF8b...2cE4f5261

Execution Trace

Cans.claim( tokenIds=[2734, 9277], amounts=[1, 2, 2, 1, 6, 6] )
  • SODA.ownerOf( tokenId=2734 ) => ( 0x16feEddc44704b4773a37F2F9D329660a279f391 )
  • SODA.ownerOf( tokenId=9277 ) => ( 0x16feEddc44704b4773a37F2F9D329660a279f391 )
    File 1 of 2: Cans
    // Sources flattened with hardhat v2.6.8 https://hardhat.org
    
    // File contracts/Functional.sol
    
    pragma solidity ^0.8.0;
    
    
    abstract contract Functional {
        function toString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
                digits -= 1;
                buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                value /= 10;
            }
            return string(buffer);
        }
        
        bool private _reentryKey = false;
        modifier reentryLock {
            require(!_reentryKey, "attempt to reenter a locked function");
            _reentryKey = true;
            _;
            _reentryKey = false;
        }
    }
    
    
    // File contracts/interfaces/IERC165.sol
    
    // OpenZeppelin Contracts v4.4.0 (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 contracts/interfaces/IERC1155.sol
    
    // OpenZeppelin Contracts v4.4.0 (token/ERC1155/IERC1155.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Required interface of an ERC1155 compliant contract, as defined in the
     * https://eips.ethereum.org/EIPS/eip-1155[EIP].
     *
     * _Available since v3.1._
     */
    interface IERC1155 is IERC165 {
        /**
         * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
         */
        event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);
    
        /**
         * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
         * transfers.
         */
        event TransferBatch(
            address indexed operator,
            address indexed from,
            address indexed to,
            uint256[] ids,
            uint256[] values
        );
    
        /**
         * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
         * `approved`.
         */
        event ApprovalForAll(address indexed account, address indexed operator, bool approved);
    
        /**
         * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
         *
         * If an {URI} event was emitted for `id`, the standard
         * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
         * returned by {IERC1155MetadataURI-uri}.
         */
        event URI(string value, uint256 indexed id);
    
        /**
         * @dev Returns the amount of tokens of token type `id` owned by `account`.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         */
        function balanceOf(address account, uint256 id) external view returns (uint256);
    
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
         *
         * Requirements:
         *
         * - `accounts` and `ids` must have the same length.
         */
        function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
            external
            view
            returns (uint256[] memory);
    
        /**
         * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
         *
         * Emits an {ApprovalForAll} event.
         *
         * Requirements:
         *
         * - `operator` cannot be the caller.
         */
        function setApprovalForAll(address operator, bool approved) external;
    
        /**
         * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address account, address operator) external view returns (bool);
    
        /**
         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
         *
         * Emits a {TransferSingle} event.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - If the caller is not `from`, it must be have been approved to spend ``from``'s tokens via {setApprovalForAll}.
         * - `from` must have a balance of tokens of type `id` of at least `amount`.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
         * acceptance magic value.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes calldata data
        ) external;
    
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
         *
         * Emits a {TransferBatch} event.
         *
         * Requirements:
         *
         * - `ids` and `amounts` must have the same length.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
         * acceptance magic value.
         */
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] calldata ids,
            uint256[] calldata amounts,
            bytes calldata data
        ) external;
    }
    
    
    // File contracts/interfaces/IERC1155Receiver.sol
    
    // OpenZeppelin Contracts v4.4.0 (token/ERC1155/IERC1155Receiver.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev _Available since v3.1._
     */
    interface IERC1155Receiver is IERC165 {
        /**
            @dev Handles the receipt of a single ERC1155 token type. This function is
            called at the end of a `safeTransferFrom` after the balance has been updated.
            To accept the transfer, this must return
            `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))`
            (i.e. 0xf23a6e61, or its own function selector).
            @param operator The address which initiated the transfer (i.e. msg.sender)
            @param from The address which previously owned the token
            @param id The ID of the token being transferred
            @param value The amount of tokens being transferred
            @param data Additional data with no specified format
            @return `bytes4(keccak256("onERC1155Received(address,address,uint256,uint256,bytes)"))` if transfer is allowed
        */
        function onERC1155Received(
            address operator,
            address from,
            uint256 id,
            uint256 value,
            bytes calldata data
        ) external returns (bytes4);
    
        /**
            @dev Handles the receipt of a multiple ERC1155 token types. This function
            is called at the end of a `safeBatchTransferFrom` after the balances have
            been updated. To accept the transfer(s), this must return
            `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))`
            (i.e. 0xbc197c81, or its own function selector).
            @param operator The address which initiated the batch transfer (i.e. msg.sender)
            @param from The address which previously owned the token
            @param ids An array containing ids of each token being transferred (order and length must match values array)
            @param values An array containing amounts of each token being transferred (order and length must match ids array)
            @param data Additional data with no specified format
            @return `bytes4(keccak256("onERC1155BatchReceived(address,address,uint256[],uint256[],bytes)"))` if transfer is allowed
        */
        function onERC1155BatchReceived(
            address operator,
            address from,
            uint256[] calldata ids,
            uint256[] calldata values,
            bytes calldata data
        ) external returns (bytes4);
    }
    
    
    // File contracts/interfaces/IERC1155MetadataURI.sol
    
    // OpenZeppelin Contracts v4.4.0 (token/ERC1155/extensions/IERC1155MetadataURI.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Interface of the optional ERC1155MetadataExtension interface, as defined
     * in the https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[EIP].
     *
     * _Available since v3.1._
     */
    interface IERC1155MetadataURI is IERC1155 {
        /**
         * @dev Returns the URI for token type `id`.
         *
         * If the `\{id\}` substring is present in the URI, it must be replaced by
         * clients with the actual token type ID.
         */
        function uri(uint256 id) external view returns (string memory);
    }
    
    
    // File contracts/utils/Address.sol
    
    // OpenZeppelin Contracts v4.4.0 (utils/Address.sol)
    
    pragma solidity ^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;
            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");
    
            (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");
    
            (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");
    
            (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");
    
            (bool success, bytes memory returndata) = target.delegatecall(data);
            return verifyCallResult(success, returndata, errorMessage);
        }
    
        /**
         * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason 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 {
                // 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
    
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    
    // File contracts/utils/Context.sol
    
    // OpenZeppelin Contracts v4.4.0 (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 contracts/utils/ERC165.sol
    
    // OpenZeppelin Contracts v4.4.0 (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 contracts/ERC1155.sol
    
    // OpenZeppelin Contracts v4.4.0 (token/ERC1155/ERC1155.sol)
    
    pragma solidity ^0.8.0;
    
    
    
    
    
    
    /**
     * @dev Implementation of the basic standard multi-token.
     * See https://eips.ethereum.org/EIPS/eip-1155
     * Originally based on code by Enjin: https://github.com/enjin/erc-1155
     *
     * _Available since v3.1._
     */
    contract ERC1155 is Context, ERC165, IERC1155, IERC1155MetadataURI {
        using Address for address;
    
        // Mapping from token ID to account balances
        mapping(address => uint32[7]) private _balances;
        uint[] private tokens;
    
        // Mapping from account to operator approvals
        mapping(address => mapping(address => bool)) private _operatorApprovals;
    
        // Used as the URI for all token types by relying on ID substitution, e.g. https://token-cdn-domain/{id}.json
        string private _uri;
    
        /**
         * @dev See {_setURI}.
         */
        constructor(string memory uri_) {
            _setURI(uri_);
            tokens = new uint[](7);
            for(uint i = 0; i < 7; i++) {
                tokens[i] = i;
            }
        }
    
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
            return
                interfaceId == type(IERC1155).interfaceId ||
                interfaceId == type(IERC1155MetadataURI).interfaceId ||
                super.supportsInterface(interfaceId);
        }
    
        /**
         * @dev See {IERC1155MetadataURI-uri}.
         *
         * This implementation returns the same URI for *all* token types. It relies
         * on the token type ID substitution mechanism
         * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
         *
         * Clients calling this function must replace the `\{id\}` substring with the
         * actual token type ID.
         */
        function uri(uint256) public view virtual override returns (string memory) {
            return _uri;
        }
    
        /**
         * @dev See {IERC1155-balanceOf}.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         */
        function balanceOf(address account, uint256 id) public view virtual override returns (uint256) {
            require(account != address(0), "ERC1155: balance query for the zero address");
            return _balances[account][id];
        }
    
        /**
         * @dev See {IERC1155-balanceOf}.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         */
        function balanceOfAccount(address account) public view virtual returns (uint32[7] memory) {
            require(account != address(0), "ERC1155: balance query for the zero address");
            return _balances[account];
        }
    
        /**
         * @dev See {IERC1155-balanceOfBatch}.
         *
         * Requirements:
         *
         * - `accounts` and `ids` must have the same length.
         */
        function balanceOfBatch(address[] memory accounts, uint256[] memory ids)
            public
            view
            virtual
            override
            returns (uint256[] memory)
        {
            require(accounts.length == ids.length, "ERC1155: accounts and ids length mismatch");
    
            uint256[] memory batchBalances = new uint256[](accounts.length);
    
            for (uint256 i = 0; i < accounts.length; ++i) {
                batchBalances[i] = balanceOf(accounts[i], ids[i]);
            }
    
            return batchBalances;
        }
    
        /**
         * @dev See {IERC1155-setApprovalForAll}.
    d burner addres     */
        function setApprovalForAll(address operator, bool approved) public virtual override {
            _setApprovalForAll(_msgSender(), operator, approved);
        }
    
        /**
         * @dev See {IERC1155-isApprovedForAll}.
         */
        function isApprovedForAll(address account, address operator) public view virtual override returns (bool) {
            return _operatorApprovals[account][operator];
        }
    
        /**
         * @dev See {IERC1155-safeTransferFrom}.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) public virtual override {
            require(
                from == _msgSender() || isApprovedForAll(from, _msgSender()),
                "ERC1155: caller is not owner nor approved"
            );
            _safeTransferFrom(from, to, id, amount, data);
        }
    
        /**
         * @dev See {IERC1155-safeBatchTransferFrom}.
         */
        function safeBatchTransferFrom(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) public virtual override {
            require(
                from == _msgSender() || isApprovedForAll(from, _msgSender()),
                "ERC1155: transfer caller is not owner nor approved"
            );
            _safeBatchTransferFrom(from, to, ids, amounts, data);
        }
    
        /**
         * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
         *
         * Emits a {TransferSingle} event.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `from` must have a balance of tokens of type `id` of at least `amount`.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
         * acceptance magic value.
         */
        function _safeTransferFrom(
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) internal virtual {
            require(to != address(0), "ERC1155: transfer to the zero address");
    
            address operator = _msgSender();
    
            _beforeTokenTransfer(operator, from, to, _asSingletonArray(id), _asSingletonArray(amount), data);
    
            uint256 fromBalance = _balances[from][id];
            require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
            unchecked {
                _balances[from][id] = uint32(fromBalance - amount);
            }
            _balances[to][id] += uint32(amount);
    
            emit TransferSingle(operator, from, to, id, amount);
    
            _doSafeTransferAcceptanceCheck(operator, from, to, id, amount, data);
        }
    
        function _safeSeedWallets(
            address[] calldata to,
            uint256 amount
        ) internal {
            uint32 amt = uint32(amount);
            uint32 blasts = amt/6;
            for(uint j = 0; j < to.length; j++) {
                address t = to[j];
                _balances[t][0] = amt;
                _balances[t][1] = amt;
                _balances[t][2] = amt;
                _balances[t][3] = amt;
                _balances[t][4] = amt;
                _balances[t][5] = amt;
                _balances[t][6] = blasts;
            }
        }
    
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_safeTransferFrom}.
         *
         * Emits a {TransferBatch} event.
         *
         * Requirements:
         *
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
         * acceptance magic value.
         */
        function _safeBatchTransferFrom(
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {
            require(ids.length == amounts.length, "ERC1155: ids and amounts length mismatch");
            require(to != address(0), "ERC1155: transfer to the zero address");
    
            address operator = _msgSender();
    
            _beforeTokenTransfer(operator, from, to, ids, amounts, data);
    
            for (uint256 i = 0; i < ids.length; ++i) {
                uint256 id = ids[i];
                uint256 amount = amounts[i];
    
                uint256 fromBalance = _balances[from][id];
                require(fromBalance >= amount, "ERC1155: insufficient balance for transfer");
                unchecked {
                    _balances[from][id] = uint32(fromBalance - amount);
                }
                _balances[to][id] += uint32(amount);
            }
    
            emit TransferBatch(operator, from, to, ids, amounts);
    
            _doSafeBatchTransferAcceptanceCheck(operator, from, to, ids, amounts, data);
        }
    
        /**
         * @dev Sets a new URI for all token types, by relying on the token type ID
         * substitution mechanism
         * https://eips.ethereum.org/EIPS/eip-1155#metadata[defined in the EIP].
         *
         * By this mechanism, any occurrence of the `\{id\}` substring in either the
         * URI or any of the amounts in the JSON file at said URI will be replaced by
         * clients with the token type ID.
         *
         * For example, the `https://token-cdn-domain/\{id\}.json` URI would be
         * interpreted by clients as
         * `https://token-cdn-domain/000000000000000000000000000000000000000000000000000000000004cce0.json`
         * for token type ID 0x4cce0.
         *
         * See {uri}.
         *
         * Because these URIs cannot be meaningfully represented by the {URI} event,
         * this function emits no events.
         */
        function _setURI(string memory newuri) internal virtual {
            _uri = newuri;
        }
    
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_mint}.
         *
         * Requirements:
         *
         * - `ids` and `amounts` must have the same length.
         * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
         * acceptance magic value.
         */
        function _mintBatch(
            address to,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {
            require(to != address(0), "ERC1155: mint to the zero address");
            require(7 == amounts.length, "ERC1155: ids and amounts length mismatch");
    
            address operator = _msgSender();
    
            _beforeTokenTransfer(operator, address(0), to, tokens, amounts, data);
    
            for (uint256 i = 0; i < amounts.length; i++) {
                _balances[to][i] += uint32(amounts[i]);
            }
    
            emit TransferBatch(operator, address(0), to, tokens, amounts);
    
            _doSafeBatchTransferAcceptanceCheck(operator, address(0), to, tokens, amounts, data);
        }
    
        /**
         * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {_burn}.
         *
         * Requirements:
         *
         * - `ids` and `amounts` must have the same length.
         */
        function _burnBatch(
            address from,
            uint256[] memory amounts
        ) internal virtual {
            require(from != address(0), "ERC1155: burn from the zero address");
            require(7 == amounts.length, "ERC1155: ids and amounts length mismatch");
    
            address operator = _msgSender();
    
            _beforeTokenTransfer(operator, from, address(0), tokens, amounts, "");
    
            for (uint256 i = 0; i < amounts.length; i++) {
                _balances[from][i] -= uint32(amounts[i]);
            }
    
            emit TransferBatch(operator, from, address(0), tokens, amounts);
        }
    
        /**
         * @dev Approve `operator` to operate on all of `owner` tokens
         *
         * Emits a {ApprovalForAll} event.
         */
        function _setApprovalForAll(
            address owner,
            address operator,
            bool approved
        ) internal virtual {
            require(owner != operator, "ERC1155: setting approval status for self");
            _operatorApprovals[owner][operator] = approved;
            emit ApprovalForAll(owner, operator, approved);
        }
    
        /**
         * @dev Hook that is called before any token transfer. This includes minting
         * and burning, as well as batched variants.
         *
         * The same hook is called on both single and batched variants. For single
         * transfers, the length of the `id` and `amount` arrays will be 1.
         *
         * Calling conditions (for each `id` and `amount` pair):
         *
         * - When `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * of token type `id` will be  transferred to `to`.
         * - When `from` is zero, `amount` tokens of token type `id` will be minted
         * for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens of token type `id`
         * will be burned.
         * - `from` and `to` are never both zero.
         * - `ids` and `amounts` have the same, non-zero length.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(
            address operator,
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) internal virtual {}
    
        function _doSafeTransferAcceptanceCheck(
            address operator,
            address from,
            address to,
            uint256 id,
            uint256 amount,
            bytes memory data
        ) private {
            if (to.isContract()) {
                try IERC1155Receiver(to).onERC1155Received(operator, from, id, amount, data) returns (bytes4 response) {
                    if (response != IERC1155Receiver.onERC1155Received.selector) {
                        revert("ERC1155: ERC1155Receiver rejected tokens");
                    }
                } catch Error(string memory reason) {
                    revert(reason);
                } catch {
                    revert("ERC1155: transfer to non ERC1155Receiver implementer");
                }
            }
        }
    
        function _doSafeBatchTransferAcceptanceCheck(
            address operator,
            address from,
            address to,
            uint256[] memory ids,
            uint256[] memory amounts,
            bytes memory data
        ) private {
            if (to.isContract()) {
                try IERC1155Receiver(to).onERC1155BatchReceived(operator, from, ids, amounts, data) returns (
                    bytes4 response
                ) {
                    if (response != IERC1155Receiver.onERC1155BatchReceived.selector) {
                        revert("ERC1155: ERC1155Receiver rejected tokens");
                    }
                } catch Error(string memory reason) {
                    revert(reason);
                } catch {
                    revert("ERC1155: transfer to non ERC1155Receiver implementer");
                }
            }
        }
    
        function _asSingletonArray(uint256 element) private pure returns (uint256[] memory) {
            uint256[] memory array = new uint256[](1);
            array[0] = element;
    
            return array;
        }
    }
    
    
    // File contracts/utils/Ownable.sol
    
    // OpenZeppelin Contracts v4.4.1 (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 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 {
            _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 contracts/Cans.sol
    
    // contracts/Cans.sol
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    
    
    contract SODAContract {
        function ownerOf(uint256 tokenId) public view virtual returns (address) {
        }
    }
    
    contract Cans is ERC1155, Ownable, Functional {
        uint public constant CHERRY = 0;
        uint public constant ORANGE = 1;
        uint public constant LEMON = 2;
        uint public constant SOUR_APPLE = 3;
        uint public constant BLUE_RASPBERRY = 4;
        uint public constant GRAPE = 5;
        uint public constant RAINBOW_BLAST = 6;
        uint public constant YIELD_PERIOD = 1 weeks;
        uint public constant MAX_YIELD = 333;
        uint public START_TIME;
        uint public END_TIME;
        uint8[9998] private amountClaimed;
        bool public CLAIM_ENABLED = false;
        SODAContract soda;
        address public SODA_CONTRACT;
        string private baseURI;
    
        constructor(address sodaContract, string memory _baseURI) public ERC1155(_baseURI) {
            baseURI = _baseURI;
            uint[] memory amts = new uint[](7);
            amts[0] = 20000;
            amts[1] = 20000;
            amts[2] = 20000;
            amts[3] = 20000;
            amts[4] = 20000;
            amts[5] = 20000;
            amts[6] = 3000;
            _mintBatch(msg.sender, amts, "");
            soda = SODAContract(sodaContract);
            SODA_CONTRACT = sodaContract;
            START_TIME = block.timestamp - YIELD_PERIOD;
            END_TIME = START_TIME + (YIELD_PERIOD * MAX_YIELD);
        }
    
        function cansClaimed(uint tokenId) external view returns(uint) {
            return amountClaimed[ tokenId ];
        }
    
        function cansUnclaimed(uint tokenId) external view returns(uint) {
            return currentPayout() - amountClaimed[tokenId];
        }
    
        function unclaimedTotal(uint[] memory tokenIds) external view returns(uint) {
            uint totalClaimed = 0;
    
            for(uint i = 0; i < tokenIds.length; i++) {
                totalClaimed += amountClaimed[tokenIds[i]];
            }
    
            return (currentPayout()*tokenIds.length) - totalClaimed;
        }
    
        function claim(uint[] calldata tokenIds, uint[] calldata amounts) external reentryLock {
            require(CLAIM_ENABLED, "Cans: claiming is disabled");
            require(amounts.length == 6, "Cans: Amount of each fruit flavor not specified.");
            uint payout = currentPayout();
            uint nTokens = tokenIds.length;
            uint totalAvailable = payout * nTokens;
    
            for(uint i = 0; i < nTokens; i++) {
                uint id = tokenIds[i];
                require(soda.ownerOf(id) == msg.sender, "Cans: Sender does not own this SODA.");
                totalAvailable -= uint(amountClaimed[id]);
                amountClaimed[id] = uint8(payout);
            }
            delete payout;
    
            uint claimTotal = amounts[0] + 
                amounts[1] + 
                amounts[2] + 
                amounts[3] + 
                amounts[4] + 
                amounts[5];
            uint remainder = totalAvailable - claimTotal;
            delete totalAvailable;
    
            require(remainder >= 0, "Cans: Attempted to claim wrong amount of Cans.");
    
            uint[] memory amts = new uint[](7);
            amts[0] = amounts[0];
            amts[1] = amounts[1];
            amts[2] = amounts[2];
            amts[3] = amounts[3];
            amts[4] = amounts[4];
            amts[5] = amounts[5];
            amts[6] = (claimTotal / 6);
            delete claimTotal;
    
            _mintBatch(msg.sender, amts, "");
            delete amts;
    
            // Reimburse Cans unclaimed, if necessary
            for(uint i = 0; i < remainder; i++) {
                amountClaimed[tokenIds[i%nTokens]]--;
            }
        }
    
        function burn(uint[] calldata amounts) external {
            _burnBatch(msg.sender, amounts);
        }
    
        function setTokenURI(string memory newURI) external onlyOwner {
            _setURI(newURI);
        }
    
        function seedWallets(address[] calldata to, uint amount) external onlyOwner {
            require(!CLAIM_ENABLED);
            _safeSeedWallets(to, amount);
        }
    
        function enableClaiming() external onlyOwner {
            CLAIM_ENABLED = true;
        }
    
        function currentPayout() internal view returns(uint) {
            uint start = block.timestamp;
            return ((start < END_TIME ? start : END_TIME)-START_TIME) / YIELD_PERIOD;
        }
    
        function uri(uint256 id) public view override returns (string memory)
        {
            require(id <= 6, "URI requested for invalid serum type");
            return string(abi.encodePacked(baseURI, toString(id)));
        }
    }

    File 2 of 2: SODA
    // Sources flattened with hardhat v2.6.8 https://hardhat.org
    
    // File contracts/IERC165.sol
    
    // SPDX-License-Identifier: MIT
    
    pragma solidity ^0.8.0;
    
    /*
        Fully commented standard ERC721 Distilled from OpenZeppelin Docs
        Base for Building ERC721 by Martin McConnell
        All the utility without the fluff.
    */
    
    
    interface IERC165 {
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    
    
    // File contracts/IERC721.sol
    
    pragma solidity ^0.8.0;
    
    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`.
        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 contracts/IERC721Receiver.sol
    
    pragma solidity ^0.8.0;
    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 contracts/IERC721Metadata.sol
    
    pragma solidity ^0.8.0;
    
    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 contracts/Context.sol
    
    pragma solidity ^0.8.0;
    
    
    
    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 contracts/Ownable.sol
    
    pragma solidity ^0.8.0;
    
    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() {
            _setOwner(_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 {
            _setOwner(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");
            _setOwner(newOwner);
        }
    
        function _setOwner(address newOwner) private {
            address oldOwner = _owner;
            _owner = newOwner;
            emit OwnershipTransferred(oldOwner, newOwner);
        }
    }
    
    
    // File contracts/Functional.sol
    
    pragma solidity ^0.8.0;
    
    
    abstract contract Functional {
        function toString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
                digits -= 1;
                buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                value /= 10;
            }
            return string(buffer);
        }
        
        bool private _reentryKey = false;
        modifier reentryLock {
            require(!_reentryKey, "attempt to reenter a locked function");
            _reentryKey = true;
            _;
            _reentryKey = false;
        }
    }
    
    
    // File contracts/Address.sol
    
    pragma solidity ^0.8.0;
    
    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;
            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");
    
            (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");
    
            (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");
    
            (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");
    
            (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
    
                    assembly {
                        let returndata_size := mload(returndata)
                        revert(add(32, returndata), returndata_size)
                    }
                } else {
                    revert(errorMessage);
                }
            }
        }
    }
    
    
    // File contracts/ControlledAccess.sol
    
    pragma solidity ^0.8.0;
    
    /* @title ControlledAccess
     * @dev The ControlledAccess contract allows function to be restricted to users
     * that possess a signed authorization from the owner of the contract. This signed
     * message includes the user to give permission to and the contract address to prevent
     * reusing the same authorization message on different contract with same owner.
     */
    
    contract ControlledAccess is Ownable {
        address public signerAddress;
    
        /*
         * @dev Requires msg.sender to have valid access message.
         * @param _v ECDSA signature parameter v.
         * @param _r ECDSA signature parameters r.
         * @param _s ECDSA signature parameters s.
         */
        modifier onlyValidAccess(
            bytes32 _r,
            bytes32 _s,
            uint8 _v
        ) {
            require(isValidAccessMessage(msg.sender, _r, _s, _v));
            _;
        }
    
        function setSignerAddress(address newAddress) external onlyOwner {
            signerAddress = newAddress;
        }
    
        /*
         * @dev Verifies if message was signed by owner to give access to _add for this contract.
         *      Assumes Geth signature prefix.
         * @param _add Address of agent with access
         * @param _v ECDSA signature parameter v.
         * @param _r ECDSA signature parameters r.
         * @param _s ECDSA signature parameters s.
         * @return Validity of access message for a given address.
         */
        function isValidAccessMessage(
            address _add,
            bytes32 _r,
            bytes32 _s,
            uint8 _v
        ) public view returns (bool) {
            bytes32 hash = keccak256(abi.encode(owner(), _add));
            bytes32 message = keccak256(
                abi.encodePacked("\x19Ethereum Signed Message:\n32", hash)
            );
            address sig = ecrecover(message, _v, _r, _s);
    
            require(signerAddress == sig, "Signature does not match");
    
            return signerAddress == sig;
        }
    }
    
    
    // File contracts/SODA.sol
    
    // ******************************************************************************************************************************
    // **************************************************  Start of Main Contract ***************************************************
    // ******************************************************************************************************************************
    
    pragma solidity ^0.8.0;
    
    
    
    
    
    
    
    contract SODA is IERC721, Ownable, Functional, ControlledAccess {
    
        using Address for address;
    
        // Token name
        string private _name;
    
        // Token symbol
        string private _symbol;
    
        // URI Root Location for Json Files
        string private _baseURI;
    
        // Provenance hash proving random distribution
        string public provenanceHash;
    
        // 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;
    
        // Specific Functionality
        bool public mintActive;
        bool public presaleActive;
        uint256 public price;
        uint256 public totalTokens;
        uint256 public numberMinted;
        uint256 public maxPerWallet;
        uint256 public maxPerTx;
        uint256 public reservedTokens;
    
        uint256 public startingIndex;
        uint256 public startingIndexBlock;
        mapping(address => uint256) private _tokensMintedby;
    
        /**
         * @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
         */
        constructor() {
            _name = "Society of Derivative Apes";
            _symbol = "SODA";
    
            mintActive = false;
            presaleActive = false;
            totalTokens = 9999; // 0-9998
            price = 0.04 ether;
            maxPerWallet = 6;
            maxPerTx = 3;
            reservedTokens = 100; // reserved for giveaways and such
        }
    
        //@dev See {IERC165-supportsInterface}. Interfaces Supported by this Standard
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            return  interfaceId == type(IERC721).interfaceId ||
                    interfaceId == type(IERC721Metadata).interfaceId ||
                    interfaceId == type(IERC165).interfaceId ||
                    interfaceId == SODA.onERC721Received.selector;
        }
    
        // Standard Withdraw function for the owner to pull the contract
        function withdraw() external onlyOwner {
            uint256 sendAmount = address(this).balance;
    
            address founders = payable(0x62F9ACbD11350FB05B3215507dD1f6e05ed27aF5);
            address liam = payable(0x3C31abE4b91c9e8bD39fB505CD98c59fc78cD8E6);
            address drew = payable(0x30A8Bac5AED69b9fF46d4fC04A48388cDe5D3A59);
            address yeti = payable(0xDF808192A2cb234e276eEF4551228e422a5b6B1A);
            address community = payable(0x9fcDD9A89C0a5F8933659077b0Caf2c1EF20ac21);
    
            bool success;
            (success, ) = founders.call{value: ((sendAmount * 51)/100)}("");
            require(success, "Transaction Unsuccessful");
    
            (success, ) = liam.call{value: ((sendAmount * 13)/100)}("");
            require(success, "Transaction Unsuccessful");
    
            (success, ) = drew.call{value: ((sendAmount * 13)/100)}("");
            require(success, "Transaction Unsuccessful");
    
            (success, ) = yeti.call{value: ((sendAmount * 13)/100)}("");
            require(success, "Transaction Unsuccessful");
    
            (success, ) = community.call{value: ((sendAmount * 10)/100)}("");
            require(success, "Transaction Unsuccessful");
         }
    
        function airDrop(address[] memory _to) external onlyOwner {
            uint256 qty = _to.length;
            require((numberMinted + qty) > numberMinted, "Math overflow error");
            require((numberMinted + qty) < totalTokens, "Cannot fill order");
    
            uint256 mintSeedValue = numberMinted;
            if (reservedTokens >= qty) {
                reservedTokens -= qty;
            } else {
                reservedTokens = 0;
            }
    
            for(uint256 i = 0; i < qty; i++) {
                _safeMint(_to[i], mintSeedValue + i);
                numberMinted ++;  //reservedTokens can be reset, numberMinted can not
            }
        }
    
        function mint(uint256 qty) external payable reentryLock {
            require(mintActive);
            require((qty + reservedTokens + numberMinted) < totalTokens, "Mint: Not enough availability");
            require(qty <= maxPerTx, "Mint: Max tokens per transaction exceeded");
            require((_tokensMintedby[_msgSender()] + qty) <= maxPerWallet, "Mint: Max tokens per wallet exceeded");
            require(msg.value >= qty * price, "Mint: Insufficient Funds");
    
            uint256 mintSeedValue = numberMinted; //Store the starting value of the mint batch
    
            //Handle ETH transactions
            uint256 cashIn = msg.value;
            uint256 cashChange = cashIn - (qty * price);
    
            //send tokens
            for(uint256 i = 0; i < qty; i++) {
                _safeMint(_msgSender(), mintSeedValue + i);
                numberMinted ++;
                _tokensMintedby[_msgSender()] ++;
            }
    
            if (cashChange > 0){
                (bool success, ) = msg.sender.call{value: cashChange}("");
                require(success, "Mint: unable to send change to user");
            }
        }
    
        function presaleMint(uint256 qty,
            bytes32 _r,
            bytes32 _s,
            uint8 _v
                            ) external payable onlyValidAccess(_r, _s, _v) reentryLock {
            require(presaleActive);
            require((_tokensMintedby[_msgSender()] + qty) <= maxPerTx, "Presale Mint: Max tokens during presale exceeded");
            require((qty + reservedTokens + numberMinted) < totalTokens, "Mint: Not enough availability");
            require(msg.value >= qty * price, "Mint: Insufficient Funds");
    
            uint256 mintSeedValue = numberMinted; //Store the starting value of the mint batch
    
            //Handle ETH transactions
            uint256 cashIn = msg.value;
            uint256 cashChange = cashIn - (qty * price);
    
            //send tokens
            for(uint256 i = 0; i < qty; i++) {
                _safeMint(_msgSender(), mintSeedValue + i);
                numberMinted ++;
                _tokensMintedby[_msgSender()] ++;
            }
    
            if (cashChange > 0){
                (bool success, ) = msg.sender.call{value: cashChange}("");
                require(success, "Mint: unable to send change to user");
            }
        }
    
    
        // allows holders to burn their own tokens if desired
        /*
        function burn(uint256 tokenID) external {
            require(_msgSender() == ownerOf(tokenID));
            _burn(tokenID);
        }
        */
        //////////////////////////////////////////////////////////////
        //////////////////// Setters and Getters /////////////////////
        //////////////////////////////////////////////////////////////
    
        function setMaxPerWallet(uint256 maxWallet) external onlyOwner {
            maxPerWallet = maxWallet;
        }
    
        function setMaxPerTx(uint256 newMax) external onlyOwner {
            maxPerTx = newMax;
        }
    
        function setBaseURI(string memory newURI) public onlyOwner {
            _baseURI = newURI;
       }
    
        function activateMint() public onlyOwner {
            mintActive = true;
        }
    
        function activatePresale() public onlyOwner {
            presaleActive = true;
        }
    
        function deactivateMint() public onlyOwner {
            mintActive = false;
        }
    
        function deactivatePresale() public onlyOwner {
            presaleActive = false;
        }
    
        function setPrice(uint256 newPrice) public onlyOwner {
            price = newPrice;
        }
    
        function setTotalTokens(uint256 numTokens) public onlyOwner {
            totalTokens = numTokens;
        }
    
        function totalSupply() external view returns (uint256) {
            return numberMinted;
        }
    
        function getBalance(address tokenAddress) view external returns (uint256) {
            return _balances[tokenAddress];
        }
    
        /**
         * @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 _balances[owner];
        }
    
        /**
         * @dev See {IERC721-ownerOf}.
         */
        function ownerOf(uint256 tokenId) public view virtual override returns (address) {
            address owner = _owners[tokenId];
            require(owner != address(0), "ERC721: owner query for nonexistent token");
            return owner;
        }
    
        /**
         * @dev See {IERC721-approve}.
         */
        function approve(address to, uint256 tokenId) public virtual override {
            address owner = ownerOf(tokenId);
            require(to != owner, "ERC721: approval to current owner");
    
            require(
                msg.sender == owner || isApprovedForAll(owner, msg.sender),
                "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 != msg.sender, "ERC721: approve to caller");
    
            _operatorApprovals[msg.sender][operator] = approved;
            emit ApprovalForAll(msg.sender, 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(msg.sender, 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(msg.sender, 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 _owners[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) {
            require(_exists(tokenId), "ERC721: operator query for nonexistent token");
            address owner = ownerOf(tokenId);
            return (spender == owner || getApproved(tokenId) == spender || isApprovedForAll(owner, 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);
    
            _balances[to] += 1;
            _owners[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 = ownerOf(tokenId);
    
            _beforeTokenTransfer(owner, address(0), tokenId);
    
            // Clear approvals
            _approve(address(0), tokenId);
    
            _balances[owner] -= 1;
            delete _owners[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(ownerOf(tokenId) == from, "ERC721: transfer of token that is not own");
            require(to != address(0), "ERC721: transfer to the zero address");
    
            _beforeTokenTransfer(from, to, tokenId);
    
            // Clear approvals from the previous owner
            _approve(address(0), tokenId);
    
            _balances[from] -= 1;
            _balances[to] += 1;
            _owners[tokenId] = to;
    
            emit Transfer(from, to, tokenId);
        }
    
        /**
         * @dev Approve `to` to operate on `tokenId`
         *
         * Emits a {Approval} event.
         */
        function _approve(address to, uint256 tokenId) internal virtual {
            _tokenApprovals[tokenId] = to;
            emit Approval(ownerOf(tokenId), to, tokenId);
        }
    
        /**
         * @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(msg.sender, from, tokenId, _data) returns (bytes4 retval) {
                    return retval == IERC721Receiver(to).onERC721Received.selector;
                } catch (bytes memory reason) {
                    if (reason.length == 0) {
                        revert("ERC721: transfer to non ERC721Receiver implementer");
                    } else {
                        assembly {
                            revert(add(32, reason), mload(reason))
                        }
                    }
                }
            } else {
                return true;
            }
        }
    
        // *********************** ERC721 Token Receiver **********************
        /**
         * @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) {
            //InterfaceID=0x150b7a02
            return this.onERC721Received.selector;
        }
    
        /**
         * @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` and `to` are never both zero.
         *
         * 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 {}
    
        // **************************************** Metadata Standard Functions **********
        //@dev Returns the token collection name.
        function name() external view returns (string memory){
            return _name;
        }
    
        //@dev Returns the token collection symbol.
        function symbol() external view returns (string memory){
            return _symbol;
        }
    
        //@dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
        function tokenURI(uint256 tokenId) external view returns (string memory){
            require(_exists(tokenId), "ERC721Metadata: URI query for nonexistent token");
    
            return string(abi.encodePacked(_baseURI, toString(tokenId), ".json")); /// 0.json 135.json
    
        }
    
        function contractURI() public view returns (string memory) {
                return string(abi.encodePacked(_baseURI,"contract.json"));
        }
    
        function setProvenanceHash(string calldata hash) public onlyOwner {
            provenanceHash = hash;
        }
    
        /**
         * Set the starting index for the collection
         */
        function setStartingIndex() public onlyOwner {
            require(startingIndex == 0, "Starting index is already set");
            require(startingIndexBlock != 0, "Starting index block must be set");
    
            startingIndex = uint256(blockhash(startingIndexBlock)) % totalTokens;
            // Just a sanity case in the worst case if this function is called late (EVM only stores last 256 block hashes)
            if (block.number % startingIndexBlock > 255) {
                startingIndex = uint256(blockhash(block.number - 1)) % totalTokens;
            }
            // Prevent default sequence
            if (startingIndex == 0) {
                startingIndex = startingIndex + 1;
            }
        }
    
        /**
         * Set the starting index block for the collection, essentially unblocking
         * setting starting index
         */
        function setStartingIndexBlock() public onlyOwner {
            require(startingIndex == 0, "Starting index is already set");
    
            startingIndexBlock = block.number;
        }
    
        receive() external payable {}
    
        fallback() external payable {}
    }