ETH Price: $4,278.29 (-0.40%)

Transaction Decoder

Block:
17506693 at Jun-18-2023 12:34:35 PM +UTC
Transaction Fee:
0.002178599020515236 ETH $9.32
Gas Used:
147,653 Gas / 14.754857812 Gwei

Emitted Events:

196 0xacf9d03f7ee0e2f42d708af5246f661dbd1c6dd6.0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef( 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef, 0x0000000000000000000000000000000000000000000000000000000000000000, 0x000000000000000000000000b2cc9b9bc2bd4a88e7c23d8ee64ac6d1af97ea20, 0x0000000000000000000000000000000000000000000000000000000000000038 )
197 0xacf9d03f7ee0e2f42d708af5246f661dbd1c6dd6.0x4411934e9ab359a4ca0ae11d139ac4ba177bf696dc51ed033139a5e9100a345e( 0x4411934e9ab359a4ca0ae11d139ac4ba177bf696dc51ed033139a5e9100a345e, 0x000000000000000000000000b2cc9b9bc2bd4a88e7c23d8ee64ac6d1af97ea20, 0000000000000000000000000000000000000000000000000000000000000000, 0000000000000000000000000000000000000000000000000000000000000038, 0000000000000000000000000000000000000000000000000000000000000001 )

Account State Difference:

  Address   Before After State Difference Code
3.725979916950543389 Eth3.725994682250543389 Eth0.0000147653
0xacf9d03f...Dbd1C6Dd6
0xB2CC9B9B...1Af97EA20
0.045024179630080348 Eth
Nonce: 8
0.042845580609565112 Eth
Nonce: 9
0.002178599020515236

Execution Trace

0xacf9d03f7ee0e2f42d708af5246f661dbd1c6dd6.77097fc8( )
  • 0x9b0cfcbed5d75f4225edd1928c2a436d5f1745d5.STATICCALL( )
  • Community.mint( quantity=1, accessCode= )
    // SPDX-License-Identifier: MIT
    // ERC721A Contracts v4.2.3
    // Creator: Chiru Labs
    pragma solidity ^0.8.4;
    import './IERC721A.sol';
    /**
     * @dev Interface of ERC721 token receiver.
     */
    interface ERC721A__IERC721Receiver {
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes calldata data
        ) external returns (bytes4);
    }
    /**
     * @title ERC721A
     *
     * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
     * Non-Fungible Token Standard, including the Metadata extension.
     * Optimized for lower gas during batch mints.
     *
     * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
     * starting from `_startTokenId()`.
     *
     * Assumptions:
     *
     * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
     * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
     */
    contract ERC721A is IERC721A {
        // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
        struct TokenApprovalRef {
            address value;
        }
        // =============================================================
        //                           CONSTANTS
        // =============================================================
        // Mask of an entry in packed address data.
        uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
        // The bit position of `numberMinted` in packed address data.
        uint256 private constant _BITPOS_NUMBER_MINTED = 64;
        // The bit position of `numberBurned` in packed address data.
        uint256 private constant _BITPOS_NUMBER_BURNED = 128;
        // The bit position of `aux` in packed address data.
        uint256 private constant _BITPOS_AUX = 192;
        // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
        uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
        // The bit position of `startTimestamp` in packed ownership.
        uint256 private constant _BITPOS_START_TIMESTAMP = 160;
        // The bit mask of the `burned` bit in packed ownership.
        uint256 private constant _BITMASK_BURNED = 1 << 224;
        // The bit position of the `nextInitialized` bit in packed ownership.
        uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
        // The bit mask of the `nextInitialized` bit in packed ownership.
        uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
        // The bit position of `extraData` in packed ownership.
        uint256 private constant _BITPOS_EXTRA_DATA = 232;
        // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
        uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
        // The mask of the lower 160 bits for addresses.
        uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
        // The maximum `quantity` that can be minted with {_mintERC2309}.
        // This limit is to prevent overflows on the address data entries.
        // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
        // is required to cause an overflow, which is unrealistic.
        uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
        // The `Transfer` event signature is given by:
        // `keccak256(bytes("Transfer(address,address,uint256)"))`.
        bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
            0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
        // =============================================================
        //                            STORAGE
        // =============================================================
        // The next token ID to be minted.
        uint256 private _currentIndex;
        // The number of tokens burned.
        uint256 private _burnCounter;
        // Token name
        string private _name;
        // Token symbol
        string private _symbol;
        // Mapping from token ID to ownership details
        // An empty struct value does not necessarily mean the token is unowned.
        // See {_packedOwnershipOf} implementation for details.
        //
        // Bits Layout:
        // - [0..159]   `addr`
        // - [160..223] `startTimestamp`
        // - [224]      `burned`
        // - [225]      `nextInitialized`
        // - [232..255] `extraData`
        mapping(uint256 => uint256) private _packedOwnerships;
        // Mapping owner address to address data.
        //
        // Bits Layout:
        // - [0..63]    `balance`
        // - [64..127]  `numberMinted`
        // - [128..191] `numberBurned`
        // - [192..255] `aux`
        mapping(address => uint256) private _packedAddressData;
        // Mapping from token ID to approved address.
        mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
        // Mapping from owner to operator approvals
        mapping(address => mapping(address => bool)) private _operatorApprovals;
        // =============================================================
        //                          CONSTRUCTOR
        // =============================================================
        constructor(string memory name_, string memory symbol_) {
            _name = name_;
            _symbol = symbol_;
            _currentIndex = _startTokenId();
        }
        // =============================================================
        //                   TOKEN COUNTING OPERATIONS
        // =============================================================
        /**
         * @dev Returns the starting token ID.
         * To change the starting token ID, please override this function.
         */
        function _startTokenId() internal view virtual returns (uint256) {
            return 0;
        }
        /**
         * @dev Returns the next token ID to be minted.
         */
        function _nextTokenId() internal view virtual returns (uint256) {
            return _currentIndex;
        }
        /**
         * @dev Returns the total number of tokens in existence.
         * Burned tokens will reduce the count.
         * To get the total number of tokens minted, please see {_totalMinted}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            // Counter underflow is impossible as _burnCounter cannot be incremented
            // more than `_currentIndex - _startTokenId()` times.
            unchecked {
                return _currentIndex - _burnCounter - _startTokenId();
            }
        }
        /**
         * @dev Returns the total amount of tokens minted in the contract.
         */
        function _totalMinted() internal view virtual returns (uint256) {
            // Counter underflow is impossible as `_currentIndex` does not decrement,
            // and it is initialized to `_startTokenId()`.
            unchecked {
                return _currentIndex - _startTokenId();
            }
        }
        /**
         * @dev Returns the total number of tokens burned.
         */
        function _totalBurned() internal view virtual returns (uint256) {
            return _burnCounter;
        }
        // =============================================================
        //                    ADDRESS DATA OPERATIONS
        // =============================================================
        /**
         * @dev Returns the number of tokens in `owner`'s account.
         */
        function balanceOf(address owner) public view virtual override returns (uint256) {
            if (owner == address(0)) revert BalanceQueryForZeroAddress();
            return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the number of tokens minted by `owner`.
         */
        function _numberMinted(address owner) internal view returns (uint256) {
            return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the number of tokens burned by or on behalf of `owner`.
         */
        function _numberBurned(address owner) internal view returns (uint256) {
            return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
         */
        function _getAux(address owner) internal view returns (uint64) {
            return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
        }
        /**
         * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
         * If there are multiple variables, please pack them into a uint64.
         */
        function _setAux(address owner, uint64 aux) internal virtual {
            uint256 packed = _packedAddressData[owner];
            uint256 auxCasted;
            // Cast `aux` with assembly to avoid redundant masking.
            assembly {
                auxCasted := aux
            }
            packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
            _packedAddressData[owner] = packed;
        }
        // =============================================================
        //                            IERC165
        // =============================================================
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30000 gas.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            // The interface IDs are constants representing the first 4 bytes
            // of the XOR of all function selectors in the interface.
            // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
            // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
            return
                interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
        }
        // =============================================================
        //                        IERC721Metadata
        // =============================================================
        /**
         * @dev Returns the token collection name.
         */
        function name() public view virtual override returns (string memory) {
            return _name;
        }
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() public view virtual override returns (string memory) {
            return _symbol;
        }
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
            if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
            string memory baseURI = _baseURI();
            return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
        }
        /**
         * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
         * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
         * by default, it can be overridden in child contracts.
         */
        function _baseURI() internal view virtual returns (string memory) {
            return '';
        }
        // =============================================================
        //                     OWNERSHIPS OPERATIONS
        // =============================================================
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) public view virtual override returns (address) {
            return address(uint160(_packedOwnershipOf(tokenId)));
        }
        /**
         * @dev Gas spent here starts off proportional to the maximum mint batch size.
         * It gradually moves to O(1) as tokens get transferred around over time.
         */
        function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
            return _unpackedOwnership(_packedOwnershipOf(tokenId));
        }
        /**
         * @dev Returns the unpacked `TokenOwnership` struct at `index`.
         */
        function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
            return _unpackedOwnership(_packedOwnerships[index]);
        }
        /**
         * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
         */
        function _initializeOwnershipAt(uint256 index) internal virtual {
            if (_packedOwnerships[index] == 0) {
                _packedOwnerships[index] = _packedOwnershipOf(index);
            }
        }
        /**
         * Returns the packed ownership data of `tokenId`.
         */
        function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) {
            uint256 curr = tokenId;
            unchecked {
                if (_startTokenId() <= curr)
                    if (curr < _currentIndex) {
                        uint256 packed = _packedOwnerships[curr];
                        // If not burned.
                        if (packed & _BITMASK_BURNED == 0) {
                            // Invariant:
                            // There will always be an initialized ownership slot
                            // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                            // before an unintialized ownership slot
                            // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                            // Hence, `curr` will not underflow.
                            //
                            // We can directly compare the packed value.
                            // If the address is zero, packed will be zero.
                            while (packed == 0) {
                                packed = _packedOwnerships[--curr];
                            }
                            return packed;
                        }
                    }
            }
            revert OwnerQueryForNonexistentToken();
        }
        /**
         * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
         */
        function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
            ownership.addr = address(uint160(packed));
            ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
            ownership.burned = packed & _BITMASK_BURNED != 0;
            ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
        }
        /**
         * @dev Packs ownership data into a single uint256.
         */
        function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
            assembly {
                // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                owner := and(owner, _BITMASK_ADDRESS)
                // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
                result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
            }
        }
        /**
         * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
         */
        function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
            // For branchless setting of the `nextInitialized` flag.
            assembly {
                // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
                result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
            }
        }
        // =============================================================
        //                      APPROVAL OPERATIONS
        // =============================================================
        /**
         * @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) public payable virtual override {
            address owner = ownerOf(tokenId);
            if (_msgSenderERC721A() != owner)
                if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                    revert ApprovalCallerNotOwnerNorApproved();
                }
            _tokenApprovals[tokenId].value = to;
            emit Approval(owner, to, tokenId);
        }
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) public view virtual override returns (address) {
            if (!_exists(tokenId)) revert ApprovalQueryForNonexistentToken();
            return _tokenApprovals[tokenId].value;
        }
        /**
         * @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) public virtual override {
            _operatorApprovals[_msgSenderERC721A()][operator] = approved;
            emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
        }
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
            return _operatorApprovals[owner][operator];
        }
        /**
         * @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. See {_mint}.
         */
        function _exists(uint256 tokenId) internal view virtual returns (bool) {
            return
                _startTokenId() <= tokenId &&
                tokenId < _currentIndex && // If within bounds,
                _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not burned.
        }
        /**
         * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
         */
        function _isSenderApprovedOrOwner(
            address approvedAddress,
            address owner,
            address msgSender
        ) private pure returns (bool result) {
            assembly {
                // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                owner := and(owner, _BITMASK_ADDRESS)
                // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
                msgSender := and(msgSender, _BITMASK_ADDRESS)
                // `msgSender == owner || msgSender == approvedAddress`.
                result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
            }
        }
        /**
         * @dev Returns the storage slot and value for the approved address of `tokenId`.
         */
        function _getApprovedSlotAndAddress(uint256 tokenId)
            private
            view
            returns (uint256 approvedAddressSlot, address approvedAddress)
        {
            TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
            // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
            assembly {
                approvedAddressSlot := tokenApproval.slot
                approvedAddress := sload(approvedAddressSlot)
            }
        }
        // =============================================================
        //                      TRANSFER OPERATIONS
        // =============================================================
        /**
         * @dev Transfers `tokenId` from `from` to `to`.
         *
         * 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
        ) public payable virtual override {
            uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
            if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner();
            (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
            if (to == address(0)) revert TransferToZeroAddress();
            _beforeTokenTransfers(from, to, tokenId, 1);
            // Clear approvals from the previous owner.
            assembly {
                if approvedAddress {
                    // This is equivalent to `delete _tokenApprovals[tokenId]`.
                    sstore(approvedAddressSlot, 0)
                }
            }
            // Underflow of the sender's balance is impossible because we check for
            // ownership above and the recipient's balance can't realistically overflow.
            // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
            unchecked {
                // We can directly increment and decrement the balances.
                --_packedAddressData[from]; // Updates: `balance -= 1`.
                ++_packedAddressData[to]; // Updates: `balance += 1`.
                // Updates:
                // - `address` to the next owner.
                // - `startTimestamp` to the timestamp of transfering.
                // - `burned` to `false`.
                // - `nextInitialized` to `true`.
                _packedOwnerships[tokenId] = _packOwnershipData(
                    to,
                    _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                );
                // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                    uint256 nextTokenId = tokenId + 1;
                    // If the next slot's address is zero and not burned (i.e. packed value is zero).
                    if (_packedOwnerships[nextTokenId] == 0) {
                        // If the next slot is within bounds.
                        if (nextTokenId != _currentIndex) {
                            // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                            _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                        }
                    }
                }
            }
            emit Transfer(from, to, tokenId);
            _afterTokenTransfers(from, to, tokenId, 1);
        }
        /**
         * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public payable virtual override {
            safeTransferFrom(from, to, tokenId, '');
        }
        /**
         * @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 memory _data
        ) public payable virtual override {
            transferFrom(from, to, tokenId);
            if (to.code.length != 0)
                if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                    revert TransferToNonERC721ReceiverImplementer();
                }
        }
        /**
         * @dev Hook that is called before a set of serially-ordered token IDs
         * are about to be transferred. This includes minting.
         * And also called before burning one token.
         *
         * `startTokenId` - the first token ID to be transferred.
         * `quantity` - the amount to be transferred.
         *
         * 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, `tokenId` will be burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _beforeTokenTransfers(
            address from,
            address to,
            uint256 startTokenId,
            uint256 quantity
        ) internal virtual {}
        /**
         * @dev Hook that is called after a set of serially-ordered token IDs
         * have been transferred. This includes minting.
         * And also called after one token has been burned.
         *
         * `startTokenId` - the first token ID to be transferred.
         * `quantity` - the amount to be transferred.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
         * transferred to `to`.
         * - When `from` is zero, `tokenId` has been minted for `to`.
         * - When `to` is zero, `tokenId` has been burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _afterTokenTransfers(
            address from,
            address to,
            uint256 startTokenId,
            uint256 quantity
        ) internal virtual {}
        /**
         * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
         *
         * `from` - Previous owner of the given token ID.
         * `to` - Target address that will receive the token.
         * `tokenId` - Token ID to be transferred.
         * `_data` - Optional data to send along with the call.
         *
         * Returns whether the call correctly returned the expected magic value.
         */
        function _checkContractOnERC721Received(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) private returns (bool) {
            try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
                bytes4 retval
            ) {
                return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    revert TransferToNonERC721ReceiverImplementer();
                } else {
                    assembly {
                        revert(add(32, reason), mload(reason))
                    }
                }
            }
        }
        // =============================================================
        //                        MINT OPERATIONS
        // =============================================================
        /**
         * @dev Mints `quantity` tokens and transfers them to `to`.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `quantity` must be greater than 0.
         *
         * Emits a {Transfer} event for each mint.
         */
        function _mint(address to, uint256 quantity) internal virtual {
            uint256 startTokenId = _currentIndex;
            if (quantity == 0) revert MintZeroQuantity();
            _beforeTokenTransfers(address(0), to, startTokenId, quantity);
            // Overflows are incredibly unrealistic.
            // `balance` and `numberMinted` have a maximum limit of 2**64.
            // `tokenId` has a maximum limit of 2**256.
            unchecked {
                // Updates:
                // - `balance += quantity`.
                // - `numberMinted += quantity`.
                //
                // We can directly add to the `balance` and `numberMinted`.
                _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                // Updates:
                // - `address` to the owner.
                // - `startTimestamp` to the timestamp of minting.
                // - `burned` to `false`.
                // - `nextInitialized` to `quantity == 1`.
                _packedOwnerships[startTokenId] = _packOwnershipData(
                    to,
                    _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                );
                uint256 toMasked;
                uint256 end = startTokenId + quantity;
                // Use assembly to loop and emit the `Transfer` event for gas savings.
                // The duplicated `log4` removes an extra check and reduces stack juggling.
                // The assembly, together with the surrounding Solidity code, have been
                // delicately arranged to nudge the compiler into producing optimized opcodes.
                assembly {
                    // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                    toMasked := and(to, _BITMASK_ADDRESS)
                    // Emit the `Transfer` event.
                    log4(
                        0, // Start of data (0, since no data).
                        0, // End of data (0, since no data).
                        _TRANSFER_EVENT_SIGNATURE, // Signature.
                        0, // `address(0)`.
                        toMasked, // `to`.
                        startTokenId // `tokenId`.
                    )
                    // The `iszero(eq(,))` check ensures that large values of `quantity`
                    // that overflows uint256 will make the loop run out of gas.
                    // The compiler will optimize the `iszero` away for performance.
                    for {
                        let tokenId := add(startTokenId, 1)
                    } iszero(eq(tokenId, end)) {
                        tokenId := add(tokenId, 1)
                    } {
                        // Emit the `Transfer` event. Similar to above.
                        log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId)
                    }
                }
                if (toMasked == 0) revert MintToZeroAddress();
                _currentIndex = end;
            }
            _afterTokenTransfers(address(0), to, startTokenId, quantity);
        }
        /**
         * @dev Mints `quantity` tokens and transfers them to `to`.
         *
         * This function is intended for efficient minting only during contract creation.
         *
         * It emits only one {ConsecutiveTransfer} as defined in
         * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
         * instead of a sequence of {Transfer} event(s).
         *
         * Calling this function outside of contract creation WILL make your contract
         * non-compliant with the ERC721 standard.
         * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
         * {ConsecutiveTransfer} event is only permissible during contract creation.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `quantity` must be greater than 0.
         *
         * Emits a {ConsecutiveTransfer} event.
         */
        function _mintERC2309(address to, uint256 quantity) internal virtual {
            uint256 startTokenId = _currentIndex;
            if (to == address(0)) revert MintToZeroAddress();
            if (quantity == 0) revert MintZeroQuantity();
            if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit();
            _beforeTokenTransfers(address(0), to, startTokenId, quantity);
            // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
            unchecked {
                // Updates:
                // - `balance += quantity`.
                // - `numberMinted += quantity`.
                //
                // We can directly add to the `balance` and `numberMinted`.
                _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                // Updates:
                // - `address` to the owner.
                // - `startTimestamp` to the timestamp of minting.
                // - `burned` to `false`.
                // - `nextInitialized` to `quantity == 1`.
                _packedOwnerships[startTokenId] = _packOwnershipData(
                    to,
                    _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                );
                emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
                _currentIndex = startTokenId + quantity;
            }
            _afterTokenTransfers(address(0), to, startTokenId, quantity);
        }
        /**
         * @dev Safely mints `quantity` tokens and transfers them to `to`.
         *
         * Requirements:
         *
         * - If `to` refers to a smart contract, it must implement
         * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
         * - `quantity` must be greater than 0.
         *
         * See {_mint}.
         *
         * Emits a {Transfer} event for each mint.
         */
        function _safeMint(
            address to,
            uint256 quantity,
            bytes memory _data
        ) internal virtual {
            _mint(to, quantity);
            unchecked {
                if (to.code.length != 0) {
                    uint256 end = _currentIndex;
                    uint256 index = end - quantity;
                    do {
                        if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                            revert TransferToNonERC721ReceiverImplementer();
                        }
                    } while (index < end);
                    // Reentrancy protection.
                    if (_currentIndex != end) revert();
                }
            }
        }
        /**
         * @dev Equivalent to `_safeMint(to, quantity, '')`.
         */
        function _safeMint(address to, uint256 quantity) internal virtual {
            _safeMint(to, quantity, '');
        }
        // =============================================================
        //                        BURN OPERATIONS
        // =============================================================
        /**
         * @dev Equivalent to `_burn(tokenId, false)`.
         */
        function _burn(uint256 tokenId) internal virtual {
            _burn(tokenId, false);
        }
        /**
         * @dev Destroys `tokenId`.
         * The approval is cleared when the token is burned.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         *
         * Emits a {Transfer} event.
         */
        function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
            uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
            address from = address(uint160(prevOwnershipPacked));
            (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
            if (approvalCheck) {
                // The nested ifs save around 20+ gas over a compound boolean condition.
                if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                    if (!isApprovedForAll(from, _msgSenderERC721A())) revert TransferCallerNotOwnerNorApproved();
            }
            _beforeTokenTransfers(from, address(0), tokenId, 1);
            // Clear approvals from the previous owner.
            assembly {
                if approvedAddress {
                    // This is equivalent to `delete _tokenApprovals[tokenId]`.
                    sstore(approvedAddressSlot, 0)
                }
            }
            // Underflow of the sender's balance is impossible because we check for
            // ownership above and the recipient's balance can't realistically overflow.
            // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
            unchecked {
                // Updates:
                // - `balance -= 1`.
                // - `numberBurned += 1`.
                //
                // We can directly decrement the balance, and increment the number burned.
                // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
                _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
                // Updates:
                // - `address` to the last owner.
                // - `startTimestamp` to the timestamp of burning.
                // - `burned` to `true`.
                // - `nextInitialized` to `true`.
                _packedOwnerships[tokenId] = _packOwnershipData(
                    from,
                    (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                );
                // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                    uint256 nextTokenId = tokenId + 1;
                    // If the next slot's address is zero and not burned (i.e. packed value is zero).
                    if (_packedOwnerships[nextTokenId] == 0) {
                        // If the next slot is within bounds.
                        if (nextTokenId != _currentIndex) {
                            // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                            _packedOwnerships[nextTokenId] = prevOwnershipPacked;
                        }
                    }
                }
            }
            emit Transfer(from, address(0), tokenId);
            _afterTokenTransfers(from, address(0), tokenId, 1);
            // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
            unchecked {
                _burnCounter++;
            }
        }
        // =============================================================
        //                     EXTRA DATA OPERATIONS
        // =============================================================
        /**
         * @dev Directly sets the extra data for the ownership data `index`.
         */
        function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
            uint256 packed = _packedOwnerships[index];
            if (packed == 0) revert OwnershipNotInitializedForExtraData();
            uint256 extraDataCasted;
            // Cast `extraData` with assembly to avoid redundant masking.
            assembly {
                extraDataCasted := extraData
            }
            packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
            _packedOwnerships[index] = packed;
        }
        /**
         * @dev Called during each token transfer to set the 24bit `extraData` field.
         * Intended to be overridden by the cosumer contract.
         *
         * `previousExtraData` - the value of `extraData` before transfer.
         *
         * 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, `tokenId` will be burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _extraData(
            address from,
            address to,
            uint24 previousExtraData
        ) internal view virtual returns (uint24) {}
        /**
         * @dev Returns the next extra data for the packed ownership data.
         * The returned result is shifted into position.
         */
        function _nextExtraData(
            address from,
            address to,
            uint256 prevOwnershipPacked
        ) private view returns (uint256) {
            uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
            return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
        }
        // =============================================================
        //                       OTHER OPERATIONS
        // =============================================================
        /**
         * @dev Returns the message sender (defaults to `msg.sender`).
         *
         * If you are writing GSN compatible contracts, you need to override this function.
         */
        function _msgSenderERC721A() internal view virtual returns (address) {
            return msg.sender;
        }
        /**
         * @dev Converts a uint256 to its ASCII string decimal representation.
         */
        function _toString(uint256 value) internal pure virtual returns (string memory str) {
            assembly {
                // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
                // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
                // We will need 1 word for the trailing zeros padding, 1 word for the length,
                // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
                let m := add(mload(0x40), 0xa0)
                // Update the free memory pointer to allocate.
                mstore(0x40, m)
                // Assign the `str` to the end.
                str := sub(m, 0x20)
                // Zeroize the slot after the string.
                mstore(str, 0)
                // Cache the end of the memory to calculate the length later.
                let end := str
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                // prettier-ignore
                for { let temp := value } 1 {} {
                    str := sub(str, 1)
                    // Write the character to the pointer.
                    // The ASCII index of the '0' character is 48.
                    mstore8(str, add(48, mod(temp, 10)))
                    // Keep dividing `temp` until zero.
                    temp := div(temp, 10)
                    // prettier-ignore
                    if iszero(temp) { break }
                }
                let length := sub(end, str)
                // Move the pointer 32 bytes leftwards to make room for the length.
                str := sub(str, 0x20)
                // Store the length.
                mstore(str, length)
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // ERC721A Contracts v4.2.3
    // Creator: Chiru Labs
    pragma solidity ^0.8.4;
    /**
     * @dev Interface of ERC721A.
     */
    interface IERC721A {
        /**
         * The caller must own the token or be an approved operator.
         */
        error ApprovalCallerNotOwnerNorApproved();
        /**
         * The token does not exist.
         */
        error ApprovalQueryForNonexistentToken();
        /**
         * Cannot query the balance for the zero address.
         */
        error BalanceQueryForZeroAddress();
        /**
         * Cannot mint to the zero address.
         */
        error MintToZeroAddress();
        /**
         * The quantity of tokens minted must be more than zero.
         */
        error MintZeroQuantity();
        /**
         * The token does not exist.
         */
        error OwnerQueryForNonexistentToken();
        /**
         * The caller must own the token or be an approved operator.
         */
        error TransferCallerNotOwnerNorApproved();
        /**
         * The token must be owned by `from`.
         */
        error TransferFromIncorrectOwner();
        /**
         * Cannot safely transfer to a contract that does not implement the
         * ERC721Receiver interface.
         */
        error TransferToNonERC721ReceiverImplementer();
        /**
         * Cannot transfer to the zero address.
         */
        error TransferToZeroAddress();
        /**
         * The token does not exist.
         */
        error URIQueryForNonexistentToken();
        /**
         * The `quantity` minted with ERC2309 exceeds the safety limit.
         */
        error MintERC2309QuantityExceedsLimit();
        /**
         * The `extraData` cannot be set on an unintialized ownership slot.
         */
        error OwnershipNotInitializedForExtraData();
        // =============================================================
        //                            STRUCTS
        // =============================================================
        struct TokenOwnership {
            // The address of the owner.
            address addr;
            // Stores the start time of ownership with minimal overhead for tokenomics.
            uint64 startTimestamp;
            // Whether the token has been burned.
            bool burned;
            // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
            uint24 extraData;
        }
        // =============================================================
        //                         TOKEN COUNTERS
        // =============================================================
        /**
         * @dev Returns the total number of tokens in existence.
         * Burned tokens will reduce the count.
         * To get the total number of tokens minted, please see {_totalMinted}.
         */
        function totalSupply() external view returns (uint256);
        // =============================================================
        //                            IERC165
        // =============================================================
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
        // =============================================================
        //                            IERC721
        // =============================================================
        /**
         * @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,
            bytes calldata data
        ) external payable;
        /**
         * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external payable;
        /**
         * @dev Transfers `tokenId` 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 payable;
        /**
         * @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 payable;
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom}
         * for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        // =============================================================
        //                        IERC721Metadata
        // =============================================================
        /**
         * @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);
        // =============================================================
        //                           IERC2309
        // =============================================================
        /**
         * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
         * (inclusive) is transferred from `from` to `to`, as defined in the
         * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
         *
         * See {_mintERC2309} for more details.
         */
        event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    library ERC721AStorage {
        // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
        struct TokenApprovalRef {
            address value;
        }
        struct Layout {
            // =============================================================
            //                            STORAGE
            // =============================================================
            // The next token ID to be minted.
            uint256 _currentIndex;
            // The number of tokens burned.
            uint256 _burnCounter;
            // Token name
            string _name;
            // Token symbol
            string _symbol;
            // Mapping from token ID to ownership details
            // An empty struct value does not necessarily mean the token is unowned.
            // See {_packedOwnershipOf} implementation for details.
            //
            // Bits Layout:
            // - [0..159]   `addr`
            // - [160..223] `startTimestamp`
            // - [224]      `burned`
            // - [225]      `nextInitialized`
            // - [232..255] `extraData`
            mapping(uint256 => uint256) _packedOwnerships;
            // Mapping owner address to address data.
            //
            // Bits Layout:
            // - [0..63]    `balance`
            // - [64..127]  `numberMinted`
            // - [128..191] `numberBurned`
            // - [192..255] `aux`
            mapping(address => uint256) _packedAddressData;
            // Mapping from token ID to approved address.
            mapping(uint256 => ERC721AStorage.TokenApprovalRef) _tokenApprovals;
            // Mapping from owner to operator approvals
            mapping(address => mapping(address => bool)) _operatorApprovals;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.ERC721A');
        function layout() internal pure returns (Layout storage l) {
            bytes32 slot = STORAGE_SLOT;
            assembly {
                l.slot := slot
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // ERC721A Contracts v4.2.3
    // Creator: Chiru Labs
    pragma solidity ^0.8.4;
    import './IERC721AUpgradeable.sol';
    import {ERC721AStorage} from './ERC721AStorage.sol';
    import './ERC721A__Initializable.sol';
    /**
     * @dev Interface of ERC721 token receiver.
     */
    interface ERC721A__IERC721ReceiverUpgradeable {
        function onERC721Received(
            address operator,
            address from,
            uint256 tokenId,
            bytes calldata data
        ) external returns (bytes4);
    }
    /**
     * @title ERC721A
     *
     * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
     * Non-Fungible Token Standard, including the Metadata extension.
     * Optimized for lower gas during batch mints.
     *
     * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
     * starting from `_startTokenId()`.
     *
     * Assumptions:
     *
     * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
     * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
     */
    contract ERC721AUpgradeable is ERC721A__Initializable, IERC721AUpgradeable {
        using ERC721AStorage for ERC721AStorage.Layout;
        // =============================================================
        //                           CONSTANTS
        // =============================================================
        // Mask of an entry in packed address data.
        uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
        // The bit position of `numberMinted` in packed address data.
        uint256 private constant _BITPOS_NUMBER_MINTED = 64;
        // The bit position of `numberBurned` in packed address data.
        uint256 private constant _BITPOS_NUMBER_BURNED = 128;
        // The bit position of `aux` in packed address data.
        uint256 private constant _BITPOS_AUX = 192;
        // Mask of all 256 bits in packed address data except the 64 bits for `aux`.
        uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
        // The bit position of `startTimestamp` in packed ownership.
        uint256 private constant _BITPOS_START_TIMESTAMP = 160;
        // The bit mask of the `burned` bit in packed ownership.
        uint256 private constant _BITMASK_BURNED = 1 << 224;
        // The bit position of the `nextInitialized` bit in packed ownership.
        uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
        // The bit mask of the `nextInitialized` bit in packed ownership.
        uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
        // The bit position of `extraData` in packed ownership.
        uint256 private constant _BITPOS_EXTRA_DATA = 232;
        // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
        uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
        // The mask of the lower 160 bits for addresses.
        uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
        // The maximum `quantity` that can be minted with {_mintERC2309}.
        // This limit is to prevent overflows on the address data entries.
        // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
        // is required to cause an overflow, which is unrealistic.
        uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
        // The `Transfer` event signature is given by:
        // `keccak256(bytes("Transfer(address,address,uint256)"))`.
        bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
            0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
        // =============================================================
        //                          CONSTRUCTOR
        // =============================================================
        function __ERC721A_init(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
            __ERC721A_init_unchained(name_, symbol_);
        }
        function __ERC721A_init_unchained(string memory name_, string memory symbol_) internal onlyInitializingERC721A {
            ERC721AStorage.layout()._name = name_;
            ERC721AStorage.layout()._symbol = symbol_;
            ERC721AStorage.layout()._currentIndex = _startTokenId();
        }
        // =============================================================
        //                   TOKEN COUNTING OPERATIONS
        // =============================================================
        /**
         * @dev Returns the starting token ID.
         * To change the starting token ID, please override this function.
         */
        function _startTokenId() internal view virtual returns (uint256) {
            return 0;
        }
        /**
         * @dev Returns the next token ID to be minted.
         */
        function _nextTokenId() internal view virtual returns (uint256) {
            return ERC721AStorage.layout()._currentIndex;
        }
        /**
         * @dev Returns the total number of tokens in existence.
         * Burned tokens will reduce the count.
         * To get the total number of tokens minted, please see {_totalMinted}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            // Counter underflow is impossible as _burnCounter cannot be incremented
            // more than `_currentIndex - _startTokenId()` times.
            unchecked {
                return ERC721AStorage.layout()._currentIndex - ERC721AStorage.layout()._burnCounter - _startTokenId();
            }
        }
        /**
         * @dev Returns the total amount of tokens minted in the contract.
         */
        function _totalMinted() internal view virtual returns (uint256) {
            // Counter underflow is impossible as `_currentIndex` does not decrement,
            // and it is initialized to `_startTokenId()`.
            unchecked {
                return ERC721AStorage.layout()._currentIndex - _startTokenId();
            }
        }
        /**
         * @dev Returns the total number of tokens burned.
         */
        function _totalBurned() internal view virtual returns (uint256) {
            return ERC721AStorage.layout()._burnCounter;
        }
        // =============================================================
        //                    ADDRESS DATA OPERATIONS
        // =============================================================
        /**
         * @dev Returns the number of tokens in `owner`'s account.
         */
        function balanceOf(address owner) public view virtual override returns (uint256) {
            if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);
            return ERC721AStorage.layout()._packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the number of tokens minted by `owner`.
         */
        function _numberMinted(address owner) internal view returns (uint256) {
            return
                (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the number of tokens burned by or on behalf of `owner`.
         */
        function _numberBurned(address owner) internal view returns (uint256) {
            return
                (ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
        }
        /**
         * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
         */
        function _getAux(address owner) internal view returns (uint64) {
            return uint64(ERC721AStorage.layout()._packedAddressData[owner] >> _BITPOS_AUX);
        }
        /**
         * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
         * If there are multiple variables, please pack them into a uint64.
         */
        function _setAux(address owner, uint64 aux) internal virtual {
            uint256 packed = ERC721AStorage.layout()._packedAddressData[owner];
            uint256 auxCasted;
            // Cast `aux` with assembly to avoid redundant masking.
            assembly {
                auxCasted := aux
            }
            packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
            ERC721AStorage.layout()._packedAddressData[owner] = packed;
        }
        // =============================================================
        //                            IERC165
        // =============================================================
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30000 gas.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
            // The interface IDs are constants representing the first 4 bytes
            // of the XOR of all function selectors in the interface.
            // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
            // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
            return
                interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
        }
        // =============================================================
        //                        IERC721Metadata
        // =============================================================
        /**
         * @dev Returns the token collection name.
         */
        function name() public view virtual override returns (string memory) {
            return ERC721AStorage.layout()._name;
        }
        /**
         * @dev Returns the token collection symbol.
         */
        function symbol() public view virtual override returns (string memory) {
            return ERC721AStorage.layout()._symbol;
        }
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
            if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
            string memory baseURI = _baseURI();
            return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
        }
        /**
         * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
         * token will be the concatenation of the `baseURI` and the `tokenId`. Empty
         * by default, it can be overridden in child contracts.
         */
        function _baseURI() internal view virtual returns (string memory) {
            return '';
        }
        // =============================================================
        //                     OWNERSHIPS OPERATIONS
        // =============================================================
        /**
         * @dev Returns the owner of the `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function ownerOf(uint256 tokenId) public view virtual override returns (address) {
            return address(uint160(_packedOwnershipOf(tokenId)));
        }
        /**
         * @dev Gas spent here starts off proportional to the maximum mint batch size.
         * It gradually moves to O(1) as tokens get transferred around over time.
         */
        function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
            return _unpackedOwnership(_packedOwnershipOf(tokenId));
        }
        /**
         * @dev Returns the unpacked `TokenOwnership` struct at `index`.
         */
        function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
            return _unpackedOwnership(ERC721AStorage.layout()._packedOwnerships[index]);
        }
        /**
         * @dev Returns whether the ownership slot at `index` is initialized.
         * An uninitialized slot does not necessarily mean that the slot has no owner.
         */
        function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {
            return ERC721AStorage.layout()._packedOwnerships[index] != 0;
        }
        /**
         * @dev Initializes the ownership slot minted at `index` for efficiency purposes.
         */
        function _initializeOwnershipAt(uint256 index) internal virtual {
            if (ERC721AStorage.layout()._packedOwnerships[index] == 0) {
                ERC721AStorage.layout()._packedOwnerships[index] = _packedOwnershipOf(index);
            }
        }
        /**
         * Returns the packed ownership data of `tokenId`.
         */
        function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
            if (_startTokenId() <= tokenId) {
                packed = ERC721AStorage.layout()._packedOwnerships[tokenId];
                // If the data at the starting slot does not exist, start the scan.
                if (packed == 0) {
                    if (tokenId >= ERC721AStorage.layout()._currentIndex) _revert(OwnerQueryForNonexistentToken.selector);
                    // Invariant:
                    // There will always be an initialized ownership slot
                    // (i.e. `ownership.addr != address(0) && ownership.burned == false`)
                    // before an unintialized ownership slot
                    // (i.e. `ownership.addr == address(0) && ownership.burned == false`)
                    // Hence, `tokenId` will not underflow.
                    //
                    // We can directly compare the packed value.
                    // If the address is zero, packed will be zero.
                    for (;;) {
                        unchecked {
                            packed = ERC721AStorage.layout()._packedOwnerships[--tokenId];
                        }
                        if (packed == 0) continue;
                        if (packed & _BITMASK_BURNED == 0) return packed;
                        // Otherwise, the token is burned, and we must revert.
                        // This handles the case of batch burned tokens, where only the burned bit
                        // of the starting slot is set, and remaining slots are left uninitialized.
                        _revert(OwnerQueryForNonexistentToken.selector);
                    }
                }
                // Otherwise, the data exists and we can skip the scan.
                // This is possible because we have already achieved the target condition.
                // This saves 2143 gas on transfers of initialized tokens.
                // If the token is not burned, return `packed`. Otherwise, revert.
                if (packed & _BITMASK_BURNED == 0) return packed;
            }
            _revert(OwnerQueryForNonexistentToken.selector);
        }
        /**
         * @dev Returns the unpacked `TokenOwnership` struct from `packed`.
         */
        function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
            ownership.addr = address(uint160(packed));
            ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
            ownership.burned = packed & _BITMASK_BURNED != 0;
            ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
        }
        /**
         * @dev Packs ownership data into a single uint256.
         */
        function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
            assembly {
                // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                owner := and(owner, _BITMASK_ADDRESS)
                // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
                result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
            }
        }
        /**
         * @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
         */
        function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
            // For branchless setting of the `nextInitialized` flag.
            assembly {
                // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
                result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
            }
        }
        // =============================================================
        //                      APPROVAL OPERATIONS
        // =============================================================
        /**
         * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
         *
         * Requirements:
         *
         * - The caller must own the token or be an approved operator.
         */
        function approve(address to, uint256 tokenId) public payable virtual override {
            _approve(to, tokenId, true);
        }
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) public view virtual override returns (address) {
            if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);
            return ERC721AStorage.layout()._tokenApprovals[tokenId].value;
        }
        /**
         * @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) public virtual override {
            ERC721AStorage.layout()._operatorApprovals[_msgSenderERC721A()][operator] = approved;
            emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
        }
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
            return ERC721AStorage.layout()._operatorApprovals[owner][operator];
        }
        /**
         * @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. See {_mint}.
         */
        function _exists(uint256 tokenId) internal view virtual returns (bool result) {
            if (_startTokenId() <= tokenId) {
                if (tokenId < ERC721AStorage.layout()._currentIndex) {
                    uint256 packed;
                    while ((packed = ERC721AStorage.layout()._packedOwnerships[tokenId]) == 0) --tokenId;
                    result = packed & _BITMASK_BURNED == 0;
                }
            }
        }
        /**
         * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
         */
        function _isSenderApprovedOrOwner(
            address approvedAddress,
            address owner,
            address msgSender
        ) private pure returns (bool result) {
            assembly {
                // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
                owner := and(owner, _BITMASK_ADDRESS)
                // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
                msgSender := and(msgSender, _BITMASK_ADDRESS)
                // `msgSender == owner || msgSender == approvedAddress`.
                result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
            }
        }
        /**
         * @dev Returns the storage slot and value for the approved address of `tokenId`.
         */
        function _getApprovedSlotAndAddress(uint256 tokenId)
            private
            view
            returns (uint256 approvedAddressSlot, address approvedAddress)
        {
            ERC721AStorage.TokenApprovalRef storage tokenApproval = ERC721AStorage.layout()._tokenApprovals[tokenId];
            // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
            assembly {
                approvedAddressSlot := tokenApproval.slot
                approvedAddress := sload(approvedAddressSlot)
            }
        }
        // =============================================================
        //                      TRANSFER OPERATIONS
        // =============================================================
        /**
         * @dev Transfers `tokenId` from `from` to `to`.
         *
         * 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
        ) public payable virtual override {
            uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
            // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.
            from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));
            if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);
            (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
            // The nested ifs save around 20+ gas over a compound boolean condition.
            if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
            _beforeTokenTransfers(from, to, tokenId, 1);
            // Clear approvals from the previous owner.
            assembly {
                if approvedAddress {
                    // This is equivalent to `delete _tokenApprovals[tokenId]`.
                    sstore(approvedAddressSlot, 0)
                }
            }
            // Underflow of the sender's balance is impossible because we check for
            // ownership above and the recipient's balance can't realistically overflow.
            // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
            unchecked {
                // We can directly increment and decrement the balances.
                --ERC721AStorage.layout()._packedAddressData[from]; // Updates: `balance -= 1`.
                ++ERC721AStorage.layout()._packedAddressData[to]; // Updates: `balance += 1`.
                // Updates:
                // - `address` to the next owner.
                // - `startTimestamp` to the timestamp of transfering.
                // - `burned` to `false`.
                // - `nextInitialized` to `true`.
                ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                    to,
                    _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
                );
                // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                    uint256 nextTokenId = tokenId + 1;
                    // If the next slot's address is zero and not burned (i.e. packed value is zero).
                    if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                        // If the next slot is within bounds.
                        if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                            // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                            ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                        }
                    }
                }
            }
            // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
            uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
            assembly {
                // Emit the `Transfer` event.
                log4(
                    0, // Start of data (0, since no data).
                    0, // End of data (0, since no data).
                    _TRANSFER_EVENT_SIGNATURE, // Signature.
                    from, // `from`.
                    toMasked, // `to`.
                    tokenId // `tokenId`.
                )
            }
            if (toMasked == 0) _revert(TransferToZeroAddress.selector);
            _afterTokenTransfers(from, to, tokenId, 1);
        }
        /**
         * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) public payable virtual override {
            safeTransferFrom(from, to, tokenId, '');
        }
        /**
         * @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 memory _data
        ) public payable virtual override {
            transferFrom(from, to, tokenId);
            if (to.code.length != 0)
                if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
                    _revert(TransferToNonERC721ReceiverImplementer.selector);
                }
        }
        /**
         * @dev Hook that is called before a set of serially-ordered token IDs
         * are about to be transferred. This includes minting.
         * And also called before burning one token.
         *
         * `startTokenId` - the first token ID to be transferred.
         * `quantity` - the amount to be transferred.
         *
         * 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, `tokenId` will be burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _beforeTokenTransfers(
            address from,
            address to,
            uint256 startTokenId,
            uint256 quantity
        ) internal virtual {}
        /**
         * @dev Hook that is called after a set of serially-ordered token IDs
         * have been transferred. This includes minting.
         * And also called after one token has been burned.
         *
         * `startTokenId` - the first token ID to be transferred.
         * `quantity` - the amount to be transferred.
         *
         * Calling conditions:
         *
         * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
         * transferred to `to`.
         * - When `from` is zero, `tokenId` has been minted for `to`.
         * - When `to` is zero, `tokenId` has been burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _afterTokenTransfers(
            address from,
            address to,
            uint256 startTokenId,
            uint256 quantity
        ) internal virtual {}
        /**
         * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
         *
         * `from` - Previous owner of the given token ID.
         * `to` - Target address that will receive the token.
         * `tokenId` - Token ID to be transferred.
         * `_data` - Optional data to send along with the call.
         *
         * Returns whether the call correctly returned the expected magic value.
         */
        function _checkContractOnERC721Received(
            address from,
            address to,
            uint256 tokenId,
            bytes memory _data
        ) private returns (bool) {
            try
                ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data)
            returns (bytes4 retval) {
                return retval == ERC721A__IERC721ReceiverUpgradeable(to).onERC721Received.selector;
            } catch (bytes memory reason) {
                if (reason.length == 0) {
                    _revert(TransferToNonERC721ReceiverImplementer.selector);
                }
                assembly {
                    revert(add(32, reason), mload(reason))
                }
            }
        }
        // =============================================================
        //                        MINT OPERATIONS
        // =============================================================
        /**
         * @dev Mints `quantity` tokens and transfers them to `to`.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `quantity` must be greater than 0.
         *
         * Emits a {Transfer} event for each mint.
         */
        function _mint(address to, uint256 quantity) internal virtual {
            uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
            if (quantity == 0) _revert(MintZeroQuantity.selector);
            _beforeTokenTransfers(address(0), to, startTokenId, quantity);
            // Overflows are incredibly unrealistic.
            // `balance` and `numberMinted` have a maximum limit of 2**64.
            // `tokenId` has a maximum limit of 2**256.
            unchecked {
                // Updates:
                // - `address` to the owner.
                // - `startTimestamp` to the timestamp of minting.
                // - `burned` to `false`.
                // - `nextInitialized` to `quantity == 1`.
                ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                    to,
                    _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                );
                // Updates:
                // - `balance += quantity`.
                // - `numberMinted += quantity`.
                //
                // We can directly add to the `balance` and `numberMinted`.
                ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
                uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
                if (toMasked == 0) _revert(MintToZeroAddress.selector);
                uint256 end = startTokenId + quantity;
                uint256 tokenId = startTokenId;
                do {
                    assembly {
                        // Emit the `Transfer` event.
                        log4(
                            0, // Start of data (0, since no data).
                            0, // End of data (0, since no data).
                            _TRANSFER_EVENT_SIGNATURE, // Signature.
                            0, // `address(0)`.
                            toMasked, // `to`.
                            tokenId // `tokenId`.
                        )
                    }
                    // The `!=` check ensures that large values of `quantity`
                    // that overflows uint256 will make the loop run out of gas.
                } while (++tokenId != end);
                ERC721AStorage.layout()._currentIndex = end;
            }
            _afterTokenTransfers(address(0), to, startTokenId, quantity);
        }
        /**
         * @dev Mints `quantity` tokens and transfers them to `to`.
         *
         * This function is intended for efficient minting only during contract creation.
         *
         * It emits only one {ConsecutiveTransfer} as defined in
         * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
         * instead of a sequence of {Transfer} event(s).
         *
         * Calling this function outside of contract creation WILL make your contract
         * non-compliant with the ERC721 standard.
         * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
         * {ConsecutiveTransfer} event is only permissible during contract creation.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - `quantity` must be greater than 0.
         *
         * Emits a {ConsecutiveTransfer} event.
         */
        function _mintERC2309(address to, uint256 quantity) internal virtual {
            uint256 startTokenId = ERC721AStorage.layout()._currentIndex;
            if (to == address(0)) _revert(MintToZeroAddress.selector);
            if (quantity == 0) _revert(MintZeroQuantity.selector);
            if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);
            _beforeTokenTransfers(address(0), to, startTokenId, quantity);
            // Overflows are unrealistic due to the above check for `quantity` to be below the limit.
            unchecked {
                // Updates:
                // - `balance += quantity`.
                // - `numberMinted += quantity`.
                //
                // We can directly add to the `balance` and `numberMinted`.
                ERC721AStorage.layout()._packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
                // Updates:
                // - `address` to the owner.
                // - `startTimestamp` to the timestamp of minting.
                // - `burned` to `false`.
                // - `nextInitialized` to `quantity == 1`.
                ERC721AStorage.layout()._packedOwnerships[startTokenId] = _packOwnershipData(
                    to,
                    _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
                );
                emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
                ERC721AStorage.layout()._currentIndex = startTokenId + quantity;
            }
            _afterTokenTransfers(address(0), to, startTokenId, quantity);
        }
        /**
         * @dev Safely mints `quantity` tokens and transfers them to `to`.
         *
         * Requirements:
         *
         * - If `to` refers to a smart contract, it must implement
         * {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
         * - `quantity` must be greater than 0.
         *
         * See {_mint}.
         *
         * Emits a {Transfer} event for each mint.
         */
        function _safeMint(
            address to,
            uint256 quantity,
            bytes memory _data
        ) internal virtual {
            _mint(to, quantity);
            unchecked {
                if (to.code.length != 0) {
                    uint256 end = ERC721AStorage.layout()._currentIndex;
                    uint256 index = end - quantity;
                    do {
                        if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
                            _revert(TransferToNonERC721ReceiverImplementer.selector);
                        }
                    } while (index < end);
                    // Reentrancy protection.
                    if (ERC721AStorage.layout()._currentIndex != end) _revert(bytes4(0));
                }
            }
        }
        /**
         * @dev Equivalent to `_safeMint(to, quantity, '')`.
         */
        function _safeMint(address to, uint256 quantity) internal virtual {
            _safeMint(to, quantity, '');
        }
        // =============================================================
        //                       APPROVAL OPERATIONS
        // =============================================================
        /**
         * @dev Equivalent to `_approve(to, tokenId, false)`.
         */
        function _approve(address to, uint256 tokenId) internal virtual {
            _approve(to, tokenId, false);
        }
        /**
         * @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:
         *
         * - `tokenId` must exist.
         *
         * Emits an {Approval} event.
         */
        function _approve(
            address to,
            uint256 tokenId,
            bool approvalCheck
        ) internal virtual {
            address owner = ownerOf(tokenId);
            if (approvalCheck && _msgSenderERC721A() != owner)
                if (!isApprovedForAll(owner, _msgSenderERC721A())) {
                    _revert(ApprovalCallerNotOwnerNorApproved.selector);
                }
            ERC721AStorage.layout()._tokenApprovals[tokenId].value = to;
            emit Approval(owner, to, tokenId);
        }
        // =============================================================
        //                        BURN OPERATIONS
        // =============================================================
        /**
         * @dev Equivalent to `_burn(tokenId, false)`.
         */
        function _burn(uint256 tokenId) internal virtual {
            _burn(tokenId, false);
        }
        /**
         * @dev Destroys `tokenId`.
         * The approval is cleared when the token is burned.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         *
         * Emits a {Transfer} event.
         */
        function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
            uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
            address from = address(uint160(prevOwnershipPacked));
            (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
            if (approvalCheck) {
                // The nested ifs save around 20+ gas over a compound boolean condition.
                if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
                    if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
            }
            _beforeTokenTransfers(from, address(0), tokenId, 1);
            // Clear approvals from the previous owner.
            assembly {
                if approvedAddress {
                    // This is equivalent to `delete _tokenApprovals[tokenId]`.
                    sstore(approvedAddressSlot, 0)
                }
            }
            // Underflow of the sender's balance is impossible because we check for
            // ownership above and the recipient's balance can't realistically overflow.
            // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
            unchecked {
                // Updates:
                // - `balance -= 1`.
                // - `numberBurned += 1`.
                //
                // We can directly decrement the balance, and increment the number burned.
                // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
                ERC721AStorage.layout()._packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
                // Updates:
                // - `address` to the last owner.
                // - `startTimestamp` to the timestamp of burning.
                // - `burned` to `true`.
                // - `nextInitialized` to `true`.
                ERC721AStorage.layout()._packedOwnerships[tokenId] = _packOwnershipData(
                    from,
                    (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
                );
                // If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
                if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
                    uint256 nextTokenId = tokenId + 1;
                    // If the next slot's address is zero and not burned (i.e. packed value is zero).
                    if (ERC721AStorage.layout()._packedOwnerships[nextTokenId] == 0) {
                        // If the next slot is within bounds.
                        if (nextTokenId != ERC721AStorage.layout()._currentIndex) {
                            // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
                            ERC721AStorage.layout()._packedOwnerships[nextTokenId] = prevOwnershipPacked;
                        }
                    }
                }
            }
            emit Transfer(from, address(0), tokenId);
            _afterTokenTransfers(from, address(0), tokenId, 1);
            // Overflow not possible, as _burnCounter cannot be exceed _currentIndex times.
            unchecked {
                ERC721AStorage.layout()._burnCounter++;
            }
        }
        // =============================================================
        //                     EXTRA DATA OPERATIONS
        // =============================================================
        /**
         * @dev Directly sets the extra data for the ownership data `index`.
         */
        function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
            uint256 packed = ERC721AStorage.layout()._packedOwnerships[index];
            if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);
            uint256 extraDataCasted;
            // Cast `extraData` with assembly to avoid redundant masking.
            assembly {
                extraDataCasted := extraData
            }
            packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
            ERC721AStorage.layout()._packedOwnerships[index] = packed;
        }
        /**
         * @dev Called during each token transfer to set the 24bit `extraData` field.
         * Intended to be overridden by the cosumer contract.
         *
         * `previousExtraData` - the value of `extraData` before transfer.
         *
         * 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, `tokenId` will be burned by `from`.
         * - `from` and `to` are never both zero.
         */
        function _extraData(
            address from,
            address to,
            uint24 previousExtraData
        ) internal view virtual returns (uint24) {}
        /**
         * @dev Returns the next extra data for the packed ownership data.
         * The returned result is shifted into position.
         */
        function _nextExtraData(
            address from,
            address to,
            uint256 prevOwnershipPacked
        ) private view returns (uint256) {
            uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
            return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
        }
        // =============================================================
        //                       OTHER OPERATIONS
        // =============================================================
        /**
         * @dev Returns the message sender (defaults to `msg.sender`).
         *
         * If you are writing GSN compatible contracts, you need to override this function.
         */
        function _msgSenderERC721A() internal view virtual returns (address) {
            return msg.sender;
        }
        /**
         * @dev Converts a uint256 to its ASCII string decimal representation.
         */
        function _toString(uint256 value) internal pure virtual returns (string memory str) {
            assembly {
                // The maximum value of a uint256 contains 78 digits (1 byte per digit), but
                // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
                // We will need 1 word for the trailing zeros padding, 1 word for the length,
                // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
                let m := add(mload(0x40), 0xa0)
                // Update the free memory pointer to allocate.
                mstore(0x40, m)
                // Assign the `str` to the end.
                str := sub(m, 0x20)
                // Zeroize the slot after the string.
                mstore(str, 0)
                // Cache the end of the memory to calculate the length later.
                let end := str
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                // prettier-ignore
                for { let temp := value } 1 {} {
                    str := sub(str, 1)
                    // Write the character to the pointer.
                    // The ASCII index of the '0' character is 48.
                    mstore8(str, add(48, mod(temp, 10)))
                    // Keep dividing `temp` until zero.
                    temp := div(temp, 10)
                    // prettier-ignore
                    if iszero(temp) { break }
                }
                let length := sub(end, str)
                // Move the pointer 32 bytes leftwards to make room for the length.
                str := sub(str, 0x20)
                // Store the length.
                mstore(str, length)
            }
        }
        /**
         * @dev For more efficient reverts.
         */
        function _revert(bytes4 errorSelector) internal pure {
            assembly {
                mstore(0x00, errorSelector)
                revert(0x00, 0x04)
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev This is a base contract to aid in writing upgradeable diamond facet contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     */
    import {ERC721A__InitializableStorage} from './ERC721A__InitializableStorage.sol';
    abstract contract ERC721A__Initializable {
        using ERC721A__InitializableStorage for ERC721A__InitializableStorage.Layout;
        /**
         * @dev Modifier to protect an initializer function from being invoked twice.
         */
        modifier initializerERC721A() {
            // If the contract is initializing we ignore whether _initialized is set in order to support multiple
            // inheritance patterns, but we only do this in the context of a constructor, because in other contexts the
            // contract may have been reentered.
            require(
                ERC721A__InitializableStorage.layout()._initializing
                    ? _isConstructor()
                    : !ERC721A__InitializableStorage.layout()._initialized,
                'ERC721A__Initializable: contract is already initialized'
            );
            bool isTopLevelCall = !ERC721A__InitializableStorage.layout()._initializing;
            if (isTopLevelCall) {
                ERC721A__InitializableStorage.layout()._initializing = true;
                ERC721A__InitializableStorage.layout()._initialized = true;
            }
            _;
            if (isTopLevelCall) {
                ERC721A__InitializableStorage.layout()._initializing = false;
            }
        }
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} modifier, directly or indirectly.
         */
        modifier onlyInitializingERC721A() {
            require(
                ERC721A__InitializableStorage.layout()._initializing,
                'ERC721A__Initializable: contract is not initializing'
            );
            _;
        }
        /// @dev Returns true if and only if the function is running in the constructor
        function _isConstructor() private view returns (bool) {
            // extcodesize checks the size of the code stored in an address, and
            // address returns the current address. Since the code is still not
            // deployed when running a constructor, any checks on its code size will
            // yield zero, making it an effective way to detect if a contract is
            // under construction or not.
            address self = address(this);
            uint256 cs;
            assembly {
                cs := extcodesize(self)
            }
            return cs == 0;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.0;
    /**
     * @dev This is a base storage for the  initialization function for upgradeable diamond facet contracts
     **/
    library ERC721A__InitializableStorage {
        struct Layout {
            /*
             * Indicates that the contract has been initialized.
             */
            bool _initialized;
            /*
             * Indicates that the contract is in the process of being initialized.
             */
            bool _initializing;
        }
        bytes32 internal constant STORAGE_SLOT = keccak256('ERC721A.contracts.storage.initializable.facet');
        function layout() internal pure returns (Layout storage l) {
            bytes32 slot = STORAGE_SLOT;
            assembly {
                l.slot := slot
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // ERC721A Contracts v4.2.3
    // Creator: Chiru Labs
    pragma solidity ^0.8.4;
    /**
     * @dev Interface of ERC721A.
     */
    interface IERC721AUpgradeable {
        /**
         * The caller must own the token or be an approved operator.
         */
        error ApprovalCallerNotOwnerNorApproved();
        /**
         * The token does not exist.
         */
        error ApprovalQueryForNonexistentToken();
        /**
         * Cannot query the balance for the zero address.
         */
        error BalanceQueryForZeroAddress();
        /**
         * Cannot mint to the zero address.
         */
        error MintToZeroAddress();
        /**
         * The quantity of tokens minted must be more than zero.
         */
        error MintZeroQuantity();
        /**
         * The token does not exist.
         */
        error OwnerQueryForNonexistentToken();
        /**
         * The caller must own the token or be an approved operator.
         */
        error TransferCallerNotOwnerNorApproved();
        /**
         * The token must be owned by `from`.
         */
        error TransferFromIncorrectOwner();
        /**
         * Cannot safely transfer to a contract that does not implement the
         * ERC721Receiver interface.
         */
        error TransferToNonERC721ReceiverImplementer();
        /**
         * Cannot transfer to the zero address.
         */
        error TransferToZeroAddress();
        /**
         * The token does not exist.
         */
        error URIQueryForNonexistentToken();
        /**
         * The `quantity` minted with ERC2309 exceeds the safety limit.
         */
        error MintERC2309QuantityExceedsLimit();
        /**
         * The `extraData` cannot be set on an unintialized ownership slot.
         */
        error OwnershipNotInitializedForExtraData();
        // =============================================================
        //                            STRUCTS
        // =============================================================
        struct TokenOwnership {
            // The address of the owner.
            address addr;
            // Stores the start time of ownership with minimal overhead for tokenomics.
            uint64 startTimestamp;
            // Whether the token has been burned.
            bool burned;
            // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
            uint24 extraData;
        }
        // =============================================================
        //                         TOKEN COUNTERS
        // =============================================================
        /**
         * @dev Returns the total number of tokens in existence.
         * Burned tokens will reduce the count.
         * To get the total number of tokens minted, please see {_totalMinted}.
         */
        function totalSupply() external view returns (uint256);
        // =============================================================
        //                            IERC165
        // =============================================================
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
        // =============================================================
        //                            IERC721
        // =============================================================
        /**
         * @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,
            bytes calldata data
        ) external payable;
        /**
         * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
         */
        function safeTransferFrom(
            address from,
            address to,
            uint256 tokenId
        ) external payable;
        /**
         * @dev Transfers `tokenId` 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 payable;
        /**
         * @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 payable;
        /**
         * @dev Approve or remove `operator` as an operator for the caller.
         * Operators can call {transferFrom} or {safeTransferFrom}
         * for any token owned by the caller.
         *
         * Requirements:
         *
         * - The `operator` cannot be the caller.
         *
         * Emits an {ApprovalForAll} event.
         */
        function setApprovalForAll(address operator, bool _approved) external;
        /**
         * @dev Returns the account approved for `tokenId` token.
         *
         * Requirements:
         *
         * - `tokenId` must exist.
         */
        function getApproved(uint256 tokenId) external view returns (address operator);
        /**
         * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
         *
         * See {setApprovalForAll}.
         */
        function isApprovedForAll(address owner, address operator) external view returns (bool);
        // =============================================================
        //                        IERC721Metadata
        // =============================================================
        /**
         * @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);
        // =============================================================
        //                           IERC2309
        // =============================================================
        /**
         * @dev Emitted when tokens in `fromTokenId` to `toTokenId`
         * (inclusive) is transferred from `from` to `to`, as defined in the
         * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
         *
         * See {_mintERC2309} for more details.
         */
        event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    // This program is free software: you can redistribute it and/or modify
    // it under the terms of the GNU General Public License as published by
    // the Free Software Foundation, either version 3 of the License, or
    // (at your option) any later version.
    // This program is distributed in the hope that it will be useful,
    // but WITHOUT ANY WARRANTY; without even the implied warranty of
    // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    // GNU General Public License for more details.
    // You should have received a copy of the GNU General Public License
    // along with this program.  If not, see <http://www.gnu.org/licenses/>.
    pragma solidity >=0.5.0;
    contract DSTest {
        event log                    (string);
        event logs                   (bytes);
        event log_address            (address);
        event log_bytes32            (bytes32);
        event log_int                (int);
        event log_uint               (uint);
        event log_bytes              (bytes);
        event log_string             (string);
        event log_named_address      (string key, address val);
        event log_named_bytes32      (string key, bytes32 val);
        event log_named_decimal_int  (string key, int val, uint decimals);
        event log_named_decimal_uint (string key, uint val, uint decimals);
        event log_named_int          (string key, int val);
        event log_named_uint         (string key, uint val);
        event log_named_bytes        (string key, bytes val);
        event log_named_string       (string key, string val);
        bool public IS_TEST = true;
        bool private _failed;
        address constant HEVM_ADDRESS =
            address(bytes20(uint160(uint256(keccak256('hevm cheat code')))));
        modifier mayRevert() { _; }
        modifier testopts(string memory) { _; }
        function failed() public returns (bool) {
            if (_failed) {
                return _failed;
            } else {
                bool globalFailed = false;
                if (hasHEVMContext()) {
                    (, bytes memory retdata) = HEVM_ADDRESS.call(
                        abi.encodePacked(
                            bytes4(keccak256("load(address,bytes32)")),
                            abi.encode(HEVM_ADDRESS, bytes32("failed"))
                        )
                    );
                    globalFailed = abi.decode(retdata, (bool));
                }
                return globalFailed;
            }
        }
        function fail() internal virtual {
            if (hasHEVMContext()) {
                (bool status, ) = HEVM_ADDRESS.call(
                    abi.encodePacked(
                        bytes4(keccak256("store(address,bytes32,bytes32)")),
                        abi.encode(HEVM_ADDRESS, bytes32("failed"), bytes32(uint256(0x01)))
                    )
                );
                status; // Silence compiler warnings
            }
            _failed = true;
        }
        function hasHEVMContext() internal view returns (bool) {
            uint256 hevmCodeSize = 0;
            assembly {
                hevmCodeSize := extcodesize(0x7109709ECfa91a80626fF3989D68f67F5b1DD12D)
            }
            return hevmCodeSize > 0;
        }
        modifier logs_gas() {
            uint startGas = gasleft();
            _;
            uint endGas = gasleft();
            emit log_named_uint("gas", startGas - endGas);
        }
        function assertTrue(bool condition) internal {
            if (!condition) {
                emit log("Error: Assertion Failed");
                fail();
            }
        }
        function assertTrue(bool condition, string memory err) internal {
            if (!condition) {
                emit log_named_string("Error", err);
                assertTrue(condition);
            }
        }
        function assertEq(address a, address b) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [address]");
                emit log_named_address("      Left", a);
                emit log_named_address("     Right", b);
                fail();
            }
        }
        function assertEq(address a, address b, string memory err) internal {
            if (a != b) {
                emit log_named_string ("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq(bytes32 a, bytes32 b) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [bytes32]");
                emit log_named_bytes32("      Left", a);
                emit log_named_bytes32("     Right", b);
                fail();
            }
        }
        function assertEq(bytes32 a, bytes32 b, string memory err) internal {
            if (a != b) {
                emit log_named_string ("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq32(bytes32 a, bytes32 b) internal {
            assertEq(a, b);
        }
        function assertEq32(bytes32 a, bytes32 b, string memory err) internal {
            assertEq(a, b, err);
        }
        function assertEq(int a, int b) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [int]");
                emit log_named_int("      Left", a);
                emit log_named_int("     Right", b);
                fail();
            }
        }
        function assertEq(int a, int b, string memory err) internal {
            if (a != b) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq(uint a, uint b) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [uint]");
                emit log_named_uint("      Left", a);
                emit log_named_uint("     Right", b);
                fail();
            }
        }
        function assertEq(uint a, uint b, string memory err) internal {
            if (a != b) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertEqDecimal(int a, int b, uint decimals) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [decimal int]");
                emit log_named_decimal_int("      Left", a, decimals);
                emit log_named_decimal_int("     Right", b, decimals);
                fail();
            }
        }
        function assertEqDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a != b) {
                emit log_named_string("Error", err);
                assertEqDecimal(a, b, decimals);
            }
        }
        function assertEqDecimal(uint a, uint b, uint decimals) internal {
            if (a != b) {
                emit log("Error: a == b not satisfied [decimal uint]");
                emit log_named_decimal_uint("      Left", a, decimals);
                emit log_named_decimal_uint("     Right", b, decimals);
                fail();
            }
        }
        function assertEqDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a != b) {
                emit log_named_string("Error", err);
                assertEqDecimal(a, b, decimals);
            }
        }
        function assertNotEq(address a, address b) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [address]");
                emit log_named_address("      Left", a);
                emit log_named_address("     Right", b);
                fail();
            }
        }
        function assertNotEq(address a, address b, string memory err) internal {
            if (a == b) {
                emit log_named_string ("Error", err);
                assertNotEq(a, b);
            }
        }
        function assertNotEq(bytes32 a, bytes32 b) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [bytes32]");
                emit log_named_bytes32("      Left", a);
                emit log_named_bytes32("     Right", b);
                fail();
            }
        }
        function assertNotEq(bytes32 a, bytes32 b, string memory err) internal {
            if (a == b) {
                emit log_named_string ("Error", err);
                assertNotEq(a, b);
            }
        }
        function assertNotEq32(bytes32 a, bytes32 b) internal {
            assertNotEq(a, b);
        }
        function assertNotEq32(bytes32 a, bytes32 b, string memory err) internal {
            assertNotEq(a, b, err);
        }
        function assertNotEq(int a, int b) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [int]");
                emit log_named_int("      Left", a);
                emit log_named_int("     Right", b);
                fail();
            }
        }
        function assertNotEq(int a, int b, string memory err) internal {
            if (a == b) {
                emit log_named_string("Error", err);
                assertNotEq(a, b);
            }
        }
        function assertNotEq(uint a, uint b) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [uint]");
                emit log_named_uint("      Left", a);
                emit log_named_uint("     Right", b);
                fail();
            }
        }
        function assertNotEq(uint a, uint b, string memory err) internal {
            if (a == b) {
                emit log_named_string("Error", err);
                assertNotEq(a, b);
            }
        }
        function assertNotEqDecimal(int a, int b, uint decimals) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [decimal int]");
                emit log_named_decimal_int("      Left", a, decimals);
                emit log_named_decimal_int("     Right", b, decimals);
                fail();
            }
        }
        function assertNotEqDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a == b) {
                emit log_named_string("Error", err);
                assertNotEqDecimal(a, b, decimals);
            }
        }
        function assertNotEqDecimal(uint a, uint b, uint decimals) internal {
            if (a == b) {
                emit log("Error: a != b not satisfied [decimal uint]");
                emit log_named_decimal_uint("      Left", a, decimals);
                emit log_named_decimal_uint("     Right", b, decimals);
                fail();
            }
        }
        function assertNotEqDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a == b) {
                emit log_named_string("Error", err);
                assertNotEqDecimal(a, b, decimals);
            }
        }
        function assertGt(uint a, uint b) internal {
            if (a <= b) {
                emit log("Error: a > b not satisfied [uint]");
                emit log_named_uint("  Value a", a);
                emit log_named_uint("  Value b", b);
                fail();
            }
        }
        function assertGt(uint a, uint b, string memory err) internal {
            if (a <= b) {
                emit log_named_string("Error", err);
                assertGt(a, b);
            }
        }
        function assertGt(int a, int b) internal {
            if (a <= b) {
                emit log("Error: a > b not satisfied [int]");
                emit log_named_int("  Value a", a);
                emit log_named_int("  Value b", b);
                fail();
            }
        }
        function assertGt(int a, int b, string memory err) internal {
            if (a <= b) {
                emit log_named_string("Error", err);
                assertGt(a, b);
            }
        }
        function assertGtDecimal(int a, int b, uint decimals) internal {
            if (a <= b) {
                emit log("Error: a > b not satisfied [decimal int]");
                emit log_named_decimal_int("  Value a", a, decimals);
                emit log_named_decimal_int("  Value b", b, decimals);
                fail();
            }
        }
        function assertGtDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a <= b) {
                emit log_named_string("Error", err);
                assertGtDecimal(a, b, decimals);
            }
        }
        function assertGtDecimal(uint a, uint b, uint decimals) internal {
            if (a <= b) {
                emit log("Error: a > b not satisfied [decimal uint]");
                emit log_named_decimal_uint("  Value a", a, decimals);
                emit log_named_decimal_uint("  Value b", b, decimals);
                fail();
            }
        }
        function assertGtDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a <= b) {
                emit log_named_string("Error", err);
                assertGtDecimal(a, b, decimals);
            }
        }
        function assertGe(uint a, uint b) internal {
            if (a < b) {
                emit log("Error: a >= b not satisfied [uint]");
                emit log_named_uint("  Value a", a);
                emit log_named_uint("  Value b", b);
                fail();
            }
        }
        function assertGe(uint a, uint b, string memory err) internal {
            if (a < b) {
                emit log_named_string("Error", err);
                assertGe(a, b);
            }
        }
        function assertGe(int a, int b) internal {
            if (a < b) {
                emit log("Error: a >= b not satisfied [int]");
                emit log_named_int("  Value a", a);
                emit log_named_int("  Value b", b);
                fail();
            }
        }
        function assertGe(int a, int b, string memory err) internal {
            if (a < b) {
                emit log_named_string("Error", err);
                assertGe(a, b);
            }
        }
        function assertGeDecimal(int a, int b, uint decimals) internal {
            if (a < b) {
                emit log("Error: a >= b not satisfied [decimal int]");
                emit log_named_decimal_int("  Value a", a, decimals);
                emit log_named_decimal_int("  Value b", b, decimals);
                fail();
            }
        }
        function assertGeDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a < b) {
                emit log_named_string("Error", err);
                assertGeDecimal(a, b, decimals);
            }
        }
        function assertGeDecimal(uint a, uint b, uint decimals) internal {
            if (a < b) {
                emit log("Error: a >= b not satisfied [decimal uint]");
                emit log_named_decimal_uint("  Value a", a, decimals);
                emit log_named_decimal_uint("  Value b", b, decimals);
                fail();
            }
        }
        function assertGeDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a < b) {
                emit log_named_string("Error", err);
                assertGeDecimal(a, b, decimals);
            }
        }
        function assertLt(uint a, uint b) internal {
            if (a >= b) {
                emit log("Error: a < b not satisfied [uint]");
                emit log_named_uint("  Value a", a);
                emit log_named_uint("  Value b", b);
                fail();
            }
        }
        function assertLt(uint a, uint b, string memory err) internal {
            if (a >= b) {
                emit log_named_string("Error", err);
                assertLt(a, b);
            }
        }
        function assertLt(int a, int b) internal {
            if (a >= b) {
                emit log("Error: a < b not satisfied [int]");
                emit log_named_int("  Value a", a);
                emit log_named_int("  Value b", b);
                fail();
            }
        }
        function assertLt(int a, int b, string memory err) internal {
            if (a >= b) {
                emit log_named_string("Error", err);
                assertLt(a, b);
            }
        }
        function assertLtDecimal(int a, int b, uint decimals) internal {
            if (a >= b) {
                emit log("Error: a < b not satisfied [decimal int]");
                emit log_named_decimal_int("  Value a", a, decimals);
                emit log_named_decimal_int("  Value b", b, decimals);
                fail();
            }
        }
        function assertLtDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a >= b) {
                emit log_named_string("Error", err);
                assertLtDecimal(a, b, decimals);
            }
        }
        function assertLtDecimal(uint a, uint b, uint decimals) internal {
            if (a >= b) {
                emit log("Error: a < b not satisfied [decimal uint]");
                emit log_named_decimal_uint("  Value a", a, decimals);
                emit log_named_decimal_uint("  Value b", b, decimals);
                fail();
            }
        }
        function assertLtDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a >= b) {
                emit log_named_string("Error", err);
                assertLtDecimal(a, b, decimals);
            }
        }
        function assertLe(uint a, uint b) internal {
            if (a > b) {
                emit log("Error: a <= b not satisfied [uint]");
                emit log_named_uint("  Value a", a);
                emit log_named_uint("  Value b", b);
                fail();
            }
        }
        function assertLe(uint a, uint b, string memory err) internal {
            if (a > b) {
                emit log_named_string("Error", err);
                assertLe(a, b);
            }
        }
        function assertLe(int a, int b) internal {
            if (a > b) {
                emit log("Error: a <= b not satisfied [int]");
                emit log_named_int("  Value a", a);
                emit log_named_int("  Value b", b);
                fail();
            }
        }
        function assertLe(int a, int b, string memory err) internal {
            if (a > b) {
                emit log_named_string("Error", err);
                assertLe(a, b);
            }
        }
        function assertLeDecimal(int a, int b, uint decimals) internal {
            if (a > b) {
                emit log("Error: a <= b not satisfied [decimal int]");
                emit log_named_decimal_int("  Value a", a, decimals);
                emit log_named_decimal_int("  Value b", b, decimals);
                fail();
            }
        }
        function assertLeDecimal(int a, int b, uint decimals, string memory err) internal {
            if (a > b) {
                emit log_named_string("Error", err);
                assertLeDecimal(a, b, decimals);
            }
        }
        function assertLeDecimal(uint a, uint b, uint decimals) internal {
            if (a > b) {
                emit log("Error: a <= b not satisfied [decimal uint]");
                emit log_named_decimal_uint("  Value a", a, decimals);
                emit log_named_decimal_uint("  Value b", b, decimals);
                fail();
            }
        }
        function assertLeDecimal(uint a, uint b, uint decimals, string memory err) internal {
            if (a > b) {
                emit log_named_string("Error", err);
                assertLeDecimal(a, b, decimals);
            }
        }
        function assertEq(string memory a, string memory b) internal {
            if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
                emit log("Error: a == b not satisfied [string]");
                emit log_named_string("      Left", a);
                emit log_named_string("     Right", b);
                fail();
            }
        }
        function assertEq(string memory a, string memory b, string memory err) internal {
            if (keccak256(abi.encodePacked(a)) != keccak256(abi.encodePacked(b))) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertNotEq(string memory a, string memory b) internal {
            if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) {
                emit log("Error: a != b not satisfied [string]");
                emit log_named_string("      Left", a);
                emit log_named_string("     Right", b);
                fail();
            }
        }
        function assertNotEq(string memory a, string memory b, string memory err) internal {
            if (keccak256(abi.encodePacked(a)) == keccak256(abi.encodePacked(b))) {
                emit log_named_string("Error", err);
                assertNotEq(a, b);
            }
        }
        function checkEq0(bytes memory a, bytes memory b) internal pure returns (bool ok) {
            ok = true;
            if (a.length == b.length) {
                for (uint i = 0; i < a.length; i++) {
                    if (a[i] != b[i]) {
                        ok = false;
                    }
                }
            } else {
                ok = false;
            }
        }
        function assertEq0(bytes memory a, bytes memory b) internal {
            if (!checkEq0(a, b)) {
                emit log("Error: a == b not satisfied [bytes]");
                emit log_named_bytes("      Left", a);
                emit log_named_bytes("     Right", b);
                fail();
            }
        }
        function assertEq0(bytes memory a, bytes memory b, string memory err) internal {
            if (!checkEq0(a, b)) {
                emit log_named_string("Error", err);
                assertEq0(a, b);
            }
        }
        function assertNotEq0(bytes memory a, bytes memory b) internal {
            if (checkEq0(a, b)) {
                emit log("Error: a != b not satisfied [bytes]");
                emit log_named_bytes("      Left", a);
                emit log_named_bytes("     Right", b);
                fail();
            }
        }
        function assertNotEq0(bytes memory a, bytes memory b, string memory err) internal {
            if (checkEq0(a, b)) {
                emit log_named_string("Error", err);
                assertNotEq0(a, b);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    import {StdStorage} from "./StdStorage.sol";
    import {Vm, VmSafe} from "./Vm.sol";
    abstract contract CommonBase {
        // Cheat code address, 0x7109709ECfa91a80626fF3989D68f67F5b1DD12D.
        address internal constant VM_ADDRESS = address(uint160(uint256(keccak256("hevm cheat code"))));
        // console.sol and console2.sol work by executing a staticcall to this address.
        address internal constant CONSOLE = 0x000000000000000000636F6e736F6c652e6c6f67;
        // Default address for tx.origin and msg.sender, 0x1804c8AB1F12E6bbf3894d4083f33e07309d1f38.
        address internal constant DEFAULT_SENDER = address(uint160(uint256(keccak256("foundry default caller"))));
        // Address of the test contract, deployed by the DEFAULT_SENDER.
        address internal constant DEFAULT_TEST_CONTRACT = 0x5615dEB798BB3E4dFa0139dFa1b3D433Cc23b72f;
        // Deterministic deployment address of the Multicall3 contract.
        address internal constant MULTICALL3_ADDRESS = 0xcA11bde05977b3631167028862bE2a173976CA11;
        uint256 internal constant UINT256_MAX =
            115792089237316195423570985008687907853269984665640564039457584007913129639935;
        Vm internal constant vm = Vm(VM_ADDRESS);
        StdStorage internal stdstore;
    }
    abstract contract TestBase is CommonBase {}
    abstract contract ScriptBase is CommonBase {
        // Used when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.
        address internal constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
        VmSafe internal constant vmSafe = VmSafe(VM_ADDRESS);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    import {DSTest} from "ds-test/test.sol";
    import {stdMath} from "./StdMath.sol";
    abstract contract StdAssertions is DSTest {
        event log_array(uint256[] val);
        event log_array(int256[] val);
        event log_array(address[] val);
        event log_named_array(string key, uint256[] val);
        event log_named_array(string key, int256[] val);
        event log_named_array(string key, address[] val);
        function fail(string memory err) internal virtual {
            emit log_named_string("Error", err);
            fail();
        }
        function assertFalse(bool data) internal virtual {
            assertTrue(!data);
        }
        function assertFalse(bool data, string memory err) internal virtual {
            assertTrue(!data, err);
        }
        function assertEq(bool a, bool b) internal virtual {
            if (a != b) {
                emit log("Error: a == b not satisfied [bool]");
                emit log_named_string("      Left", a ? "true" : "false");
                emit log_named_string("     Right", b ? "true" : "false");
                fail();
            }
        }
        function assertEq(bool a, bool b, string memory err) internal virtual {
            if (a != b) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq(bytes memory a, bytes memory b) internal virtual {
            assertEq0(a, b);
        }
        function assertEq(bytes memory a, bytes memory b, string memory err) internal virtual {
            assertEq0(a, b, err);
        }
        function assertEq(uint256[] memory a, uint256[] memory b) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log("Error: a == b not satisfied [uint[]]");
                emit log_named_array("      Left", a);
                emit log_named_array("     Right", b);
                fail();
            }
        }
        function assertEq(int256[] memory a, int256[] memory b) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log("Error: a == b not satisfied [int[]]");
                emit log_named_array("      Left", a);
                emit log_named_array("     Right", b);
                fail();
            }
        }
        function assertEq(address[] memory a, address[] memory b) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log("Error: a == b not satisfied [address[]]");
                emit log_named_array("      Left", a);
                emit log_named_array("     Right", b);
                fail();
            }
        }
        function assertEq(uint256[] memory a, uint256[] memory b, string memory err) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq(int256[] memory a, int256[] memory b, string memory err) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        function assertEq(address[] memory a, address[] memory b, string memory err) internal virtual {
            if (keccak256(abi.encode(a)) != keccak256(abi.encode(b))) {
                emit log_named_string("Error", err);
                assertEq(a, b);
            }
        }
        // Legacy helper
        function assertEqUint(uint256 a, uint256 b) internal virtual {
            assertEq(uint256(a), uint256(b));
        }
        function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log("Error: a ~= b not satisfied [uint]");
                emit log_named_uint("      Left", a);
                emit log_named_uint("     Right", b);
                emit log_named_uint(" Max Delta", maxDelta);
                emit log_named_uint("     Delta", delta);
                fail();
            }
        }
        function assertApproxEqAbs(uint256 a, uint256 b, uint256 maxDelta, string memory err) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log_named_string("Error", err);
                assertApproxEqAbs(a, b, maxDelta);
            }
        }
        function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log("Error: a ~= b not satisfied [uint]");
                emit log_named_decimal_uint("      Left", a, decimals);
                emit log_named_decimal_uint("     Right", b, decimals);
                emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
                emit log_named_decimal_uint("     Delta", delta, decimals);
                fail();
            }
        }
        function assertApproxEqAbsDecimal(uint256 a, uint256 b, uint256 maxDelta, uint256 decimals, string memory err)
            internal
            virtual
        {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log_named_string("Error", err);
                assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
            }
        }
        function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log("Error: a ~= b not satisfied [int]");
                emit log_named_int("       Left", a);
                emit log_named_int("      Right", b);
                emit log_named_uint(" Max Delta", maxDelta);
                emit log_named_uint("     Delta", delta);
                fail();
            }
        }
        function assertApproxEqAbs(int256 a, int256 b, uint256 maxDelta, string memory err) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log_named_string("Error", err);
                assertApproxEqAbs(a, b, maxDelta);
            }
        }
        function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals) internal virtual {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log("Error: a ~= b not satisfied [int]");
                emit log_named_decimal_int("      Left", a, decimals);
                emit log_named_decimal_int("     Right", b, decimals);
                emit log_named_decimal_uint(" Max Delta", maxDelta, decimals);
                emit log_named_decimal_uint("     Delta", delta, decimals);
                fail();
            }
        }
        function assertApproxEqAbsDecimal(int256 a, int256 b, uint256 maxDelta, uint256 decimals, string memory err)
            internal
            virtual
        {
            uint256 delta = stdMath.delta(a, b);
            if (delta > maxDelta) {
                emit log_named_string("Error", err);
                assertApproxEqAbsDecimal(a, b, maxDelta, decimals);
            }
        }
        function assertApproxEqRel(
            uint256 a,
            uint256 b,
            uint256 maxPercentDelta // An 18 decimal fixed point number, where 1e18 == 100%
        ) internal virtual {
            if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log("Error: a ~= b not satisfied [uint]");
                emit log_named_uint("        Left", a);
                emit log_named_uint("       Right", b);
                emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
                emit log_named_decimal_uint("     % Delta", percentDelta * 100, 18);
                fail();
            }
        }
        function assertApproxEqRel(
            uint256 a,
            uint256 b,
            uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
            string memory err
        ) internal virtual {
            if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log_named_string("Error", err);
                assertApproxEqRel(a, b, maxPercentDelta);
            }
        }
        function assertApproxEqRelDecimal(
            uint256 a,
            uint256 b,
            uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
            uint256 decimals
        ) internal virtual {
            if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log("Error: a ~= b not satisfied [uint]");
                emit log_named_decimal_uint("        Left", a, decimals);
                emit log_named_decimal_uint("       Right", b, decimals);
                emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
                emit log_named_decimal_uint("     % Delta", percentDelta * 100, 18);
                fail();
            }
        }
        function assertApproxEqRelDecimal(
            uint256 a,
            uint256 b,
            uint256 maxPercentDelta, // An 18 decimal fixed point number, where 1e18 == 100%
            uint256 decimals,
            string memory err
        ) internal virtual {
            if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log_named_string("Error", err);
                assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
            }
        }
        function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta) internal virtual {
            if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log("Error: a ~= b not satisfied [int]");
                emit log_named_int("        Left", a);
                emit log_named_int("       Right", b);
                emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
                emit log_named_decimal_uint("     % Delta", percentDelta * 100, 18);
                fail();
            }
        }
        function assertApproxEqRel(int256 a, int256 b, uint256 maxPercentDelta, string memory err) internal virtual {
            if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log_named_string("Error", err);
                assertApproxEqRel(a, b, maxPercentDelta);
            }
        }
        function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals) internal virtual {
            if (b == 0) return assertEq(a, b); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log("Error: a ~= b not satisfied [int]");
                emit log_named_decimal_int("        Left", a, decimals);
                emit log_named_decimal_int("       Right", b, decimals);
                emit log_named_decimal_uint(" Max % Delta", maxPercentDelta * 100, 18);
                emit log_named_decimal_uint("     % Delta", percentDelta * 100, 18);
                fail();
            }
        }
        function assertApproxEqRelDecimal(int256 a, int256 b, uint256 maxPercentDelta, uint256 decimals, string memory err)
            internal
            virtual
        {
            if (b == 0) return assertEq(a, b, err); // If the left is 0, right must be too.
            uint256 percentDelta = stdMath.percentDelta(a, b);
            if (percentDelta > maxPercentDelta) {
                emit log_named_string("Error", err);
                assertApproxEqRelDecimal(a, b, maxPercentDelta, decimals);
            }
        }
        function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB) internal virtual {
            assertEqCall(target, callDataA, target, callDataB, true);
        }
        function assertEqCall(address targetA, bytes memory callDataA, address targetB, bytes memory callDataB)
            internal
            virtual
        {
            assertEqCall(targetA, callDataA, targetB, callDataB, true);
        }
        function assertEqCall(address target, bytes memory callDataA, bytes memory callDataB, bool strictRevertData)
            internal
            virtual
        {
            assertEqCall(target, callDataA, target, callDataB, strictRevertData);
        }
        function assertEqCall(
            address targetA,
            bytes memory callDataA,
            address targetB,
            bytes memory callDataB,
            bool strictRevertData
        ) internal virtual {
            (bool successA, bytes memory returnDataA) = address(targetA).call(callDataA);
            (bool successB, bytes memory returnDataB) = address(targetB).call(callDataB);
            if (successA && successB) {
                assertEq(returnDataA, returnDataB, "Call return data does not match");
            }
            if (!successA && !successB && strictRevertData) {
                assertEq(returnDataA, returnDataB, "Call revert data does not match");
            }
            if (!successA && successB) {
                emit log("Error: Calls were not equal");
                emit log_named_bytes("  Left call revert data", returnDataA);
                emit log_named_bytes(" Right call return data", returnDataB);
                fail();
            }
            if (successA && !successB) {
                emit log("Error: Calls were not equal");
                emit log_named_bytes("  Left call return data", returnDataA);
                emit log_named_bytes(" Right call revert data", returnDataB);
                fail();
            }
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    import {VmSafe} from "./Vm.sol";
    /**
     * StdChains provides information about EVM compatible chains that can be used in scripts/tests.
     * For each chain, the chain's name, chain ID, and a default RPC URL are provided. Chains are
     * identified by their alias, which is the same as the alias in the `[rpc_endpoints]` section of
     * the `foundry.toml` file. For best UX, ensure the alias in the `foundry.toml` file match the
     * alias used in this contract, which can be found as the first argument to the
     * `setChainWithDefaultRpcUrl` call in the `initializeStdChains` function.
     *
     * There are two main ways to use this contract:
     *   1. Set a chain with `setChain(string memory chainAlias, ChainData memory chain)` or
     *      `setChain(string memory chainAlias, Chain memory chain)`
     *   2. Get a chain with `getChain(string memory chainAlias)` or `getChain(uint256 chainId)`.
     *
     * The first time either of those are used, chains are initialized with the default set of RPC URLs.
     * This is done in `initializeStdChains`, which uses `setChainWithDefaultRpcUrl`. Defaults are recorded in
     * `defaultRpcUrls`.
     *
     * The `setChain` function is straightforward, and it simply saves off the given chain data.
     *
     * The `getChain` methods use `getChainWithUpdatedRpcUrl` to return a chain. For example, let's say
     * we want to retrieve `mainnet`'s RPC URL:
     *   - If you haven't set any mainnet chain info with `setChain`, you haven't specified that
     *     chain in `foundry.toml` and no env var is set, the default data and RPC URL will be returned.
     *   - If you have set a mainnet RPC URL in `foundry.toml` it will return that, if valid (e.g. if
     *     a URL is given or if an environment variable is given and that environment variable exists).
     *     Otherwise, the default data is returned.
     *   - If you specified data with `setChain` it will return that.
     *
     * Summarizing the above, the prioritization hierarchy is `setChain` -> `foundry.toml` -> environment variable -> defaults.
     */
    abstract contract StdChains {
        VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
        bool private stdChainsInitialized;
        struct ChainData {
            string name;
            uint256 chainId;
            string rpcUrl;
        }
        struct Chain {
            // The chain name.
            string name;
            // The chain's Chain ID.
            uint256 chainId;
            // The chain's alias. (i.e. what gets specified in `foundry.toml`).
            string chainAlias;
            // A default RPC endpoint for this chain.
            // NOTE: This default RPC URL is included for convenience to facilitate quick tests and
            // experimentation. Do not use this RPC URL for production test suites, CI, or other heavy
            // usage as you will be throttled and this is a disservice to others who need this endpoint.
            string rpcUrl;
        }
        // Maps from the chain's alias (matching the alias in the `foundry.toml` file) to chain data.
        mapping(string => Chain) private chains;
        // Maps from the chain's alias to it's default RPC URL.
        mapping(string => string) private defaultRpcUrls;
        // Maps from a chain ID to it's alias.
        mapping(uint256 => string) private idToAlias;
        bool private fallbackToDefaultRpcUrls = true;
        // The RPC URL will be fetched from config or defaultRpcUrls if possible.
        function getChain(string memory chainAlias) internal virtual returns (Chain memory chain) {
            require(bytes(chainAlias).length != 0, "StdChains getChain(string): Chain alias cannot be the empty string.");
            initializeStdChains();
            chain = chains[chainAlias];
            require(
                chain.chainId != 0,
                string(abi.encodePacked("StdChains getChain(string): Chain with alias \\"", chainAlias, "\\" not found."))
            );
            chain = getChainWithUpdatedRpcUrl(chainAlias, chain);
        }
        function getChain(uint256 chainId) internal virtual returns (Chain memory chain) {
            require(chainId != 0, "StdChains getChain(uint256): Chain ID cannot be 0.");
            initializeStdChains();
            string memory chainAlias = idToAlias[chainId];
            chain = chains[chainAlias];
            require(
                chain.chainId != 0,
                string(abi.encodePacked("StdChains getChain(uint256): Chain with ID ", vm.toString(chainId), " not found."))
            );
            chain = getChainWithUpdatedRpcUrl(chainAlias, chain);
        }
        // set chain info, with priority to argument's rpcUrl field.
        function setChain(string memory chainAlias, ChainData memory chain) internal virtual {
            require(
                bytes(chainAlias).length != 0,
                "StdChains setChain(string,ChainData): Chain alias cannot be the empty string."
            );
            require(chain.chainId != 0, "StdChains setChain(string,ChainData): Chain ID cannot be 0.");
            initializeStdChains();
            string memory foundAlias = idToAlias[chain.chainId];
            require(
                bytes(foundAlias).length == 0 || keccak256(bytes(foundAlias)) == keccak256(bytes(chainAlias)),
                string(
                    abi.encodePacked(
                        "StdChains setChain(string,ChainData): Chain ID ",
                        vm.toString(chain.chainId),
                        " already used by \\"",
                        foundAlias,
                        "\\"."
                    )
                )
            );
            uint256 oldChainId = chains[chainAlias].chainId;
            delete idToAlias[oldChainId];
            chains[chainAlias] =
                Chain({name: chain.name, chainId: chain.chainId, chainAlias: chainAlias, rpcUrl: chain.rpcUrl});
            idToAlias[chain.chainId] = chainAlias;
        }
        // set chain info, with priority to argument's rpcUrl field.
        function setChain(string memory chainAlias, Chain memory chain) internal virtual {
            setChain(chainAlias, ChainData({name: chain.name, chainId: chain.chainId, rpcUrl: chain.rpcUrl}));
        }
        function _toUpper(string memory str) private pure returns (string memory) {
            bytes memory strb = bytes(str);
            bytes memory copy = new bytes(strb.length);
            for (uint256 i = 0; i < strb.length; i++) {
                bytes1 b = strb[i];
                if (b >= 0x61 && b <= 0x7A) {
                    copy[i] = bytes1(uint8(b) - 32);
                } else {
                    copy[i] = b;
                }
            }
            return string(copy);
        }
        // lookup rpcUrl, in descending order of priority:
        // current -> config (foundry.toml) -> environment variable -> default
        function getChainWithUpdatedRpcUrl(string memory chainAlias, Chain memory chain) private returns (Chain memory) {
            if (bytes(chain.rpcUrl).length == 0) {
                try vm.rpcUrl(chainAlias) returns (string memory configRpcUrl) {
                    chain.rpcUrl = configRpcUrl;
                } catch (bytes memory err) {
                    string memory envName = string(abi.encodePacked(_toUpper(chainAlias), "_RPC_URL"));
                    if (fallbackToDefaultRpcUrls) {
                        chain.rpcUrl = vm.envOr(envName, defaultRpcUrls[chainAlias]);
                    } else {
                        chain.rpcUrl = vm.envString(envName);
                    }
                    // distinguish 'not found' from 'cannot read'
                    bytes memory notFoundError =
                        abi.encodeWithSignature("CheatCodeError", string(abi.encodePacked("invalid rpc url ", chainAlias)));
                    if (keccak256(notFoundError) != keccak256(err) || bytes(chain.rpcUrl).length == 0) {
                        /// @solidity memory-safe-assembly
                        assembly {
                            revert(add(32, err), mload(err))
                        }
                    }
                }
            }
            return chain;
        }
        function setFallbackToDefaultRpcUrls(bool useDefault) internal {
            fallbackToDefaultRpcUrls = useDefault;
        }
        function initializeStdChains() private {
            if (stdChainsInitialized) return;
            stdChainsInitialized = true;
            // If adding an RPC here, make sure to test the default RPC URL in `testRpcs`
            setChainWithDefaultRpcUrl("anvil", ChainData("Anvil", 31337, "http://127.0.0.1:8545"));
            setChainWithDefaultRpcUrl(
                "mainnet", ChainData("Mainnet", 1, "https://mainnet.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b")
            );
            setChainWithDefaultRpcUrl(
                "goerli", ChainData("Goerli", 5, "https://goerli.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b")
            );
            setChainWithDefaultRpcUrl(
                "sepolia", ChainData("Sepolia", 11155111, "https://sepolia.infura.io/v3/f4a0bdad42674adab5fc0ac077ffab2b")
            );
            setChainWithDefaultRpcUrl("optimism", ChainData("Optimism", 10, "https://mainnet.optimism.io"));
            setChainWithDefaultRpcUrl("optimism_goerli", ChainData("Optimism Goerli", 420, "https://goerli.optimism.io"));
            setChainWithDefaultRpcUrl("arbitrum_one", ChainData("Arbitrum One", 42161, "https://arb1.arbitrum.io/rpc"));
            setChainWithDefaultRpcUrl(
                "arbitrum_one_goerli", ChainData("Arbitrum One Goerli", 421613, "https://goerli-rollup.arbitrum.io/rpc")
            );
            setChainWithDefaultRpcUrl("arbitrum_nova", ChainData("Arbitrum Nova", 42170, "https://nova.arbitrum.io/rpc"));
            setChainWithDefaultRpcUrl("polygon", ChainData("Polygon", 137, "https://polygon-rpc.com"));
            setChainWithDefaultRpcUrl(
                "polygon_mumbai", ChainData("Polygon Mumbai", 80001, "https://rpc-mumbai.maticvigil.com")
            );
            setChainWithDefaultRpcUrl("avalanche", ChainData("Avalanche", 43114, "https://api.avax.network/ext/bc/C/rpc"));
            setChainWithDefaultRpcUrl(
                "avalanche_fuji", ChainData("Avalanche Fuji", 43113, "https://api.avax-test.network/ext/bc/C/rpc")
            );
            setChainWithDefaultRpcUrl(
                "bnb_smart_chain", ChainData("BNB Smart Chain", 56, "https://bsc-dataseed1.binance.org")
            );
            setChainWithDefaultRpcUrl(
                "bnb_smart_chain_testnet",
                ChainData("BNB Smart Chain Testnet", 97, "https://rpc.ankr.com/bsc_testnet_chapel")
            );
            setChainWithDefaultRpcUrl("gnosis_chain", ChainData("Gnosis Chain", 100, "https://rpc.gnosischain.com"));
        }
        // set chain info, with priority to chainAlias' rpc url in foundry.toml
        function setChainWithDefaultRpcUrl(string memory chainAlias, ChainData memory chain) private {
            string memory rpcUrl = chain.rpcUrl;
            defaultRpcUrls[chainAlias] = rpcUrl;
            chain.rpcUrl = "";
            setChain(chainAlias, chain);
            chain.rpcUrl = rpcUrl; // restore argument
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    import {StdStorage, stdStorage} from "./StdStorage.sol";
    import {Vm} from "./Vm.sol";
    abstract contract StdCheatsSafe {
        Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
        bool private gasMeteringOff;
        // Data structures to parse Transaction objects from the broadcast artifact
        // that conform to EIP1559. The Raw structs is what is parsed from the JSON
        // and then converted to the one that is used by the user for better UX.
        struct RawTx1559 {
            string[] arguments;
            address contractAddress;
            string contractName;
            // json value name = function
            string functionSig;
            bytes32 hash;
            // json value name = tx
            RawTx1559Detail txDetail;
            // json value name = type
            string opcode;
        }
        struct RawTx1559Detail {
            AccessList[] accessList;
            bytes data;
            address from;
            bytes gas;
            bytes nonce;
            address to;
            bytes txType;
            bytes value;
        }
        struct Tx1559 {
            string[] arguments;
            address contractAddress;
            string contractName;
            string functionSig;
            bytes32 hash;
            Tx1559Detail txDetail;
            string opcode;
        }
        struct Tx1559Detail {
            AccessList[] accessList;
            bytes data;
            address from;
            uint256 gas;
            uint256 nonce;
            address to;
            uint256 txType;
            uint256 value;
        }
        // Data structures to parse Transaction objects from the broadcast artifact
        // that DO NOT conform to EIP1559. The Raw structs is what is parsed from the JSON
        // and then converted to the one that is used by the user for better UX.
        struct TxLegacy {
            string[] arguments;
            address contractAddress;
            string contractName;
            string functionSig;
            string hash;
            string opcode;
            TxDetailLegacy transaction;
        }
        struct TxDetailLegacy {
            AccessList[] accessList;
            uint256 chainId;
            bytes data;
            address from;
            uint256 gas;
            uint256 gasPrice;
            bytes32 hash;
            uint256 nonce;
            bytes1 opcode;
            bytes32 r;
            bytes32 s;
            uint256 txType;
            address to;
            uint8 v;
            uint256 value;
        }
        struct AccessList {
            address accessAddress;
            bytes32[] storageKeys;
        }
        // Data structures to parse Receipt objects from the broadcast artifact.
        // The Raw structs is what is parsed from the JSON
        // and then converted to the one that is used by the user for better UX.
        struct RawReceipt {
            bytes32 blockHash;
            bytes blockNumber;
            address contractAddress;
            bytes cumulativeGasUsed;
            bytes effectiveGasPrice;
            address from;
            bytes gasUsed;
            RawReceiptLog[] logs;
            bytes logsBloom;
            bytes status;
            address to;
            bytes32 transactionHash;
            bytes transactionIndex;
        }
        struct Receipt {
            bytes32 blockHash;
            uint256 blockNumber;
            address contractAddress;
            uint256 cumulativeGasUsed;
            uint256 effectiveGasPrice;
            address from;
            uint256 gasUsed;
            ReceiptLog[] logs;
            bytes logsBloom;
            uint256 status;
            address to;
            bytes32 transactionHash;
            uint256 transactionIndex;
        }
        // Data structures to parse the entire broadcast artifact, assuming the
        // transactions conform to EIP1559.
        struct EIP1559ScriptArtifact {
            string[] libraries;
            string path;
            string[] pending;
            Receipt[] receipts;
            uint256 timestamp;
            Tx1559[] transactions;
            TxReturn[] txReturns;
        }
        struct RawEIP1559ScriptArtifact {
            string[] libraries;
            string path;
            string[] pending;
            RawReceipt[] receipts;
            TxReturn[] txReturns;
            uint256 timestamp;
            RawTx1559[] transactions;
        }
        struct RawReceiptLog {
            // json value = address
            address logAddress;
            bytes32 blockHash;
            bytes blockNumber;
            bytes data;
            bytes logIndex;
            bool removed;
            bytes32[] topics;
            bytes32 transactionHash;
            bytes transactionIndex;
            bytes transactionLogIndex;
        }
        struct ReceiptLog {
            // json value = address
            address logAddress;
            bytes32 blockHash;
            uint256 blockNumber;
            bytes data;
            uint256 logIndex;
            bytes32[] topics;
            uint256 transactionIndex;
            uint256 transactionLogIndex;
            bool removed;
        }
        struct TxReturn {
            string internalType;
            string value;
        }
        struct Account {
            address addr;
            uint256 key;
        }
        function assumeNoPrecompiles(address addr) internal virtual {
            // Assembly required since `block.chainid` was introduced in 0.8.0.
            uint256 chainId;
            assembly {
                chainId := chainid()
            }
            assumeNoPrecompiles(addr, chainId);
        }
        function assumeNoPrecompiles(address addr, uint256 chainId) internal pure virtual {
            // Note: For some chains like Optimism these are technically predeploys (i.e. bytecode placed at a specific
            // address), but the same rationale for excluding them applies so we include those too.
            // These should be present on all EVM-compatible chains.
            vm.assume(addr < address(0x1) || addr > address(0x9));
            // forgefmt: disable-start
            if (chainId == 10 || chainId == 420) {
                // https://github.com/ethereum-optimism/optimism/blob/eaa371a0184b56b7ca6d9eb9cb0a2b78b2ccd864/op-bindings/predeploys/addresses.go#L6-L21
                vm.assume(addr < address(0x4200000000000000000000000000000000000000) || addr > address(0x4200000000000000000000000000000000000800));
            } else if (chainId == 42161 || chainId == 421613) {
                // https://developer.arbitrum.io/useful-addresses#arbitrum-precompiles-l2-same-on-all-arb-chains
                vm.assume(addr < address(0x0000000000000000000000000000000000000064) || addr > address(0x0000000000000000000000000000000000000068));
            } else if (chainId == 43114 || chainId == 43113) {
                // https://github.com/ava-labs/subnet-evm/blob/47c03fd007ecaa6de2c52ea081596e0a88401f58/precompile/params.go#L18-L59
                vm.assume(addr < address(0x0100000000000000000000000000000000000000) || addr > address(0x01000000000000000000000000000000000000ff));
                vm.assume(addr < address(0x0200000000000000000000000000000000000000) || addr > address(0x02000000000000000000000000000000000000FF));
                vm.assume(addr < address(0x0300000000000000000000000000000000000000) || addr > address(0x03000000000000000000000000000000000000Ff));
            }
            // forgefmt: disable-end
        }
        function readEIP1559ScriptArtifact(string memory path)
            internal
            view
            virtual
            returns (EIP1559ScriptArtifact memory)
        {
            string memory data = vm.readFile(path);
            bytes memory parsedData = vm.parseJson(data);
            RawEIP1559ScriptArtifact memory rawArtifact = abi.decode(parsedData, (RawEIP1559ScriptArtifact));
            EIP1559ScriptArtifact memory artifact;
            artifact.libraries = rawArtifact.libraries;
            artifact.path = rawArtifact.path;
            artifact.timestamp = rawArtifact.timestamp;
            artifact.pending = rawArtifact.pending;
            artifact.txReturns = rawArtifact.txReturns;
            artifact.receipts = rawToConvertedReceipts(rawArtifact.receipts);
            artifact.transactions = rawToConvertedEIPTx1559s(rawArtifact.transactions);
            return artifact;
        }
        function rawToConvertedEIPTx1559s(RawTx1559[] memory rawTxs) internal pure virtual returns (Tx1559[] memory) {
            Tx1559[] memory txs = new Tx1559[](rawTxs.length);
            for (uint256 i; i < rawTxs.length; i++) {
                txs[i] = rawToConvertedEIPTx1559(rawTxs[i]);
            }
            return txs;
        }
        function rawToConvertedEIPTx1559(RawTx1559 memory rawTx) internal pure virtual returns (Tx1559 memory) {
            Tx1559 memory transaction;
            transaction.arguments = rawTx.arguments;
            transaction.contractName = rawTx.contractName;
            transaction.functionSig = rawTx.functionSig;
            transaction.hash = rawTx.hash;
            transaction.txDetail = rawToConvertedEIP1559Detail(rawTx.txDetail);
            transaction.opcode = rawTx.opcode;
            return transaction;
        }
        function rawToConvertedEIP1559Detail(RawTx1559Detail memory rawDetail)
            internal
            pure
            virtual
            returns (Tx1559Detail memory)
        {
            Tx1559Detail memory txDetail;
            txDetail.data = rawDetail.data;
            txDetail.from = rawDetail.from;
            txDetail.to = rawDetail.to;
            txDetail.nonce = _bytesToUint(rawDetail.nonce);
            txDetail.txType = _bytesToUint(rawDetail.txType);
            txDetail.value = _bytesToUint(rawDetail.value);
            txDetail.gas = _bytesToUint(rawDetail.gas);
            txDetail.accessList = rawDetail.accessList;
            return txDetail;
        }
        function readTx1559s(string memory path) internal view virtual returns (Tx1559[] memory) {
            string memory deployData = vm.readFile(path);
            bytes memory parsedDeployData = vm.parseJson(deployData, ".transactions");
            RawTx1559[] memory rawTxs = abi.decode(parsedDeployData, (RawTx1559[]));
            return rawToConvertedEIPTx1559s(rawTxs);
        }
        function readTx1559(string memory path, uint256 index) internal view virtual returns (Tx1559 memory) {
            string memory deployData = vm.readFile(path);
            string memory key = string(abi.encodePacked(".transactions[", vm.toString(index), "]"));
            bytes memory parsedDeployData = vm.parseJson(deployData, key);
            RawTx1559 memory rawTx = abi.decode(parsedDeployData, (RawTx1559));
            return rawToConvertedEIPTx1559(rawTx);
        }
        // Analogous to readTransactions, but for receipts.
        function readReceipts(string memory path) internal view virtual returns (Receipt[] memory) {
            string memory deployData = vm.readFile(path);
            bytes memory parsedDeployData = vm.parseJson(deployData, ".receipts");
            RawReceipt[] memory rawReceipts = abi.decode(parsedDeployData, (RawReceipt[]));
            return rawToConvertedReceipts(rawReceipts);
        }
        function readReceipt(string memory path, uint256 index) internal view virtual returns (Receipt memory) {
            string memory deployData = vm.readFile(path);
            string memory key = string(abi.encodePacked(".receipts[", vm.toString(index), "]"));
            bytes memory parsedDeployData = vm.parseJson(deployData, key);
            RawReceipt memory rawReceipt = abi.decode(parsedDeployData, (RawReceipt));
            return rawToConvertedReceipt(rawReceipt);
        }
        function rawToConvertedReceipts(RawReceipt[] memory rawReceipts) internal pure virtual returns (Receipt[] memory) {
            Receipt[] memory receipts = new Receipt[](rawReceipts.length);
            for (uint256 i; i < rawReceipts.length; i++) {
                receipts[i] = rawToConvertedReceipt(rawReceipts[i]);
            }
            return receipts;
        }
        function rawToConvertedReceipt(RawReceipt memory rawReceipt) internal pure virtual returns (Receipt memory) {
            Receipt memory receipt;
            receipt.blockHash = rawReceipt.blockHash;
            receipt.to = rawReceipt.to;
            receipt.from = rawReceipt.from;
            receipt.contractAddress = rawReceipt.contractAddress;
            receipt.effectiveGasPrice = _bytesToUint(rawReceipt.effectiveGasPrice);
            receipt.cumulativeGasUsed = _bytesToUint(rawReceipt.cumulativeGasUsed);
            receipt.gasUsed = _bytesToUint(rawReceipt.gasUsed);
            receipt.status = _bytesToUint(rawReceipt.status);
            receipt.transactionIndex = _bytesToUint(rawReceipt.transactionIndex);
            receipt.blockNumber = _bytesToUint(rawReceipt.blockNumber);
            receipt.logs = rawToConvertedReceiptLogs(rawReceipt.logs);
            receipt.logsBloom = rawReceipt.logsBloom;
            receipt.transactionHash = rawReceipt.transactionHash;
            return receipt;
        }
        function rawToConvertedReceiptLogs(RawReceiptLog[] memory rawLogs)
            internal
            pure
            virtual
            returns (ReceiptLog[] memory)
        {
            ReceiptLog[] memory logs = new ReceiptLog[](rawLogs.length);
            for (uint256 i; i < rawLogs.length; i++) {
                logs[i].logAddress = rawLogs[i].logAddress;
                logs[i].blockHash = rawLogs[i].blockHash;
                logs[i].blockNumber = _bytesToUint(rawLogs[i].blockNumber);
                logs[i].data = rawLogs[i].data;
                logs[i].logIndex = _bytesToUint(rawLogs[i].logIndex);
                logs[i].topics = rawLogs[i].topics;
                logs[i].transactionIndex = _bytesToUint(rawLogs[i].transactionIndex);
                logs[i].transactionLogIndex = _bytesToUint(rawLogs[i].transactionLogIndex);
                logs[i].removed = rawLogs[i].removed;
            }
            return logs;
        }
        // Deploy a contract by fetching the contract bytecode from
        // the artifacts directory
        // e.g. `deployCode(code, abi.encode(arg1,arg2,arg3))`
        function deployCode(string memory what, bytes memory args) internal virtual returns (address addr) {
            bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
            /// @solidity memory-safe-assembly
            assembly {
                addr := create(0, add(bytecode, 0x20), mload(bytecode))
            }
            require(addr != address(0), "StdCheats deployCode(string,bytes): Deployment failed.");
        }
        function deployCode(string memory what) internal virtual returns (address addr) {
            bytes memory bytecode = vm.getCode(what);
            /// @solidity memory-safe-assembly
            assembly {
                addr := create(0, add(bytecode, 0x20), mload(bytecode))
            }
            require(addr != address(0), "StdCheats deployCode(string): Deployment failed.");
        }
        /// @dev deploy contract with value on construction
        function deployCode(string memory what, bytes memory args, uint256 val) internal virtual returns (address addr) {
            bytes memory bytecode = abi.encodePacked(vm.getCode(what), args);
            /// @solidity memory-safe-assembly
            assembly {
                addr := create(val, add(bytecode, 0x20), mload(bytecode))
            }
            require(addr != address(0), "StdCheats deployCode(string,bytes,uint256): Deployment failed.");
        }
        function deployCode(string memory what, uint256 val) internal virtual returns (address addr) {
            bytes memory bytecode = vm.getCode(what);
            /// @solidity memory-safe-assembly
            assembly {
                addr := create(val, add(bytecode, 0x20), mload(bytecode))
            }
            require(addr != address(0), "StdCheats deployCode(string,uint256): Deployment failed.");
        }
        // creates a labeled address and the corresponding private key
        function makeAddrAndKey(string memory name) internal virtual returns (address addr, uint256 privateKey) {
            privateKey = uint256(keccak256(abi.encodePacked(name)));
            addr = vm.addr(privateKey);
            vm.label(addr, name);
        }
        // creates a labeled address
        function makeAddr(string memory name) internal virtual returns (address addr) {
            (addr,) = makeAddrAndKey(name);
        }
        // creates a struct containing both a labeled address and the corresponding private key
        function makeAccount(string memory name) internal virtual returns (Account memory account) {
            (account.addr, account.key) = makeAddrAndKey(name);
        }
        function deriveRememberKey(string memory mnemonic, uint32 index)
            internal
            virtual
            returns (address who, uint256 privateKey)
        {
            privateKey = vm.deriveKey(mnemonic, index);
            who = vm.rememberKey(privateKey);
        }
        function _bytesToUint(bytes memory b) private pure returns (uint256) {
            require(b.length <= 32, "StdCheats _bytesToUint(bytes): Bytes length exceeds 32.");
            return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
        }
        function isFork() internal view virtual returns (bool status) {
            try vm.activeFork() {
                status = true;
            } catch (bytes memory) {}
        }
        modifier skipWhenForking() {
            if (!isFork()) {
                _;
            }
        }
        modifier skipWhenNotForking() {
            if (isFork()) {
                _;
            }
        }
        modifier noGasMetering() {
            vm.pauseGasMetering();
            // To prevent turning gas monitoring back on with nested functions that use this modifier,
            // we check if gasMetering started in the off position. If it did, we don't want to turn
            // it back on until we exit the top level function that used the modifier
            //
            // i.e. funcA() noGasMetering { funcB() }, where funcB has noGasMetering as well.
            // funcA will have `gasStartedOff` as false, funcB will have it as true,
            // so we only turn metering back on at the end of the funcA
            bool gasStartedOff = gasMeteringOff;
            gasMeteringOff = true;
            _;
            // if gas metering was on when this modifier was called, turn it back on at the end
            if (!gasStartedOff) {
                gasMeteringOff = false;
                vm.resumeGasMetering();
            }
        }
        // a cheat for fuzzing addresses that are payable only
        // see https://github.com/foundry-rs/foundry/issues/3631
        function assumePayable(address addr) internal virtual {
            (bool success,) = payable(addr).call{value: 0}("");
            vm.assume(success);
        }
    }
    // Wrappers around cheatcodes to avoid footguns
    abstract contract StdCheats is StdCheatsSafe {
        using stdStorage for StdStorage;
        StdStorage private stdstore;
        Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
        // Skip forward or rewind time by the specified number of seconds
        function skip(uint256 time) internal virtual {
            vm.warp(block.timestamp + time);
        }
        function rewind(uint256 time) internal virtual {
            vm.warp(block.timestamp - time);
        }
        // Setup a prank from an address that has some ether
        function hoax(address msgSender) internal virtual {
            vm.deal(msgSender, 1 << 128);
            vm.prank(msgSender);
        }
        function hoax(address msgSender, uint256 give) internal virtual {
            vm.deal(msgSender, give);
            vm.prank(msgSender);
        }
        function hoax(address msgSender, address origin) internal virtual {
            vm.deal(msgSender, 1 << 128);
            vm.prank(msgSender, origin);
        }
        function hoax(address msgSender, address origin, uint256 give) internal virtual {
            vm.deal(msgSender, give);
            vm.prank(msgSender, origin);
        }
        // Start perpetual prank from an address that has some ether
        function startHoax(address msgSender) internal virtual {
            vm.deal(msgSender, 1 << 128);
            vm.startPrank(msgSender);
        }
        function startHoax(address msgSender, uint256 give) internal virtual {
            vm.deal(msgSender, give);
            vm.startPrank(msgSender);
        }
        // Start perpetual prank from an address that has some ether
        // tx.origin is set to the origin parameter
        function startHoax(address msgSender, address origin) internal virtual {
            vm.deal(msgSender, 1 << 128);
            vm.startPrank(msgSender, origin);
        }
        function startHoax(address msgSender, address origin, uint256 give) internal virtual {
            vm.deal(msgSender, give);
            vm.startPrank(msgSender, origin);
        }
        function changePrank(address msgSender) internal virtual {
            vm.stopPrank();
            vm.startPrank(msgSender);
        }
        function changePrank(address msgSender, address txOrigin) internal virtual {
            vm.stopPrank();
            vm.startPrank(msgSender, txOrigin);
        }
        // The same as Vm's `deal`
        // Use the alternative signature for ERC20 tokens
        function deal(address to, uint256 give) internal virtual {
            vm.deal(to, give);
        }
        // Set the balance of an account for any ERC20 token
        // Use the alternative signature to update `totalSupply`
        function deal(address token, address to, uint256 give) internal virtual {
            deal(token, to, give, false);
        }
        // Set the balance of an account for any ERC1155 token
        // Use the alternative signature to update `totalSupply`
        function dealERC1155(address token, address to, uint256 id, uint256 give) internal virtual {
            dealERC1155(token, to, id, give, false);
        }
        function deal(address token, address to, uint256 give, bool adjust) internal virtual {
            // get current balance
            (, bytes memory balData) = token.call(abi.encodeWithSelector(0x70a08231, to));
            uint256 prevBal = abi.decode(balData, (uint256));
            // update balance
            stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(give);
            // update total supply
            if (adjust) {
                (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0x18160ddd));
                uint256 totSup = abi.decode(totSupData, (uint256));
                if (give < prevBal) {
                    totSup -= (prevBal - give);
                } else {
                    totSup += (give - prevBal);
                }
                stdstore.target(token).sig(0x18160ddd).checked_write(totSup);
            }
        }
        function dealERC1155(address token, address to, uint256 id, uint256 give, bool adjust) internal virtual {
            // get current balance
            (, bytes memory balData) = token.call(abi.encodeWithSelector(0x00fdd58e, to, id));
            uint256 prevBal = abi.decode(balData, (uint256));
            // update balance
            stdstore.target(token).sig(0x00fdd58e).with_key(to).with_key(id).checked_write(give);
            // update total supply
            if (adjust) {
                (, bytes memory totSupData) = token.call(abi.encodeWithSelector(0xbd85b039, id));
                require(
                    totSupData.length != 0,
                    "StdCheats deal(address,address,uint,uint,bool): target contract is not ERC1155Supply."
                );
                uint256 totSup = abi.decode(totSupData, (uint256));
                if (give < prevBal) {
                    totSup -= (prevBal - give);
                } else {
                    totSup += (give - prevBal);
                }
                stdstore.target(token).sig(0xbd85b039).with_key(id).checked_write(totSup);
            }
        }
        function dealERC721(address token, address to, uint256 id) internal virtual {
            // check if token id is already minted and the actual owner.
            (bool successMinted, bytes memory ownerData) = token.staticcall(abi.encodeWithSelector(0x6352211e, id));
            require(successMinted, "StdCheats deal(address,address,uint,bool): id not minted.");
            // get owner current balance
            (, bytes memory fromBalData) = token.call(abi.encodeWithSelector(0x70a08231, abi.decode(ownerData, (address))));
            uint256 fromPrevBal = abi.decode(fromBalData, (uint256));
            // get new user current balance
            (, bytes memory toBalData) = token.call(abi.encodeWithSelector(0x70a08231, to));
            uint256 toPrevBal = abi.decode(toBalData, (uint256));
            // update balances
            stdstore.target(token).sig(0x70a08231).with_key(abi.decode(ownerData, (address))).checked_write(--fromPrevBal);
            stdstore.target(token).sig(0x70a08231).with_key(to).checked_write(++toPrevBal);
            // update owner
            stdstore.target(token).sig(0x6352211e).with_key(id).checked_write(to);
        }
    }
    // SPDX-License-Identifier: MIT
    // Panics work for versions >=0.8.0, but we lowered the pragma to make this compatible with Test
    pragma solidity >=0.6.2 <0.9.0;
    library stdError {
        bytes public constant assertionError = abi.encodeWithSignature("Panic(uint256)", 0x01);
        bytes public constant arithmeticError = abi.encodeWithSignature("Panic(uint256)", 0x11);
        bytes public constant divisionError = abi.encodeWithSignature("Panic(uint256)", 0x12);
        bytes public constant enumConversionError = abi.encodeWithSignature("Panic(uint256)", 0x21);
        bytes public constant encodeStorageError = abi.encodeWithSignature("Panic(uint256)", 0x22);
        bytes public constant popError = abi.encodeWithSignature("Panic(uint256)", 0x31);
        bytes public constant indexOOBError = abi.encodeWithSignature("Panic(uint256)", 0x32);
        bytes public constant memOverflowError = abi.encodeWithSignature("Panic(uint256)", 0x41);
        bytes public constant zeroVarError = abi.encodeWithSignature("Panic(uint256)", 0x51);
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    contract StdInvariant {
        struct FuzzSelector {
            address addr;
            bytes4[] selectors;
        }
        address[] private _excludedContracts;
        address[] private _excludedSenders;
        address[] private _targetedContracts;
        address[] private _targetedSenders;
        string[] private _excludedArtifacts;
        string[] private _targetedArtifacts;
        FuzzSelector[] private _targetedArtifactSelectors;
        FuzzSelector[] private _targetedSelectors;
        // Functions for users:
        // These are intended to be called in tests.
        function excludeContract(address newExcludedContract_) internal {
            _excludedContracts.push(newExcludedContract_);
        }
        function excludeSender(address newExcludedSender_) internal {
            _excludedSenders.push(newExcludedSender_);
        }
        function excludeArtifact(string memory newExcludedArtifact_) internal {
            _excludedArtifacts.push(newExcludedArtifact_);
        }
        function targetArtifact(string memory newTargetedArtifact_) internal {
            _targetedArtifacts.push(newTargetedArtifact_);
        }
        function targetArtifactSelector(FuzzSelector memory newTargetedArtifactSelector_) internal {
            _targetedArtifactSelectors.push(newTargetedArtifactSelector_);
        }
        function targetContract(address newTargetedContract_) internal {
            _targetedContracts.push(newTargetedContract_);
        }
        function targetSelector(FuzzSelector memory newTargetedSelector_) internal {
            _targetedSelectors.push(newTargetedSelector_);
        }
        function targetSender(address newTargetedSender_) internal {
            _targetedSenders.push(newTargetedSender_);
        }
        // Functions for forge:
        // These are called by forge to run invariant tests and don't need to be called in tests.
        function excludeArtifacts() public view returns (string[] memory excludedArtifacts_) {
            excludedArtifacts_ = _excludedArtifacts;
        }
        function excludeContracts() public view returns (address[] memory excludedContracts_) {
            excludedContracts_ = _excludedContracts;
        }
        function excludeSenders() public view returns (address[] memory excludedSenders_) {
            excludedSenders_ = _excludedSenders;
        }
        function targetArtifacts() public view returns (string[] memory targetedArtifacts_) {
            targetedArtifacts_ = _targetedArtifacts;
        }
        function targetArtifactSelectors() public view returns (FuzzSelector[] memory targetedArtifactSelectors_) {
            targetedArtifactSelectors_ = _targetedArtifactSelectors;
        }
        function targetContracts() public view returns (address[] memory targetedContracts_) {
            targetedContracts_ = _targetedContracts;
        }
        function targetSelectors() public view returns (FuzzSelector[] memory targetedSelectors_) {
            targetedSelectors_ = _targetedSelectors;
        }
        function targetSenders() public view returns (address[] memory targetedSenders_) {
            targetedSenders_ = _targetedSenders;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.0 <0.9.0;
    pragma experimental ABIEncoderV2;
    import {VmSafe} from "./Vm.sol";
    // Helpers for parsing and writing JSON files
    // To parse:
    // ```
    // using stdJson for string;
    // string memory json = vm.readFile("some_peth");
    // json.parseUint("<json_path>");
    // ```
    // To write:
    // ```
    // using stdJson for string;
    // string memory json = "deploymentArtifact";
    // Contract contract = new Contract();
    // json.serialize("contractAddress", address(contract));
    // json = json.serialize("deploymentTimes", uint(1));
    // // store the stringified JSON to the 'json' variable we have been using as a key
    // // as we won't need it any longer
    // string memory json2 = "finalArtifact";
    // string memory final = json2.serialize("depArtifact", json);
    // final.write("<some_path>");
    // ```
    library stdJson {
        VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
        function parseRaw(string memory json, string memory key) internal pure returns (bytes memory) {
            return vm.parseJson(json, key);
        }
        function readUint(string memory json, string memory key) internal returns (uint256) {
            return vm.parseJsonUint(json, key);
        }
        function readUintArray(string memory json, string memory key) internal returns (uint256[] memory) {
            return vm.parseJsonUintArray(json, key);
        }
        function readInt(string memory json, string memory key) internal returns (int256) {
            return vm.parseJsonInt(json, key);
        }
        function readIntArray(string memory json, string memory key) internal returns (int256[] memory) {
            return vm.parseJsonIntArray(json, key);
        }
        function readBytes32(string memory json, string memory key) internal returns (bytes32) {
            return vm.parseJsonBytes32(json, key);
        }
        function readBytes32Array(string memory json, string memory key) internal returns (bytes32[] memory) {
            return vm.parseJsonBytes32Array(json, key);
        }
        function readString(string memory json, string memory key) internal returns (string memory) {
            return vm.parseJsonString(json, key);
        }
        function readStringArray(string memory json, string memory key) internal returns (string[] memory) {
            return vm.parseJsonStringArray(json, key);
        }
        function readAddress(string memory json, string memory key) internal returns (address) {
            return vm.parseJsonAddress(json, key);
        }
        function readAddressArray(string memory json, string memory key) internal returns (address[] memory) {
            return vm.parseJsonAddressArray(json, key);
        }
        function readBool(string memory json, string memory key) internal returns (bool) {
            return vm.parseJsonBool(json, key);
        }
        function readBoolArray(string memory json, string memory key) internal returns (bool[] memory) {
            return vm.parseJsonBoolArray(json, key);
        }
        function readBytes(string memory json, string memory key) internal returns (bytes memory) {
            return vm.parseJsonBytes(json, key);
        }
        function readBytesArray(string memory json, string memory key) internal returns (bytes[] memory) {
            return vm.parseJsonBytesArray(json, key);
        }
        function serialize(string memory jsonKey, string memory key, bool value) internal returns (string memory) {
            return vm.serializeBool(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, bool[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeBool(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, uint256 value) internal returns (string memory) {
            return vm.serializeUint(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, uint256[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeUint(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, int256 value) internal returns (string memory) {
            return vm.serializeInt(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, int256[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeInt(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, address value) internal returns (string memory) {
            return vm.serializeAddress(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, address[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeAddress(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, bytes32 value) internal returns (string memory) {
            return vm.serializeBytes32(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, bytes32[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeBytes32(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, bytes memory value) internal returns (string memory) {
            return vm.serializeBytes(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, bytes[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeBytes(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, string memory value)
            internal
            returns (string memory)
        {
            return vm.serializeString(jsonKey, key, value);
        }
        function serialize(string memory jsonKey, string memory key, string[] memory value)
            internal
            returns (string memory)
        {
            return vm.serializeString(jsonKey, key, value);
        }
        function write(string memory jsonKey, string memory path) internal {
            vm.writeJson(jsonKey, path);
        }
        function write(string memory jsonKey, string memory path, string memory valueKey) internal {
            vm.writeJson(jsonKey, path, valueKey);
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    library stdMath {
        int256 private constant INT256_MIN = -57896044618658097711785492504343953926634992332820282019728792003956564819968;
        function abs(int256 a) internal pure returns (uint256) {
            // Required or it will fail when `a = type(int256).min`
            if (a == INT256_MIN) {
                return 57896044618658097711785492504343953926634992332820282019728792003956564819968;
            }
            return uint256(a > 0 ? a : -a);
        }
        function delta(uint256 a, uint256 b) internal pure returns (uint256) {
            return a > b ? a - b : b - a;
        }
        function delta(int256 a, int256 b) internal pure returns (uint256) {
            // a and b are of the same sign
            // this works thanks to two's complement, the left-most bit is the sign bit
            if ((a ^ b) > -1) {
                return delta(abs(a), abs(b));
            }
            // a and b are of opposite signs
            return abs(a) + abs(b);
        }
        function percentDelta(uint256 a, uint256 b) internal pure returns (uint256) {
            uint256 absDelta = delta(a, b);
            return absDelta * 1e18 / b;
        }
        function percentDelta(int256 a, int256 b) internal pure returns (uint256) {
            uint256 absDelta = delta(a, b);
            uint256 absB = abs(b);
            return absDelta * 1e18 / absB;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    import {Vm} from "./Vm.sol";
    struct StdStorage {
        mapping(address => mapping(bytes4 => mapping(bytes32 => uint256))) slots;
        mapping(address => mapping(bytes4 => mapping(bytes32 => bool))) finds;
        bytes32[] _keys;
        bytes4 _sig;
        uint256 _depth;
        address _target;
        bytes32 _set;
    }
    library stdStorageSafe {
        event SlotFound(address who, bytes4 fsig, bytes32 keysHash, uint256 slot);
        event WARNING_UninitedSlot(address who, uint256 slot);
        Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
        function sigs(string memory sigStr) internal pure returns (bytes4) {
            return bytes4(keccak256(bytes(sigStr)));
        }
        /// @notice find an arbitrary storage slot given a function sig, input data, address of the contract and a value to check against
        // slot complexity:
        //  if flat, will be bytes32(uint256(uint));
        //  if map, will be keccak256(abi.encode(key, uint(slot)));
        //  if deep map, will be keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))));
        //  if map struct, will be bytes32(uint256(keccak256(abi.encode(key1, keccak256(abi.encode(key0, uint(slot)))))) + structFieldDepth);
        function find(StdStorage storage self) internal returns (uint256) {
            address who = self._target;
            bytes4 fsig = self._sig;
            uint256 field_depth = self._depth;
            bytes32[] memory ins = self._keys;
            // calldata to test against
            if (self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
                return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
            }
            bytes memory cald = abi.encodePacked(fsig, flatten(ins));
            vm.record();
            bytes32 fdat;
            {
                (, bytes memory rdat) = who.staticcall(cald);
                fdat = bytesToBytes32(rdat, 32 * field_depth);
            }
            (bytes32[] memory reads,) = vm.accesses(address(who));
            if (reads.length == 1) {
                bytes32 curr = vm.load(who, reads[0]);
                if (curr == bytes32(0)) {
                    emit WARNING_UninitedSlot(who, uint256(reads[0]));
                }
                if (fdat != curr) {
                    require(
                        false,
                        "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
                    );
                }
                emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[0]));
                self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[0]);
                self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
            } else if (reads.length > 1) {
                for (uint256 i = 0; i < reads.length; i++) {
                    bytes32 prev = vm.load(who, reads[i]);
                    if (prev == bytes32(0)) {
                        emit WARNING_UninitedSlot(who, uint256(reads[i]));
                    }
                    // store
                    vm.store(who, reads[i], bytes32(hex"1337"));
                    bool success;
                    bytes memory rdat;
                    {
                        (success, rdat) = who.staticcall(cald);
                        fdat = bytesToBytes32(rdat, 32 * field_depth);
                    }
                    if (success && fdat == bytes32(hex"1337")) {
                        // we found which of the slots is the actual one
                        emit SlotFound(who, fsig, keccak256(abi.encodePacked(ins, field_depth)), uint256(reads[i]));
                        self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = uint256(reads[i]);
                        self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))] = true;
                        vm.store(who, reads[i], prev);
                        break;
                    }
                    vm.store(who, reads[i], prev);
                }
            } else {
                revert("stdStorage find(StdStorage): No storage use detected for target.");
            }
            require(
                self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))],
                "stdStorage find(StdStorage): Slot(s) not found."
            );
            delete self._target;
            delete self._sig;
            delete self._keys;
            delete self._depth;
            return self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))];
        }
        function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
            self._target = _target;
            return self;
        }
        function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
            self._sig = _sig;
            return self;
        }
        function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
            self._sig = sigs(_sig);
            return self;
        }
        function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
            self._keys.push(bytes32(uint256(uint160(who))));
            return self;
        }
        function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
            self._keys.push(bytes32(amt));
            return self;
        }
        function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
            self._keys.push(key);
            return self;
        }
        function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
            self._depth = _depth;
            return self;
        }
        function read(StdStorage storage self) private returns (bytes memory) {
            address t = self._target;
            uint256 s = find(self);
            return abi.encode(vm.load(t, bytes32(s)));
        }
        function read_bytes32(StdStorage storage self) internal returns (bytes32) {
            return abi.decode(read(self), (bytes32));
        }
        function read_bool(StdStorage storage self) internal returns (bool) {
            int256 v = read_int(self);
            if (v == 0) return false;
            if (v == 1) return true;
            revert("stdStorage read_bool(StdStorage): Cannot decode. Make sure you are reading a bool.");
        }
        function read_address(StdStorage storage self) internal returns (address) {
            return abi.decode(read(self), (address));
        }
        function read_uint(StdStorage storage self) internal returns (uint256) {
            return abi.decode(read(self), (uint256));
        }
        function read_int(StdStorage storage self) internal returns (int256) {
            return abi.decode(read(self), (int256));
        }
        function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {
            bytes32 out;
            uint256 max = b.length > 32 ? 32 : b.length;
            for (uint256 i = 0; i < max; i++) {
                out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
            }
            return out;
        }
        function flatten(bytes32[] memory b) private pure returns (bytes memory) {
            bytes memory result = new bytes(b.length * 32);
            for (uint256 i = 0; i < b.length; i++) {
                bytes32 k = b[i];
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(add(result, add(32, mul(32, i))), k)
                }
            }
            return result;
        }
    }
    library stdStorage {
        Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
        function sigs(string memory sigStr) internal pure returns (bytes4) {
            return stdStorageSafe.sigs(sigStr);
        }
        function find(StdStorage storage self) internal returns (uint256) {
            return stdStorageSafe.find(self);
        }
        function target(StdStorage storage self, address _target) internal returns (StdStorage storage) {
            return stdStorageSafe.target(self, _target);
        }
        function sig(StdStorage storage self, bytes4 _sig) internal returns (StdStorage storage) {
            return stdStorageSafe.sig(self, _sig);
        }
        function sig(StdStorage storage self, string memory _sig) internal returns (StdStorage storage) {
            return stdStorageSafe.sig(self, _sig);
        }
        function with_key(StdStorage storage self, address who) internal returns (StdStorage storage) {
            return stdStorageSafe.with_key(self, who);
        }
        function with_key(StdStorage storage self, uint256 amt) internal returns (StdStorage storage) {
            return stdStorageSafe.with_key(self, amt);
        }
        function with_key(StdStorage storage self, bytes32 key) internal returns (StdStorage storage) {
            return stdStorageSafe.with_key(self, key);
        }
        function depth(StdStorage storage self, uint256 _depth) internal returns (StdStorage storage) {
            return stdStorageSafe.depth(self, _depth);
        }
        function checked_write(StdStorage storage self, address who) internal {
            checked_write(self, bytes32(uint256(uint160(who))));
        }
        function checked_write(StdStorage storage self, uint256 amt) internal {
            checked_write(self, bytes32(amt));
        }
        function checked_write(StdStorage storage self, bool write) internal {
            bytes32 t;
            /// @solidity memory-safe-assembly
            assembly {
                t := write
            }
            checked_write(self, t);
        }
        function checked_write(StdStorage storage self, bytes32 set) internal {
            address who = self._target;
            bytes4 fsig = self._sig;
            uint256 field_depth = self._depth;
            bytes32[] memory ins = self._keys;
            bytes memory cald = abi.encodePacked(fsig, flatten(ins));
            if (!self.finds[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]) {
                find(self);
            }
            bytes32 slot = bytes32(self.slots[who][fsig][keccak256(abi.encodePacked(ins, field_depth))]);
            bytes32 fdat;
            {
                (, bytes memory rdat) = who.staticcall(cald);
                fdat = bytesToBytes32(rdat, 32 * field_depth);
            }
            bytes32 curr = vm.load(who, slot);
            if (fdat != curr) {
                require(
                    false,
                    "stdStorage find(StdStorage): Packed slot. This would cause dangerous overwriting and currently isn't supported."
                );
            }
            vm.store(who, slot, set);
            delete self._target;
            delete self._sig;
            delete self._keys;
            delete self._depth;
        }
        function read_bytes32(StdStorage storage self) internal returns (bytes32) {
            return stdStorageSafe.read_bytes32(self);
        }
        function read_bool(StdStorage storage self) internal returns (bool) {
            return stdStorageSafe.read_bool(self);
        }
        function read_address(StdStorage storage self) internal returns (address) {
            return stdStorageSafe.read_address(self);
        }
        function read_uint(StdStorage storage self) internal returns (uint256) {
            return stdStorageSafe.read_uint(self);
        }
        function read_int(StdStorage storage self) internal returns (int256) {
            return stdStorageSafe.read_int(self);
        }
        // Private function so needs to be copied over
        function bytesToBytes32(bytes memory b, uint256 offset) private pure returns (bytes32) {
            bytes32 out;
            uint256 max = b.length > 32 ? 32 : b.length;
            for (uint256 i = 0; i < max; i++) {
                out |= bytes32(b[offset + i] & 0xFF) >> (i * 8);
            }
            return out;
        }
        // Private function so needs to be copied over
        function flatten(bytes32[] memory b) private pure returns (bytes memory) {
            bytes memory result = new bytes(b.length * 32);
            for (uint256 i = 0; i < b.length; i++) {
                bytes32 k = b[i];
                /// @solidity memory-safe-assembly
                assembly {
                    mstore(add(result, add(32, mul(32, i))), k)
                }
            }
            return result;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.4.22 <0.9.0;
    import {Vm} from "./Vm.sol";
    library StdStyle {
        Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
        string constant RED = "\\u001b[91m";
        string constant GREEN = "\\u001b[92m";
        string constant YELLOW = "\\u001b[93m";
        string constant BLUE = "\\u001b[94m";
        string constant MAGENTA = "\\u001b[95m";
        string constant CYAN = "\\u001b[96m";
        string constant BOLD = "\\u001b[1m";
        string constant DIM = "\\u001b[2m";
        string constant ITALIC = "\\u001b[3m";
        string constant UNDERLINE = "\\u001b[4m";
        string constant INVERSE = "\\u001b[7m";
        string constant RESET = "\\u001b[0m";
        function styleConcat(string memory style, string memory self) private pure returns (string memory) {
            return string(abi.encodePacked(style, self, RESET));
        }
        function red(string memory self) internal pure returns (string memory) {
            return styleConcat(RED, self);
        }
        function red(uint256 self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function red(int256 self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function red(address self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function red(bool self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function redBytes(bytes memory self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function redBytes32(bytes32 self) internal pure returns (string memory) {
            return red(vm.toString(self));
        }
        function green(string memory self) internal pure returns (string memory) {
            return styleConcat(GREEN, self);
        }
        function green(uint256 self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function green(int256 self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function green(address self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function green(bool self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function greenBytes(bytes memory self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function greenBytes32(bytes32 self) internal pure returns (string memory) {
            return green(vm.toString(self));
        }
        function yellow(string memory self) internal pure returns (string memory) {
            return styleConcat(YELLOW, self);
        }
        function yellow(uint256 self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function yellow(int256 self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function yellow(address self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function yellow(bool self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function yellowBytes(bytes memory self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function yellowBytes32(bytes32 self) internal pure returns (string memory) {
            return yellow(vm.toString(self));
        }
        function blue(string memory self) internal pure returns (string memory) {
            return styleConcat(BLUE, self);
        }
        function blue(uint256 self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function blue(int256 self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function blue(address self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function blue(bool self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function blueBytes(bytes memory self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function blueBytes32(bytes32 self) internal pure returns (string memory) {
            return blue(vm.toString(self));
        }
        function magenta(string memory self) internal pure returns (string memory) {
            return styleConcat(MAGENTA, self);
        }
        function magenta(uint256 self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function magenta(int256 self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function magenta(address self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function magenta(bool self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function magentaBytes(bytes memory self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function magentaBytes32(bytes32 self) internal pure returns (string memory) {
            return magenta(vm.toString(self));
        }
        function cyan(string memory self) internal pure returns (string memory) {
            return styleConcat(CYAN, self);
        }
        function cyan(uint256 self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function cyan(int256 self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function cyan(address self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function cyan(bool self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function cyanBytes(bytes memory self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function cyanBytes32(bytes32 self) internal pure returns (string memory) {
            return cyan(vm.toString(self));
        }
        function bold(string memory self) internal pure returns (string memory) {
            return styleConcat(BOLD, self);
        }
        function bold(uint256 self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function bold(int256 self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function bold(address self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function bold(bool self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function boldBytes(bytes memory self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function boldBytes32(bytes32 self) internal pure returns (string memory) {
            return bold(vm.toString(self));
        }
        function dim(string memory self) internal pure returns (string memory) {
            return styleConcat(DIM, self);
        }
        function dim(uint256 self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function dim(int256 self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function dim(address self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function dim(bool self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function dimBytes(bytes memory self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function dimBytes32(bytes32 self) internal pure returns (string memory) {
            return dim(vm.toString(self));
        }
        function italic(string memory self) internal pure returns (string memory) {
            return styleConcat(ITALIC, self);
        }
        function italic(uint256 self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function italic(int256 self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function italic(address self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function italic(bool self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function italicBytes(bytes memory self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function italicBytes32(bytes32 self) internal pure returns (string memory) {
            return italic(vm.toString(self));
        }
        function underline(string memory self) internal pure returns (string memory) {
            return styleConcat(UNDERLINE, self);
        }
        function underline(uint256 self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function underline(int256 self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function underline(address self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function underline(bool self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function underlineBytes(bytes memory self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function underlineBytes32(bytes32 self) internal pure returns (string memory) {
            return underline(vm.toString(self));
        }
        function inverse(string memory self) internal pure returns (string memory) {
            return styleConcat(INVERSE, self);
        }
        function inverse(uint256 self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
        function inverse(int256 self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
        function inverse(address self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
        function inverse(bool self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
        function inverseBytes(bytes memory self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
        function inverseBytes32(bytes32 self) internal pure returns (string memory) {
            return inverse(vm.toString(self));
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    import {IMulticall3} from "./interfaces/IMulticall3.sol";
    // TODO Remove import.
    import {VmSafe} from "./Vm.sol";
    abstract contract StdUtils {
        /*//////////////////////////////////////////////////////////////////////////
                                         CONSTANTS
        //////////////////////////////////////////////////////////////////////////*/
        IMulticall3 private constant multicall = IMulticall3(0xcA11bde05977b3631167028862bE2a173976CA11);
        VmSafe private constant vm = VmSafe(address(uint160(uint256(keccak256("hevm cheat code")))));
        address private constant CONSOLE2_ADDRESS = 0x000000000000000000636F6e736F6c652e6c6f67;
        uint256 private constant INT256_MIN_ABS =
            57896044618658097711785492504343953926634992332820282019728792003956564819968;
        uint256 private constant UINT256_MAX =
            115792089237316195423570985008687907853269984665640564039457584007913129639935;
        // Used by default when deploying with create2, https://github.com/Arachnid/deterministic-deployment-proxy.
        address private constant CREATE2_FACTORY = 0x4e59b44847b379578588920cA78FbF26c0B4956C;
        /*//////////////////////////////////////////////////////////////////////////
                                     INTERNAL FUNCTIONS
        //////////////////////////////////////////////////////////////////////////*/
        function _bound(uint256 x, uint256 min, uint256 max) internal pure virtual returns (uint256 result) {
            require(min <= max, "StdUtils bound(uint256,uint256,uint256): Max is less than min.");
            // If x is between min and max, return x directly. This is to ensure that dictionary values
            // do not get shifted if the min is nonzero. More info: https://github.com/foundry-rs/forge-std/issues/188
            if (x >= min && x <= max) return x;
            uint256 size = max - min + 1;
            // If the value is 0, 1, 2, 3, wrap that to min, min+1, min+2, min+3. Similarly for the UINT256_MAX side.
            // This helps ensure coverage of the min/max values.
            if (x <= 3 && size > x) return min + x;
            if (x >= UINT256_MAX - 3 && size > UINT256_MAX - x) return max - (UINT256_MAX - x);
            // Otherwise, wrap x into the range [min, max], i.e. the range is inclusive.
            if (x > max) {
                uint256 diff = x - max;
                uint256 rem = diff % size;
                if (rem == 0) return max;
                result = min + rem - 1;
            } else if (x < min) {
                uint256 diff = min - x;
                uint256 rem = diff % size;
                if (rem == 0) return min;
                result = max - rem + 1;
            }
        }
        function bound(uint256 x, uint256 min, uint256 max) internal view virtual returns (uint256 result) {
            result = _bound(x, min, max);
            console2_log("Bound Result", result);
        }
        function bound(int256 x, int256 min, int256 max) internal view virtual returns (int256 result) {
            require(min <= max, "StdUtils bound(int256,int256,int256): Max is less than min.");
            // Shifting all int256 values to uint256 to use _bound function. The range of two types are:
            // int256 : -(2**255) ~ (2**255 - 1)
            // uint256:     0     ~ (2**256 - 1)
            // So, add 2**255, INT256_MIN_ABS to the integer values.
            //
            // If the given integer value is -2**255, we cannot use `-uint256(-x)` because of the overflow.
            // So, use `~uint256(x) + 1` instead.
            uint256 _x = x < 0 ? (INT256_MIN_ABS - ~uint256(x) - 1) : (uint256(x) + INT256_MIN_ABS);
            uint256 _min = min < 0 ? (INT256_MIN_ABS - ~uint256(min) - 1) : (uint256(min) + INT256_MIN_ABS);
            uint256 _max = max < 0 ? (INT256_MIN_ABS - ~uint256(max) - 1) : (uint256(max) + INT256_MIN_ABS);
            uint256 y = _bound(_x, _min, _max);
            // To move it back to int256 value, subtract INT256_MIN_ABS at here.
            result = y < INT256_MIN_ABS ? int256(~(INT256_MIN_ABS - y) + 1) : int256(y - INT256_MIN_ABS);
            console2_log("Bound result", vm.toString(result));
        }
        function bytesToUint(bytes memory b) internal pure virtual returns (uint256) {
            require(b.length <= 32, "StdUtils bytesToUint(bytes): Bytes length exceeds 32.");
            return abi.decode(abi.encodePacked(new bytes(32 - b.length), b), (uint256));
        }
        /// @dev Compute the address a contract will be deployed at for a given deployer address and nonce
        /// @notice adapted from Solmate implementation (https://github.com/Rari-Capital/solmate/blob/main/src/utils/LibRLP.sol)
        function computeCreateAddress(address deployer, uint256 nonce) internal pure virtual returns (address) {
            // forgefmt: disable-start
            // The integer zero is treated as an empty byte string, and as a result it only has a length prefix, 0x80, computed via 0x80 + 0.
            // A one byte integer uses its own value as its length prefix, there is no additional "0x80 + length" prefix that comes before it.
            if (nonce == 0x00)      return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, bytes1(0x80))));
            if (nonce <= 0x7f)      return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd6), bytes1(0x94), deployer, uint8(nonce))));
            // Nonces greater than 1 byte all follow a consistent encoding scheme, where each value is preceded by a prefix of 0x80 + length.
            if (nonce <= 2**8 - 1)  return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd7), bytes1(0x94), deployer, bytes1(0x81), uint8(nonce))));
            if (nonce <= 2**16 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd8), bytes1(0x94), deployer, bytes1(0x82), uint16(nonce))));
            if (nonce <= 2**24 - 1) return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xd9), bytes1(0x94), deployer, bytes1(0x83), uint24(nonce))));
            // forgefmt: disable-end
            // More details about RLP encoding can be found here: https://eth.wiki/fundamentals/rlp
            // 0xda = 0xc0 (short RLP prefix) + 0x16 (length of: 0x94 ++ proxy ++ 0x84 ++ nonce)
            // 0x94 = 0x80 + 0x14 (0x14 = the length of an address, 20 bytes, in hex)
            // 0x84 = 0x80 + 0x04 (0x04 = the bytes length of the nonce, 4 bytes, in hex)
            // We assume nobody can have a nonce large enough to require more than 32 bytes.
            return addressFromLast20Bytes(
                keccak256(abi.encodePacked(bytes1(0xda), bytes1(0x94), deployer, bytes1(0x84), uint32(nonce)))
            );
        }
        function computeCreate2Address(bytes32 salt, bytes32 initcodeHash, address deployer)
            internal
            pure
            virtual
            returns (address)
        {
            return addressFromLast20Bytes(keccak256(abi.encodePacked(bytes1(0xff), deployer, salt, initcodeHash)));
        }
        /// @dev returns the address of a contract created with CREATE2 using the default CREATE2 deployer
        function computeCreate2Address(bytes32 salt, bytes32 initCodeHash) internal pure returns (address) {
            return computeCreate2Address(salt, initCodeHash, CREATE2_FACTORY);
        }
        /// @dev returns the hash of the init code (creation code + no args) used in CREATE2 with no constructor arguments
        /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
        function hashInitCode(bytes memory creationCode) internal pure returns (bytes32) {
            return hashInitCode(creationCode, "");
        }
        /// @dev returns the hash of the init code (creation code + ABI-encoded args) used in CREATE2
        /// @param creationCode the creation code of a contract C, as returned by type(C).creationCode
        /// @param args the ABI-encoded arguments to the constructor of C
        function hashInitCode(bytes memory creationCode, bytes memory args) internal pure returns (bytes32) {
            return keccak256(abi.encodePacked(creationCode, args));
        }
        // Performs a single call with Multicall3 to query the ERC-20 token balances of the given addresses.
        function getTokenBalances(address token, address[] memory addresses)
            internal
            virtual
            returns (uint256[] memory balances)
        {
            uint256 tokenCodeSize;
            assembly {
                tokenCodeSize := extcodesize(token)
            }
            require(tokenCodeSize > 0, "StdUtils getTokenBalances(address,address[]): Token address is not a contract.");
            // ABI encode the aggregate call to Multicall3.
            uint256 length = addresses.length;
            IMulticall3.Call[] memory calls = new IMulticall3.Call[](length);
            for (uint256 i = 0; i < length; ++i) {
                // 0x70a08231 = bytes4("balanceOf(address)"))
                calls[i] = IMulticall3.Call({target: token, callData: abi.encodeWithSelector(0x70a08231, (addresses[i]))});
            }
            // Make the aggregate call.
            (, bytes[] memory returnData) = multicall.aggregate(calls);
            // ABI decode the return data and return the balances.
            balances = new uint256[](length);
            for (uint256 i = 0; i < length; ++i) {
                balances[i] = abi.decode(returnData[i], (uint256));
            }
        }
        /*//////////////////////////////////////////////////////////////////////////
                                     PRIVATE FUNCTIONS
        //////////////////////////////////////////////////////////////////////////*/
        function addressFromLast20Bytes(bytes32 bytesValue) private pure returns (address) {
            return address(uint160(uint256(bytesValue)));
        }
        // Used to prevent the compilation of console, which shortens the compilation time when console is not used elsewhere.
        function console2_log(string memory p0, uint256 p1) private view {
            (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,uint256)", p0, p1));
            status;
        }
        function console2_log(string memory p0, string memory p1) private view {
            (bool status,) = address(CONSOLE2_ADDRESS).staticcall(abi.encodeWithSignature("log(string,string)", p0, p1));
            status;
        }
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    // 💬 ABOUT
    // Standard Library's default Test
    // 🧩 MODULES
    import {console} from "./console.sol";
    import {console2} from "./console2.sol";
    import {StdAssertions} from "./StdAssertions.sol";
    import {StdChains} from "./StdChains.sol";
    import {StdCheats} from "./StdCheats.sol";
    import {stdError} from "./StdError.sol";
    import {StdInvariant} from "./StdInvariant.sol";
    import {stdJson} from "./StdJson.sol";
    import {stdMath} from "./StdMath.sol";
    import {StdStorage, stdStorage} from "./StdStorage.sol";
    import {StdUtils} from "./StdUtils.sol";
    import {Vm} from "./Vm.sol";
    import {StdStyle} from "./StdStyle.sol";
    // 📦 BOILERPLATE
    import {TestBase} from "./Base.sol";
    import {DSTest} from "ds-test/test.sol";
    // ⭐️ TEST
    abstract contract Test is DSTest, StdAssertions, StdChains, StdCheats, StdInvariant, StdUtils, TestBase {
    // Note: IS_TEST() must return true.
    // Note: Must have failure system, https://github.com/dapphub/ds-test/blob/cd98eff28324bfac652e63a239a60632a761790b/src/test.sol#L39-L76.
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    // Cheatcodes are marked as view/pure/none using the following rules:
    // 0. A call's observable behaviour includes its return value, logs, reverts and state writes,
    // 1. If you can influence a later call's observable behaviour, you're neither `view` nor `pure (you are modifying some state be it the EVM, interpreter, filesystem, etc),
    // 2. Otherwise if you can be influenced by an earlier call, or if reading some state, you're `view`,
    // 3. Otherwise you're `pure`.
    interface VmSafe {
        struct Log {
            bytes32[] topics;
            bytes data;
            address emitter;
        }
        struct Rpc {
            string key;
            string url;
        }
        struct FsMetadata {
            bool isDir;
            bool isSymlink;
            uint256 length;
            bool readOnly;
            uint256 modified;
            uint256 accessed;
            uint256 created;
        }
        // Loads a storage slot from an address
        function load(address target, bytes32 slot) external view returns (bytes32 data);
        // Signs data
        function sign(uint256 privateKey, bytes32 digest) external pure returns (uint8 v, bytes32 r, bytes32 s);
        // Gets the address for a given private key
        function addr(uint256 privateKey) external pure returns (address keyAddr);
        // Gets the nonce of an account
        function getNonce(address account) external view returns (uint64 nonce);
        // Performs a foreign function call via the terminal
        function ffi(string[] calldata commandInput) external returns (bytes memory result);
        // Sets environment variables
        function setEnv(string calldata name, string calldata value) external;
        // Reads environment variables, (name) => (value)
        function envBool(string calldata name) external view returns (bool value);
        function envUint(string calldata name) external view returns (uint256 value);
        function envInt(string calldata name) external view returns (int256 value);
        function envAddress(string calldata name) external view returns (address value);
        function envBytes32(string calldata name) external view returns (bytes32 value);
        function envString(string calldata name) external view returns (string memory value);
        function envBytes(string calldata name) external view returns (bytes memory value);
        // Reads environment variables as arrays
        function envBool(string calldata name, string calldata delim) external view returns (bool[] memory value);
        function envUint(string calldata name, string calldata delim) external view returns (uint256[] memory value);
        function envInt(string calldata name, string calldata delim) external view returns (int256[] memory value);
        function envAddress(string calldata name, string calldata delim) external view returns (address[] memory value);
        function envBytes32(string calldata name, string calldata delim) external view returns (bytes32[] memory value);
        function envString(string calldata name, string calldata delim) external view returns (string[] memory value);
        function envBytes(string calldata name, string calldata delim) external view returns (bytes[] memory value);
        // Read environment variables with default value
        function envOr(string calldata name, bool defaultValue) external returns (bool value);
        function envOr(string calldata name, uint256 defaultValue) external returns (uint256 value);
        function envOr(string calldata name, int256 defaultValue) external returns (int256 value);
        function envOr(string calldata name, address defaultValue) external returns (address value);
        function envOr(string calldata name, bytes32 defaultValue) external returns (bytes32 value);
        function envOr(string calldata name, string calldata defaultValue) external returns (string memory value);
        function envOr(string calldata name, bytes calldata defaultValue) external returns (bytes memory value);
        // Read environment variables as arrays with default value
        function envOr(string calldata name, string calldata delim, bool[] calldata defaultValue)
            external
            returns (bool[] memory value);
        function envOr(string calldata name, string calldata delim, uint256[] calldata defaultValue)
            external
            returns (uint256[] memory value);
        function envOr(string calldata name, string calldata delim, int256[] calldata defaultValue)
            external
            returns (int256[] memory value);
        function envOr(string calldata name, string calldata delim, address[] calldata defaultValue)
            external
            returns (address[] memory value);
        function envOr(string calldata name, string calldata delim, bytes32[] calldata defaultValue)
            external
            returns (bytes32[] memory value);
        function envOr(string calldata name, string calldata delim, string[] calldata defaultValue)
            external
            returns (string[] memory value);
        function envOr(string calldata name, string calldata delim, bytes[] calldata defaultValue)
            external
            returns (bytes[] memory value);
        // Records all storage reads and writes
        function record() external;
        // Gets all accessed reads and write slot from a recording session, for a given address
        function accesses(address target) external returns (bytes32[] memory readSlots, bytes32[] memory writeSlots);
        // Gets the _creation_ bytecode from an artifact file. Takes in the relative path to the json file
        function getCode(string calldata artifactPath) external view returns (bytes memory creationBytecode);
        // Gets the _deployed_ bytecode from an artifact file. Takes in the relative path to the json file
        function getDeployedCode(string calldata artifactPath) external view returns (bytes memory runtimeBytecode);
        // Labels an address in call traces
        function label(address account, string calldata newLabel) external;
        // Using the address that calls the test contract, has the next call (at this call depth only) create a transaction that can later be signed and sent onchain
        function broadcast() external;
        // Has the next call (at this call depth only) create a transaction with the address provided as the sender that can later be signed and sent onchain
        function broadcast(address signer) external;
        // Has the next call (at this call depth only) create a transaction with the private key provided as the sender that can later be signed and sent onchain
        function broadcast(uint256 privateKey) external;
        // Using the address that calls the test contract, has all subsequent calls (at this call depth only) create transactions that can later be signed and sent onchain
        function startBroadcast() external;
        // Has all subsequent calls (at this call depth only) create transactions with the address provided that can later be signed and sent onchain
        function startBroadcast(address signer) external;
        // Has all subsequent calls (at this call depth only) create transactions with the private key provided that can later be signed and sent onchain
        function startBroadcast(uint256 privateKey) external;
        // Stops collecting onchain transactions
        function stopBroadcast() external;
        // Reads the entire content of file to string
        function readFile(string calldata path) external view returns (string memory data);
        // Reads the entire content of file as binary. Path is relative to the project root.
        function readFileBinary(string calldata path) external view returns (bytes memory data);
        // Get the path of the current project root
        function projectRoot() external view returns (string memory path);
        // Get the metadata for a file/directory
        function fsMetadata(string calldata fileOrDir) external returns (FsMetadata memory metadata);
        // Reads next line of file to string
        function readLine(string calldata path) external view returns (string memory line);
        // Writes data to file, creating a file if it does not exist, and entirely replacing its contents if it does.
        function writeFile(string calldata path, string calldata data) external;
        // Writes binary data to a file, creating a file if it does not exist, and entirely replacing its contents if it does.
        // Path is relative to the project root.
        function writeFileBinary(string calldata path, bytes calldata data) external;
        // Writes line to file, creating a file if it does not exist.
        function writeLine(string calldata path, string calldata data) external;
        // Closes file for reading, resetting the offset and allowing to read it from beginning with readLine.
        function closeFile(string calldata path) external;
        // Removes file. This cheatcode will revert in the following situations, but is not limited to just these cases:
        // - Path points to a directory.
        // - The file doesn't exist.
        // - The user lacks permissions to remove the file.
        function removeFile(string calldata path) external;
        // Convert values to a string
        function toString(address value) external pure returns (string memory stringifiedValue);
        function toString(bytes calldata value) external pure returns (string memory stringifiedValue);
        function toString(bytes32 value) external pure returns (string memory stringifiedValue);
        function toString(bool value) external pure returns (string memory stringifiedValue);
        function toString(uint256 value) external pure returns (string memory stringifiedValue);
        function toString(int256 value) external pure returns (string memory stringifiedValue);
        // Convert values from a string
        function parseBytes(string calldata stringifiedValue) external pure returns (bytes memory parsedValue);
        function parseAddress(string calldata stringifiedValue) external pure returns (address parsedValue);
        function parseUint(string calldata stringifiedValue) external pure returns (uint256 parsedValue);
        function parseInt(string calldata stringifiedValue) external pure returns (int256 parsedValue);
        function parseBytes32(string calldata stringifiedValue) external pure returns (bytes32 parsedValue);
        function parseBool(string calldata stringifiedValue) external pure returns (bool parsedValue);
        // Record all the transaction logs
        function recordLogs() external;
        // Gets all the recorded logs
        function getRecordedLogs() external returns (Log[] memory logs);
        // Derive a private key from a provided mnenomic string (or mnenomic file path) at the derivation path m/44'/60'/0'/0/{index}
        function deriveKey(string calldata mnemonic, uint32 index) external pure returns (uint256 privateKey);
        // Derive a private key from a provided mnenomic string (or mnenomic file path) at {derivationPath}{index}
        function deriveKey(string calldata mnemonic, string calldata derivationPath, uint32 index)
            external
            pure
            returns (uint256 privateKey);
        // Adds a private key to the local forge wallet and returns the address
        function rememberKey(uint256 privateKey) external returns (address keyAddr);
        //
        // parseJson
        //
        // ----
        // In case the returned value is a JSON object, it's encoded as a ABI-encoded tuple. As JSON objects
        // don't have the notion of ordered, but tuples do, they JSON object is encoded with it's fields ordered in
        // ALPHABETICAL order. That means that in order to successfully decode the tuple, we need to define a tuple that
        // encodes the fields in the same order, which is alphabetical. In the case of Solidity structs, they are encoded
        // as tuples, with the attributes in the order in which they are defined.
        // For example: json = { 'a': 1, 'b': 0xa4tb......3xs}
        // a: uint256
        // b: address
        // To decode that json, we need to define a struct or a tuple as follows:
        // struct json = { uint256 a; address b; }
        // If we defined a json struct with the opposite order, meaning placing the address b first, it would try to
        // decode the tuple in that order, and thus fail.
        // ----
        // Given a string of JSON, return it as ABI-encoded
        function parseJson(string calldata json, string calldata key) external pure returns (bytes memory abiEncodedData);
        function parseJson(string calldata json) external pure returns (bytes memory abiEncodedData);
        // The following parseJson cheatcodes will do type coercion, for the type that they indicate.
        // For example, parseJsonUint will coerce all values to a uint256. That includes stringified numbers '12'
        // and hex numbers '0xEF'.
        // Type coercion works ONLY for discrete values or arrays. That means that the key must return a value or array, not
        // a JSON object.
        function parseJsonUint(string calldata, string calldata) external returns (uint256);
        function parseJsonUintArray(string calldata, string calldata) external returns (uint256[] memory);
        function parseJsonInt(string calldata, string calldata) external returns (int256);
        function parseJsonIntArray(string calldata, string calldata) external returns (int256[] memory);
        function parseJsonBool(string calldata, string calldata) external returns (bool);
        function parseJsonBoolArray(string calldata, string calldata) external returns (bool[] memory);
        function parseJsonAddress(string calldata, string calldata) external returns (address);
        function parseJsonAddressArray(string calldata, string calldata) external returns (address[] memory);
        function parseJsonString(string calldata, string calldata) external returns (string memory);
        function parseJsonStringArray(string calldata, string calldata) external returns (string[] memory);
        function parseJsonBytes(string calldata, string calldata) external returns (bytes memory);
        function parseJsonBytesArray(string calldata, string calldata) external returns (bytes[] memory);
        function parseJsonBytes32(string calldata, string calldata) external returns (bytes32);
        function parseJsonBytes32Array(string calldata, string calldata) external returns (bytes32[] memory);
        // Serialize a key and value to a JSON object stored in-memory that can be later written to a file
        // It returns the stringified version of the specific JSON file up to that moment.
        function serializeBool(string calldata objectKey, string calldata valueKey, bool value)
            external
            returns (string memory json);
        function serializeUint(string calldata objectKey, string calldata valueKey, uint256 value)
            external
            returns (string memory json);
        function serializeInt(string calldata objectKey, string calldata valueKey, int256 value)
            external
            returns (string memory json);
        function serializeAddress(string calldata objectKey, string calldata valueKey, address value)
            external
            returns (string memory json);
        function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32 value)
            external
            returns (string memory json);
        function serializeString(string calldata objectKey, string calldata valueKey, string calldata value)
            external
            returns (string memory json);
        function serializeBytes(string calldata objectKey, string calldata valueKey, bytes calldata value)
            external
            returns (string memory json);
        function serializeBool(string calldata objectKey, string calldata valueKey, bool[] calldata values)
            external
            returns (string memory json);
        function serializeUint(string calldata objectKey, string calldata valueKey, uint256[] calldata values)
            external
            returns (string memory json);
        function serializeInt(string calldata objectKey, string calldata valueKey, int256[] calldata values)
            external
            returns (string memory json);
        function serializeAddress(string calldata objectKey, string calldata valueKey, address[] calldata values)
            external
            returns (string memory json);
        function serializeBytes32(string calldata objectKey, string calldata valueKey, bytes32[] calldata values)
            external
            returns (string memory json);
        function serializeString(string calldata objectKey, string calldata valueKey, string[] calldata values)
            external
            returns (string memory json);
        function serializeBytes(string calldata objectKey, string calldata valueKey, bytes[] calldata values)
            external
            returns (string memory json);
        //
        // writeJson
        //
        // ----
        // Write a serialized JSON object to a file. If the file exists, it will be overwritten.
        // Let's assume we want to write the following JSON to a file:
        //
        // { "boolean": true, "number": 342, "object": { "title": "finally json serialization" } }
        //
        // ```
        //  string memory json1 = "some key";
        //  vm.serializeBool(json1, "boolean", true);
        //  vm.serializeBool(json1, "number", uint256(342));
        //  json2 = "some other key";
        //  string memory output = vm.serializeString(json2, "title", "finally json serialization");
        //  string memory finalJson = vm.serialize(json1, "object", output);
        //  vm.writeJson(finalJson, "./output/example.json");
        // ```
        // The critical insight is that every invocation of serialization will return the stringified version of the JSON
        // up to that point. That means we can construct arbitrary JSON objects and then use the return stringified version
        // to serialize them as values to another JSON object.
        //
        // json1 and json2 are simply keys used by the backend to keep track of the objects. So vm.serializeJson(json1,..)
        // will find the object in-memory that is keyed by "some key".
        function writeJson(string calldata json, string calldata path) external;
        // Write a serialized JSON object to an **existing** JSON file, replacing a value with key = <value_key>
        // This is useful to replace a specific value of a JSON file, without having to parse the entire thing
        function writeJson(string calldata json, string calldata path, string calldata valueKey) external;
        // Returns the RPC url for the given alias
        function rpcUrl(string calldata rpcAlias) external view returns (string memory json);
        // Returns all rpc urls and their aliases `[alias, url][]`
        function rpcUrls() external view returns (string[2][] memory urls);
        // Returns all rpc urls and their aliases as structs.
        function rpcUrlStructs() external view returns (Rpc[] memory urls);
        // If the condition is false, discard this run's fuzz inputs and generate new ones.
        function assume(bool condition) external pure;
        // Pauses gas metering (i.e. gas usage is not counted). Noop if already paused.
        function pauseGasMetering() external;
        // Resumes gas metering (i.e. gas usage is counted again). Noop if already on.
        function resumeGasMetering() external;
    }
    interface Vm is VmSafe {
        // Sets block.timestamp
        function warp(uint256 newTimestamp) external;
        // Sets block.height
        function roll(uint256 newHeight) external;
        // Sets block.basefee
        function fee(uint256 newBasefee) external;
        // Sets block.difficulty
        function difficulty(uint256 newDifficulty) external;
        // Sets block.chainid
        function chainId(uint256 newChainId) external;
        // Sets tx.gasprice
        function txGasPrice(uint256 newGasPrice) external;
        // Stores a value to an address' storage slot.
        function store(address target, bytes32 slot, bytes32 value) external;
        // Sets the nonce of an account; must be higher than the current nonce of the account
        function setNonce(address account, uint64 newNonce) external;
        // Sets the *next* call's msg.sender to be the input address
        function prank(address msgSender) external;
        // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called
        function startPrank(address msgSender) external;
        // Sets the *next* call's msg.sender to be the input address, and the tx.origin to be the second input
        function prank(address msgSender, address txOrigin) external;
        // Sets all subsequent calls' msg.sender to be the input address until `stopPrank` is called, and the tx.origin to be the second input
        function startPrank(address msgSender, address txOrigin) external;
        // Resets subsequent calls' msg.sender to be `address(this)`
        function stopPrank() external;
        // Sets an address' balance
        function deal(address account, uint256 newBalance) external;
        // Sets an address' code
        function etch(address target, bytes calldata newRuntimeBytecode) external;
        // Expects an error on next call
        function expectRevert(bytes calldata revertData) external;
        function expectRevert(bytes4 revertData) external;
        function expectRevert() external;
        // Prepare an expected log with all four checks enabled.
        // Call this function, then emit an event, then call a function. Internally after the call, we check if
        // logs were emitted in the expected order with the expected topics and data.
        // Second form also checks supplied address against emitting contract.
        function expectEmit() external;
        function expectEmit(address emitter) external;
        // Prepare an expected log with (bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData).
        // Call this function, then emit an event, then call a function. Internally after the call, we check if
        // logs were emitted in the expected order with the expected topics and data (as specified by the booleans).
        // Second form also checks supplied address against emitting contract.
        function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData) external;
        function expectEmit(bool checkTopic1, bool checkTopic2, bool checkTopic3, bool checkData, address emitter)
            external;
        // Mocks a call to an address, returning specified data.
        // Calldata can either be strict or a partial match, e.g. if you only
        // pass a Solidity selector to the expected calldata, then the entire Solidity
        // function will be mocked.
        function mockCall(address callee, bytes calldata data, bytes calldata returnData) external;
        // Mocks a call to an address with a specific msg.value, returning specified data.
        // Calldata match takes precedence over msg.value in case of ambiguity.
        function mockCall(address callee, uint256 msgValue, bytes calldata data, bytes calldata returnData) external;
        // Reverts a call to an address with specified revert data.
        function mockCallRevert(address callee, bytes calldata data, bytes calldata revertData) external;
        // Reverts a call to an address with a specific msg.value, with specified revert data.
        function mockCallRevert(address callee, uint256 msgValue, bytes calldata data, bytes calldata revertData)
            external;
        // Clears all mocked calls
        function clearMockedCalls() external;
        // Expects a call to an address with the specified calldata.
        // Calldata can either be a strict or a partial match
        function expectCall(address callee, bytes calldata data) external;
        // Expects a call to an address with the specified msg.value and calldata
        function expectCall(address callee, uint256 msgValue, bytes calldata data) external;
        // Expect a call to an address with the specified msg.value, gas, and calldata.
        function expectCall(address callee, uint256 msgValue, uint64 gas, bytes calldata data) external;
        // Expect a call to an address with the specified msg.value and calldata, and a *minimum* amount of gas.
        function expectCallMinGas(address callee, uint256 msgValue, uint64 minGas, bytes calldata data) external;
        // Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the current subcontext. If any other
        // memory is written to, the test will fail. Can be called multiple times to add more ranges to the set.
        function expectSafeMemory(uint64 min, uint64 max) external;
        // Only allows memory writes to offsets [0x00, 0x60) ∪ [min, max) in the next created subcontext.
        // If any other memory is written to, the test will fail. Can be called multiple times to add more ranges
        // to the set.
        function expectSafeMemoryCall(uint64 min, uint64 max) external;
        // Sets block.coinbase
        function coinbase(address newCoinbase) external;
        // Snapshot the current state of the evm.
        // Returns the id of the snapshot that was created.
        // To revert a snapshot use `revertTo`
        function snapshot() external returns (uint256 snapshotId);
        // Revert the state of the EVM to a previous snapshot
        // Takes the snapshot id to revert to.
        // This deletes the snapshot and all snapshots taken after the given snapshot id.
        function revertTo(uint256 snapshotId) external returns (bool success);
        // Creates a new fork with the given endpoint and block and returns the identifier of the fork
        function createFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);
        // Creates a new fork with the given endpoint and the _latest_ block and returns the identifier of the fork
        function createFork(string calldata urlOrAlias) external returns (uint256 forkId);
        // Creates a new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before the transaction,
        // and returns the identifier of the fork
        function createFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);
        // Creates _and_ also selects a new fork with the given endpoint and block and returns the identifier of the fork
        function createSelectFork(string calldata urlOrAlias, uint256 blockNumber) external returns (uint256 forkId);
        // Creates _and_ also selects new fork with the given endpoint and at the block the given transaction was mined in, replays all transaction mined in the block before
        // the transaction, returns the identifier of the fork
        function createSelectFork(string calldata urlOrAlias, bytes32 txHash) external returns (uint256 forkId);
        // Creates _and_ also selects a new fork with the given endpoint and the latest block and returns the identifier of the fork
        function createSelectFork(string calldata urlOrAlias) external returns (uint256 forkId);
        // Takes a fork identifier created by `createFork` and sets the corresponding forked state as active.
        function selectFork(uint256 forkId) external;
        /// Returns the identifier of the currently active fork. Reverts if no fork is currently active.
        function activeFork() external view returns (uint256 forkId);
        // Updates the currently active fork to given block number
        // This is similar to `roll` but for the currently active fork
        function rollFork(uint256 blockNumber) external;
        // Updates the currently active fork to given transaction
        // this will `rollFork` with the number of the block the transaction was mined in and replays all transaction mined before it in the block
        function rollFork(bytes32 txHash) external;
        // Updates the given fork to given block number
        function rollFork(uint256 forkId, uint256 blockNumber) external;
        // Updates the given fork to block number of the given transaction and replays all transaction mined before it in the block
        function rollFork(uint256 forkId, bytes32 txHash) external;
        // Marks that the account(s) should use persistent storage across fork swaps in a multifork setup
        // Meaning, changes made to the state of this account will be kept when switching forks
        function makePersistent(address account) external;
        function makePersistent(address account0, address account1) external;
        function makePersistent(address account0, address account1, address account2) external;
        function makePersistent(address[] calldata accounts) external;
        // Revokes persistent status from the address, previously added via `makePersistent`
        function revokePersistent(address account) external;
        function revokePersistent(address[] calldata accounts) external;
        // Returns true if the account is marked as persistent
        function isPersistent(address account) external view returns (bool persistent);
        // In forking mode, explicitly grant the given address cheatcode access
        function allowCheatcodes(address account) external;
        // Fetches the given transaction from the active fork and executes it on the current state
        function transact(bytes32 txHash) external;
        // Fetches the given transaction from the given fork and executes it on the current state
        function transact(uint256 forkId, bytes32 txHash) external;
    }
    // SPDX-License-Identifier: MIT
    pragma solidity >=0.4.22 <0.9.0;
    library console {
        address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
        function _sendLogPayload(bytes memory payload) private view {
            uint256 payloadLength = payload.length;
            address consoleAddress = CONSOLE_ADDRESS;
            /// @solidity memory-safe-assembly
            assembly {
                let payloadStart := add(payload, 32)
                let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
            }
        }
        function log() internal view {
            _sendLogPayload(abi.encodeWithSignature("log()"));
        }
        function logInt(int p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(int)", p0));
        }
        function logUint(uint p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
        }
        function logString(string memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
        }
        function logBool(bool p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
        }
        function logAddress(address p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
        }
        function logBytes(bytes memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
        }
        function logBytes1(bytes1 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
        }
        function logBytes2(bytes2 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
        }
        function logBytes3(bytes3 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
        }
        function logBytes4(bytes4 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
        }
        function logBytes5(bytes5 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
        }
        function logBytes6(bytes6 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
        }
        function logBytes7(bytes7 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
        }
        function logBytes8(bytes8 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
        }
        function logBytes9(bytes9 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
        }
        function logBytes10(bytes10 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
        }
        function logBytes11(bytes11 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
        }
        function logBytes12(bytes12 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
        }
        function logBytes13(bytes13 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
        }
        function logBytes14(bytes14 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
        }
        function logBytes15(bytes15 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
        }
        function logBytes16(bytes16 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
        }
        function logBytes17(bytes17 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
        }
        function logBytes18(bytes18 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
        }
        function logBytes19(bytes19 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
        }
        function logBytes20(bytes20 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
        }
        function logBytes21(bytes21 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
        }
        function logBytes22(bytes22 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
        }
        function logBytes23(bytes23 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
        }
        function logBytes24(bytes24 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
        }
        function logBytes25(bytes25 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
        }
        function logBytes26(bytes26 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
        }
        function logBytes27(bytes27 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
        }
        function logBytes28(bytes28 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
        }
        function logBytes29(bytes29 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
        }
        function logBytes30(bytes30 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
        }
        function logBytes31(bytes31 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
        }
        function logBytes32(bytes32 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
        }
        function log(uint p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint)", p0));
        }
        function log(string memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
        }
        function log(bool p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
        }
        function log(address p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
        }
        function log(uint p0, uint p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint)", p0, p1));
        }
        function log(uint p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string)", p0, p1));
        }
        function log(uint p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool)", p0, p1));
        }
        function log(uint p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address)", p0, p1));
        }
        function log(string memory p0, uint p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint)", p0, p1));
        }
        function log(string memory p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
        }
        function log(string memory p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
        }
        function log(string memory p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
        }
        function log(bool p0, uint p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint)", p0, p1));
        }
        function log(bool p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
        }
        function log(bool p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
        }
        function log(bool p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
        }
        function log(address p0, uint p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint)", p0, p1));
        }
        function log(address p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
        }
        function log(address p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
        }
        function log(address p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
        }
        function log(uint p0, uint p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint)", p0, p1, p2));
        }
        function log(uint p0, uint p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string)", p0, p1, p2));
        }
        function log(uint p0, uint p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool)", p0, p1, p2));
        }
        function log(uint p0, uint p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address)", p0, p1, p2));
        }
        function log(uint p0, string memory p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint)", p0, p1, p2));
        }
        function log(uint p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,string)", p0, p1, p2));
        }
        function log(uint p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool)", p0, p1, p2));
        }
        function log(uint p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,address)", p0, p1, p2));
        }
        function log(uint p0, bool p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint)", p0, p1, p2));
        }
        function log(uint p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string)", p0, p1, p2));
        }
        function log(uint p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool)", p0, p1, p2));
        }
        function log(uint p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address)", p0, p1, p2));
        }
        function log(uint p0, address p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint)", p0, p1, p2));
        }
        function log(uint p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,string)", p0, p1, p2));
        }
        function log(uint p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool)", p0, p1, p2));
        }
        function log(uint p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,address)", p0, p1, p2));
        }
        function log(string memory p0, uint p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint)", p0, p1, p2));
        }
        function log(string memory p0, uint p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,string)", p0, p1, p2));
        }
        function log(string memory p0, uint p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool)", p0, p1, p2));
        }
        function log(string memory p0, uint p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,address)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
        }
        function log(string memory p0, address p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint)", p0, p1, p2));
        }
        function log(string memory p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
        }
        function log(string memory p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
        }
        function log(string memory p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
        }
        function log(bool p0, uint p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint)", p0, p1, p2));
        }
        function log(bool p0, uint p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string)", p0, p1, p2));
        }
        function log(bool p0, uint p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool)", p0, p1, p2));
        }
        function log(bool p0, uint p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
        }
        function log(bool p0, bool p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint)", p0, p1, p2));
        }
        function log(bool p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
        }
        function log(bool p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
        }
        function log(bool p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
        }
        function log(bool p0, address p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint)", p0, p1, p2));
        }
        function log(bool p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
        }
        function log(bool p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
        }
        function log(bool p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
        }
        function log(address p0, uint p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint)", p0, p1, p2));
        }
        function log(address p0, uint p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,string)", p0, p1, p2));
        }
        function log(address p0, uint p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool)", p0, p1, p2));
        }
        function log(address p0, uint p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,address)", p0, p1, p2));
        }
        function log(address p0, string memory p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint)", p0, p1, p2));
        }
        function log(address p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
        }
        function log(address p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
        }
        function log(address p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
        }
        function log(address p0, bool p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint)", p0, p1, p2));
        }
        function log(address p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
        }
        function log(address p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
        }
        function log(address p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
        }
        function log(address p0, address p1, uint p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint)", p0, p1, p2));
        }
        function log(address p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
        }
        function log(address p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
        }
        function log(address p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
        }
        function log(uint p0, uint p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,string)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,uint,address)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,string)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,string,address)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,string)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,bool,address)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,string)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, uint p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,uint,address,address)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,string)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,uint,address)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,string)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,string,address)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,string)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,bool,address)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,string)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,string,address,address)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,string)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,uint,address)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,string)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,string,address)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,string)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,bool,address,address)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,string)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,uint,address)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,string)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,string,address)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,string)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,bool,address)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,uint)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,string)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,bool)", p0, p1, p2, p3));
        }
        function log(uint p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint,address,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,uint,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,uint,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,uint)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,uint,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,uint)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,uint)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,uint)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,uint)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,uint)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,uint)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, uint p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
        }
    }// SPDX-License-Identifier: MIT
    pragma solidity >=0.4.22 <0.9.0;
    /// @dev The original console.sol uses `int` and `uint` for computing function selectors, but it should
    /// use `int256` and `uint256`. This modified version fixes that. This version is recommended
    /// over `console.sol` if you don't need compatibility with Hardhat as the logs will show up in
    /// forge stack traces. If you do need compatibility with Hardhat, you must use `console.sol`.
    /// Reference: https://github.com/NomicFoundation/hardhat/issues/2178
    library console2 {
        address constant CONSOLE_ADDRESS = address(0x000000000000000000636F6e736F6c652e6c6f67);
        function _sendLogPayload(bytes memory payload) private view {
            uint256 payloadLength = payload.length;
            address consoleAddress = CONSOLE_ADDRESS;
            /// @solidity memory-safe-assembly
            assembly {
                let payloadStart := add(payload, 32)
                let r := staticcall(gas(), consoleAddress, payloadStart, payloadLength, 0, 0)
            }
        }
        function log() internal view {
            _sendLogPayload(abi.encodeWithSignature("log()"));
        }
        function logInt(int256 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
        }
        function logUint(uint256 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
        }
        function logString(string memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
        }
        function logBool(bool p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
        }
        function logAddress(address p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
        }
        function logBytes(bytes memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes)", p0));
        }
        function logBytes1(bytes1 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes1)", p0));
        }
        function logBytes2(bytes2 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes2)", p0));
        }
        function logBytes3(bytes3 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes3)", p0));
        }
        function logBytes4(bytes4 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes4)", p0));
        }
        function logBytes5(bytes5 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes5)", p0));
        }
        function logBytes6(bytes6 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes6)", p0));
        }
        function logBytes7(bytes7 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes7)", p0));
        }
        function logBytes8(bytes8 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes8)", p0));
        }
        function logBytes9(bytes9 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes9)", p0));
        }
        function logBytes10(bytes10 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes10)", p0));
        }
        function logBytes11(bytes11 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes11)", p0));
        }
        function logBytes12(bytes12 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes12)", p0));
        }
        function logBytes13(bytes13 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes13)", p0));
        }
        function logBytes14(bytes14 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes14)", p0));
        }
        function logBytes15(bytes15 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes15)", p0));
        }
        function logBytes16(bytes16 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes16)", p0));
        }
        function logBytes17(bytes17 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes17)", p0));
        }
        function logBytes18(bytes18 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes18)", p0));
        }
        function logBytes19(bytes19 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes19)", p0));
        }
        function logBytes20(bytes20 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes20)", p0));
        }
        function logBytes21(bytes21 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes21)", p0));
        }
        function logBytes22(bytes22 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes22)", p0));
        }
        function logBytes23(bytes23 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes23)", p0));
        }
        function logBytes24(bytes24 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes24)", p0));
        }
        function logBytes25(bytes25 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes25)", p0));
        }
        function logBytes26(bytes26 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes26)", p0));
        }
        function logBytes27(bytes27 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes27)", p0));
        }
        function logBytes28(bytes28 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes28)", p0));
        }
        function logBytes29(bytes29 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes29)", p0));
        }
        function logBytes30(bytes30 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes30)", p0));
        }
        function logBytes31(bytes31 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes31)", p0));
        }
        function logBytes32(bytes32 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bytes32)", p0));
        }
        function log(uint256 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256)", p0));
        }
        function log(int256 p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(int256)", p0));
        }
        function log(string memory p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string)", p0));
        }
        function log(bool p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool)", p0));
        }
        function log(address p0) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address)", p0));
        }
        function log(uint256 p0, uint256 p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256)", p0, p1));
        }
        function log(uint256 p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string)", p0, p1));
        }
        function log(uint256 p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool)", p0, p1));
        }
        function log(uint256 p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address)", p0, p1));
        }
        function log(string memory p0, uint256 p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256)", p0, p1));
        }
        function log(string memory p0, int256 p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,int256)", p0, p1));
        }
        function log(string memory p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string)", p0, p1));
        }
        function log(string memory p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool)", p0, p1));
        }
        function log(string memory p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address)", p0, p1));
        }
        function log(bool p0, uint256 p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256)", p0, p1));
        }
        function log(bool p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string)", p0, p1));
        }
        function log(bool p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool)", p0, p1));
        }
        function log(bool p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address)", p0, p1));
        }
        function log(address p0, uint256 p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256)", p0, p1));
        }
        function log(address p0, string memory p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string)", p0, p1));
        }
        function log(address p0, bool p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool)", p0, p1));
        }
        function log(address p0, address p1) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address)", p0, p1));
        }
        function log(uint256 p0, uint256 p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256)", p0, p1, p2));
        }
        function log(uint256 p0, uint256 p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string)", p0, p1, p2));
        }
        function log(uint256 p0, uint256 p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool)", p0, p1, p2));
        }
        function log(uint256 p0, uint256 p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address)", p0, p1, p2));
        }
        function log(uint256 p0, string memory p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256)", p0, p1, p2));
        }
        function log(uint256 p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string)", p0, p1, p2));
        }
        function log(uint256 p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool)", p0, p1, p2));
        }
        function log(uint256 p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address)", p0, p1, p2));
        }
        function log(uint256 p0, bool p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256)", p0, p1, p2));
        }
        function log(uint256 p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string)", p0, p1, p2));
        }
        function log(uint256 p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool)", p0, p1, p2));
        }
        function log(uint256 p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address)", p0, p1, p2));
        }
        function log(uint256 p0, address p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256)", p0, p1, p2));
        }
        function log(uint256 p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string)", p0, p1, p2));
        }
        function log(uint256 p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool)", p0, p1, p2));
        }
        function log(uint256 p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address)", p0, p1, p2));
        }
        function log(string memory p0, uint256 p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256)", p0, p1, p2));
        }
        function log(string memory p0, uint256 p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string)", p0, p1, p2));
        }
        function log(string memory p0, uint256 p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool)", p0, p1, p2));
        }
        function log(string memory p0, uint256 p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool)", p0, p1, p2));
        }
        function log(string memory p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool)", p0, p1, p2));
        }
        function log(string memory p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address)", p0, p1, p2));
        }
        function log(string memory p0, address p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256)", p0, p1, p2));
        }
        function log(string memory p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string)", p0, p1, p2));
        }
        function log(string memory p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool)", p0, p1, p2));
        }
        function log(string memory p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address)", p0, p1, p2));
        }
        function log(bool p0, uint256 p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256)", p0, p1, p2));
        }
        function log(bool p0, uint256 p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string)", p0, p1, p2));
        }
        function log(bool p0, uint256 p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool)", p0, p1, p2));
        }
        function log(bool p0, uint256 p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool)", p0, p1, p2));
        }
        function log(bool p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address)", p0, p1, p2));
        }
        function log(bool p0, bool p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256)", p0, p1, p2));
        }
        function log(bool p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string)", p0, p1, p2));
        }
        function log(bool p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool)", p0, p1, p2));
        }
        function log(bool p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address)", p0, p1, p2));
        }
        function log(bool p0, address p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256)", p0, p1, p2));
        }
        function log(bool p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string)", p0, p1, p2));
        }
        function log(bool p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool)", p0, p1, p2));
        }
        function log(bool p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address)", p0, p1, p2));
        }
        function log(address p0, uint256 p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256)", p0, p1, p2));
        }
        function log(address p0, uint256 p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string)", p0, p1, p2));
        }
        function log(address p0, uint256 p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool)", p0, p1, p2));
        }
        function log(address p0, uint256 p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address)", p0, p1, p2));
        }
        function log(address p0, string memory p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256)", p0, p1, p2));
        }
        function log(address p0, string memory p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string)", p0, p1, p2));
        }
        function log(address p0, string memory p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool)", p0, p1, p2));
        }
        function log(address p0, string memory p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address)", p0, p1, p2));
        }
        function log(address p0, bool p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256)", p0, p1, p2));
        }
        function log(address p0, bool p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string)", p0, p1, p2));
        }
        function log(address p0, bool p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool)", p0, p1, p2));
        }
        function log(address p0, bool p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address)", p0, p1, p2));
        }
        function log(address p0, address p1, uint256 p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256)", p0, p1, p2));
        }
        function log(address p0, address p1, string memory p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string)", p0, p1, p2));
        }
        function log(address p0, address p1, bool p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool)", p0, p1, p2));
        }
        function log(address p0, address p1, address p2) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address)", p0, p1, p2));
        }
        function log(uint256 p0, uint256 p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,uint256,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,string,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,bool,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, uint256 p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,uint256,address,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,uint256,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,string,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,bool,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,string,address,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,uint256,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,string,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,bool,address,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,uint256,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,string,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,bool,address)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,uint256)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,string)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,bool)", p0, p1, p2, p3));
        }
        function log(uint256 p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(uint256,address,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,uint256,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, uint256 p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,uint256,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,uint256,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,string,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,uint256,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,bool,address,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,uint256,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,string,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,bool,address)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,uint256)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,string)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,bool)", p0, p1, p2, p3));
        }
        function log(string memory p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(string,address,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,uint256,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, uint256 p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,uint256,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,uint256,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,string,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,uint256,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,bool,address,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,uint256,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,string,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,bool,address)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,uint256)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,string)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,bool)", p0, p1, p2, p3));
        }
        function log(bool p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(bool,address,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,uint256,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, uint256 p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,uint256,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,uint256,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, string memory p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,string,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,uint256,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, bool p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,bool,address,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint256 p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint256 p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint256 p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, uint256 p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,uint256,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, string memory p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,string,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, bool p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,bool,address)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, uint256 p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,uint256)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, string memory p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,string)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, bool p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,bool)", p0, p1, p2, p3));
        }
        function log(address p0, address p1, address p2, address p3) internal view {
            _sendLogPayload(abi.encodeWithSignature("log(address,address,address,address)", p0, p1, p2, p3));
        }
    }// SPDX-License-Identifier: MIT
    pragma solidity >=0.6.2 <0.9.0;
    pragma experimental ABIEncoderV2;
    interface IMulticall3 {
        struct Call {
            address target;
            bytes callData;
        }
        struct Call3 {
            address target;
            bool allowFailure;
            bytes callData;
        }
        struct Call3Value {
            address target;
            bool allowFailure;
            uint256 value;
            bytes callData;
        }
        struct Result {
            bool success;
            bytes returnData;
        }
        function aggregate(Call[] calldata calls)
            external
            payable
            returns (uint256 blockNumber, bytes[] memory returnData);
        function aggregate3(Call3[] calldata calls) external payable returns (Result[] memory returnData);
        function aggregate3Value(Call3Value[] calldata calls) external payable returns (Result[] memory returnData);
        function blockAndAggregate(Call[] calldata calls)
            external
            payable
            returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
        function getBasefee() external view returns (uint256 basefee);
        function getBlockHash(uint256 blockNumber) external view returns (bytes32 blockHash);
        function getBlockNumber() external view returns (uint256 blockNumber);
        function getChainId() external view returns (uint256 chainid);
        function getCurrentBlockCoinbase() external view returns (address coinbase);
        function getCurrentBlockDifficulty() external view returns (uint256 difficulty);
        function getCurrentBlockGasLimit() external view returns (uint256 gaslimit);
        function getCurrentBlockTimestamp() external view returns (uint256 timestamp);
        function getEthBalance(address addr) external view returns (uint256 balance);
        function getLastBlockHash() external view returns (bytes32 blockHash);
        function tryAggregate(bool requireSuccess, Call[] calldata calls)
            external
            payable
            returns (Result[] memory returnData);
        function tryBlockAndAggregate(bool requireSuccess, Call[] calldata calls)
            external
            payable
            returns (uint256 blockNumber, bytes32 blockHash, Result[] memory returnData);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol)
    pragma solidity ^0.8.0;
    import "../utils/introspection/IERC165.sol";
    /**
     * @dev Interface for the NFT Royalty Standard.
     *
     * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
     * support for royalty payments across all NFT marketplaces and ecosystem participants.
     *
     * _Available since v4.5._
     */
    interface IERC2981 is IERC165 {
        /**
         * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
         * exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
         */
        function royaltyInfo(uint256 tokenId, uint256 salePrice)
            external
            view
            returns (address receiver, uint256 royaltyAmount);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
    pragma solidity ^0.8.0;
    import "../../interfaces/IERC2981.sol";
    import "../../utils/introspection/ERC165.sol";
    /**
     * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
     *
     * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
     * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
     *
     * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
     * fee is specified in basis points by default.
     *
     * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
     * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
     * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
     *
     * _Available since v4.5._
     */
    abstract contract ERC2981 is IERC2981, ERC165 {
        struct RoyaltyInfo {
            address receiver;
            uint96 royaltyFraction;
        }
        RoyaltyInfo private _defaultRoyaltyInfo;
        mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
        /**
         * @dev See {IERC165-supportsInterface}.
         */
        function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
            return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
        }
        /**
         * @inheritdoc IERC2981
         */
        function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
            RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
            if (royalty.receiver == address(0)) {
                royalty = _defaultRoyaltyInfo;
            }
            uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
            return (royalty.receiver, royaltyAmount);
        }
        /**
         * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
         * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
         * override.
         */
        function _feeDenominator() internal pure virtual returns (uint96) {
            return 10000;
        }
        /**
         * @dev Sets the royalty information that all ids in this contract will default to.
         *
         * Requirements:
         *
         * - `receiver` cannot be the zero address.
         * - `feeNumerator` cannot be greater than the fee denominator.
         */
        function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
            require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
            require(receiver != address(0), "ERC2981: invalid receiver");
            _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
        }
        /**
         * @dev Removes default royalty information.
         */
        function _deleteDefaultRoyalty() internal virtual {
            delete _defaultRoyaltyInfo;
        }
        /**
         * @dev Sets the royalty information for a specific token id, overriding the global default.
         *
         * Requirements:
         *
         * - `receiver` cannot be the zero address.
         * - `feeNumerator` cannot be greater than the fee denominator.
         */
        function _setTokenRoyalty(
            uint256 tokenId,
            address receiver,
            uint96 feeNumerator
        ) internal virtual {
            require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
            require(receiver != address(0), "ERC2981: Invalid parameters");
            _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
        }
        /**
         * @dev Resets royalty information for the token id back to the global default.
         */
        function _resetTokenRoyalty(uint256 tokenId) internal virtual {
            delete _tokenRoyaltyInfo[tokenId];
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (utils/Strings.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev String operations.
     */
    library Strings {
        bytes16 private constant _HEX_SYMBOLS = "0123456789abcdef";
        uint8 private constant _ADDRESS_LENGTH = 20;
        /**
         * @dev Converts a `uint256` to its ASCII `string` decimal representation.
         */
        function toString(uint256 value) internal pure returns (string memory) {
            // Inspired by OraclizeAPI's implementation - MIT licence
            // https://github.com/oraclize/ethereum-api/blob/b42146b063c7d6ee1358846c198246239e9360e8/oraclizeAPI_0.4.25.sol
            if (value == 0) {
                return "0";
            }
            uint256 temp = value;
            uint256 digits;
            while (temp != 0) {
                digits++;
                temp /= 10;
            }
            bytes memory buffer = new bytes(digits);
            while (value != 0) {
                digits -= 1;
                buffer[digits] = bytes1(uint8(48 + uint256(value % 10)));
                value /= 10;
            }
            return string(buffer);
        }
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
         */
        function toHexString(uint256 value) internal pure returns (string memory) {
            if (value == 0) {
                return "0x00";
            }
            uint256 temp = value;
            uint256 length = 0;
            while (temp != 0) {
                length++;
                temp >>= 8;
            }
            return toHexString(value, length);
        }
        /**
         * @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
         */
        function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
            bytes memory buffer = new bytes(2 * length + 2);
            buffer[0] = "0";
            buffer[1] = "x";
            for (uint256 i = 2 * length + 1; i > 1; --i) {
                buffer[i] = _HEX_SYMBOLS[value & 0xf];
                value >>= 4;
            }
            require(value == 0, "Strings: hex length insufficient");
            return string(buffer);
        }
        /**
         * @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal representation.
         */
        function toHexString(address addr) internal pure returns (string memory) {
            return toHexString(uint256(uint160(addr)), _ADDRESS_LENGTH);
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
    pragma solidity ^0.8.0;
    import "./IERC165.sol";
    /**
     * @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;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
    pragma solidity ^0.8.0;
    /**
     * @dev Interface of the ERC165 standard, as defined in the
     * https://eips.ethereum.org/EIPS/eip-165[EIP].
     *
     * Implementers can declare support of contract interfaces, which can then be
     * queried by others ({ERC165Checker}).
     *
     * For an implementation, see {ERC165}.
     */
    interface IERC165 {
        /**
         * @dev Returns true if this contract implements the interface defined by
         * `interfaceId`. See the corresponding
         * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
         * to learn more about how these ids are created.
         *
         * This function call must use less than 30 000 gas.
         */
        function supportsInterface(bytes4 interfaceId) external view returns (bool);
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
    pragma solidity ^0.8.0;
    import "../utils/ContextUpgradeable.sol";
    import "../proxy/utils/Initializable.sol";
    /**
     * @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 OwnableUpgradeable is Initializable, ContextUpgradeable {
        address private _owner;
        event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
        /**
         * @dev Initializes the contract setting the deployer as the initial owner.
         */
        function __Ownable_init() internal onlyInitializing {
            __Ownable_init_unchained();
        }
        function __Ownable_init_unchained() internal onlyInitializing {
            _transferOwnership(_msgSender());
        }
        /**
         * @dev Throws if called by any account other than the owner.
         */
        modifier onlyOwner() {
            _checkOwner();
            _;
        }
        /**
         * @dev Returns the address of the current owner.
         */
        function owner() public view virtual returns (address) {
            return _owner;
        }
        /**
         * @dev Throws if the sender is not the owner.
         */
        function _checkOwner() internal view virtual {
            require(owner() == _msgSender(), "Ownable: caller is not the owner");
        }
        /**
         * @dev Leaves the contract without owner. It will not be possible to call
         * `onlyOwner` functions 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);
        }
        /**
         * @dev This empty reserved space is put in place to allow future versions to add new
         * variables without shifting down storage in the inheritance chain.
         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
         */
        uint256[49] private __gap;
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/Initializable.sol)
    pragma solidity ^0.8.2;
    import "../../utils/AddressUpgradeable.sol";
    /**
     * @dev This is a base contract to aid in writing upgradeable contracts, or any kind of contract that will be deployed
     * behind a proxy. Since proxied contracts do not make use of a constructor, it's common to move constructor logic to an
     * external initializer function, usually called `initialize`. It then becomes necessary to protect this initializer
     * function so it can only be called once. The {initializer} modifier provided by this contract will have this effect.
     *
     * The initialization functions use a version number. Once a version number is used, it is consumed and cannot be
     * reused. This mechanism prevents re-execution of each "step" but allows the creation of new initialization steps in
     * case an upgrade adds a module that needs to be initialized.
     *
     * For example:
     *
     * [.hljs-theme-light.nopadding]
     * ```solidity
     * contract MyToken is ERC20Upgradeable {
     *     function initialize() initializer public {
     *         __ERC20_init("MyToken", "MTK");
     *     }
     * }
     *
     * contract MyTokenV2 is MyToken, ERC20PermitUpgradeable {
     *     function initializeV2() reinitializer(2) public {
     *         __ERC20Permit_init("MyToken");
     *     }
     * }
     * ```
     *
     * TIP: To avoid leaving the proxy in an uninitialized state, the initializer function should be called as early as
     * possible by providing the encoded function call as the `_data` argument to {ERC1967Proxy-constructor}.
     *
     * CAUTION: When used with inheritance, manual care must be taken to not invoke a parent initializer twice, or to ensure
     * that all initializers are idempotent. This is not verified automatically as constructors are by Solidity.
     *
     * [CAUTION]
     * ====
     * Avoid leaving a contract uninitialized.
     *
     * An uninitialized contract can be taken over by an attacker. This applies to both a proxy and its implementation
     * contract, which may impact the proxy. To prevent the implementation contract from being used, you should invoke
     * the {_disableInitializers} function in the constructor to automatically lock it when it is deployed:
     *
     * [.hljs-theme-light.nopadding]
     * ```
     * /// @custom:oz-upgrades-unsafe-allow constructor
     * constructor() {
     *     _disableInitializers();
     * }
     * ```
     * ====
     */
    abstract contract Initializable {
        /**
         * @dev Indicates that the contract has been initialized.
         * @custom:oz-retyped-from bool
         */
        uint8 private _initialized;
        /**
         * @dev Indicates that the contract is in the process of being initialized.
         */
        bool private _initializing;
        /**
         * @dev Triggered when the contract has been initialized or reinitialized.
         */
        event Initialized(uint8 version);
        /**
         * @dev A modifier that defines a protected initializer function that can be invoked at most once. In its scope,
         * `onlyInitializing` functions can be used to initialize parent contracts.
         *
         * Similar to `reinitializer(1)`, except that functions marked with `initializer` can be nested in the context of a
         * constructor.
         *
         * Emits an {Initialized} event.
         */
        modifier initializer() {
            bool isTopLevelCall = !_initializing;
            require(
                (isTopLevelCall && _initialized < 1) || (!AddressUpgradeable.isContract(address(this)) && _initialized == 1),
                "Initializable: contract is already initialized"
            );
            _initialized = 1;
            if (isTopLevelCall) {
                _initializing = true;
            }
            _;
            if (isTopLevelCall) {
                _initializing = false;
                emit Initialized(1);
            }
        }
        /**
         * @dev A modifier that defines a protected reinitializer function that can be invoked at most once, and only if the
         * contract hasn't been initialized to a greater version before. In its scope, `onlyInitializing` functions can be
         * used to initialize parent contracts.
         *
         * A reinitializer may be used after the original initialization step. This is essential to configure modules that
         * are added through upgrades and that require initialization.
         *
         * When `version` is 1, this modifier is similar to `initializer`, except that functions marked with `reinitializer`
         * cannot be nested. If one is invoked in the context of another, execution will revert.
         *
         * Note that versions can jump in increments greater than 1; this implies that if multiple reinitializers coexist in
         * a contract, executing them in the right order is up to the developer or operator.
         *
         * WARNING: setting the version to 255 will prevent any future reinitialization.
         *
         * Emits an {Initialized} event.
         */
        modifier reinitializer(uint8 version) {
            require(!_initializing && _initialized < version, "Initializable: contract is already initialized");
            _initialized = version;
            _initializing = true;
            _;
            _initializing = false;
            emit Initialized(version);
        }
        /**
         * @dev Modifier to protect an initialization function so that it can only be invoked by functions with the
         * {initializer} and {reinitializer} modifiers, directly or indirectly.
         */
        modifier onlyInitializing() {
            require(_initializing, "Initializable: contract is not initializing");
            _;
        }
        /**
         * @dev Locks the contract, preventing any future reinitialization. This cannot be part of an initializer call.
         * Calling this in the constructor of a contract will prevent that contract from being initialized or reinitialized
         * to any version. It is recommended to use this to lock implementation contracts that are designed to be called
         * through proxies.
         *
         * Emits an {Initialized} event the first time it is successfully executed.
         */
        function _disableInitializers() internal virtual {
            require(!_initializing, "Initializable: contract is initializing");
            if (_initialized != type(uint8).max) {
                _initialized = type(uint8).max;
                emit Initialized(type(uint8).max);
            }
        }
        /**
         * @dev Returns the highest version that has been initialized. See {reinitializer}.
         */
        function _getInitializedVersion() internal view returns (uint8) {
            return _initialized;
        }
        /**
         * @dev Returns `true` if the contract is currently initializing. See {onlyInitializing}.
         */
        function _isInitializing() internal view returns (bool) {
            return _initializing;
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol)
    pragma solidity ^0.8.1;
    /**
     * @dev Collection of functions related to the address type
     */
    library AddressUpgradeable {
        /**
         * @dev Returns true if `account` is a contract.
         *
         * [IMPORTANT]
         * ====
         * It is unsafe to assume that an address for which this function returns
         * false is an externally-owned account (EOA) and not a contract.
         *
         * Among others, `isContract` will return false for the following
         * types of addresses:
         *
         *  - an externally-owned account
         *  - a contract in construction
         *  - an address where a contract will be created
         *  - an address where a contract lived, but was destroyed
         *
         * Furthermore, `isContract` will also return true if the target contract within
         * the same transaction is already scheduled for destruction by `SELFDESTRUCT`,
         * which only has an effect at the end of a transaction.
         * ====
         *
         * [IMPORTANT]
         * ====
         * You shouldn't rely on `isContract` to protect against flash loan attacks!
         *
         * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
         * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
         * constructor.
         * ====
         */
        function isContract(address account) internal view returns (bool) {
            // This method relies on extcodesize/address.code.length, which returns 0
            // for contracts in construction, since the code is only stored at the end
            // of the constructor execution.
            return account.code.length > 0;
        }
        /**
         * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
         * `recipient`, forwarding all available gas and reverting on errors.
         *
         * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
         * of certain opcodes, possibly making contracts go over the 2300 gas limit
         * imposed by `transfer`, making them unable to receive funds via
         * `transfer`. {sendValue} removes this limitation.
         *
         * https://consensys.net/diligence/blog/2019/09/stop-using-soliditys-transfer-now/[Learn more].
         *
         * IMPORTANT: because control is transferred to `recipient`, care must be
         * taken to not create reentrancy vulnerabilities. Consider using
         * {ReentrancyGuard} or the
         * https://solidity.readthedocs.io/en/v0.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 functionCallWithValue(target, data, 0, "Address: low-level call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
         * `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal returns (bytes memory) {
            return functionCallWithValue(target, data, 0, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but also transferring `value` wei to `target`.
         *
         * Requirements:
         *
         * - the calling contract must have an ETH balance of at least `value`.
         * - the called Solidity function must be `payable`.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(address target, bytes memory data, uint256 value) internal returns (bytes memory) {
            return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
        }
        /**
         * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
         * with `errorMessage` as a fallback revert reason when `target` reverts.
         *
         * _Available since v3.1._
         */
        function functionCallWithValue(
            address target,
            bytes memory data,
            uint256 value,
            string memory errorMessage
        ) internal returns (bytes memory) {
            require(address(this).balance >= value, "Address: insufficient balance for call");
            (bool success, bytes memory returndata) = target.call{value: value}(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
            return functionStaticCall(target, data, "Address: low-level static call failed");
        }
        /**
         * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
         * but performing a static call.
         *
         * _Available since v3.3._
         */
        function functionStaticCall(
            address target,
            bytes memory data,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            (bool success, bytes memory returndata) = target.staticcall(data);
            return verifyCallResultFromTarget(target, success, returndata, errorMessage);
        }
        /**
         * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
         * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
         *
         * _Available since v4.8._
         */
        function verifyCallResultFromTarget(
            address target,
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal view returns (bytes memory) {
            if (success) {
                if (returndata.length == 0) {
                    // only check isContract if the call was successful and the return data is empty
                    // otherwise we already know that it was a contract
                    require(isContract(target), "Address: call to non-contract");
                }
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        /**
         * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
         * revert reason or using the provided one.
         *
         * _Available since v4.3._
         */
        function verifyCallResult(
            bool success,
            bytes memory returndata,
            string memory errorMessage
        ) internal pure returns (bytes memory) {
            if (success) {
                return returndata;
            } else {
                _revert(returndata, errorMessage);
            }
        }
        function _revert(bytes memory returndata, string memory errorMessage) private pure {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
    pragma solidity ^0.8.0;
    import "../proxy/utils/Initializable.sol";
    /**
     * @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 ContextUpgradeable is Initializable {
        function __Context_init() internal onlyInitializing {
        }
        function __Context_init_unchained() internal onlyInitializing {
        }
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
        /**
         * @dev This empty reserved space is put in place to allow future versions to add new
         * variables without shifting down storage in the inheritance chain.
         * See https://docs.openzeppelin.com/contracts/4.x/upgradeable#storage_gaps
         */
        uint256[50] private __gap;
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.16;
    interface IUpgradeable {
        /**
         * @notice Contract version number.
         *
         * @return uint256 The version number.
         */
        function version() external pure returns (uint256);
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.16;
    import "forge-std/Test.sol";
    import "openzeppelin-contracts/contracts/token/common/ERC2981.sol";
    import "openzeppelin-contracts/contracts/utils/Strings.sol";
    import "ERC721A/ERC721A.sol";
    import "ERC721A-Upgradeable/ERC721AUpgradeable.sol";
    import "contracts-upgradeable/contracts/access/OwnableUpgradeable.sol";
    import "../storage/CommunityStorage.sol";
    import "../interfaces/ICommunity.sol";
    import "../../../interfaces/IUpgradeable.sol";
    import "../lib/types.sol";
    error SoldOut();
    error NotWhiteListed();
    error InvalidPrice();
    error FundWithdrawFailed();
    error InvalidQuantity();
    error NotTransferrable();
    contract Community is ERC721AUpgradeable, ERC2981, OwnableUpgradeable, CommunityStorage, ICommunity, IUpgradeable {
        uint256 constant MAX_BPS = 10000; 
        uint256 constant DEFAULT_OWNER_FEE=9900;
        uint256 constant ATTICC_FEE = 100;
        address constant ATTICC_ADDRESS = 0x4BCdD74A35e028DaE62cb1D48528E71843e2AC7d;
        
        event UserMinting(address indexed user, uint256 price, uint256 startIdx, uint256 quantity);
        
        constructor() {
            _disableInitializers();
        }
        function initialize(Types.CommunityConfig memory config) initializerERC721A initializer public {
            __ERC721A_init(config.name, config.symbol);
            _transferOwnership(config.owner);
            tokenUriCommon_ = config.tokenUriCommon;
            totalSupply_ = config.totalSupply;
            price_ = config.price;
            description_ = config.description;
            maxPerWallet_ = config.maxPerWallet;
            accessCode_ = config.accessCode;
            isTransferable_ = config.isTransferable;
            _setDefaultRoyalty(config.owner, config.royaltyAmount);
            withdrawAddresses_ = new address[](5);
            withdrawPercentages_ = new uint256[](5);
            _initFeeCollector();
            withdrawAddresses_[1]= config.owner;
            withdrawPercentages_[1] = DEFAULT_OWNER_FEE;
            accessCodeEnabled_ = (bytes(accessCode_).length > 0);
            royalty_ = config.royaltyAmount;
            isMintable_ = true;
        }
        function _initFeeCollector() private {
            withdrawAddresses_[0] = ATTICC_ADDRESS;
            withdrawPercentages_[0] = ATTICC_FEE;
        }
        function _startTokenId() internal view virtual override returns (uint256) {
            return 1;
        }
        function setPrice(uint256 newPrice) external onlyOwner {
            price_ = newPrice;
        }
        
        function setAccessCodeEnabled(bool enabled_) external onlyOwner {
            accessCodeEnabled_ = enabled_;
        }
        function setPerWalletMax(uint256 _val) external onlyOwner {
            maxPerWallet_ = _val;
        }
        function setTotalSupply(uint256 supply) external onlyOwner {
            require(supply == 0 || supply > totalMinted_, "Total Supply can only be increased and not reduced");
            totalSupply_ = supply;
        }
        function setRoyaltyInfo(address receiver, uint96 feeBasisPoints)
            external
            onlyOwner
        {
            _setDefaultRoyalty(receiver, feeBasisPoints);
            royalty_ = feeBasisPoints;
        }
        function setIsMintable(bool isMintable) external onlyOwner {
            isMintable_ = isMintable;
        }
        function setAccessCode(string memory accessCode) external onlyOwner {
            accessCode_ = accessCode;
            if (bytes(accessCode_).length == 0) {
                accessCodeEnabled_ = false;
            } else if ((bytes(accessCode_).length > 0) && accessCodeEnabled_ == false) {
                accessCodeEnabled_ = true;
            }
        }
        function setTokenUriCommon(string memory tokenUriCommon) external onlyOwner {
            tokenUriCommon_ = tokenUriCommon;
        }
        function setTransferable(bool isTransferable) external onlyOwner {
            isTransferable_ = isTransferable;
        }
        function updateWithdrawRecipient(address payable _address, uint256 _percentage) external onlyOwner {
            require(_percentage >= 100 && _percentage <= 10000, "percentage only can be between 100 and 10000");
            require(withdrawAddresses_.length == withdrawPercentages_.length, "mismatched num of recipients and percentage");
            uint256 currentAllocated = 0;
            uint256 recipient;
            for (uint256 i; i < withdrawAddresses_.length; i++) {
                if (_address != withdrawAddresses_[i]) {
                    currentAllocated += withdrawPercentages_[i];
                } else {
                    recipient = i;
                }
            }
            require(_percentage <= (MAX_BPS - currentAllocated), "PERCENTAGE overflow");
            withdrawPercentages_[recipient] = _percentage;
        }
        function addWithdrawRecipient(address payable _address, uint256 _percentage) external onlyOwner {
            require(_percentage >= 100 && _percentage <= 10000, "percentage only can be between 100 and 10000");
            require(withdrawAddresses_.length == withdrawPercentages_.length, "mismatched num of recipients and percentage");
            uint256 currentAllocated = 0;
            for (uint256 i; i < withdrawAddresses_.length; i++) { 
                currentAllocated += withdrawPercentages_[i];
            }
            require(_percentage <= (MAX_BPS - currentAllocated), "PERCENTAGE overflow");
            withdrawAddresses_.push(_address);
            withdrawPercentages_.push(_percentage);
        }
        function mint(
            uint256 quantity,
            string memory accessCode
        ) external payable {
            if (!isMintable_) revert("Minting ended");
            if (totalSupply_ > 0 && totalMinted_ + quantity > totalSupply_) revert("Token Overflow");
            if (price_ > 0 && msg.value < price_ * quantity) revert("Insufficient Payment Amount");
            if (accessCodeEnabled_ && keccak256(abi.encodePacked(accessCode)) != keccak256(abi.encodePacked(accessCode_))) revert("No access code provided");
            if (maxPerWallet_ > 0 && addressMintBalance[msg.sender] + quantity > maxPerWallet_) revert("over limit for maxPerWallet");
            uint256 nextId = _nextTokenId();
            _mint(msg.sender, quantity);
            addressMintBalance[msg.sender] += quantity;
            totalMinted_ += quantity;
            for (uint256 i = 0; i < quantity; ++i) {
                tokenInitiated[nextId+i] = true;
            }
            emit UserMinting(msg.sender, price_, nextId, quantity);
        }
        function _withdraw(address _address, uint256 _amount) private {
            (bool success, ) = _address.call{value: _amount}("");
            if (!success) revert FundWithdrawFailed();
        }
        function withdraw() external onlyOwner {
            uint256 balance = address(this).balance;
            for (uint256 i; i < withdrawAddresses_.length; i++) {
                _withdraw(withdrawAddresses_[i], (balance * withdrawPercentages_[i]) / MAX_BPS);
            }
        }
        /**
         * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
         */
        function tokenURI(uint256 tokenId) public view override(ERC721AUpgradeable) returns (string memory) {
            return tokenUriCommon_;
        }
        /// @dev The following functions are overrides required by Solidity.
        function _beforeTokenTransfers(
            address from,
            address to,
            uint256 tokenId,
            uint256 quantity
        ) internal override(ERC721AUpgradeable) {
           super._beforeTokenTransfers(from, to, tokenId, quantity);
           require(isTransferable_ || !tokenInitiated[tokenId], "token is not transferrable");
        }
        function supportsInterface(bytes4 interfaceId)
            public
            view
            override(ERC721AUpgradeable, ERC2981)
            returns (bool)
        {
            return interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
                interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
                interfaceId == 0x5b5e139f || super.supportsInterface(interfaceId);
        }
        function version() external pure override returns (uint256) {
            return VERSION;
        }
    }
    // SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity ^0.8.16;
    import "../lib/types.sol";
    interface ICommunity {
        function initialize(Types.CommunityConfig memory params) external;
    }// SPDX-License-Identifier: MIT
    pragma solidity ^0.8.16;
    library Types {
        bytes32 internal constant SALT = keccak256(bytes("ATTProtocolV1"));
        struct AtticcAddresses {
            address communityBeacon;
        }
        struct AtticcBootstrapParams {
            address communityFactory;
        }
        struct CommunityFeatureStorage {
            uint256 totalCommunities;
            mapping(uint256 => Types.CommunityConfig) communitiesById;
        }
        struct CommunityConfig {
            address proxy;
            address owner;
            string name;
            string symbol;
            string description;
            // if totalSupply_ is 0, then unlimited supply
            uint256 totalSupply;
            uint256 price;
            uint256 maxPerWallet;
            // if accessCode is "", then no restricted access
            string  accessCode;
            string  tokenUriCommon;
            uint96  royaltyAmount;
            bool isTransferable;
            bool accessCodeUsed;
        }
        struct CommunityParameters {
            string name;
            string symbol;
            string description;
            // if totalSupply_ is 0, then unlimited supply
            uint256 totalSupply;
            uint256 price;
            uint256 maxPerWallet;
            // if accessCode is "", then no restricted access
            string  accessCode;
            string  tokenUriCommon;
            uint96 royaltyAmount;
            bool isTransferable;
            bool accessCodeUsed;
        }
        struct EngineBootstrapParams {
            address engineOwner;
            address communityFactory;
        }
    }// SPDX-License-Identifier: GPL-3.0-or-later
    pragma solidity 0.8.16;
    abstract contract CommunityStorage {
        uint256 internal constant VERSION = 17;
        address[] public withdrawAddresses_;
        uint256[] public withdrawPercentages_;
        // if totalSupply_ is 0, then unlimited supply
        uint256 public totalSupply_ = 0;
        uint256 public totalMinted_ = 0;
        uint256 public price_;
        uint256 public maxPerWallet_;
        string  internal tokenUriCommon_;
        string  internal description_;
        string internal accessCode_;    
        bool public isTransferable_;
        mapping(address => uint256) public addressMintBalance;
        mapping(uint256 => bool) public tokenInitiated;
        mapping(uint256 => string) public tokenUri;  
        bool public isMintable_ = true;
        bool public accessCodeEnabled_ = false;
        // deprecated, not used 
        uint96 public defaultRoyaltyAmt_ = 0; // note this is the bps so need to devided by _feeDenominator
        // this is just to backward compatibility for old deployments
        uint96 public royalty_ = 0;
    }