// Contract: CryptoBlobs
// Target function: function optimize(
away);
                    } else {
                        delete claimableGiveaway;
                        delete account;
                        delete number;
                    }
                } else {
                    delete account;
                    delete number;
                }

                // Revert if nothing to claim.
                uint256 claimableTotal = claimableHourlyDrops + claimableSacrifices + claimableReferrals + claimableGiveaway;
                if (claimableTotal == 0) revert ACCOUNT_HAS_NOTHING_TO_CLAIM();

                // Update demand multiplier.
                // Paid mints increases the multiplier by 0.01% and 0.03% after 20,000 for increased volatility.
                // Free mints decreases the multiplier by 0.01% and 0.03% after 20,000 for increased volatility for every 2.
                if (claimableTotal >= 2) { // If claiming two or more.
                    uint256 multiplierIncrement;
                    if (tokensMintedPurchase + tokensMintedFree < _increasedVolatilityThreshold) {
                        multiplierIncrement = (claimableTotal / 2) * _volatilityBase; // Increase.
                    } else {
                        multiplierIncrement = (claimableTotal / 2) * _volatilityBase * _volatilityMultiplier; // Increase.
                    }
                    if (_temporaryDemandMultiplier > multiplierIncrement) {
                        _temporaryDemandMultiplier -= uint32(multiplierIncrement); // Decrease.
                    } else {
                        delete _temporaryDemandMultiplier; // Cannot be negative.
                    }
                }

                // Mint token(s).
                _mint(
                    msg.sender,                                 // recipient
                    0,                                          // purchased mints
                    claimableTotal,                             // free mints
                    safeBlockTimestamp,                         // timestamp
                    tokensMintedPurchase + tokensMintedFree     // tokens minted
                );

                emit MintFree(      // 0x7236fe0badcff1706816875cc9df7b9b481c3fb939efe1e7967099499db621d9
                    msg.sender,     // address indexed account
                    account,        // address indexed contractAddress
                    number,         // uint256 tokenId
                    ((              // uint256 data
                        ((
                            ((
                                claimableHourlyDrops            // -XXXXXXXXXXXXXX hourly drops claimed (max 1 per tx)
                            * 10**2) + claimableSacrifices)     // X--XXXXXXXXXXXX sacrifices claimed (max 10 per tx)
                        * 10**2) + claimableReferrals)          // XXX--XXXXXXXXXX referrals claimed (max 10 per tx)
                    * 10**10) + block.timestamp)                // XXXXX---------- timestamp
                );
            }
        }
    }

    /**
        @notice Approves `to` to be a token operator of `tokenId`.
        @dev You must be the owner of `tokenId` or an account operator of the owner.
        @dev Only a single account can be approved at a time.
        @dev Approve the zero address to clear the current approval.
        @dev The approval is cleared when the token is transferred.
        @param to The address of the account to approve.
        @param tokenId The token ID of the CryptoBlob to manage.
    */
    function approve(address to, uint256 tokenId) public virtual override {
        // Get the owner of `tokenId`.
        address owner = ownerOf(tokenId);

        // Cannot approve the current owner.
        if (to == owner) revert CANNOT_APPROVE_THIS_ADDRESS();

        // Revert if not the owner and not approved for all.
        if (msg.sender != owner && !isApprovedForAll(owner, msg.sender)) revert RESTRICTED_ACCESS();

        // Approve `to` to manage `tokenId`.
        _token[tokenId].approval = to;

        emit Approval(  // 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925
            owner,      // address indexed owner
            to,         // address indexed approved
            tokenId     // uint256 indexed tokenId
        );
    }

    /**
        @notice Approves `to` to be an account operator of your account.
        @dev Account operators can do everything the owner can do expect sign messages and manage their account operators.
        @dev Preapproved services: OpenSea, X2Y2, LooksRare, Rarible, 0x Protocol v4, Element, SudoSwap, NFTX, and NFTTrader.
        @dev You can revoke these services using {setApprovalForAll} or visit CryptoBlobs.com for a batch tx to revoke all at once.
        @dev SuperCollectiv will permanently disable preapproved services if any issues are discovered with these contracts.
        @dev Services that list your account operators will not detect that these addresses have
        @dev been approved unless you reapprove each service with {setApprovalForAll} or {batch}.
        @param operator The address of the account to update the operator status of.
        @param approved The approval status to set `operator` to.
    */
    function setApprovalForAll(address operator, bool approved)
        public
        virtual
        override
    {
        unchecked {
            if (msg.sender == operator) revert CANNOT_APPROVE_THIS_ADDRESS();

            // Numbers are used to enable the preapproved services feature. Works similarly to an enum.
            // Values:
            // 0 = default
            // 1 = revoked
            // 2 = approved

            if (approved) {
                _account[msg.sender].approvals[operator] = 2; // Approve.
            } else {
                _account[msg.sender].approvals[operator] = 1; // Revoked.
            }

            emit ApprovalForAll(    // 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31
                msg.sender,         // address indexed owner
                operator,           // address indexed operator
                approved            // bool approved
            );
        }
    }

    /**
        @notice Transfers `tokenId` from `from` to `to`.
        @param from The address of the account that owns `tokenId`.
        @param to The address of the account to transfer `tokenId` to.
        @param tokenId The token ID of the CryptoBlob to transfer.
    */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        // Reverts if the sender does not have access.
        // The owner's address is returned if the sender does have access.
        address owner = _revertIfNoAccess(msg.sender, tokenId);
        if (owner != from) revert FROM_ADDRESS_DOES_NOT_MATCH_THE_OWNERS_ADDRESS();
        // Transfer the CryptoBlob to the new owner.
        _transfer(owner, to, tokenId);
    }

    /**
        @notice Safely transfers `tokenId` from `from` to `to` by checking onERC721Received if `to` is a contract.
        @param from The address of the account that owns `tokenId`.
        @param to The address of the account to transfer `tokenId` to.
        @param tokenId The token ID of the CryptoBlob to transfer.
    */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) public virtual override {
        safeTransferFrom(from, to, tokenId, "");
    }

    /**
        @notice Safely transfers `tokenId` from `from` to `to` by checking onERC721Received if `to` is a contract.
        @param from The address of the account that owns `tokenId`.
        @param to The address of the account to transfer `tokenId` to.
        @param tokenId The token ID of the CryptoBlob to transfer.
        @param data Bytes of data to send to `to`.
    */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes memory data
    ) public virtual override {
        // Transfer the CryptoBlob if the sender has access to it.
        transferFrom(from, to, tokenId);
        // Check if 'to' supports ERC721 NFTs so the CryptoBlob does not get stuck.
        if (_isContractPastConstruction(to)) {
            try IERC721Receiver(to).onERC721Received(msg.sender, from, tokenId, data) returns (bytes4 retval) {
                if (retval != IERC721Receiver.onERC721Received.selector) revert CONTRACT_DOES_NOT_HAVE_ONERC721RECEIVED_IMPLEMENTED();
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert CONTRACT_DOES_NOT_HAVE_ONERC721RECEIVED_IMPLEMENTED();
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
    }

    /**
        @notice Allows you to make multiple transactions in a single transaction.
        @dev Categories: 0 {transferFrom}, 1 {setApprovalForAll}, 2 {approve}, 3 {manageTrades}, 4 {optimize}, 5 {sacrifice}.
        @dev Each transaction is separately encoded and processed in the order of the array.
        @param batchDataEncoded The encoded batch data.
    */
    function batch(
        bytes[] memory batchDataEncoded
    ) external {
        unchecked {
            for (uint256 i; i < batchDataEncoded.length; i++) {

                // Decode this transaction.
                BatchData memory batchData = abi.decode(batchDataEncoded[i], (BatchData));

                // Determine function and transact.
                if (batchData.category == 0) {
                    // Transfer the CryptoBlob if the sender has access to it.
                    transferFrom(batchData.account1, batchData.account2, batchData.tokenId);
                } else if (batchData.category == 1) {
                    // Approve or revoke an account operator.
                    setApprovalForAll(batchData.account1, batchData.approved);
                } else if (batchData.category == 2) {
                    // Approve or revoke a token operator.
                    approve(batchData.account1, batchData.tokenId);
                } else if (batchData.category == 3) {
                    // Cancel a trade or lock/unlock trades for an account you have access to.
                    manageTrades(batchData.account1, batchData.hash);
                } else if (batchData.category == 4) {
                    // Optimize CryptoBlobs.
                    optimize(batchData.tokenIds);
                } else if (batchData.category == 5) {
                    // Sacrifice CryptoBlobs.
                    sacrifice(batchData.tokenId, batchData.tokenIds);
                }
            }
        }
    }

    /**
        @notice Cancel a trade or lock/unlock your trades on the integrated trading platform.
        @dev This has no effect on third-party NFT marketplaces.
        @dev Locking your trades prevents others from completing them.
        @dev Trades that auto-expire will continue to countdown when they're locked.
        @param account The account to manage the trades of. Can be an account you are an operator of.
        @param hash The hash of the trade to cancel. 0 bytes to unlock trades. 1 byte to lock trades.
    */
    function manageTrades(
        address account,
        bytes32 hash
    ) public {
        unchecked {
            // Check if the caller has access.
            if (msg.sender != account && !isApprovedForAll(account, msg.sender)) revert RESTRICTED_ACCESS();

            if (hash == 0x0000000000000000000000000000000000000000000000000000000000000000) { // Unlock trades.
                delete _account[account].timestampTradesLocked;
            } else if (hash == 0x0000000000000000000000000000000000000000000000000000000000000001) { // Lock trades.
                _account[account].timestampTradesLocked = _safeBlockTimestamp();
            } else if (_account[account].timestampTradeHashUsed[hash] == 0) { // Cancel trade if not cancelled.
                // The block timestamp is multiplied by 10 to store a binary number. 0 means cancelled. 1 means completed.
                _account[account].timestampTradeHashUsed[hash] = block.timestamp * 10;
            } else {
                revert RESTRICTED_ACCESS();
            }

            uint256[] memory empty = new uint256[](0); // Empty array.

            // msg.sender is `taker` when isTrade is false, which can be an account operator.
            emit Trade(             // 0x10d92c47650ef2b2a841f26c951f4391ccbb731e57d36a67665a0d138e08ef09
                hash,               // address indexed hash
                account,            // address indexed maker
                msg.sender,         // address indexed taker
                empty,              // uint256[] makerIds
                empty,              // uint256[] takerIds
                0,                  // uint256 price
                0,                  // uint256 expiry
                block.timestamp,    // uint256 timestamp
                false               // bool isTrade
            );
        }
    }

    /**
        @notice Confirm a trade on the integrated trading platform.
        @dev Buy, sell, and trade multiple CryptoBlobs at a time.
        @dev Makers and takers can trade CryptoBlobs that they have access to. 
        @dev Approve accounts with {approve} or {setApprovalForAll}.
        @dev Makers do not need to approve this contract to trade.
        @dev Only takers can transfer ETH in a trade. Makers can't deposit ETH.
        @dev Use {manageTrades} to cancel a trade or lock/unlock your trades.
        @dev The trading platform does not currently support EIP-712.
        @param maker The address of the maker.
        @param taker The address of the taker.
        @param makerIds The CryptoBlob IDs `maker` has access to trade.
        @param takerIds The CryptoBlob IDs `taker` has access to trade.
        @param price The price (in WEI) the `taker` must pay to `maker` to complete the trade.
        @param expiry The timestamp the trade auto-expires, or 0 for never expires.
        @param salt Salt allows the same trade parameters to be used again, resulting in a different hash.
        @param signature The signature is the hash of the trade signed by the maker.
    */
    function trade(
        address maker,
        address taker,
        uint256[] memory makerIds,
        uint256[] memory takerIds,
        uint256 price,
        uint256 expiry,
        uint256 salt,
        bytes memory signature
    ) external payable nonReentrant {
        unchecked {

            // Check if trading is paused.
            if (_tradingPaused) revert TRADING_IS_CURRENTLY_DISABLED();

            // Revert if the trade is private and if the sender is not the taker.
            if (taker != address(0) && msg.sender != taker) revert TRADE_IS_NOT_FOR_YOU();

            // Revert if the amount sent is insufficient.
            if (msg.value < price) revert INSUFFICIENT_FUNDS_SENT();

            // Get the hash and errors for the trade.
            (bytes32 hash, uint256[8] memory errors) = isTradeApprovedAndValid(
                maker,
                taker,
                makerIds,
                takerIds,
                price,
                expiry,
                salt,
                signature, 
                false
            );

            // Revert if the trade contains errors.
            for (uint256 i; i < errors.length; i++) if (errors[i] != 0) revert INVALID_TRADE();

            // Transfer sale price to the maker.
            if (price > 0) _transferEther(maker, price);

            // Transfer CryptoBlobs.
            // Third-party NFT marketplaces require an approval to use {transferFrom}, but this trading platform uses {_transfer}, 
            // an internal function, to bypass approvals. This allows takers to complete trades on the maker's behalf using a signature.
            // Note that {_revertIfNoAccess} returns the owner's address because makers and takers can be approved accounts.

            // Transfer maker IDs. Reverts if the maker does not have access to transfer a maker ID.
            for (uint256 i; i < makerIds.length; i++) _transfer(_revertIfNoAccess(maker, makerIds[i]), msg.sender, makerIds[i]);

            // Transfer taker IDs. Reverts if the sender does not have access to transfer a taker ID.
            for (uint256 i; i < takerIds.length; i++) _transfer(_revertIfNoAccess(msg.sender, takerIds[i]), maker, takerIds[i]);

            // Use the trade hash.
            // The block timestamp is multiplied by 10 to store a binary number. 0 means cancelled. 1 means completed.
            _account[maker].timestampTradeHashUsed[hash] = (block.timestamp * 10) + 1;

            emit Trade(             // 0x10d92c47650ef2b2a841f26c951f4391ccbb731e57d36a67665a0d138e08ef09
                hash,               // bytes32 hash
                maker,              // address indexed maker
                msg.sender,         // address indexed taker
                makerIds,           // uint256[] makerIds
                takerIds,           // uint256[] takerIds
                price,              // uint256 price
                expiry,             // uint256 expiry
                block.timestamp,    // uint256 timestamp
                true                // bool isTrade
            );
        }
    }