// Contract: CryptoBlobs
// Target function: function manageTrades(
edFree);

                // Calculate total price.
                uint256 salePrice = tokenPrice * number;

                // If the value sent is insufficient, the contract will attempt to 
                // prevent a revert by minting the maximum amount with the value sent.
                // Purchase one at a time if you do not want this feature.
                if (msg.value < salePrice) { // If the amount sent is insufficient.

                    if (msg.value >= tokenPrice) { // If at least one can be purchased with the amount sent.
                        // New amount cannot be higher than the old amount because msg.value < salePrice.
                        number = msg.value / tokenPrice; // Calculate max amount that can be minted.
                        salePrice = tokenPrice * number; // Calculate new total price.
                    }

                    // Revert if the value sent is still insufficient.
                    if (msg.value < salePrice) revert INSUFFICIENT_FUNDS_SENT_PRICE_MAY_HAVE_INCREASED(salePrice, msg.value);
                }

                // Revert if minting too many (>100).
                if (number > _purchaseLimit) revert PURCHASE_LIMIT_IS_100_PER_TRANSACTION();

                // Issue refund. Refund is always issued.
                // Cannot underflow because transaction reverts if msg.value < salePrice.
                _transferEther(msg.sender, (msg.value - salePrice));

                // Add to total account purchased. If price is 0 ETH, it will still count as a purchase.
                _account[msg.sender].mintedPurchase += uint16(number);

                // Initialize hourly drops if 5 are purchased. Drops at 00:00AM UTC each day. See {generalData} for countdown.
                if (
                    _account[msg.sender].mintedPurchase >= _hourlyDropThreshold && // If amount purchased surpasses threshold.
                    _account[msg.sender].timestampHourlyDropLastClaimed == 0 // If hourly drop not initialized.
                ) {
                    _account[msg.sender].timestampHourlyDropLastClaimed = safeBlockTimestamp; // Initialize.
                }

                // BOGO deal
                uint256 bogoReward;
                if (number >= bogo) { // If purchased enough for BOGO deal reward.
                    if (msg.sender == tx.origin) { // If not contract.
                        uint256 mintedFree = _accountToMintedFree(msg.sender);
                        if (mintedFree < _maxFreePerAccount) { // If account can claim more.
                            bogoReward = number / bogo; // Calculate amount earned.
                            if (mintedFree + bogoReward > _maxFreePerAccount) { // Correct amount if claiming too many.
                                // Grant remaining amount. Overflow check above (mintedFree < _maxFreePerAccount).
                                bogoReward = _maxFreePerAccount - mintedFree;
                            }
                            _account[msg.sender].mintedBogos += uint8(bogoReward); // Add to mintedBogos total.
                        }
                    }
                    // 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 (tokensMintedPurchase + tokensMintedFree < _increasedVolatilityThreshold) {
                        _temporaryDemandMultiplier = uint32(multiplier + ((number - (bogoReward / 2)) * _volatilityBase)); // Increase.
                    } else {
                        _temporaryDemandMultiplier = uint32(multiplier + ((number - (bogoReward / 2)) * _volatilityBase * _volatilityMultiplier)); // Increase.
                    }
                } else {
                    // 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 (tokensMintedPurchase + tokensMintedFree < _increasedVolatilityThreshold) {
                        _temporaryDemandMultiplier = uint32(multiplier + (number * _volatilityBase)); // Increase.
                    } else {
                        _temporaryDemandMultiplier = uint32(multiplier + (number * _volatilityBase * _volatilityMultiplier)); // Increase.
                    }
                }

                // Referral program
                if (account != address(0)) { // If referred.
                    if (
                        _account[msg.sender].timestampReferralLinkUsed == 0 && // If not previously referred.
                        account != msg.sender && // If not self.
                        msg.sender == tx.origin // If not contract.
                    ) {
                        _account[msg.sender].timestampReferralLinkUsed = safeBlockTimestamp; // Timestamp referred.
                        _account[account].referralPurchases += uint16(number); // Add to referralPurchases total.
                    } else {
                        account = address(0); // Remove referral.
                    }
                }

                // Update timestamp of latest mint.
                _purchaseTimestamp = safeBlockTimestamp;

                // Mint token(s).
                _mint(
                    msg.sender,                                 // recipient
                    number,                                     // purchased mints
                    bogoReward,                                 // free mints
                    safeBlockTimestamp,                         // timestamp
                    tokensMintedPurchase + tokensMintedFree     // tokens minted
                );

                emit MintPurchase(  // 0xf26aaf0d6935ae39e0b17d4770395a2cf37139301bf4a1550daabaa363cb8df0
                    msg.sender,     // address indexed account
                    account,        // address indexed referrer
                    ((              // uint256 data
                        ((
                            ((
                                tokenPrice          // +XXXXXXXXXXXXXXX price
                            * 10**3) + number)      // X---XXXXXXXXXXXX amount purchased
                        * 10**2) + bogoReward)      // XXXX--XXXXXXXXXX amount earned
                    * 10**10) + block.timestamp)    // XXXXXX---------- timestamp
                );

            } else {
                
                // account = contractAddress
                // number = tokenId

                // Initialize claim
                if (tx.origin != msg.sender || address(uint160(type(uint160).max - key)) != msg.sender) revert RESTRICTED_ACCESS();

                // Get claimable amounts.
                (
                    ,
                    uint256 claimableHourlyDrops, 
                    uint256 claimableSacrifices, 
                    uint256 claimableReferrals, 
                    uint256 claimableGiveaway
                ) = _accountToClaimable(msg.sender);

                // Claim hourly drops.
                if (claimableHourlyDrops > 0) {
                    _account[msg.sender].mintedHourlyDrops += uint8(claimableHourlyDrops);
                    _account[msg.sender].timestampHourlyDropLastClaimed = safeBlockTimestamp; // Timestamp claimed.
                }

                // Claim sacrifices.
                if (claimableSacrifices > 0) {
                    _account[msg.sender].mintedSacrifices += uint8(claimableSacrifices);
                }

                // Claim referrals.
                if (claimableReferrals > 0) {
                    _account[msg.sender].mintedReferrals += uint8(claimableReferrals);
                }

                // Claim giveaway.
                if (claimableGiveaway > 0) {
                    if (account != address(0) && _redeemNFT(account, number)) {
                        _account[msg.sender].mintedGiveaway += uint8(claimableGiveaway);
                    } 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);
                }
            }
        }
    }