S Price: $0.788257 (-5.13%)
    /

    Contract Diff Checker

    Contract Name:
    Token

    Contract Source Code:

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/ERC20.sol)
    
    pragma solidity ^0.8.0;
    
    import "./IERC20.sol";
    import "./extensions/IERC20Metadata.sol";
    import "../../utils/Context.sol";
    
    /**
     * @dev Implementation of the {IERC20} interface.
     *
     * This implementation is agnostic to the way tokens are created. This means
     * that a supply mechanism has to be added in a derived contract using {_mint}.
     * For a generic mechanism see {ERC20PresetMinterPauser}.
     *
     * TIP: For a detailed writeup see our guide
     * https://forum.openzeppelin.com/t/how-to-implement-erc20-supply-mechanisms/226[How
     * to implement supply mechanisms].
     *
     * The default value of {decimals} is 18. To change this, you should override
     * this function so it returns a different value.
     *
     * We have followed general OpenZeppelin Contracts guidelines: functions revert
     * instead returning `false` on failure. This behavior is nonetheless
     * conventional and does not conflict with the expectations of ERC20
     * applications.
     *
     * Additionally, an {Approval} event is emitted on calls to {transferFrom}.
     * This allows applications to reconstruct the allowance for all accounts just
     * by listening to said events. Other implementations of the EIP may not emit
     * these events, as it isn't required by the specification.
     *
     * Finally, the non-standard {decreaseAllowance} and {increaseAllowance}
     * functions have been added to mitigate the well-known issues around setting
     * allowances. See {IERC20-approve}.
     */
    contract ERC20 is Context, IERC20, IERC20Metadata {
        mapping(address => uint256) private _balances;
    
        mapping(address => mapping(address => uint256)) private _allowances;
    
        uint256 private _totalSupply;
    
        string private _name;
        string private _symbol;
    
        /**
         * @dev Sets the values for {name} and {symbol}.
         *
         * All two of these values are immutable: they can only be set once during
         * construction.
         */
        constructor(string memory name_, string memory symbol_) {
            _name = name_;
            _symbol = symbol_;
        }
    
        /**
         * @dev Returns the name of the token.
         */
        function name() public view virtual override returns (string memory) {
            return _name;
        }
    
        /**
         * @dev Returns the symbol of the token, usually a shorter version of the
         * name.
         */
        function symbol() public view virtual override returns (string memory) {
            return _symbol;
        }
    
        /**
         * @dev Returns the number of decimals used to get its user representation.
         * For example, if `decimals` equals `2`, a balance of `505` tokens should
         * be displayed to a user as `5.05` (`505 / 10 ** 2`).
         *
         * Tokens usually opt for a value of 18, imitating the relationship between
         * Ether and Wei. This is the default value returned by this function, unless
         * it's overridden.
         *
         * NOTE: This information is only used for _display_ purposes: it in
         * no way affects any of the arithmetic of the contract, including
         * {IERC20-balanceOf} and {IERC20-transfer}.
         */
        function decimals() public view virtual override returns (uint8) {
            return 18;
        }
    
        /**
         * @dev See {IERC20-totalSupply}.
         */
        function totalSupply() public view virtual override returns (uint256) {
            return _totalSupply;
        }
    
        /**
         * @dev See {IERC20-balanceOf}.
         */
        function balanceOf(address account) public view virtual override returns (uint256) {
            return _balances[account];
        }
    
        /**
         * @dev See {IERC20-transfer}.
         *
         * Requirements:
         *
         * - `to` cannot be the zero address.
         * - the caller must have a balance of at least `amount`.
         */
        function transfer(address to, uint256 amount) public virtual override returns (bool) {
            address owner = _msgSender();
            _transfer(owner, to, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-allowance}.
         */
        function allowance(address owner, address spender) public view virtual override returns (uint256) {
            return _allowances[owner][spender];
        }
    
        /**
         * @dev See {IERC20-approve}.
         *
         * NOTE: If `amount` is the maximum `uint256`, the allowance is not updated on
         * `transferFrom`. This is semantically equivalent to an infinite approval.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function approve(address spender, uint256 amount) public virtual override returns (bool) {
            address owner = _msgSender();
            _approve(owner, spender, amount);
            return true;
        }
    
        /**
         * @dev See {IERC20-transferFrom}.
         *
         * Emits an {Approval} event indicating the updated allowance. This is not
         * required by the EIP. See the note at the beginning of {ERC20}.
         *
         * NOTE: Does not update the allowance if the current allowance
         * is the maximum `uint256`.
         *
         * Requirements:
         *
         * - `from` and `to` cannot be the zero address.
         * - `from` must have a balance of at least `amount`.
         * - the caller must have allowance for ``from``'s tokens of at least
         * `amount`.
         */
        function transferFrom(address from, address to, uint256 amount) public virtual override returns (bool) {
            address spender = _msgSender();
            _spendAllowance(from, spender, amount);
            _transfer(from, to, amount);
            return true;
        }
    
        /**
         * @dev Atomically increases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         */
        function increaseAllowance(address spender, uint256 addedValue) public virtual returns (bool) {
            address owner = _msgSender();
            _approve(owner, spender, allowance(owner, spender) + addedValue);
            return true;
        }
    
        /**
         * @dev Atomically decreases the allowance granted to `spender` by the caller.
         *
         * This is an alternative to {approve} that can be used as a mitigation for
         * problems described in {IERC20-approve}.
         *
         * Emits an {Approval} event indicating the updated allowance.
         *
         * Requirements:
         *
         * - `spender` cannot be the zero address.
         * - `spender` must have allowance for the caller of at least
         * `subtractedValue`.
         */
        function decreaseAllowance(address spender, uint256 subtractedValue) public virtual returns (bool) {
            address owner = _msgSender();
            uint256 currentAllowance = allowance(owner, spender);
            require(currentAllowance >= subtractedValue, "ERC20: decreased allowance below zero");
            unchecked {
                _approve(owner, spender, currentAllowance - subtractedValue);
            }
    
            return true;
        }
    
        /**
         * @dev Moves `amount` of tokens from `from` to `to`.
         *
         * This internal function is equivalent to {transfer}, and can be used to
         * e.g. implement automatic token fees, slashing mechanisms, etc.
         *
         * Emits a {Transfer} event.
         *
         * Requirements:
         *
         * - `from` cannot be the zero address.
         * - `to` cannot be the zero address.
         * - `from` must have a balance of at least `amount`.
         */
        function _transfer(address from, address to, uint256 amount) internal virtual {
            require(from != address(0), "ERC20: transfer from the zero address");
            require(to != address(0), "ERC20: transfer to the zero address");
    
            _beforeTokenTransfer(from, to, amount);
    
            uint256 fromBalance = _balances[from];
            require(fromBalance >= amount, "ERC20: transfer amount exceeds balance");
            unchecked {
                _balances[from] = fromBalance - amount;
                // Overflow not possible: the sum of all balances is capped by totalSupply, and the sum is preserved by
                // decrementing then incrementing.
                _balances[to] += amount;
            }
    
            emit Transfer(from, to, amount);
    
            _afterTokenTransfer(from, to, amount);
        }
    
        /** @dev Creates `amount` tokens and assigns them to `account`, increasing
         * the total supply.
         *
         * Emits a {Transfer} event with `from` set to the zero address.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         */
        function _mint(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: mint to the zero address");
    
            _beforeTokenTransfer(address(0), account, amount);
    
            _totalSupply += amount;
            unchecked {
                // Overflow not possible: balance + amount is at most totalSupply + amount, which is checked above.
                _balances[account] += amount;
            }
            emit Transfer(address(0), account, amount);
    
            _afterTokenTransfer(address(0), account, amount);
        }
    
        /**
         * @dev Destroys `amount` tokens from `account`, reducing the
         * total supply.
         *
         * Emits a {Transfer} event with `to` set to the zero address.
         *
         * Requirements:
         *
         * - `account` cannot be the zero address.
         * - `account` must have at least `amount` tokens.
         */
        function _burn(address account, uint256 amount) internal virtual {
            require(account != address(0), "ERC20: burn from the zero address");
    
            _beforeTokenTransfer(account, address(0), amount);
    
            uint256 accountBalance = _balances[account];
            require(accountBalance >= amount, "ERC20: burn amount exceeds balance");
            unchecked {
                _balances[account] = accountBalance - amount;
                // Overflow not possible: amount <= accountBalance <= totalSupply.
                _totalSupply -= amount;
            }
    
            emit Transfer(account, address(0), amount);
    
            _afterTokenTransfer(account, address(0), amount);
        }
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the `owner` s tokens.
         *
         * This internal function is equivalent to `approve`, and can be used to
         * e.g. set automatic allowances for certain subsystems, etc.
         *
         * Emits an {Approval} event.
         *
         * Requirements:
         *
         * - `owner` cannot be the zero address.
         * - `spender` cannot be the zero address.
         */
        function _approve(address owner, address spender, uint256 amount) internal virtual {
            require(owner != address(0), "ERC20: approve from the zero address");
            require(spender != address(0), "ERC20: approve to the zero address");
    
            _allowances[owner][spender] = amount;
            emit Approval(owner, spender, amount);
        }
    
        /**
         * @dev Updates `owner` s allowance for `spender` based on spent `amount`.
         *
         * Does not update the allowance amount in case of infinite allowance.
         * Revert if not enough allowance is available.
         *
         * Might emit an {Approval} event.
         */
        function _spendAllowance(address owner, address spender, uint256 amount) internal virtual {
            uint256 currentAllowance = allowance(owner, spender);
            if (currentAllowance != type(uint256).max) {
                require(currentAllowance >= amount, "ERC20: insufficient allowance");
                unchecked {
                    _approve(owner, spender, currentAllowance - amount);
                }
            }
        }
    
        /**
         * @dev Hook that is called before any transfer of tokens. This includes
         * minting and burning.
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * will be transferred to `to`.
         * - when `from` is zero, `amount` tokens will be minted for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens will be burned.
         * - `from` and `to` are never both zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _beforeTokenTransfer(address from, address to, uint256 amount) internal virtual {}
    
        /**
         * @dev Hook that is called after any transfer of tokens. This includes
         * minting and burning.
         *
         * Calling conditions:
         *
         * - when `from` and `to` are both non-zero, `amount` of ``from``'s tokens
         * has been transferred to `to`.
         * - when `from` is zero, `amount` tokens have been minted for `to`.
         * - when `to` is zero, `amount` of ``from``'s tokens have been burned.
         * - `from` and `to` are never both zero.
         *
         * To learn more about hooks, head to xref:ROOT:extending-contracts.adoc#using-hooks[Using Hooks].
         */
        function _afterTokenTransfer(address from, address to, uint256 amount) internal virtual {}
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/IERC20Metadata.sol)
    
    pragma solidity ^0.8.0;
    
    import "../IERC20.sol";
    
    /**
     * @dev Interface for the optional metadata functions from the ERC20 standard.
     *
     * _Available since v4.1._
     */
    interface IERC20Metadata is IERC20 {
        /**
         * @dev Returns the name of the token.
         */
        function name() external view returns (string memory);
    
        /**
         * @dev Returns the symbol of the token.
         */
        function symbol() external view returns (string memory);
    
        /**
         * @dev Returns the decimals places of the token.
         */
        function decimals() external view returns (uint8);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts (last updated v4.9.0) (token/ERC20/IERC20.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Interface of the ERC20 standard as defined in the EIP.
     */
    interface IERC20 {
        /**
         * @dev Emitted when `value` tokens are moved from one account (`from`) to
         * another (`to`).
         *
         * Note that `value` may be zero.
         */
        event Transfer(address indexed from, address indexed to, uint256 value);
    
        /**
         * @dev Emitted when the allowance of a `spender` for an `owner` is set by
         * a call to {approve}. `value` is the new allowance.
         */
        event Approval(address indexed owner, address indexed spender, uint256 value);
    
        /**
         * @dev Returns the amount of tokens in existence.
         */
        function totalSupply() external view returns (uint256);
    
        /**
         * @dev Returns the amount of tokens owned by `account`.
         */
        function balanceOf(address account) external view returns (uint256);
    
        /**
         * @dev Moves `amount` tokens from the caller's account to `to`.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transfer(address to, uint256 amount) external returns (bool);
    
        /**
         * @dev Returns the remaining number of tokens that `spender` will be
         * allowed to spend on behalf of `owner` through {transferFrom}. This is
         * zero by default.
         *
         * This value changes when {approve} or {transferFrom} are called.
         */
        function allowance(address owner, address spender) external view returns (uint256);
    
        /**
         * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * IMPORTANT: Beware that changing an allowance with this method brings the risk
         * that someone may use both the old and the new allowance by unfortunate
         * transaction ordering. One possible solution to mitigate this race
         * condition is to first reduce the spender's allowance to 0 and set the
         * desired value afterwards:
         * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
         *
         * Emits an {Approval} event.
         */
        function approve(address spender, uint256 amount) external returns (bool);
    
        /**
         * @dev Moves `amount` tokens from `from` to `to` using the
         * allowance mechanism. `amount` is then deducted from the caller's
         * allowance.
         *
         * Returns a boolean value indicating whether the operation succeeded.
         *
         * Emits a {Transfer} event.
         */
        function transferFrom(address from, address to, uint256 amount) external returns (bool);
    }

    // SPDX-License-Identifier: MIT
    // OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
    
    pragma solidity ^0.8.0;
    
    /**
     * @dev Provides information about the current execution context, including the
     * sender of the transaction and its data. While these are generally available
     * via msg.sender and msg.data, they should not be accessed in such a direct
     * manner, since when dealing with meta-transactions the account sending and
     * paying for execution may not be the actual sender (as far as an application
     * is concerned).
     *
     * This contract is only required for intermediate, library-like contracts.
     */
    abstract contract Context {
        function _msgSender() internal view virtual returns (address) {
            return msg.sender;
        }
    
        function _msgData() internal view virtual returns (bytes calldata) {
            return msg.data;
        }
    }

    // SPDX-License-Identifier: UNKNOWN
    pragma solidity 0.8.18;
    
    // Contracts/Libraries/Modifiers
    import { ERC20 } from "@openzeppelin/contracts/token/ERC20/ERC20.sol";
    import { Base64 } from "solady/src/utils/Base64.sol";
    import { LibString } from "solady/src/utils/LibString.sol";
    
    
    contract Token is ERC20 {
    
    	address internal protocol;
    	bool internal locked = true;
    
    	address internal creator;
    	string internal descripiton;
    	bytes internal image;
    	string[] internal links;
    
    	constructor(address _creator, string memory name, string memory symbol, string memory _desc, bytes memory _image, string[] memory _links, uint256 _supply, address _protocol) ERC20(name, symbol) {
    		protocol = _protocol;
    		creator = _creator;
    		descripiton = _desc;
    		image = _image;
    		links = _links;
    		_mint(msg.sender, _supply);
    	}
    
    	function unlock() external {
    		require(msg.sender == protocol && locked == true);
    		locked = false;
    	}
    
    	function updateMetadata(
    		string calldata _desc,
    		bytes calldata _image,
    		string[] calldata _links
    	) external {
    		require(msg.sender == creator);
    
    		if (bytes(_desc).length > 0) {
    			descripiton = _desc;
    		}
    		if (_image.length > 0) {
    			image = _image;
    		}
    		if (_links.length != links.length) {
    			links = _links;
    		}
    	}
    
    	function tokenURI(
    		uint256 _unused
    	)
    		public
    		view
    		returns (string memory)
    	{
    		string memory linksString = '';
    		for (uint256 i = 0; i < links.length; i++) {
    			linksString = string.concat(linksString, '"', links[i], '"');
    			if (i < links.length - 1) {
    				linksString = string.concat(linksString, ",");
    			}
    		}
    
    		return string.concat("data:application/json;base64,",
    			Base64.encode(
    				bytes(
    					string.concat(
    						"{",
    						'"creator":"', LibString.toHexString(creator), '",',
    						'"name":"', name(), '",',
    						'"symbol":"', symbol(), '",',
    						'"supply":"', LibString.toString(totalSupply() / (10 ** 18)), '",',
    						'"description":"', descripiton, '",',
    						'"links":[',linksString,'],',
    						'"image_data":"data:image/webp;base64,', Base64.encode(image), '",',
    						'"background_color":"000000"',
    						"}"
    					)
    				)
    			)
    		);
    	}
    
    	function _beforeTokenTransfer(address from, address to, uint256 amount) internal override {
    		if (locked) {
    			require(from == protocol || to == protocol, "transfer not allowed before launch");
    		}
    	}
    
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    /// @notice Library to encode strings in Base64.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol)
    /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol)
    /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <brecht@loopring.org>.
    library Base64 {
        /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
        /// See: https://datatracker.ietf.org/doc/html/rfc4648
        /// @param fileSafe  Whether to replace '+' with '-' and '/' with '_'.
        /// @param noPadding Whether to strip away the padding.
        function encode(bytes memory data, bool fileSafe, bool noPadding)
            internal
            pure
            returns (string memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let dataLength := mload(data)
    
                if dataLength {
                    // Multiply by 4/3 rounded up.
                    // The `shl(2, ...)` is equivalent to multiplying by 4.
                    let encodedLength := shl(2, div(add(dataLength, 2), 3))
    
                    // Set `result` to point to the start of the free memory.
                    result := mload(0x40)
    
                    // Store the table into the scratch space.
                    // Offsetted by -1 byte so that the `mload` will load the character.
                    // We will rewrite the free memory pointer at `0x40` later with
                    // the allocated size.
                    // The magic constant 0x0670 will turn "-_" into "+/".
                    mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef")
                    mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670)))
    
                    // Skip the first slot, which stores the length.
                    let ptr := add(result, 0x20)
                    let end := add(ptr, encodedLength)
    
                    let dataEnd := add(add(0x20, data), dataLength)
                    let dataEndValue := mload(dataEnd) // Cache the value at the `dataEnd` slot.
                    mstore(dataEnd, 0x00) // Zeroize the `dataEnd` slot to clear dirty bits.
    
                    // Run over the input, 3 bytes at a time.
                    for {} 1 {} {
                        data := add(data, 3) // Advance 3 bytes.
                        let input := mload(data)
    
                        // Write 4 bytes. Optimized for fewer stack operations.
                        mstore8(0, mload(and(shr(18, input), 0x3F)))
                        mstore8(1, mload(and(shr(12, input), 0x3F)))
                        mstore8(2, mload(and(shr(6, input), 0x3F)))
                        mstore8(3, mload(and(input, 0x3F)))
                        mstore(ptr, mload(0x00))
    
                        ptr := add(ptr, 4) // Advance 4 bytes.
                        if iszero(lt(ptr, end)) { break }
                    }
                    mstore(dataEnd, dataEndValue) // Restore the cached value at `dataEnd`.
                    mstore(0x40, add(end, 0x20)) // Allocate the memory.
                    // Equivalent to `o = [0, 2, 1][dataLength % 3]`.
                    let o := div(2, mod(dataLength, 3))
                    // Offset `ptr` and pad with '='. We can simply write over the end.
                    mstore(sub(ptr, o), shl(240, 0x3d3d))
                    // Set `o` to zero if there is padding.
                    o := mul(iszero(iszero(noPadding)), o)
                    mstore(sub(ptr, o), 0) // Zeroize the slot after the string.
                    mstore(result, sub(encodedLength, o)) // Store the length.
                }
            }
        }
    
        /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
        /// Equivalent to `encode(data, false, false)`.
        function encode(bytes memory data) internal pure returns (string memory result) {
            result = encode(data, false, false);
        }
    
        /// @dev Encodes `data` using the base64 encoding described in RFC 4648.
        /// Equivalent to `encode(data, fileSafe, false)`.
        function encode(bytes memory data, bool fileSafe)
            internal
            pure
            returns (string memory result)
        {
            result = encode(data, fileSafe, false);
        }
    
        /// @dev Decodes base64 encoded `data`.
        ///
        /// Supports:
        /// - RFC 4648 (both standard and file-safe mode).
        /// - RFC 3501 (63: ',').
        ///
        /// Does not support:
        /// - Line breaks.
        ///
        /// Note: For performance reasons,
        /// this function will NOT revert on invalid `data` inputs.
        /// Outputs for invalid inputs will simply be undefined behaviour.
        /// It is the user's responsibility to ensure that the `data`
        /// is a valid base64 encoded string.
        function decode(string memory data) internal pure returns (bytes memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                let dataLength := mload(data)
    
                if dataLength {
                    let decodedLength := mul(shr(2, dataLength), 3)
    
                    for {} 1 {} {
                        // If padded.
                        if iszero(and(dataLength, 3)) {
                            let t := xor(mload(add(data, dataLength)), 0x3d3d)
                            // forgefmt: disable-next-item
                            decodedLength := sub(
                                decodedLength,
                                add(iszero(byte(30, t)), iszero(byte(31, t)))
                            )
                            break
                        }
                        // If non-padded.
                        decodedLength := add(decodedLength, sub(and(dataLength, 3), 1))
                        break
                    }
                    result := mload(0x40)
    
                    // Write the length of the bytes.
                    mstore(result, decodedLength)
    
                    // Skip the first slot, which stores the length.
                    let ptr := add(result, 0x20)
                    let end := add(ptr, decodedLength)
    
                    // Load the table into the scratch space.
                    // Constants are optimized for smaller bytecode with zero gas overhead.
                    // `m` also doubles as the mask of the upper 6 bits.
                    let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc
                    mstore(0x5b, m)
                    mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064)
                    mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4)
    
                    for {} 1 {} {
                        // Read 4 bytes.
                        data := add(data, 4)
                        let input := mload(data)
    
                        // Write 3 bytes.
                        // forgefmt: disable-next-item
                        mstore(ptr, or(
                            and(m, mload(byte(28, input))),
                            shr(6, or(
                                and(m, mload(byte(29, input))),
                                shr(6, or(
                                    and(m, mload(byte(30, input))),
                                    shr(6, mload(byte(31, input)))
                                ))
                            ))
                        ))
                        ptr := add(ptr, 3)
                        if iszero(lt(ptr, end)) { break }
                    }
                    mstore(0x40, add(end, 0x20)) // Allocate the memory.
                    mstore(end, 0) // Zeroize the slot after the bytes.
                    mstore(0x60, 0) // Restore the zero slot.
                }
            }
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    /// @notice Library for byte related operations.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
    library LibBytes {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          STRUCTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
        /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
        /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
        struct BytesStorage {
            bytes32 _spacer;
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         CONSTANTS                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev The constant returned when the `search` is not found in the bytes.
        uint256 internal constant NOT_FOUND = type(uint256).max;
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                  BYTE STORAGE OPERATIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Sets the value of the bytes storage `$` to `s`.
        function set(BytesStorage storage $, bytes memory s) internal {
            /// @solidity memory-safe-assembly
            assembly {
                let n := mload(s)
                let packed := or(0xff, shl(8, n))
                for { let i := 0 } 1 {} {
                    if iszero(gt(n, 0xfe)) {
                        i := 0x1f
                        packed := or(n, shl(8, mload(add(s, i))))
                        if iszero(gt(n, i)) { break }
                    }
                    let o := add(s, 0x20)
                    mstore(0x00, $.slot)
                    for { let p := keccak256(0x00, 0x20) } 1 {} {
                        sstore(add(p, shr(5, i)), mload(add(o, i)))
                        i := add(i, 0x20)
                        if iszero(lt(i, n)) { break }
                    }
                    break
                }
                sstore($.slot, packed)
            }
        }
    
        /// @dev Sets the value of the bytes storage `$` to `s`.
        function setCalldata(BytesStorage storage $, bytes calldata s) internal {
            /// @solidity memory-safe-assembly
            assembly {
                let packed := or(0xff, shl(8, s.length))
                for { let i := 0 } 1 {} {
                    if iszero(gt(s.length, 0xfe)) {
                        i := 0x1f
                        packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
                        if iszero(gt(s.length, i)) { break }
                    }
                    mstore(0x00, $.slot)
                    for { let p := keccak256(0x00, 0x20) } 1 {} {
                        sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
                        i := add(i, 0x20)
                        if iszero(lt(i, s.length)) { break }
                    }
                    break
                }
                sstore($.slot, packed)
            }
        }
    
        /// @dev Sets the value of the bytes storage `$` to the empty bytes.
        function clear(BytesStorage storage $) internal {
            delete $._spacer;
        }
    
        /// @dev Returns whether the value stored is `$` is the empty bytes "".
        function isEmpty(BytesStorage storage $) internal view returns (bool) {
            return uint256($._spacer) & 0xff == uint256(0);
        }
    
        /// @dev Returns the length of the value stored in `$`.
        function length(BytesStorage storage $) internal view returns (uint256 result) {
            result = uint256($._spacer);
            /// @solidity memory-safe-assembly
            assembly {
                let n := and(0xff, result)
                result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
            }
        }
    
        /// @dev Returns the value stored in `$`.
        function get(BytesStorage storage $) internal view returns (bytes memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let o := add(result, 0x20)
                let packed := sload($.slot)
                let n := shr(8, packed)
                for { let i := 0 } 1 {} {
                    if iszero(eq(and(packed, 0xff), 0xff)) {
                        mstore(o, packed)
                        n := and(0xff, packed)
                        i := 0x1f
                        if iszero(gt(n, i)) { break }
                    }
                    mstore(0x00, $.slot)
                    for { let p := keccak256(0x00, 0x20) } 1 {} {
                        mstore(add(o, i), sload(add(p, shr(5, i))))
                        i := add(i, 0x20)
                        if iszero(lt(i, n)) { break }
                    }
                    break
                }
                mstore(result, n) // Store the length of the memory.
                mstore(add(o, n), 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
            }
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                      BYTES OPERATIONS                      */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
        function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
            internal
            pure
            returns (bytes memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let needleLen := mload(needle)
                let replacementLen := mload(replacement)
                let d := sub(result, subject) // Memory difference.
                let i := add(subject, 0x20) // Subject bytes pointer.
                mstore(0x00, add(i, mload(subject))) // End of subject.
                if iszero(gt(needleLen, mload(subject))) {
                    let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
                    let h := 0 // The hash of `needle`.
                    if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
                    let s := mload(add(needle, 0x20))
                    for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
                        let t := mload(i)
                        // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
                        if iszero(shr(m, xor(t, s))) {
                            if h {
                                if iszero(eq(keccak256(i, needleLen), h)) {
                                    mstore(add(i, d), t)
                                    i := add(i, 1)
                                    if iszero(lt(i, subjectSearchEnd)) { break }
                                    continue
                                }
                            }
                            // Copy the `replacement` one word at a time.
                            for { let j := 0 } 1 {} {
                                mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
                                j := add(j, 0x20)
                                if iszero(lt(j, replacementLen)) { break }
                            }
                            d := sub(add(d, replacementLen), needleLen)
                            if needleLen {
                                i := add(i, needleLen)
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        mstore(add(i, d), t)
                        i := add(i, 1)
                        if iszero(lt(i, subjectSearchEnd)) { break }
                    }
                }
                let end := mload(0x00)
                let n := add(sub(d, add(result, 0x20)), end)
                // Copy the rest of the bytes one word at a time.
                for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
                let o := add(i, d)
                mstore(o, 0) // Zeroize the slot after the bytes.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from left to right, starting from `from`.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function indexOf(bytes memory subject, bytes memory needle, uint256 from)
            internal
            pure
            returns (uint256 result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result := not(0) // Initialize to `NOT_FOUND`.
                for { let subjectLen := mload(subject) } 1 {} {
                    if iszero(mload(needle)) {
                        result := from
                        if iszero(gt(from, subjectLen)) { break }
                        result := subjectLen
                        break
                    }
                    let needleLen := mload(needle)
                    let subjectStart := add(subject, 0x20)
    
                    subject := add(subjectStart, from)
                    let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
                    let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
                    let s := mload(add(needle, 0x20))
    
                    if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
    
                    if iszero(lt(needleLen, 0x20)) {
                        for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                            if iszero(shr(m, xor(mload(subject), s))) {
                                if eq(keccak256(subject, needleLen), h) {
                                    result := sub(subject, subjectStart)
                                    break
                                }
                            }
                            subject := add(subject, 1)
                            if iszero(lt(subject, end)) { break }
                        }
                        break
                    }
                    for {} 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            result := sub(subject, subjectStart)
                            break
                        }
                        subject := add(subject, 1)
                        if iszero(lt(subject, end)) { break }
                    }
                    break
                }
            }
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from left to right.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
            return indexOf(subject, needle, 0);
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from right to left, starting from `from`.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
            internal
            pure
            returns (uint256 result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                for {} 1 {} {
                    result := not(0) // Initialize to `NOT_FOUND`.
                    let needleLen := mload(needle)
                    if gt(needleLen, mload(subject)) { break }
                    let w := result
    
                    let fromMax := sub(mload(subject), needleLen)
                    if iszero(gt(fromMax, from)) { from := fromMax }
    
                    let end := add(add(subject, 0x20), w)
                    subject := add(add(subject, 0x20), from)
                    if iszero(gt(subject, end)) { break }
                    // As this function is not too often used,
                    // we shall simply use keccak256 for smaller bytecode size.
                    for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
                        if eq(keccak256(subject, needleLen), h) {
                            result := sub(subject, add(end, 1))
                            break
                        }
                        subject := add(subject, w) // `sub(subject, 1)`.
                        if iszero(gt(subject, end)) { break }
                    }
                    break
                }
            }
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from right to left.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function lastIndexOf(bytes memory subject, bytes memory needle)
            internal
            pure
            returns (uint256)
        {
            return lastIndexOf(subject, needle, type(uint256).max);
        }
    
        /// @dev Returns true if `needle` is found in `subject`, false otherwise.
        function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
            return indexOf(subject, needle) != NOT_FOUND;
        }
    
        /// @dev Returns whether `subject` starts with `needle`.
        function startsWith(bytes memory subject, bytes memory needle)
            internal
            pure
            returns (bool result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let n := mload(needle)
                // Just using keccak256 directly is actually cheaper.
                let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
                result := lt(gt(n, mload(subject)), t)
            }
        }
    
        /// @dev Returns whether `subject` ends with `needle`.
        function endsWith(bytes memory subject, bytes memory needle)
            internal
            pure
            returns (bool result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let n := mload(needle)
                let notInRange := gt(n, mload(subject))
                // `subject + 0x20 + max(subject.length - needle.length, 0)`.
                let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
                // Just using keccak256 directly is actually cheaper.
                result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
            }
        }
    
        /// @dev Returns `subject` repeated `times`.
        function repeat(bytes memory subject, uint256 times)
            internal
            pure
            returns (bytes memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let l := mload(subject) // Subject length.
                if iszero(or(iszero(times), iszero(l))) {
                    result := mload(0x40)
                    subject := add(subject, 0x20)
                    let o := add(result, 0x20)
                    for {} 1 {} {
                        // Copy the `subject` one word at a time.
                        for { let j := 0 } 1 {} {
                            mstore(add(o, j), mload(add(subject, j)))
                            j := add(j, 0x20)
                            if iszero(lt(j, l)) { break }
                        }
                        o := add(o, l)
                        times := sub(times, 1)
                        if iszero(times) { break }
                    }
                    mstore(o, 0) // Zeroize the slot after the bytes.
                    mstore(0x40, add(o, 0x20)) // Allocate memory.
                    mstore(result, sub(o, add(result, 0x20))) // Store the length.
                }
            }
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
        /// `start` and `end` are byte offsets.
        function slice(bytes memory subject, uint256 start, uint256 end)
            internal
            pure
            returns (bytes memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let l := mload(subject) // Subject length.
                if iszero(gt(l, end)) { end := l }
                if iszero(gt(l, start)) { start := l }
                if lt(start, end) {
                    result := mload(0x40)
                    let n := sub(end, start)
                    let i := add(subject, start)
                    let w := not(0x1f)
                    // Copy the `subject` one word at a time, backwards.
                    for { let j := and(add(n, 0x1f), w) } 1 {} {
                        mstore(add(result, j), mload(add(i, j)))
                        j := add(j, w) // `sub(j, 0x20)`.
                        if iszero(j) { break }
                    }
                    let o := add(add(result, 0x20), n)
                    mstore(o, 0) // Zeroize the slot after the bytes.
                    mstore(0x40, add(o, 0x20)) // Allocate memory.
                    mstore(result, n) // Store the length.
                }
            }
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
        /// `start` is a byte offset.
        function slice(bytes memory subject, uint256 start)
            internal
            pure
            returns (bytes memory result)
        {
            result = slice(subject, start, type(uint256).max);
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
        /// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
        function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
            internal
            pure
            returns (bytes calldata result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
                start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
                result.offset := add(subject.offset, start)
                result.length := mul(lt(start, end), sub(end, start))
            }
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
        /// `start` is a byte offset. Faster than Solidity's native slicing.
        function sliceCalldata(bytes calldata subject, uint256 start)
            internal
            pure
            returns (bytes calldata result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
                result.offset := add(subject.offset, start)
                result.length := mul(lt(start, subject.length), sub(subject.length, start))
            }
        }
    
        /// @dev Reduces the size of `subject` to `n`.
        /// If `n` is greater than the size of `subject`, this will be a no-op.
        function truncate(bytes memory subject, uint256 n)
            internal
            pure
            returns (bytes memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result := subject
                mstore(mul(lt(n, mload(result)), result), n)
            }
        }
    
        /// @dev Returns a copy of `subject`, with the length reduced to `n`.
        /// If `n` is greater than the size of `subject`, this will be a no-op.
        function truncatedCalldata(bytes calldata subject, uint256 n)
            internal
            pure
            returns (bytes calldata result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result.offset := subject.offset
                result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
            }
        }
    
        /// @dev Returns all the indices of `needle` in `subject`.
        /// The indices are byte offsets.
        function indicesOf(bytes memory subject, bytes memory needle)
            internal
            pure
            returns (uint256[] memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let searchLen := mload(needle)
                if iszero(gt(searchLen, mload(subject))) {
                    result := mload(0x40)
                    let i := add(subject, 0x20)
                    let o := add(result, 0x20)
                    let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
                    let h := 0 // The hash of `needle`.
                    if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
                    let s := mload(add(needle, 0x20))
                    for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
                        let t := mload(i)
                        // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
                        if iszero(shr(m, xor(t, s))) {
                            if h {
                                if iszero(eq(keccak256(i, searchLen), h)) {
                                    i := add(i, 1)
                                    if iszero(lt(i, subjectSearchEnd)) { break }
                                    continue
                                }
                            }
                            mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
                            o := add(o, 0x20)
                            i := add(i, searchLen) // Advance `i` by `searchLen`.
                            if searchLen {
                                if iszero(lt(i, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        i := add(i, 1)
                        if iszero(lt(i, subjectSearchEnd)) { break }
                    }
                    mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
                    // Allocate memory for result.
                    // We allocate one more word, so this array can be recycled for {split}.
                    mstore(0x40, add(o, 0x20))
                }
            }
        }
    
        /// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes.
        function split(bytes memory subject, bytes memory delimiter)
            internal
            pure
            returns (bytes[] memory result)
        {
            uint256[] memory indices = indicesOf(subject, delimiter);
            /// @solidity memory-safe-assembly
            assembly {
                let w := not(0x1f)
                let indexPtr := add(indices, 0x20)
                let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
                mstore(add(indicesEnd, w), mload(subject))
                mstore(indices, add(mload(indices), 1))
                for { let prevIndex := 0 } 1 {} {
                    let index := mload(indexPtr)
                    mstore(indexPtr, 0x60)
                    if iszero(eq(index, prevIndex)) {
                        let element := mload(0x40)
                        let l := sub(index, prevIndex)
                        mstore(element, l) // Store the length of the element.
                        // Copy the `subject` one word at a time, backwards.
                        for { let o := and(add(l, 0x1f), w) } 1 {} {
                            mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                            o := add(o, w) // `sub(o, 0x20)`.
                            if iszero(o) { break }
                        }
                        mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
                        // Allocate memory for the length and the bytes, rounded up to a multiple of 32.
                        mstore(0x40, add(element, and(add(l, 0x3f), w)))
                        mstore(indexPtr, element) // Store the `element` into the array.
                    }
                    prevIndex := add(index, mload(delimiter))
                    indexPtr := add(indexPtr, 0x20)
                    if iszero(lt(indexPtr, indicesEnd)) { break }
                }
                result := indices
                if iszero(mload(delimiter)) {
                    result := add(indices, 0x20)
                    mstore(result, sub(mload(indices), 2))
                }
            }
        }
    
        /// @dev Returns a concatenated bytes of `a` and `b`.
        /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
        function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let w := not(0x1f)
                let aLen := mload(a)
                // Copy `a` one word at a time, backwards.
                for { let o := and(add(aLen, 0x20), w) } 1 {} {
                    mstore(add(result, o), mload(add(a, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                let bLen := mload(b)
                let output := add(result, aLen)
                // Copy `b` one word at a time, backwards.
                for { let o := and(add(bLen, 0x20), w) } 1 {} {
                    mstore(add(output, o), mload(add(b, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                let totalLen := add(aLen, bLen)
                let last := add(add(result, 0x20), totalLen)
                mstore(last, 0) // Zeroize the slot after the bytes.
                mstore(result, totalLen) // Store the length.
                mstore(0x40, add(last, 0x20)) // Allocate memory.
            }
        }
    
        /// @dev Returns whether `a` equals `b`.
        function eq(bytes memory a, bytes memory b) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
            }
        }
    
        /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes.
        function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                // These should be evaluated on compile time, as far as possible.
                let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
                let x := not(or(m, or(b, add(m, and(b, m)))))
                let r := shl(7, iszero(iszero(shr(128, x))))
                r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
                r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                r := or(r, shl(4, lt(0xffff, shr(r, x))))
                r := or(r, shl(3, lt(0xff, shr(r, x))))
                // forgefmt: disable-next-item
                result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                    xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
            }
        }
    
        /// @dev Directly returns `a` without copying.
        function directReturn(bytes memory a) internal pure {
            assembly {
                // Assumes that the bytes does not start from the scratch space.
                let retStart := sub(a, 0x20)
                let retUnpaddedSize := add(mload(a), 0x40)
                // Right pad with zeroes. Just in case the bytes is produced
                // by a method that doesn't zero right pad.
                mstore(add(retStart, retUnpaddedSize), 0)
                mstore(retStart, 0x20) // Store the return offset.
                // End the transaction, returning the bytes.
                return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
            }
        }
    
        /// @dev Directly returns `a` with minimal copying.
        function directReturn(bytes[] memory a) internal pure {
            assembly {
                let n := mload(a) // `a.length`.
                let o := add(a, 0x20) // Start of elements in `a`.
                let u := a // Highest memory slot.
                let w := not(0x1f)
                for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
                    let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
                    let s := mload(c) // `a[i]`.
                    let l := mload(s) // `a[i].length`.
                    let r := and(l, 0x1f) // `a[i].length % 32`.
                    let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
                    // If `s` comes before `o`, or `s` is not zero right padded.
                    if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
                        let m := mload(0x40)
                        mstore(m, l) // Copy `a[i].length`.
                        for {} 1 {} {
                            mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
                            z := add(z, w) // `sub(z, 0x20)`.
                            if iszero(z) { break }
                        }
                        let e := add(add(m, 0x20), l)
                        mstore(e, 0) // Zeroize the slot after the copied bytes.
                        mstore(0x40, add(e, 0x20)) // Allocate memory.
                        s := m
                    }
                    mstore(c, sub(s, o)) // Convert to calldata offset.
                    let t := add(l, add(s, 0x20))
                    if iszero(lt(t, u)) { u := t }
                }
                let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
                mstore(retStart, 0x20) // Store the return offset.
                return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
            }
        }
    
        /// @dev Returns the word at `offset`, without any bounds checks.
        /// To load an address, you can use `address(bytes20(load(a, offset)))`.
        function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(add(add(a, 0x20), offset))
            }
        }
    
        /// @dev Returns the word at `offset`, without any bounds checks.
        /// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`.
        function loadCalldata(bytes calldata a, uint256 offset)
            internal
            pure
            returns (bytes32 result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result := calldataload(add(a.offset, offset))
            }
        }
    
        /// @dev Returns empty calldata bytes. For silencing the compiler.
        function emptyCalldata() internal pure returns (bytes calldata result) {
            /// @solidity memory-safe-assembly
            assembly {
                result.length := 0
            }
        }
    }

    // SPDX-License-Identifier: MIT
    pragma solidity ^0.8.4;
    
    import {LibBytes} from "./LibBytes.sol";
    
    /// @notice Library for converting numbers into strings and other string operations.
    /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol)
    /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol)
    ///
    /// @dev Note:
    /// For performance and bytecode compactness, most of the string operations are restricted to
    /// byte strings (7-bit ASCII), except where otherwise specified.
    /// Usage of byte string operations on charsets with runes spanning two or more bytes
    /// can lead to undefined behavior.
    library LibString {
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                          STRUCTS                           */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Goated string storage struct that totally MOGs, no cap, fr.
        /// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
        /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
        struct StringStorage {
            bytes32 _spacer;
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                        CUSTOM ERRORS                       */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev The length of the output is too small to contain all the hex digits.
        error HexLengthInsufficient();
    
        /// @dev The length of the string is more than 32 bytes.
        error TooBigForSmallString();
    
        /// @dev The input string must be a 7-bit ASCII.
        error StringNot7BitASCII();
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                         CONSTANTS                          */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev The constant returned when the `search` is not found in the string.
        uint256 internal constant NOT_FOUND = type(uint256).max;
    
        /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
        uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
    
        /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
        uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
    
        /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
        uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
    
        /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
        uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
    
        /// @dev Lookup for '0123456789'.
        uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
    
        /// @dev Lookup for '0123456789abcdefABCDEF'.
        uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
    
        /// @dev Lookup for '01234567'.
        uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
    
        /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
        uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
    
        /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
        uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
    
        /// @dev Lookup for ' \t\n\r\x0b\x0c'.
        uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                 STRING STORAGE OPERATIONS                  */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Sets the value of the string storage `$` to `s`.
        function set(StringStorage storage $, string memory s) internal {
            LibBytes.set(bytesStorage($), bytes(s));
        }
    
        /// @dev Sets the value of the string storage `$` to `s`.
        function setCalldata(StringStorage storage $, string calldata s) internal {
            LibBytes.setCalldata(bytesStorage($), bytes(s));
        }
    
        /// @dev Sets the value of the string storage `$` to the empty string.
        function clear(StringStorage storage $) internal {
            delete $._spacer;
        }
    
        /// @dev Returns whether the value stored is `$` is the empty string "".
        function isEmpty(StringStorage storage $) internal view returns (bool) {
            return uint256($._spacer) & 0xff == uint256(0);
        }
    
        /// @dev Returns the length of the value stored in `$`.
        function length(StringStorage storage $) internal view returns (uint256) {
            return LibBytes.length(bytesStorage($));
        }
    
        /// @dev Returns the value stored in `$`.
        function get(StringStorage storage $) internal view returns (string memory) {
            return string(LibBytes.get(bytesStorage($)));
        }
    
        /// @dev Helper to cast `$` to a `BytesStorage`.
        function bytesStorage(StringStorage storage $)
            internal
            pure
            returns (LibBytes.BytesStorage storage casted)
        {
            /// @solidity memory-safe-assembly
            assembly {
                casted.slot := $.slot
            }
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                     DECIMAL OPERATIONS                     */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Returns the base 10 decimal representation of `value`.
        function toString(uint256 value) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            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.
                result := add(mload(0x40), 0x80)
                mstore(0x40, add(result, 0x20)) // Allocate memory.
                mstore(result, 0) // Zeroize the slot after the string.
    
                let end := result // Cache the end of the memory to calculate the length later.
                let w := not(0) // Tsk.
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                for { let temp := value } 1 {} {
                    result := add(result, w) // `sub(result, 1)`.
                    // Store the character to the pointer.
                    // The ASCII index of the '0' character is 48.
                    mstore8(result, add(48, mod(temp, 10)))
                    temp := div(temp, 10) // Keep dividing `temp` until zero.
                    if iszero(temp) { break }
                }
                let n := sub(end, result)
                result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the base 10 decimal representation of `value`.
        function toString(int256 value) internal pure returns (string memory result) {
            if (value >= 0) return toString(uint256(value));
            unchecked {
                result = toString(~uint256(value) + 1);
            }
            /// @solidity memory-safe-assembly
            assembly {
                // We still have some spare memory space on the left,
                // as we have allocated 3 words (96 bytes) for up to 78 digits.
                let n := mload(result) // Load the string length.
                mstore(result, 0x2d) // Store the '-' character.
                result := sub(result, 1) // Move back the string pointer by a byte.
                mstore(result, add(n, 1)) // Update the string length.
            }
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                   HEXADECIMAL OPERATIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Returns the hexadecimal representation of `value`,
        /// left-padded to an input length of `byteCount` bytes.
        /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
        /// giving a total length of `byteCount * 2 + 2` bytes.
        /// Reverts if `byteCount` is too small for the output to contain all the digits.
        function toHexString(uint256 value, uint256 byteCount)
            internal
            pure
            returns (string memory result)
        {
            result = toHexStringNoPrefix(value, byteCount);
            /// @solidity memory-safe-assembly
            assembly {
                let n := add(mload(result), 2) // Compute the length.
                mstore(result, 0x3078) // Store the "0x" prefix.
                result := sub(result, 2) // Move the pointer.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`,
        /// left-padded to an input length of `byteCount` bytes.
        /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
        /// giving a total length of `byteCount * 2` bytes.
        /// Reverts if `byteCount` is too small for the output to contain all the digits.
        function toHexStringNoPrefix(uint256 value, uint256 byteCount)
            internal
            pure
            returns (string memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes
                // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
                // We add 0x20 to the total and round down to a multiple of 0x20.
                // (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
                result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
                mstore(0x40, add(result, 0x20)) // Allocate memory.
                mstore(result, 0) // Zeroize the slot after the string.
    
                let end := result // Cache the end to calculate the length later.
                // Store "0123456789abcdef" in scratch space.
                mstore(0x0f, 0x30313233343536373839616263646566)
    
                let start := sub(result, add(byteCount, byteCount))
                let w := not(1) // Tsk.
                let temp := value
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                for {} 1 {} {
                    result := add(result, w) // `sub(result, 2)`.
                    mstore8(add(result, 1), mload(and(temp, 15)))
                    mstore8(result, mload(and(shr(4, temp), 15)))
                    temp := shr(8, temp)
                    if iszero(xor(result, start)) { break }
                }
                if temp {
                    mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                    revert(0x1c, 0x04)
                }
                let n := sub(end, result)
                result := sub(result, 0x20)
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
        /// As address are 20 bytes long, the output will left-padded to have
        /// a length of `20 * 2 + 2` bytes.
        function toHexString(uint256 value) internal pure returns (string memory result) {
            result = toHexStringNoPrefix(value);
            /// @solidity memory-safe-assembly
            assembly {
                let n := add(mload(result), 2) // Compute the length.
                mstore(result, 0x3078) // Store the "0x" prefix.
                result := sub(result, 2) // Move the pointer.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is prefixed with "0x".
        /// The output excludes leading "0" from the `toHexString` output.
        /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
        function toMinimalHexString(uint256 value) internal pure returns (string memory result) {
            result = toHexStringNoPrefix(value);
            /// @solidity memory-safe-assembly
            assembly {
                let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
                let n := add(mload(result), 2) // Compute the length.
                mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
                result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
                mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output excludes leading "0" from the `toHexStringNoPrefix` output.
        /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
        function toMinimalHexStringNoPrefix(uint256 value)
            internal
            pure
            returns (string memory result)
        {
            result = toHexStringNoPrefix(value);
            /// @solidity memory-safe-assembly
            assembly {
                let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
                let n := mload(result) // Get the length.
                result := add(result, o) // Move the pointer, accounting for leading zero.
                mstore(result, sub(n, o)) // Store the length, accounting for leading zero.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is encoded using 2 hexadecimal digits per byte.
        /// As address are 20 bytes long, the output will left-padded to have
        /// a length of `20 * 2` bytes.
        function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
                // 0x02 bytes for the prefix, and 0x40 bytes for the digits.
                // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
                result := add(mload(0x40), 0x80)
                mstore(0x40, add(result, 0x20)) // Allocate memory.
                mstore(result, 0) // Zeroize the slot after the string.
    
                let end := result // Cache the end to calculate the length later.
                mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
    
                let w := not(1) // Tsk.
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                for { let temp := value } 1 {} {
                    result := add(result, w) // `sub(result, 2)`.
                    mstore8(add(result, 1), mload(and(temp, 15)))
                    mstore8(result, mload(and(shr(4, temp), 15)))
                    temp := shr(8, temp)
                    if iszero(temp) { break }
                }
                let n := sub(end, result)
                result := sub(result, 0x20)
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
        /// and the alphabets are capitalized conditionally according to
        /// https://eips.ethereum.org/EIPS/eip-55
        function toHexStringChecksummed(address value) internal pure returns (string memory result) {
            result = toHexString(value);
            /// @solidity memory-safe-assembly
            assembly {
                let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
                let o := add(result, 0x22)
                let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
                let t := shl(240, 136) // `0b10001000 << 240`
                for { let i := 0 } 1 {} {
                    mstore(add(i, i), mul(t, byte(i, hashed)))
                    i := add(i, 1)
                    if eq(i, 20) { break }
                }
                mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
                o := add(o, 0x20)
                mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
        function toHexString(address value) internal pure returns (string memory result) {
            result = toHexStringNoPrefix(value);
            /// @solidity memory-safe-assembly
            assembly {
                let n := add(mload(result), 2) // Compute the length.
                mstore(result, 0x3078) // Store the "0x" prefix.
                result := sub(result, 2) // Move the pointer.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hexadecimal representation of `value`.
        /// The output is encoded using 2 hexadecimal digits per byte.
        function toHexStringNoPrefix(address value) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                // Allocate memory.
                // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
                // 0x02 bytes for the prefix, and 0x28 bytes for the digits.
                // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
                mstore(0x40, add(result, 0x80))
                mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
    
                result := add(result, 2)
                mstore(result, 40) // Store the length.
                let o := add(result, 0x20)
                mstore(add(o, 40), 0) // Zeroize the slot after the string.
                value := shl(96, value)
                // We write the string from rightmost digit to leftmost digit.
                // The following is essentially a do-while loop that also handles the zero case.
                for { let i := 0 } 1 {} {
                    let p := add(o, add(i, i))
                    let temp := byte(i, value)
                    mstore8(add(p, 1), mload(and(temp, 15)))
                    mstore8(p, mload(shr(4, temp)))
                    i := add(i, 1)
                    if eq(i, 20) { break }
                }
            }
        }
    
        /// @dev Returns the hex encoded string from the raw bytes.
        /// The output is encoded using 2 hexadecimal digits per byte.
        function toHexString(bytes memory raw) internal pure returns (string memory result) {
            result = toHexStringNoPrefix(raw);
            /// @solidity memory-safe-assembly
            assembly {
                let n := add(mload(result), 2) // Compute the length.
                mstore(result, 0x3078) // Store the "0x" prefix.
                result := sub(result, 2) // Move the pointer.
                mstore(result, n) // Store the length.
            }
        }
    
        /// @dev Returns the hex encoded string from the raw bytes.
        /// The output is encoded using 2 hexadecimal digits per byte.
        function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                let n := mload(raw)
                result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
                mstore(result, add(n, n)) // Store the length of the output.
    
                mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
                let o := add(result, 0x20)
                let end := add(raw, n)
                for {} iszero(eq(raw, end)) {} {
                    raw := add(raw, 1)
                    mstore8(add(o, 1), mload(and(mload(raw), 15)))
                    mstore8(o, mload(and(shr(4, mload(raw)), 15)))
                    o := add(o, 2)
                }
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
            }
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                   RUNE STRING OPERATIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        /// @dev Returns the number of UTF characters in the string.
        function runeCount(string memory s) internal pure returns (uint256 result) {
            /// @solidity memory-safe-assembly
            assembly {
                if mload(s) {
                    mstore(0x00, div(not(0), 255))
                    mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
                    let o := add(s, 0x20)
                    let end := add(o, mload(s))
                    for { result := 1 } 1 { result := add(result, 1) } {
                        o := add(o, byte(0, mload(shr(250, mload(o)))))
                        if iszero(lt(o, end)) { break }
                    }
                }
            }
        }
    
        /// @dev Returns if this string is a 7-bit ASCII string.
        /// (i.e. all characters codes are in [0..127])
        function is7BitASCII(string memory s) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := 1
                let mask := shl(7, div(not(0), 255))
                let n := mload(s)
                if n {
                    let o := add(s, 0x20)
                    let end := add(o, n)
                    let last := mload(end)
                    mstore(end, 0)
                    for {} 1 {} {
                        if and(mask, mload(o)) {
                            result := 0
                            break
                        }
                        o := add(o, 0x20)
                        if iszero(lt(o, end)) { break }
                    }
                    mstore(end, last)
                }
            }
        }
    
        /// @dev Returns if this string is a 7-bit ASCII string,
        /// AND all characters are in the `allowed` lookup.
        /// Note: If `s` is empty, returns true regardless of `allowed`.
        function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := 1
                if mload(s) {
                    let allowed_ := shr(128, shl(128, allowed))
                    let o := add(s, 0x20)
                    for { let end := add(o, mload(s)) } 1 {} {
                        result := and(result, shr(byte(0, mload(o)), allowed_))
                        o := add(o, 1)
                        if iszero(and(result, lt(o, end))) { break }
                    }
                }
            }
        }
    
        /// @dev Converts the bytes in the 7-bit ASCII string `s` to
        /// an allowed lookup for use in `is7BitASCII(s, allowed)`.
        /// To save runtime gas, you can cache the result in an immutable variable.
        function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
            /// @solidity memory-safe-assembly
            assembly {
                if mload(s) {
                    let o := add(s, 0x20)
                    for { let end := add(o, mload(s)) } 1 {} {
                        result := or(result, shl(byte(0, mload(o)), 1))
                        o := add(o, 1)
                        if iszero(lt(o, end)) { break }
                    }
                    if shr(128, result) {
                        mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
                        revert(0x1c, 0x04)
                    }
                }
            }
        }
    
        /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
        /*                   BYTE STRING OPERATIONS                   */
        /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
    
        // For performance and bytecode compactness, byte string operations are restricted
        // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
        // Usage of byte string operations on charsets with runes spanning two or more bytes
        // can lead to undefined behavior.
    
        /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
        function replace(string memory subject, string memory needle, string memory replacement)
            internal
            pure
            returns (string memory)
        {
            return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from left to right, starting from `from`.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function indexOf(string memory subject, string memory needle, uint256 from)
            internal
            pure
            returns (uint256)
        {
            return LibBytes.indexOf(bytes(subject), bytes(needle), from);
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from left to right.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
            return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from right to left, starting from `from`.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function lastIndexOf(string memory subject, string memory needle, uint256 from)
            internal
            pure
            returns (uint256)
        {
            return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
        }
    
        /// @dev Returns the byte index of the first location of `needle` in `subject`,
        /// needleing from right to left.
        /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
        function lastIndexOf(string memory subject, string memory needle)
            internal
            pure
            returns (uint256)
        {
            return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
        }
    
        /// @dev Returns true if `needle` is found in `subject`, false otherwise.
        function contains(string memory subject, string memory needle) internal pure returns (bool) {
            return LibBytes.contains(bytes(subject), bytes(needle));
        }
    
        /// @dev Returns whether `subject` starts with `needle`.
        function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
            return LibBytes.startsWith(bytes(subject), bytes(needle));
        }
    
        /// @dev Returns whether `subject` ends with `needle`.
        function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
            return LibBytes.endsWith(bytes(subject), bytes(needle));
        }
    
        /// @dev Returns `subject` repeated `times`.
        function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
            return string(LibBytes.repeat(bytes(subject), times));
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
        /// `start` and `end` are byte offsets.
        function slice(string memory subject, uint256 start, uint256 end)
            internal
            pure
            returns (string memory)
        {
            return string(LibBytes.slice(bytes(subject), start, end));
        }
    
        /// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
        /// `start` is a byte offset.
        function slice(string memory subject, uint256 start) internal pure returns (string memory) {
            return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
        }
    
        /// @dev Returns all the indices of `needle` in `subject`.
        /// The indices are byte offsets.
        function indicesOf(string memory subject, string memory needle)
            internal
            pure
            returns (uint256[] memory)
        {
            return LibBytes.indicesOf(bytes(subject), bytes(needle));
        }
    
        /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
        function split(string memory subject, string memory delimiter)
            internal
            pure
            returns (string[] memory result)
        {
            bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
            /// @solidity memory-safe-assembly
            assembly {
                result := a
            }
        }
    
        /// @dev Returns a concatenated string of `a` and `b`.
        /// Cheaper than `string.concat()` and does not de-align the free memory pointer.
        function concat(string memory a, string memory b) internal pure returns (string memory) {
            return string(LibBytes.concat(bytes(a), bytes(b)));
        }
    
        /// @dev Returns a copy of the string in either lowercase or UPPERCASE.
        /// WARNING! This function is only compatible with 7-bit ASCII strings.
        function toCase(string memory subject, bool toUpper)
            internal
            pure
            returns (string memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                let n := mload(subject)
                if n {
                    result := mload(0x40)
                    let o := add(result, 0x20)
                    let d := sub(subject, result)
                    let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                    for { let end := add(o, n) } 1 {} {
                        let b := byte(0, mload(add(d, o)))
                        mstore8(o, xor(and(shr(b, flags), 0x20), b))
                        o := add(o, 1)
                        if eq(o, end) { break }
                    }
                    mstore(result, n) // Store the length.
                    mstore(o, 0) // Zeroize the slot after the string.
                    mstore(0x40, add(o, 0x20)) // Allocate memory.
                }
            }
        }
    
        /// @dev Returns a string from a small bytes32 string.
        /// `s` must be null-terminated, or behavior will be undefined.
        function fromSmallString(bytes32 s) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let n := 0
                for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
                mstore(result, n) // Store the length.
                let o := add(result, 0x20)
                mstore(o, s) // Store the bytes of the string.
                mstore(add(o, n), 0) // Zeroize the slot after the string.
                mstore(0x40, add(result, 0x40)) // Allocate memory.
            }
        }
    
        /// @dev Returns the small string, with all bytes after the first null byte zeroized.
        function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
                mstore(0x00, s)
                mstore(result, 0x00)
                result := mload(0x00)
            }
        }
    
        /// @dev Returns the string as a normalized null-terminated small string.
        function toSmallString(string memory s) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(s)
                if iszero(lt(result, 33)) {
                    mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
                    revert(0x1c, 0x04)
                }
                result := shl(shl(3, sub(32, result)), mload(add(s, result)))
            }
        }
    
        /// @dev Returns a lowercased copy of the string.
        /// WARNING! This function is only compatible with 7-bit ASCII strings.
        function lower(string memory subject) internal pure returns (string memory result) {
            result = toCase(subject, false);
        }
    
        /// @dev Returns an UPPERCASED copy of the string.
        /// WARNING! This function is only compatible with 7-bit ASCII strings.
        function upper(string memory subject) internal pure returns (string memory result) {
            result = toCase(subject, true);
        }
    
        /// @dev Escapes the string to be used within HTML tags.
        function escapeHTML(string memory s) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let end := add(s, mload(s))
                let o := add(result, 0x20)
                // Store the bytes of the packed offsets and strides into the scratch space.
                // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
                mstore(0x1f, 0x900094)
                mstore(0x08, 0xc0000000a6ab)
                // Store "&quot;&amp;&#39;&lt;&gt;" into the scratch space.
                mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
                for {} iszero(eq(s, end)) {} {
                    s := add(s, 1)
                    let c := and(mload(s), 0xff)
                    // Not in `["\"","'","&","<",">"]`.
                    if iszero(and(shl(c, 1), 0x500000c400000000)) {
                        mstore8(o, c)
                        o := add(o, 1)
                        continue
                    }
                    let t := shr(248, mload(c))
                    mstore(o, mload(and(t, 0x1f)))
                    o := add(o, shr(5, t))
                }
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
            }
        }
    
        /// @dev Escapes the string to be used within double-quotes in a JSON.
        /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
        function escapeJSON(string memory s, bool addDoubleQuotes)
            internal
            pure
            returns (string memory result)
        {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                let o := add(result, 0x20)
                if addDoubleQuotes {
                    mstore8(o, 34)
                    o := add(1, o)
                }
                // Store "\\u0000" in scratch space.
                // Store "0123456789abcdef" in scratch space.
                // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
                // into the scratch space.
                mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
                // Bitmask for detecting `["\"","\\"]`.
                let e := or(shl(0x22, 1), shl(0x5c, 1))
                for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
                    s := add(s, 1)
                    let c := and(mload(s), 0xff)
                    if iszero(lt(c, 0x20)) {
                        if iszero(and(shl(c, 1), e)) {
                            // Not in `["\"","\\"]`.
                            mstore8(o, c)
                            o := add(o, 1)
                            continue
                        }
                        mstore8(o, 0x5c) // "\\".
                        mstore8(add(o, 1), c)
                        o := add(o, 2)
                        continue
                    }
                    if iszero(and(shl(c, 1), 0x3700)) {
                        // Not in `["\b","\t","\n","\f","\d"]`.
                        mstore8(0x1d, mload(shr(4, c))) // Hex value.
                        mstore8(0x1e, mload(and(c, 15))) // Hex value.
                        mstore(o, mload(0x19)) // "\\u00XX".
                        o := add(o, 6)
                        continue
                    }
                    mstore8(o, 0x5c) // "\\".
                    mstore8(add(o, 1), mload(add(c, 8)))
                    o := add(o, 2)
                }
                if addDoubleQuotes {
                    mstore8(o, 34)
                    o := add(1, o)
                }
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
            }
        }
    
        /// @dev Escapes the string to be used within double-quotes in a JSON.
        function escapeJSON(string memory s) internal pure returns (string memory result) {
            result = escapeJSON(s, false);
        }
    
        /// @dev Encodes `s` so that it can be safely used in a URI,
        /// just like `encodeURIComponent` in JavaScript.
        /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
        /// See: https://datatracker.ietf.org/doc/html/rfc2396
        /// See: https://datatracker.ietf.org/doc/html/rfc3986
        function encodeURIComponent(string memory s) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                // Store "0123456789ABCDEF" in scratch space.
                // Uppercased to be consistent with JavaScript's implementation.
                mstore(0x0f, 0x30313233343536373839414243444546)
                let o := add(result, 0x20)
                for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
                    s := add(s, 1)
                    let c := and(mload(s), 0xff)
                    // If not in `[0-9A-Z-a-z-_.!~*'()]`.
                    if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
                        mstore8(o, 0x25) // '%'.
                        mstore8(add(o, 1), mload(and(shr(4, c), 15)))
                        mstore8(add(o, 2), mload(and(c, 15)))
                        o := add(o, 3)
                        continue
                    }
                    mstore8(o, c)
                    o := add(o, 1)
                }
                mstore(result, sub(o, add(result, 0x20))) // Store the length.
                mstore(o, 0) // Zeroize the slot after the string.
                mstore(0x40, add(o, 0x20)) // Allocate memory.
            }
        }
    
        /// @dev Returns whether `a` equals `b`.
        function eq(string memory a, string memory b) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
            }
        }
    
        /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
        function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
            /// @solidity memory-safe-assembly
            assembly {
                // These should be evaluated on compile time, as far as possible.
                let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
                let x := not(or(m, or(b, add(m, and(b, m)))))
                let r := shl(7, iszero(iszero(shr(128, x))))
                r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
                r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
                r := or(r, shl(4, lt(0xffff, shr(r, x))))
                r := or(r, shl(3, lt(0xff, shr(r, x))))
                // forgefmt: disable-next-item
                result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
                    xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
            }
        }
    
        /// @dev Packs a single string with its length into a single word.
        /// Returns `bytes32(0)` if the length is zero or greater than 31.
        function packOne(string memory a) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                // We don't need to zero right pad the string,
                // since this is our own custom non-standard packing scheme.
                result :=
                    mul(
                        // Load the length and the bytes.
                        mload(add(a, 0x1f)),
                        // `length != 0 && length < 32`. Abuses underflow.
                        // Assumes that the length is valid and within the block gas limit.
                        lt(sub(mload(a), 1), 0x1f)
                    )
            }
        }
    
        /// @dev Unpacks a string packed using {packOne}.
        /// Returns the empty string if `packed` is `bytes32(0)`.
        /// If `packed` is not an output of {packOne}, the output behavior is undefined.
        function unpackOne(bytes32 packed) internal pure returns (string memory result) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40) // Grab the free memory pointer.
                mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
                mstore(result, 0) // Zeroize the length slot.
                mstore(add(result, 0x1f), packed) // Store the length and bytes.
                mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
            }
        }
    
        /// @dev Packs two strings with their lengths into a single word.
        /// Returns `bytes32(0)` if combined length is zero or greater than 30.
        function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
            /// @solidity memory-safe-assembly
            assembly {
                let aLen := mload(a)
                // We don't need to zero right pad the strings,
                // since this is our own custom non-standard packing scheme.
                result :=
                    mul(
                        or( // Load the length and the bytes of `a` and `b`.
                        shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
                        // `totalLen != 0 && totalLen < 31`. Abuses underflow.
                        // Assumes that the lengths are valid and within the block gas limit.
                        lt(sub(add(aLen, mload(b)), 1), 0x1e)
                    )
            }
        }
    
        /// @dev Unpacks strings packed using {packTwo}.
        /// Returns the empty strings if `packed` is `bytes32(0)`.
        /// If `packed` is not an output of {packTwo}, the output behavior is undefined.
        function unpackTwo(bytes32 packed)
            internal
            pure
            returns (string memory resultA, string memory resultB)
        {
            /// @solidity memory-safe-assembly
            assembly {
                resultA := mload(0x40) // Grab the free memory pointer.
                resultB := add(resultA, 0x40)
                // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
                mstore(0x40, add(resultB, 0x40))
                // Zeroize the length slots.
                mstore(resultA, 0)
                mstore(resultB, 0)
                // Store the lengths and bytes.
                mstore(add(resultA, 0x1f), packed)
                mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
                // Right pad with zeroes.
                mstore(add(add(resultA, 0x20), mload(resultA)), 0)
                mstore(add(add(resultB, 0x20), mload(resultB)), 0)
            }
        }
    
        /// @dev Directly returns `a` without copying.
        function directReturn(string memory a) internal pure {
            assembly {
                // Assumes that the string does not start from the scratch space.
                let retStart := sub(a, 0x20)
                let retUnpaddedSize := add(mload(a), 0x40)
                // Right pad with zeroes. Just in case the string is produced
                // by a method that doesn't zero right pad.
                mstore(add(retStart, retUnpaddedSize), 0)
                mstore(retStart, 0x20) // Store the return offset.
                // End the transaction, returning the string.
                return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
            }
        }
    }

    Please enter a contract address above to load the contract details and source code.

    Context size (optional):