ETH Price: $3,109.38 (-0.98%)

Token

Astro Staking Vaults (ASV)
 

Overview

Max Total Supply

1,038 ASV

Holders

1,038

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
kidice.eth
Balance
1 ASV
0xc975893ce4d5f17cb83707249ba5de0891b516fa
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
StakingVaultManager

Compiler Version
v0.8.25+commit.b61c2a91

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion, MIT license
File 1 of 8 : StakingVaultManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {VaultManager, ERC721} from "../vault/VaultManager.sol";

/// @notice Staking vault manager class.
contract StakingVaultManager is VaultManager {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CUSTOM ERRORS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev The value is locked.
    error Locked();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Address of the vault's proxy.
    address public vaultProxy;

    /// @dev Whether the vault's proxy is locked.
    bool public vaultProxyLocked;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        CONSTRUCTOR                         */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    constructor() {
        _initializeVaultManager(
            msg.sender == 0x0000000000FFe8B47B3e2130213B802212439497 ? tx.origin : msg.sender
        );
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      VAULT OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Override to return the vault proxy for use in `_createVault`.
    function _vaultProxy() internal view virtual override(VaultManager) returns (address) {
        return vaultProxy;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      ADMIN OPERATIONS                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Locks the vault proxy.
    function lockVaultProxy() public virtual onlyOwner {
        vaultProxyLocked = true;
    }

    /// @dev Sets the vault proxy.
    function setVaultProxy(address proxy) public virtual onlyOwner {
        if (vaultProxyLocked) revert Locked();
        vaultProxy = proxy;
    }
}

File 2 of 8 : VaultManager.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {ERC721} from "solady/tokens/ERC721.sol";
import {Ownable, OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {LibERC6551} from "solady/accounts/LibERC6551.sol";
import {LibString} from "solady/utils/LibString.sol";
import {ReentrancyGuard} from "soledge/utils/ReentrancyGuard.sol";

/// @notice ERC6551 vault manager class.
abstract contract VaultManager is ERC721, OwnableRoles, ReentrancyGuard {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                         CONSTANTS                          */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Address of the Asterix base ERC20.
    address public constant ASTERIX = 0x0000000000ca73A6df4C58b84C5B4b847FE8Ff39;

    /// @dev Address of the Asterix mirror ERC721.
    address public constant ASTERIX_MIRROR = 0x0000000000c26FAbFe894D13233d5ec73F61cc72;

    /// @dev The role flag for a metadata setter.
    uint256 public constant METADATA_SETTER_ROLE = _ROLE_31;

    /// @dev The scalar of ETH and most ERC20s.
    uint256 internal constant _WAD = 10 ** 18;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CUSTOM ERRORS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev An account can only have one vault at a time.
    error OnlyOneVaultPerAccount();

    /// @dev The vault owner has not enabled it for a single transfer.
    error SingleTransferNotEnabled();

    /// @dev Cannot double initialize the vault manager.
    error VaultManagerAlreadyInitialized();

    /// @dev A vault has not been created yet for the caller.
    error VaultHasNotBeenCreated();

    /// @dev The vault proxy is the zero address.
    error VaultProxyIsZeroAddress();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                           EVENTS                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Emitted when a vault is created.
    event VaultCreated(address indexed owner, uint256 indexed tokenId, address indexed vault);

    /// @dev The vault has been enabled / disabled for transfer.
    event SingleTransferEnabledSet(uint256 indexed tokenId, bool enabled);

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev For ERC721 tokenURI.
    address internal _tokenURIRenderer;

    /// @dev ERC721 name.
    string internal _name;

    /// @dev ERC721 symbol.
    string internal _symbol;

    /// @dev For ERC721 tokenURI.
    string internal _baseURI;

    /// @dev The current number of vaults in existence.
    /// The token IDs of vaults are auto-incremented, starting from 1.
    uint64 public totalVaults;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                        INITIALIZER                         */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev This MUST be called in the subclass' constructor.
    function _initializeVaultManager(address deployer) internal virtual {
        _initializeOwner(deployer);
        _grantRoles(deployer, METADATA_SETTER_ROLE);
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          METADATA                          */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev ERC721 name.
    function name() public view override(ERC721) returns (string memory) {
        return _name;
    }

    /// @dev ERC721 symbol.
    function symbol() public view override(ERC721) returns (string memory) {
        return _symbol;
    }

    /// @dev ERC721 tokenURI.
    /// Note: This function directly returns the string via assembly.
    function tokenURI(uint256 id) public view override(ERC721) returns (string memory result) {
        if (!_exists(id)) revert TokenDoesNotExist();

        address renderer = _tokenURIRenderer;
        // If `renderer` is non-zero, use it instead of `_baseURI`.
        if (renderer != address(0)) {
            /// @solidity memory-safe-assembly
            assembly {
                result := mload(0x40)
                mstore(0x00, 0xc87b56dd) // `tokenURI(uint256)`.
                mstore(0x20, id)
                if iszero(staticcall(gas(), renderer, 0x1c, 0x24, 0x00, 0x00)) {
                    returndatacopy(result, 0x00, returndatasize())
                    revert(result, returndatasize())
                }
                returndatacopy(0x00, 0x00, 0x20) // Copy the offset of the string in returndata.
                returndatacopy(result, mload(0x00), 0x20) // Copy the length of the string.
                returndatacopy(add(result, 0x20), add(mload(0x00), 0x20), mload(result)) // Copy the string.
                let end := add(add(result, 0x20), mload(result))
                mstore(end, 0) // Zeroize the word after the string.
                mstore(0x40, add(end, 0x20)) // Allocate memory.
            }
        } else if (bytes(_baseURI).length != 0) {
            result = LibString.replace(_baseURI, "{id}", LibString.toString(id));
        }
    }

    /// @dev For ERC721 trackers.
    function totalSupply() public view virtual returns (uint256) {
        return totalVaults;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                 METADATA SETTER FUNCTIONS                  */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Sets the base URI for the ERC721 token URI.
    function setBaseURI(string calldata uri) public onlyOwnerOrRoles(METADATA_SETTER_ROLE) {
        _baseURI = uri;
    }

    /// @dev Sets the token URI renderer contract.
    function setTokenURIRenderer(address renderer) public onlyOwnerOrRoles(METADATA_SETTER_ROLE) {
        _tokenURIRenderer = renderer;
    }

    /// @dev Sets the ERC721 name and symbol.
    function setNameAndSymbol(string calldata name_, string calldata symbol_)
        public
        onlyOwnerOrRoles(METADATA_SETTER_ROLE)
    {
        _name = name_;
        _symbol = symbol_;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CONFIGURABLES                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Hook to override, which is called after any Asterix deposit.
    /// This is used to check if there's an over withdrawal of Asterix tokens,
    /// for used in vesting.
    function _afterDepositAsterixFor(address owner) internal virtual {}

    /// @dev Hook to override, which is called after any Asterix withdraw.
    /// This is used to check if there's an over withdrawal of Asterix tokens,
    /// for used in vesting.
    function _afterWithdrawAsterix() internal virtual {}

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  ASTERIX VAULT OPERATIONS                  */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Creates a vault for `holder`.
    function createVaultFor(address holder) public virtual nonReentrant returns (address vault) {
        vault = _createVault(holder);
    }

    /// @dev Allows the caller to create a vault.
    function createVault() public virtual returns (address vault) {
        vault = createVaultFor(msg.sender);
    }

    /// @dev Deposits `amount` of the caller's Asterix ERC20 tokens into the vault of `holder`.
    /// A vault will be lazily created for `holder` if it does not exists.
    function depositAsterixERC20For(address holder, uint256 amount)
        public
        virtual
        nonReentrant
        returns (address vault)
    {
        vault = _createVault(holder);
        _depositBaseERC20ToVault(vault, ASTERIX, msg.sender, amount);
        _afterDepositAsterixFor(holder);
    }

    /// @dev Deposits `amount` of the caller's Asterix ERC20 tokens into the caller's vault.
    /// A vault will be lazily created for `holder` if it does not exists.
    function depositAsterixERC20(uint256 amount) public virtual returns (address vault) {
        vault = depositAsterixERC20For(msg.sender, amount);
    }

    /// @dev Deposits `tokenIds` of the caller's Asterix ERC721 tokens into the vault of `holder`.
    /// A vault will be lazily created for `holder` if it does not exists.
    function depositAsterixMirrorERC721For(address holder, uint256[] calldata tokenIds)
        public
        virtual
        nonReentrant
        returns (address vault)
    {
        vault = _createVault(holder);
        for (uint256 i; i < tokenIds.length; ++i) {
            _depositMirrorERC721ToVault(vault, ASTERIX_MIRROR, msg.sender, _get(tokenIds, i));
        }
        _afterDepositAsterixFor(holder);
    }

    /// @dev Deposits `tokenIds` of the caller's Asterix ERC721 tokens into the caller's vault.
    /// A vault will be lazily created for the caller if it does not exists.
    function depositAsterixMirrorERC721(uint256[] calldata tokenIds)
        public
        virtual
        returns (address vault)
    {
        vault = depositAsterixMirrorERC721For(msg.sender, tokenIds);
    }

    /// @dev Withdraws `amount` Asterix ERC20 tokens from the caller's vault to `to`.
    function withdrawAsterixERC20To(address to, uint256 amount)
        public
        virtual
        nonReentrant
        returns (address vault)
    {
        vault = vaultOf(msg.sender); // Must use `msg.sender`.
        if (vault == address(0)) revert VaultHasNotBeenCreated();
        _withdrawBaseERC20FromVault(vault, ASTERIX, to, amount);
        _afterWithdrawAsterix();
    }

    /// @dev Withdraws `amount` Asterix ERC20 tokens from the caller's vault to the caller.
    function withdrawAsterixERC20(uint256 amount) public virtual returns (address vault) {
        vault = withdrawAsterixERC20To(msg.sender, amount);
    }

    /// @dev Withdraws `tokenIds` Asterix ERC721 tokens from the caller's vault to `to`.
    function withdrawAsterixMirrorERC721To(address to, uint256[] calldata tokenIds)
        public
        virtual
        nonReentrant
        returns (address vault)
    {
        vault = vaultOf(msg.sender); // Must use `msg.sender`.
        if (vault == address(0)) revert VaultHasNotBeenCreated();
        for (uint256 i; i < tokenIds.length; ++i) {
            _withdrawMirrorERC721FromVault(vault, ASTERIX_MIRROR, to, _get(tokenIds, i));
        }
        _afterWithdrawAsterix();
    }

    /// @dev Withdraws `tokenIds` Asterix ERC721 tokens from the caller's vault to the caller.
    function withdrawAsterixMirrorERC721(uint256[] calldata tokenIds)
        public
        virtual
        returns (address vault)
    {
        vault = withdrawAsterixMirrorERC721To(msg.sender, tokenIds);
    }

    /// @dev Returns the maximum amount of Asterix ERC20 that can be withdrawn
    /// by the `holder` without burning any ERC721s in their vault.
    /// If the `holder` does not have a vault, the returned value is zero.
    function maxAsterixERC20WithdrawableWithoutBurningERC721s(address holder)
        public
        view
        virtual
        returns (uint256)
    {
        address vault = vaultOf(holder);
        if (vault == address(0)) return 0;
        unchecked {
            return _balanceOf(ASTERIX, vault) - _balanceOf(ASTERIX_MIRROR, vault) * _WAD;
        }
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                  GENERAL VAULT OPERATIONS                  */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Override to return a valid vault proxy address.
    function _vaultProxy() internal view virtual returns (address) {}

    /// @dev Creates a vault for the `owner`.
    /// If a vault has already been created, returns the current vault held by the `owner`.
    function _createVault(address owner) internal virtual returns (address vault) {
        vault = address(uint160(_getAux(owner)));
        if (vault != address(0)) return vault;
        unchecked {
            address proxy = _vaultProxy();
            if (proxy == address(0)) revert VaultProxyIsZeroAddress();
            uint256 tokenId = ++totalVaults; // Overflow of uint64 is impractical.
            _mintAndSetExtraDataUnchecked(owner, tokenId, 0);
            // This calls `createAccount` on the canonical ERC6551 registry,
            // which deploys a ERC6551 minimal bytecode proxy with
            // `implementation`, `salt`, `chainId`, `tokenContract` baked into the bytecode.
            vault = LibERC6551.createAccount(
                proxy, // `implementation`, which is a proxy. So we have a proxy to a proxy.
                bytes32(0), // `salt`. Always zero, for simplicity.
                block.chainid, // `chainId`.
                address(this), // `tokenContract`.
                tokenId // `tokenId`.
            );
            emit VaultCreated(owner, tokenId, vault);
            // Use Solady's ERC721 data hitchhiking functions to store the vault's address.
            _setAux(owner, uint160(vault));
        }
    }

    /// @dev Calls `setSkipNFT(bool)` on `baseERC20` for the `vault`.
    /// This function assumes `vault` has been created, and is a valid vault.
    function _setSkipNFT(address vault, address baseERC20, bool status) internal virtual {
        // `setSkipNFT(bool)`.
        _execute(vault, baseERC20, 0x2a6a935d, _toUint(status), 0, 0);
    }

    /// @dev Transfers `amount` of `baseERC20` from `from` to the `vault`.
    /// Requires that at least `amount` of `baseERC20` has been approved by `from`
    /// to be managed by this contract.
    /// This function assumes that `baseERC20` exists, and is a valid ERC20.
    /// This function assumes `vault` has been created, and is a valid vault.
    function _depositBaseERC20ToVault(
        address vault,
        address baseERC20,
        address from,
        uint256 amount
    ) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, amount) // Store the `amount` argument.
            mstore(0x40, vault) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(call(gas(), baseERC20, 0, 0x1c, 0x64, 0x00, 0x20)) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Transfers `amount` of `baseERC20` from the `vault` to `to`.
    /// This function assumes `vault` has been created, and is a valid vault.
    ///
    /// Note: If the vault has 1 or more NFT tokens, we should revert if
    /// withdrawing will lead to the burning of any NFT token.
    function _withdrawBaseERC20FromVault(
        address vault,
        address baseERC20,
        address to,
        uint256 amount
    ) internal virtual {
        // `transfer(address,uint256)`.
        _execute(vault, baseERC20, 0xa9059cbb, uint160(to), uint160(amount), 0);
    }

    /// @dev Transfers `tokenId` of `mirrorERC721` from `from` to the `vault`.
    /// Requires that either `tokenId` has been approved by `from` to be managed
    /// by this contract, or this contract has been approved as an operator for `from`.
    /// This function assumes that `mirrorERC721` exists, and is a valid ERC721.
    /// This function assumes `vault` has been created, and is a valid vault.
    function _depositMirrorERC721ToVault(
        address vault,
        address mirrorERC721,
        address from,
        uint256 tokenId
    ) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            mstore(0x60, tokenId) // Store the `tokenId` argument.
            mstore(0x40, vault) // Store the `to` argument.
            mstore(0x2c, shl(96, from)) // Store the `from` argument.
            mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`.
            // Perform the transfer, reverting upon failure.
            if iszero(call(gas(), mirrorERC721, 0, 0x1c, 0x64, 0x00, 0x20)) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
            mstore(0x60, 0) // Restore the zero slot to zero.
            mstore(0x40, m) // Restore the free memory pointer.
        }
    }

    /// @dev Transfers `tokenId` of `mirrorERC721` from the `vault` to `to`.
    /// This function assumes `vault` has been created, and is a valid vault.
    function _withdrawMirrorERC721FromVault(
        address vault,
        address mirrorERC721,
        address to,
        uint256 tokenId
    ) internal virtual {
        // `transferFrom(address,address,uint256)`.
        _execute(vault, mirrorERC721, 0x23b872dd, uint160(vault), uint160(to), tokenId);
    }

    /// @dev Helper function to call `execute` on the `vault`.
    /// This function assumes `vault` has been created, and is a valid vault.
    function _execute(
        address vault,
        address target,
        uint256 fnSelector,
        uint256 arg0,
        uint256 arg1,
        uint256 arg2
    ) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x14), target)
            mstore(m, 0x51945447000000000000000000000000) // `execute(address,uint256,bytes,uint8)`.
            mstore(add(m, 0x34), 0) // `value`.
            mstore(add(m, 0x54), 0x80) // Offset of `data`.
            mstore(add(m, 0x74), 0) // `operation`.
            mstore(add(m, 0x98), fnSelector)
            mstore(add(m, 0xb8), arg0)
            mstore(add(m, 0xd8), arg1)
            mstore(add(m, 0xf8), arg2)
            mstore(add(m, 0x94), 0x64) // `data.length`.
            if iszero(call(gas(), vault, 0, add(m, 0x10), 0x124, codesize(), 0x00)) {
                returndatacopy(m, 0x00, returndatasize())
                revert(m, returndatasize())
            }
        }
    }

    /// @dev Returns the amount of ERC20 or ERC721 `token` owned by `account`.
    /// Returns zero if the `token` does not exist.
    function _balanceOf(address token, address account) internal view returns (uint256 amount) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x14, account) // Store the `account` argument.
            mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`.
            amount :=
                mul( // The arguments of `mul` are evaluated from right to left.
                    mload(0x20),
                    and( // The arguments of `and` are evaluated from right to left.
                        gt(returndatasize(), 0x1f), // At least 32 bytes returned.
                        staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20)
                    )
                )
        }
    }

    /// @dev Returns the vault of the `owner`.
    /// Returns the zero address if owner does not have a vault.
    function vaultOf(address owner) public view virtual returns (address) {
        return address(uint160(_getAux(owner)));
    }

    /// @dev Returns the owner of the `vault`.
    /// Returns the zero address if the vault is not a valid vault.
    function vaultOwner(address vault) public view virtual returns (address result) {
        // The `tokenId` is from the ERC6551's proxy bytecode.
        uint256 tokenId = LibERC6551.tokenId(vault);
        address possibleOwner = _ownerOf(tokenId);
        // We must always validate against the vault's address stored in this contract.
        if (vaultOf(possibleOwner) == vault) result = possibleOwner;
    }

    /// @dev Returns the token ID of the `vault.
    /// Returns zero if the vault is not a valid vault.
    function vaultTokenId(address vault) public view virtual returns (uint256 result) {
        // The `tokenId` is from the ERC6551's proxy bytecode.
        uint256 tokenId = LibERC6551.tokenId(vault);
        address possibleOwner = _ownerOf(tokenId);
        // We must always validate against the vault's address stored in this contract.
        if (vaultOf(possibleOwner) == vault) result = tokenId;
    }

    /// @dev Returns the vault at `tokenId`.
    /// Returns the zero address if the vault has not been created.
    function vaultAt(uint256 tokenId) public view virtual returns (address) {
        return address(uint160(_getAux(_ownerOf(tokenId))));
    }

    /// @dev Returns if the `tokenId` has been enabled for a single transfer.
    function singleTransferEnabled(uint256 tokenId) public view virtual returns (bool) {
        return _getExtraData(tokenId) != 0;
    }

    /// @dev Enable a single transfer for the caller's vault.
    function setSingleTransferEnabled(bool enabled) public virtual nonReentrant {
        address vault = vaultOf(msg.sender);
        if (vault == address(0)) revert VaultHasNotBeenCreated();
        // `vault` is from this contract's storage,
        // so it's safe to get the `tokenId` from its immutable ERC6551 bytecode.
        uint256 tokenId = LibERC6551.tokenId(vault);
        // Use Solady's ERC721 data hitchhiking to store the enabled flag.
        _setExtraData(tokenId, uint96(_toUint(enabled)));
        emit SingleTransferEnabledSet(tokenId, enabled);
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                         OVERRIDES                          */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Hook override to ensure that an account can at most hold
    /// one vault at any time.
    ///
    /// Note: This override does not support burning logic.
    function _beforeTokenTransfer(address from, address to, uint256 tokenId)
        internal
        virtual
        override(ERC721)
    {
        if (_getAux(to) != 0) revert OnlyOneVaultPerAccount();
        if (from != address(0)) {
            if (_getExtraData(tokenId) == 0) revert SingleTransferNotEnabled();
            _setExtraData(tokenId, 0); // Reset the single token transfer to zero.
            _setAux(to, _getAux(from)); // Set `to.vault` to `from.vault`.
            _setAux(from, 0); // Set `from.vault` to `address(0)`.
        }
    }

    /// @dev Use the ownable to prevent double initialization.
    function _guardInitializeOwner() internal pure virtual override(Ownable) returns (bool) {
        return true;
    }

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                 INTERNAL / PRIVATE HELPERS                 */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Returns `b ? 1 : 0`.
    function _toUint(bool b) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := iszero(iszero(b))
        }
    }

    /// @dev Returns `max(0, x - y)`.
    function _zeroFloorSub(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := mul(gt(x, y), sub(x, y))
        }
    }

    /// @dev Returns `y == 0 ? 0 : x / y`.
    function _rawDiv(uint256 x, uint256 y) internal pure returns (uint256 z) {
        /// @solidity memory-safe-assembly
        assembly {
            z := div(x, y)
        }
    }

    /// @dev Returns `a[i]`, without bounds checks.
    function _get(uint256[] calldata a, uint256 i) internal pure returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := calldataload(add(a.offset, shl(5, i)))
        }
    }
}

File 3 of 8 : ERC721.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple ERC721 implementation with storage hitchhiking.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol)
/// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol)
///
/// @dev Note:
/// - The ERC721 standard allows for self-approvals.
///   For performance, this implementation WILL NOT revert for such actions.
///   Please add any checks with overrides if desired.
/// - For performance, methods are made payable where permitted by the ERC721 standard.
/// - The `safeTransfer` functions use the identity precompile (0x4)
///   to copy memory internally.
///
/// If you are overriding:
/// - NEVER violate the ERC721 invariant:
///   the balance of an owner MUST always be equal to their number of ownership slots.
///   The transfer functions do not have an underflow guard for user token balances.
/// - Make sure all variables written to storage are properly cleaned
//    (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood).
/// - Check that the overridden function is actually used in the function you want to
///   change the behavior of. Much of the code has been manually inlined for performance.
abstract contract ERC721 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev An account can hold up to 4294967295 tokens.
    uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Only the token owner or an approved account can manage the token.
    error NotOwnerNorApproved();

    /// @dev The token does not exist.
    error TokenDoesNotExist();

    /// @dev The token already exists.
    error TokenAlreadyExists();

    /// @dev Cannot query the balance for the zero address.
    error BalanceQueryForZeroAddress();

    /// @dev Cannot mint or transfer to the zero address.
    error TransferToZeroAddress();

    /// @dev The token must be owned by `from`.
    error TransferFromIncorrectOwner();

    /// @dev The recipient's balance has overflowed.
    error AccountBalanceOverflow();

    /// @dev Cannot safely transfer to a contract that does not implement
    /// the ERC721Receiver interface.
    error TransferToNonERC721ReceiverImplementer();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Emitted when token `id` is transferred from `from` to `to`.
    event Transfer(address indexed from, address indexed to, uint256 indexed id);

    /// @dev Emitted when `owner` enables `account` to manage the `id` token.
    event Approval(address indexed owner, address indexed account, uint256 indexed id);

    /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
    event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);

    /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
    uint256 private constant _TRANSFER_EVENT_SIGNATURE =
        0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;

    /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
    uint256 private constant _APPROVAL_EVENT_SIGNATURE =
        0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;

    /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
    uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
        0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership data slot of `id` is given by:
    /// ```
    ///     mstore(0x00, id)
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
    /// ```
    /// Bits Layout:
    /// - [0..159]   `addr`
    /// - [160..255] `extraData`
    ///
    /// The approved address slot is given by: `add(1, ownershipSlot)`.
    ///
    /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip
    ///
    /// The balance slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
    ///     mstore(0x00, owner)
    ///     let balanceSlot := keccak256(0x0c, 0x1c)
    /// ```
    /// Bits Layout:
    /// - [0..31]   `balance`
    /// - [32..255] `aux`
    ///
    /// The `operator` approval slot of `owner` is given by:
    /// ```
    ///     mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
    ///     mstore(0x00, owner)
    ///     let operatorApprovalSlot := keccak256(0x0c, 0x30)
    /// ```
    uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;

    /// @dev Pre-shifted and pre-masked constant.
    uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      ERC721 METADATA                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the token collection name.
    function name() public view virtual returns (string memory);

    /// @dev Returns the token collection symbol.
    function symbol() public view virtual returns (string memory);

    /// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
    function tokenURI(uint256 id) public view virtual returns (string memory);

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           ERC721                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function ownerOf(uint256 id) public view virtual returns (address result) {
        result = _ownerOf(id);
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(result) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns the number of tokens owned by `owner`.
    ///
    /// Requirements:
    /// - `owner` must not be the zero address.
    function balanceOf(address owner) public view virtual returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            // Revert if the `owner` is the zero address.
            if iszero(owner) {
                mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`.
                revert(0x1c, 0x04)
            }
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function getApproved(uint256 id) public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            if iszero(shl(96, sload(ownershipSlot))) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            result := sload(add(1, ownershipSlot))
        }
    }

    /// @dev Sets `account` as the approved account to manage token `id`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - The caller must be the owner of the token,
    ///   or an approved operator for the token owner.
    ///
    /// Emits an {Approval} event.
    function approve(address account, uint256 id) public payable virtual {
        _approve(msg.sender, account, id);
    }

    /// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
    function isApprovedForAll(address owner, address operator)
        public
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, owner)
            result := sload(keccak256(0x0c, 0x30))
        }
    }

    /// @dev Sets whether `operator` is approved to manage the tokens of the caller.
    ///
    /// Emits an {ApprovalForAll} event.
    function setApprovalForAll(address operator, bool isApproved) public virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`msg.sender`, `operator`).
            mstore(0x1c, operator)
            mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            // forgefmt: disable-next-item
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
        }
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function transferFrom(address from, address to, uint256 id) public payable virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if the token does not exist, or if `from` is not the owner.
            if iszero(mul(owner, eq(owner, from))) {
                // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
                mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // Revert if the caller is not the owner, nor approved.
                if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
    function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
        public
        payable
        virtual
    {
        transferFrom(from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Returns true if this contract implements the interface defined by `interfaceId`.
    /// See: https://eips.ethereum.org/EIPS/eip-165
    /// This function call must use less than 30000 gas.
    function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            let s := shr(224, interfaceId)
            // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
            result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL QUERY FUNCTIONS                  */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns if token `id` exists.
    function _exists(uint256 id) internal view virtual returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))))
        }
    }

    /// @dev Returns the owner of token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _ownerOf(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*            INTERNAL DATA HITCHHIKING FUNCTIONS             */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // For performance, no events are emitted for the hitchhiking setters.
    // Please emit your own events if required.

    /// @dev Returns the auxiliary data for `owner`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _getAux(address owner) internal view virtual returns (uint224 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            result := shr(32, sload(keccak256(0x0c, 0x1c)))
        }
    }

    /// @dev Set the auxiliary data for `owner` to `value`.
    /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
    /// Auxiliary data can be set for any address, even if it does not have any tokens.
    function _setAux(address owner, uint224 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            mstore(0x00, owner)
            let balanceSlot := keccak256(0x0c, 0x1c)
            let packed := sload(balanceSlot)
            sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
        }
    }

    /// @dev Returns the extra data for token `id`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Sets the extra data for token `id` to `value`.
    /// Minting, transferring, burning a token will not change the extra data.
    /// The extra data can be set on a non-existent token.
    function _setExtraData(uint256 id, uint96 value) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let packed := sload(ownershipSlot)
            sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL MINT FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mint(address to, uint256 id) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Revert if the token already exists.
            if shl(96, ownershipPacked) {
                mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`.
                revert(0x1c, 0x04)
            }
            // Update with the owner.
            sstore(ownershipSlot, or(ownershipPacked, to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`.
    /// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing).
    ///
    /// Requirements:
    ///
    /// - `to` cannot be the zero address.
    ///
    /// Emits a {Transfer} event.
    function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual {
        _beforeTokenTransfer(address(0), to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            to := shr(96, shl(96, to))
            // Update with the owner and extra data.
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to))
            // Increment the balance of the owner.
            {
                mstore(0x00, to)
                let balanceSlot := keccak256(0x0c, 0x1c)
                let balanceSlotPacked := add(sload(balanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(balanceSlot, balanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
        }
        _afterTokenTransfer(address(0), to, id);
    }

    /// @dev Equivalent to `_safeMint(to, id, "")`.
    function _safeMint(address to, uint256 id) internal virtual {
        _safeMint(to, id, "");
    }

    /// @dev Mints token `id` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must not exist.
    /// - `to` cannot be the zero address.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
        _mint(to, id);
        if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  INTERNAL BURN FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `_burn(address(0), id)`.
    function _burn(uint256 id) internal virtual {
        _burn(address(0), id);
    }

    /// @dev Destroys token `id`, using `by`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _burn(address by, uint256 id) internal virtual {
        address owner = ownerOf(id);
        _beforeTokenTransfer(owner, address(0), id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            // Reload the owner in case it is changed in `_beforeTokenTransfer`.
            owner := shr(96, shl(96, ownershipPacked))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Load and check the token approval.
            {
                mstore(0x00, owner)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Clear the owner.
            sstore(ownershipSlot, xor(ownershipPacked, owner))
            // Decrement the balance of `owner`.
            {
                let balanceSlot := keccak256(0x0c, 0x1c)
                sstore(balanceSlot, sub(sload(balanceSlot), 1))
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
        }
        _afterTokenTransfer(owner, address(0), id);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL APPROVAL FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    function _isApprovedOrOwner(address account, uint256 id)
        internal
        view
        virtual
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            result := 1
            // Clear the upper 96 bits.
            account := shr(96, shl(96, account))
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := shr(96, shl(96, sload(ownershipSlot)))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // Check if `account` is the `owner`.
            if iszero(eq(account, owner)) {
                mstore(0x00, owner)
                // Check if `account` is approved to manage the token.
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    result := eq(account, sload(add(1, ownershipSlot)))
                }
            }
        }
    }

    /// @dev Returns the account approved to manage token `id`.
    /// Returns the zero address instead of reverting if the token does not exist.
    function _getApproved(uint256 id) internal view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x00, id)
            mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
            result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
        }
    }

    /// @dev Equivalent to `_approve(address(0), account, id)`.
    function _approve(address account, uint256 id) internal virtual {
        _approve(address(0), account, id);
    }

    /// @dev Sets `account` as the approved account to manage token `id`, using `by`.
    ///
    /// Requirements:
    /// - Token `id` must exist.
    /// - If `by` is not the zero address, `by` must be the owner
    ///   or an approved operator for the token owner.
    ///
    /// Emits a {Approval} event.
    function _approve(address by, address account, uint256 id) internal virtual {
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            account := and(bitmaskAddress, account)
            by := and(bitmaskAddress, by)
            // Load the owner of the token.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let owner := and(bitmaskAddress, sload(ownershipSlot))
            // Revert if the token does not exist.
            if iszero(owner) {
                mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
                revert(0x1c, 0x04)
            }
            // If `by` is not the zero address, do the authorization check.
            // Revert if `by` is not the owner, nor approved.
            if iszero(or(iszero(by), eq(by, owner))) {
                mstore(0x00, owner)
                if iszero(sload(keccak256(0x0c, 0x30))) {
                    mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                    revert(0x1c, 0x04)
                }
            }
            // Sets `account` as the approved account to manage `id`.
            sstore(add(1, ownershipSlot), account)
            // Emit the {Approval} event.
            log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
        }
    }

    /// @dev Approve or remove the `operator` as an operator for `by`,
    /// without authorization checks.
    ///
    /// Emits an {ApprovalForAll} event.
    function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            by := shr(96, shl(96, by))
            operator := shr(96, shl(96, operator))
            // Convert to 0 or 1.
            isApproved := iszero(iszero(isApproved))
            // Update the `isApproved` for (`by`, `operator`).
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
            mstore(0x00, by)
            sstore(keccak256(0x0c, 0x30), isApproved)
            // Emit the {ApprovalForAll} event.
            mstore(0x00, isApproved)
            log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                INTERNAL TRANSFER FUNCTIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Equivalent to `_transfer(address(0), from, to, id)`.
    function _transfer(address from, address to, uint256 id) internal virtual {
        _transfer(address(0), from, to, id);
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    ///
    /// Emits a {Transfer} event.
    function _transfer(address by, address from, address to, uint256 id) internal virtual {
        _beforeTokenTransfer(from, to, id);
        /// @solidity memory-safe-assembly
        assembly {
            // Clear the upper 96 bits.
            let bitmaskAddress := shr(96, not(0))
            from := and(bitmaskAddress, from)
            to := and(bitmaskAddress, to)
            by := and(bitmaskAddress, by)
            // Load the ownership data.
            mstore(0x00, id)
            mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
            let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
            let ownershipPacked := sload(ownershipSlot)
            let owner := and(bitmaskAddress, ownershipPacked)
            // Revert if the token does not exist, or if `from` is not the owner.
            if iszero(mul(owner, eq(owner, from))) {
                // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
                mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
                revert(0x1c, 0x04)
            }
            // Load, check, and update the token approval.
            {
                mstore(0x00, from)
                let approvedAddress := sload(add(1, ownershipSlot))
                // If `by` is not the zero address, do the authorization check.
                // Revert if the `by` is not the owner, nor approved.
                if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) {
                    if iszero(sload(keccak256(0x0c, 0x30))) {
                        mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
                        revert(0x1c, 0x04)
                    }
                }
                // Delete the approved address if any.
                if approvedAddress { sstore(add(1, ownershipSlot), 0) }
            }
            // Update with the new owner.
            sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
            // Decrement the balance of `from`.
            {
                let fromBalanceSlot := keccak256(0x0c, 0x1c)
                sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
            }
            // Increment the balance of `to`.
            {
                mstore(0x00, to)
                let toBalanceSlot := keccak256(0x0c, 0x1c)
                let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
                // Revert if `to` is the zero address, or if the account balance overflows.
                if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
                    // `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
                    mstore(shl(2, iszero(to)), 0xea553b3401336cea)
                    revert(0x1c, 0x04)
                }
                sstore(toBalanceSlot, toBalanceSlotPacked)
            }
            // Emit the {Transfer} event.
            log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
        }
        _afterTokenTransfer(from, to, id);
    }

    /// @dev Equivalent to `_safeTransfer(from, to, id, "")`.
    function _safeTransfer(address from, address to, uint256 id) internal virtual {
        _safeTransfer(from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - The caller must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeTransfer(address from, address to, uint256 id, bytes memory data)
        internal
        virtual
    {
        _transfer(address(0), from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`.
    function _safeTransfer(address by, address from, address to, uint256 id) internal virtual {
        _safeTransfer(by, from, to, id, "");
    }

    /// @dev Transfers token `id` from `from` to `to`.
    ///
    /// Requirements:
    ///
    /// - Token `id` must exist.
    /// - `from` must be the owner of the token.
    /// - `to` cannot be the zero address.
    /// - If `by` is not the zero address,
    ///   it must be the owner of the token, or be approved to manage the token.
    /// - If `to` refers to a smart contract, it must implement
    ///   {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
    ///
    /// Emits a {Transfer} event.
    function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data)
        internal
        virtual
    {
        _transfer(by, from, to, id);
        if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                    HOOKS FOR OVERRIDING                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Hook that is called before any token transfers, including minting and burning.
    function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {}

    /// @dev Hook that is called after any token transfers, including minting and burning.
    function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {}

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                      PRIVATE HELPERS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns if `a` has bytecode of non-zero length.
    function _hasCode(address a) private view returns (bool result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := extcodesize(a) // Can handle dirty upper bits.
        }
    }

    /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
    /// Reverts if the target does not support the function correctly.
    function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
        private
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Prepare the calldata.
            let m := mload(0x40)
            let onERC721ReceivedSelector := 0x150b7a02
            mstore(m, onERC721ReceivedSelector)
            mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
            mstore(add(m, 0x40), shr(96, shl(96, from)))
            mstore(add(m, 0x60), id)
            mstore(add(m, 0x80), 0x80)
            let n := mload(data)
            mstore(add(m, 0xa0), n)
            if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
            // Revert if the call reverts.
            if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
                if returndatasize() {
                    // Bubble up the revert if the call reverts.
                    returndatacopy(m, 0x00, returndatasize())
                    revert(m, returndatasize())
                }
            }
            // Load the returndata and compare it.
            if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
                mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
                revert(0x1c, 0x04)
            }
        }
    }
}

File 4 of 8 : OwnableRoles.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import {Ownable} from "./Ownable.sol";

/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
/// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173)
/// for compatibility, the nomenclature for the 2-step ownership handover and roles
/// may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The `user`'s roles is updated to `roles`.
    /// Each bit of `roles` represents whether the role is set.
    event RolesUpdated(address indexed user, uint256 indexed roles);

    /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
    uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
        0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The role slot of `user` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
    ///     let roleSlot := keccak256(0x00, 0x20)
    /// ```
    /// This automatically ignores the upper bits of the `user` in case
    /// they are not clean, as well as keep the `keccak256` under 32-bytes.
    ///
    /// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
    uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Overwrite the roles directly without authorization guard.
    function _setRoles(address user, uint256 roles) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Store the new value.
            sstore(keccak256(0x0c, 0x20), roles)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
        }
    }

    /// @dev Updates the roles directly without authorization guard.
    /// If `on` is true, each set bit of `roles` will be turned on,
    /// otherwise, each set bit of `roles` will be turned off.
    function _updateRoles(address user, uint256 roles, bool on) internal virtual {
        /// @solidity memory-safe-assembly
        assembly {
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            let roleSlot := keccak256(0x0c, 0x20)
            // Load the current value.
            let current := sload(roleSlot)
            // Compute the updated roles if `on` is true.
            let updated := or(current, roles)
            // Compute the updated roles if `on` is false.
            // Use `and` to compute the intersection of `current` and `roles`,
            // `xor` it with `current` to flip the bits in the intersection.
            if iszero(on) { updated := xor(current, and(current, roles)) }
            // Then, store the new value.
            sstore(roleSlot, updated)
            // Emit the {RolesUpdated} event.
            log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
        }
    }

    /// @dev Grants the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn on.
    function _grantRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, true);
    }

    /// @dev Removes the roles directly without authorization guard.
    /// Each bit of `roles` represents the role to turn off.
    function _removeRoles(address user, uint256 roles) internal virtual {
        _updateRoles(user, roles, false);
    }

    /// @dev Throws if the sender does not have any of the `roles`.
    function _checkRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Throws if the sender is not the owner,
    /// and does not have any of the `roles`.
    /// Checks for ownership first, then lazily checks for roles.
    function _checkOwnerOrRoles(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner.
            // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
            if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                // Compute the role slot.
                mstore(0x0c, _ROLE_SLOT_SEED)
                mstore(0x00, caller())
                // Load the stored value, and if the `and` intersection
                // of the value and `roles` is zero, revert.
                if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Throws if the sender does not have any of the `roles`,
    /// and is not the owner.
    /// Checks for roles first, then lazily checks for ownership.
    function _checkRolesOrOwner(uint256 roles) internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, caller())
            // Load the stored value, and if the `and` intersection
            // of the value and `roles` is zero, revert.
            if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
                // If the caller is not the stored owner.
                // Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
                if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
                    mstore(0x00, 0x82b42900) // `Unauthorized()`.
                    revert(0x1c, 0x04)
                }
            }
        }
    }

    /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
                // We don't need to mask the values of `ordinals`, as Solidity
                // cleans dirty upper bits when storing variables into memory.
                roles := or(shl(mload(add(ordinals, i)), 1), roles)
            }
        }
    }

    /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
    /// This is meant for frontends like Etherscan, and is therefore not fully optimized.
    /// Not recommended to be called on-chain.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
        /// @solidity memory-safe-assembly
        assembly {
            // Grab the pointer to the free memory.
            ordinals := mload(0x40)
            let ptr := add(ordinals, 0x20)
            let o := 0
            // The absence of lookup tables, De Bruijn, etc., here is intentional for
            // smaller bytecode, as this function is not meant to be called on-chain.
            for { let t := roles } 1 {} {
                mstore(ptr, o)
                // `shr` 5 is equivalent to multiplying by 0x20.
                // Push back into the ordinals array if the bit is set.
                ptr := add(ptr, shl(5, and(t, 1)))
                o := add(o, 1)
                t := shr(o, roles)
                if iszero(t) { break }
            }
            // Store the length of `ordinals`.
            mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
            // Allocate the memory.
            mstore(0x40, ptr)
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to grant `user` `roles`.
    /// If the `user` already has a role, then it will be an no-op for the role.
    function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _grantRoles(user, roles);
    }

    /// @dev Allows the owner to remove `user` `roles`.
    /// If the `user` does not have a role, then it will be an no-op for the role.
    function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
        _removeRoles(user, roles);
    }

    /// @dev Allow the caller to remove their own roles.
    /// If the caller does not have a role, then it will be an no-op for the role.
    function renounceRoles(uint256 roles) public payable virtual {
        _removeRoles(msg.sender, roles);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the roles of `user`.
    function rolesOf(address user) public view virtual returns (uint256 roles) {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the role slot.
            mstore(0x0c, _ROLE_SLOT_SEED)
            mstore(0x00, user)
            // Load the stored value.
            roles := sload(keccak256(0x0c, 0x20))
        }
    }

    /// @dev Returns whether `user` has any of `roles`.
    function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles != 0;
    }

    /// @dev Returns whether `user` has all of `roles`.
    function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
        return rolesOf(user) & roles == roles;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by an account with `roles`.
    modifier onlyRoles(uint256 roles) virtual {
        _checkRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by the owner or by an account
    /// with `roles`. Checks for ownership first, then lazily checks for roles.
    modifier onlyOwnerOrRoles(uint256 roles) virtual {
        _checkOwnerOrRoles(roles);
        _;
    }

    /// @dev Marks a function as only callable by an account with `roles`
    /// or the owner. Checks for roles first, then lazily checks for ownership.
    modifier onlyRolesOrOwner(uint256 roles) virtual {
        _checkRolesOrOwner(roles);
        _;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       ROLE CONSTANTS                       */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    // IYKYK

    uint256 internal constant _ROLE_0 = 1 << 0;
    uint256 internal constant _ROLE_1 = 1 << 1;
    uint256 internal constant _ROLE_2 = 1 << 2;
    uint256 internal constant _ROLE_3 = 1 << 3;
    uint256 internal constant _ROLE_4 = 1 << 4;
    uint256 internal constant _ROLE_5 = 1 << 5;
    uint256 internal constant _ROLE_6 = 1 << 6;
    uint256 internal constant _ROLE_7 = 1 << 7;
    uint256 internal constant _ROLE_8 = 1 << 8;
    uint256 internal constant _ROLE_9 = 1 << 9;
    uint256 internal constant _ROLE_10 = 1 << 10;
    uint256 internal constant _ROLE_11 = 1 << 11;
    uint256 internal constant _ROLE_12 = 1 << 12;
    uint256 internal constant _ROLE_13 = 1 << 13;
    uint256 internal constant _ROLE_14 = 1 << 14;
    uint256 internal constant _ROLE_15 = 1 << 15;
    uint256 internal constant _ROLE_16 = 1 << 16;
    uint256 internal constant _ROLE_17 = 1 << 17;
    uint256 internal constant _ROLE_18 = 1 << 18;
    uint256 internal constant _ROLE_19 = 1 << 19;
    uint256 internal constant _ROLE_20 = 1 << 20;
    uint256 internal constant _ROLE_21 = 1 << 21;
    uint256 internal constant _ROLE_22 = 1 << 22;
    uint256 internal constant _ROLE_23 = 1 << 23;
    uint256 internal constant _ROLE_24 = 1 << 24;
    uint256 internal constant _ROLE_25 = 1 << 25;
    uint256 internal constant _ROLE_26 = 1 << 26;
    uint256 internal constant _ROLE_27 = 1 << 27;
    uint256 internal constant _ROLE_28 = 1 << 28;
    uint256 internal constant _ROLE_29 = 1 << 29;
    uint256 internal constant _ROLE_30 = 1 << 30;
    uint256 internal constant _ROLE_31 = 1 << 31;
    uint256 internal constant _ROLE_32 = 1 << 32;
    uint256 internal constant _ROLE_33 = 1 << 33;
    uint256 internal constant _ROLE_34 = 1 << 34;
    uint256 internal constant _ROLE_35 = 1 << 35;
    uint256 internal constant _ROLE_36 = 1 << 36;
    uint256 internal constant _ROLE_37 = 1 << 37;
    uint256 internal constant _ROLE_38 = 1 << 38;
    uint256 internal constant _ROLE_39 = 1 << 39;
    uint256 internal constant _ROLE_40 = 1 << 40;
    uint256 internal constant _ROLE_41 = 1 << 41;
    uint256 internal constant _ROLE_42 = 1 << 42;
    uint256 internal constant _ROLE_43 = 1 << 43;
    uint256 internal constant _ROLE_44 = 1 << 44;
    uint256 internal constant _ROLE_45 = 1 << 45;
    uint256 internal constant _ROLE_46 = 1 << 46;
    uint256 internal constant _ROLE_47 = 1 << 47;
    uint256 internal constant _ROLE_48 = 1 << 48;
    uint256 internal constant _ROLE_49 = 1 << 49;
    uint256 internal constant _ROLE_50 = 1 << 50;
    uint256 internal constant _ROLE_51 = 1 << 51;
    uint256 internal constant _ROLE_52 = 1 << 52;
    uint256 internal constant _ROLE_53 = 1 << 53;
    uint256 internal constant _ROLE_54 = 1 << 54;
    uint256 internal constant _ROLE_55 = 1 << 55;
    uint256 internal constant _ROLE_56 = 1 << 56;
    uint256 internal constant _ROLE_57 = 1 << 57;
    uint256 internal constant _ROLE_58 = 1 << 58;
    uint256 internal constant _ROLE_59 = 1 << 59;
    uint256 internal constant _ROLE_60 = 1 << 60;
    uint256 internal constant _ROLE_61 = 1 << 61;
    uint256 internal constant _ROLE_62 = 1 << 62;
    uint256 internal constant _ROLE_63 = 1 << 63;
    uint256 internal constant _ROLE_64 = 1 << 64;
    uint256 internal constant _ROLE_65 = 1 << 65;
    uint256 internal constant _ROLE_66 = 1 << 66;
    uint256 internal constant _ROLE_67 = 1 << 67;
    uint256 internal constant _ROLE_68 = 1 << 68;
    uint256 internal constant _ROLE_69 = 1 << 69;
    uint256 internal constant _ROLE_70 = 1 << 70;
    uint256 internal constant _ROLE_71 = 1 << 71;
    uint256 internal constant _ROLE_72 = 1 << 72;
    uint256 internal constant _ROLE_73 = 1 << 73;
    uint256 internal constant _ROLE_74 = 1 << 74;
    uint256 internal constant _ROLE_75 = 1 << 75;
    uint256 internal constant _ROLE_76 = 1 << 76;
    uint256 internal constant _ROLE_77 = 1 << 77;
    uint256 internal constant _ROLE_78 = 1 << 78;
    uint256 internal constant _ROLE_79 = 1 << 79;
    uint256 internal constant _ROLE_80 = 1 << 80;
    uint256 internal constant _ROLE_81 = 1 << 81;
    uint256 internal constant _ROLE_82 = 1 << 82;
    uint256 internal constant _ROLE_83 = 1 << 83;
    uint256 internal constant _ROLE_84 = 1 << 84;
    uint256 internal constant _ROLE_85 = 1 << 85;
    uint256 internal constant _ROLE_86 = 1 << 86;
    uint256 internal constant _ROLE_87 = 1 << 87;
    uint256 internal constant _ROLE_88 = 1 << 88;
    uint256 internal constant _ROLE_89 = 1 << 89;
    uint256 internal constant _ROLE_90 = 1 << 90;
    uint256 internal constant _ROLE_91 = 1 << 91;
    uint256 internal constant _ROLE_92 = 1 << 92;
    uint256 internal constant _ROLE_93 = 1 << 93;
    uint256 internal constant _ROLE_94 = 1 << 94;
    uint256 internal constant _ROLE_95 = 1 << 95;
    uint256 internal constant _ROLE_96 = 1 << 96;
    uint256 internal constant _ROLE_97 = 1 << 97;
    uint256 internal constant _ROLE_98 = 1 << 98;
    uint256 internal constant _ROLE_99 = 1 << 99;
    uint256 internal constant _ROLE_100 = 1 << 100;
    uint256 internal constant _ROLE_101 = 1 << 101;
    uint256 internal constant _ROLE_102 = 1 << 102;
    uint256 internal constant _ROLE_103 = 1 << 103;
    uint256 internal constant _ROLE_104 = 1 << 104;
    uint256 internal constant _ROLE_105 = 1 << 105;
    uint256 internal constant _ROLE_106 = 1 << 106;
    uint256 internal constant _ROLE_107 = 1 << 107;
    uint256 internal constant _ROLE_108 = 1 << 108;
    uint256 internal constant _ROLE_109 = 1 << 109;
    uint256 internal constant _ROLE_110 = 1 << 110;
    uint256 internal constant _ROLE_111 = 1 << 111;
    uint256 internal constant _ROLE_112 = 1 << 112;
    uint256 internal constant _ROLE_113 = 1 << 113;
    uint256 internal constant _ROLE_114 = 1 << 114;
    uint256 internal constant _ROLE_115 = 1 << 115;
    uint256 internal constant _ROLE_116 = 1 << 116;
    uint256 internal constant _ROLE_117 = 1 << 117;
    uint256 internal constant _ROLE_118 = 1 << 118;
    uint256 internal constant _ROLE_119 = 1 << 119;
    uint256 internal constant _ROLE_120 = 1 << 120;
    uint256 internal constant _ROLE_121 = 1 << 121;
    uint256 internal constant _ROLE_122 = 1 << 122;
    uint256 internal constant _ROLE_123 = 1 << 123;
    uint256 internal constant _ROLE_124 = 1 << 124;
    uint256 internal constant _ROLE_125 = 1 << 125;
    uint256 internal constant _ROLE_126 = 1 << 126;
    uint256 internal constant _ROLE_127 = 1 << 127;
    uint256 internal constant _ROLE_128 = 1 << 128;
    uint256 internal constant _ROLE_129 = 1 << 129;
    uint256 internal constant _ROLE_130 = 1 << 130;
    uint256 internal constant _ROLE_131 = 1 << 131;
    uint256 internal constant _ROLE_132 = 1 << 132;
    uint256 internal constant _ROLE_133 = 1 << 133;
    uint256 internal constant _ROLE_134 = 1 << 134;
    uint256 internal constant _ROLE_135 = 1 << 135;
    uint256 internal constant _ROLE_136 = 1 << 136;
    uint256 internal constant _ROLE_137 = 1 << 137;
    uint256 internal constant _ROLE_138 = 1 << 138;
    uint256 internal constant _ROLE_139 = 1 << 139;
    uint256 internal constant _ROLE_140 = 1 << 140;
    uint256 internal constant _ROLE_141 = 1 << 141;
    uint256 internal constant _ROLE_142 = 1 << 142;
    uint256 internal constant _ROLE_143 = 1 << 143;
    uint256 internal constant _ROLE_144 = 1 << 144;
    uint256 internal constant _ROLE_145 = 1 << 145;
    uint256 internal constant _ROLE_146 = 1 << 146;
    uint256 internal constant _ROLE_147 = 1 << 147;
    uint256 internal constant _ROLE_148 = 1 << 148;
    uint256 internal constant _ROLE_149 = 1 << 149;
    uint256 internal constant _ROLE_150 = 1 << 150;
    uint256 internal constant _ROLE_151 = 1 << 151;
    uint256 internal constant _ROLE_152 = 1 << 152;
    uint256 internal constant _ROLE_153 = 1 << 153;
    uint256 internal constant _ROLE_154 = 1 << 154;
    uint256 internal constant _ROLE_155 = 1 << 155;
    uint256 internal constant _ROLE_156 = 1 << 156;
    uint256 internal constant _ROLE_157 = 1 << 157;
    uint256 internal constant _ROLE_158 = 1 << 158;
    uint256 internal constant _ROLE_159 = 1 << 159;
    uint256 internal constant _ROLE_160 = 1 << 160;
    uint256 internal constant _ROLE_161 = 1 << 161;
    uint256 internal constant _ROLE_162 = 1 << 162;
    uint256 internal constant _ROLE_163 = 1 << 163;
    uint256 internal constant _ROLE_164 = 1 << 164;
    uint256 internal constant _ROLE_165 = 1 << 165;
    uint256 internal constant _ROLE_166 = 1 << 166;
    uint256 internal constant _ROLE_167 = 1 << 167;
    uint256 internal constant _ROLE_168 = 1 << 168;
    uint256 internal constant _ROLE_169 = 1 << 169;
    uint256 internal constant _ROLE_170 = 1 << 170;
    uint256 internal constant _ROLE_171 = 1 << 171;
    uint256 internal constant _ROLE_172 = 1 << 172;
    uint256 internal constant _ROLE_173 = 1 << 173;
    uint256 internal constant _ROLE_174 = 1 << 174;
    uint256 internal constant _ROLE_175 = 1 << 175;
    uint256 internal constant _ROLE_176 = 1 << 176;
    uint256 internal constant _ROLE_177 = 1 << 177;
    uint256 internal constant _ROLE_178 = 1 << 178;
    uint256 internal constant _ROLE_179 = 1 << 179;
    uint256 internal constant _ROLE_180 = 1 << 180;
    uint256 internal constant _ROLE_181 = 1 << 181;
    uint256 internal constant _ROLE_182 = 1 << 182;
    uint256 internal constant _ROLE_183 = 1 << 183;
    uint256 internal constant _ROLE_184 = 1 << 184;
    uint256 internal constant _ROLE_185 = 1 << 185;
    uint256 internal constant _ROLE_186 = 1 << 186;
    uint256 internal constant _ROLE_187 = 1 << 187;
    uint256 internal constant _ROLE_188 = 1 << 188;
    uint256 internal constant _ROLE_189 = 1 << 189;
    uint256 internal constant _ROLE_190 = 1 << 190;
    uint256 internal constant _ROLE_191 = 1 << 191;
    uint256 internal constant _ROLE_192 = 1 << 192;
    uint256 internal constant _ROLE_193 = 1 << 193;
    uint256 internal constant _ROLE_194 = 1 << 194;
    uint256 internal constant _ROLE_195 = 1 << 195;
    uint256 internal constant _ROLE_196 = 1 << 196;
    uint256 internal constant _ROLE_197 = 1 << 197;
    uint256 internal constant _ROLE_198 = 1 << 198;
    uint256 internal constant _ROLE_199 = 1 << 199;
    uint256 internal constant _ROLE_200 = 1 << 200;
    uint256 internal constant _ROLE_201 = 1 << 201;
    uint256 internal constant _ROLE_202 = 1 << 202;
    uint256 internal constant _ROLE_203 = 1 << 203;
    uint256 internal constant _ROLE_204 = 1 << 204;
    uint256 internal constant _ROLE_205 = 1 << 205;
    uint256 internal constant _ROLE_206 = 1 << 206;
    uint256 internal constant _ROLE_207 = 1 << 207;
    uint256 internal constant _ROLE_208 = 1 << 208;
    uint256 internal constant _ROLE_209 = 1 << 209;
    uint256 internal constant _ROLE_210 = 1 << 210;
    uint256 internal constant _ROLE_211 = 1 << 211;
    uint256 internal constant _ROLE_212 = 1 << 212;
    uint256 internal constant _ROLE_213 = 1 << 213;
    uint256 internal constant _ROLE_214 = 1 << 214;
    uint256 internal constant _ROLE_215 = 1 << 215;
    uint256 internal constant _ROLE_216 = 1 << 216;
    uint256 internal constant _ROLE_217 = 1 << 217;
    uint256 internal constant _ROLE_218 = 1 << 218;
    uint256 internal constant _ROLE_219 = 1 << 219;
    uint256 internal constant _ROLE_220 = 1 << 220;
    uint256 internal constant _ROLE_221 = 1 << 221;
    uint256 internal constant _ROLE_222 = 1 << 222;
    uint256 internal constant _ROLE_223 = 1 << 223;
    uint256 internal constant _ROLE_224 = 1 << 224;
    uint256 internal constant _ROLE_225 = 1 << 225;
    uint256 internal constant _ROLE_226 = 1 << 226;
    uint256 internal constant _ROLE_227 = 1 << 227;
    uint256 internal constant _ROLE_228 = 1 << 228;
    uint256 internal constant _ROLE_229 = 1 << 229;
    uint256 internal constant _ROLE_230 = 1 << 230;
    uint256 internal constant _ROLE_231 = 1 << 231;
    uint256 internal constant _ROLE_232 = 1 << 232;
    uint256 internal constant _ROLE_233 = 1 << 233;
    uint256 internal constant _ROLE_234 = 1 << 234;
    uint256 internal constant _ROLE_235 = 1 << 235;
    uint256 internal constant _ROLE_236 = 1 << 236;
    uint256 internal constant _ROLE_237 = 1 << 237;
    uint256 internal constant _ROLE_238 = 1 << 238;
    uint256 internal constant _ROLE_239 = 1 << 239;
    uint256 internal constant _ROLE_240 = 1 << 240;
    uint256 internal constant _ROLE_241 = 1 << 241;
    uint256 internal constant _ROLE_242 = 1 << 242;
    uint256 internal constant _ROLE_243 = 1 << 243;
    uint256 internal constant _ROLE_244 = 1 << 244;
    uint256 internal constant _ROLE_245 = 1 << 245;
    uint256 internal constant _ROLE_246 = 1 << 246;
    uint256 internal constant _ROLE_247 = 1 << 247;
    uint256 internal constant _ROLE_248 = 1 << 248;
    uint256 internal constant _ROLE_249 = 1 << 249;
    uint256 internal constant _ROLE_250 = 1 << 250;
    uint256 internal constant _ROLE_251 = 1 << 251;
    uint256 internal constant _ROLE_252 = 1 << 252;
    uint256 internal constant _ROLE_253 = 1 << 253;
    uint256 internal constant _ROLE_254 = 1 << 254;
    uint256 internal constant _ROLE_255 = 1 << 255;
}

File 5 of 8 : LibERC6551.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Library for interacting with ERC6551 accounts.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/accounts/LibERC6551.sol)
/// @author ERC6551 team (https://github.com/erc6551/reference/blob/main/src/lib/ERC6551AccountLib.sol)
library LibERC6551 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Failed to create a ERC6551 account via the registry.
    error AccountCreationFailed();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The canonical ERC6551 registry address for EVM chains.
    address internal constant REGISTRY = 0x000000006551c19487814612e58FE06813775758;

    /// @dev The canonical ERC6551 registry bytecode for EVM chains.
    /// Useful for forge tests:
    /// `vm.etch(REGISTRY, REGISTRY_BYTECODE)`.
    bytes internal constant REGISTRY_BYTECODE =
        hex"608060405234801561001057600080fd5b50600436106100365760003560e01c8063246a00211461003b5780638a54c52f1461006a575b600080fd5b61004e6100493660046101b7565b61007d565b6040516001600160a01b03909116815260200160405180910390f35b61004e6100783660046101b7565b6100e1565b600060806024608c376e5af43d82803e903d91602b57fd5bf3606c5285605d52733d60ad80600a3d3981f3363d3d373d3d3d363d7360495260ff60005360b76055206035523060601b60015284601552605560002060601b60601c60005260206000f35b600060806024608c376e5af43d82803e903d91602b57fd5bf3606c5285605d52733d60ad80600a3d3981f3363d3d373d3d3d363d7360495260ff60005360b76055206035523060601b600152846015526055600020803b61018b578560b760556000f580610157576320188a596000526004601cfd5b80606c52508284887f79f19b3655ee38b1ce526556b7731a20c8f218fbda4a3990b6cc4172fdf887226060606ca46020606cf35b8060601b60601c60005260206000f35b80356001600160a01b03811681146101b257600080fd5b919050565b600080600080600060a086880312156101cf57600080fd5b6101d88661019b565b945060208601359350604086013592506101f46060870161019b565b94979396509194608001359291505056fea2646970667358221220ea2fe53af507453c64dd7c1db05549fa47a298dfb825d6d11e1689856135f16764736f6c63430008110033";

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                ACCOUNT BYTECODE OPERATIONS                 */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the initialization code of the ERC6551 account.
    function initCode(
        address implementation_,
        bytes32 salt_,
        uint256 chainId_,
        address tokenContract_,
        uint256 tokenId_
    ) internal pure returns (bytes memory result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40) // Grab the free memory pointer..
            // Layout the variables and bytecode backwards.
            mstore(add(result, 0xb7), tokenId_)
            mstore(add(result, 0x97), shr(96, shl(96, tokenContract_)))
            mstore(add(result, 0x77), chainId_)
            mstore(add(result, 0x57), salt_)
            mstore(add(result, 0x37), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(result, 0x28), implementation_)
            mstore(add(result, 0x14), 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73)
            mstore(result, 0xb7) // Store the length.
            mstore(0x40, add(result, 0xd7)) // Allocate the memory.
        }
    }

    /// @dev Returns the initialization code hash of the ERC6551 account.
    function initCodeHash(
        address implementation_,
        bytes32 salt_,
        uint256 chainId_,
        address tokenContract_,
        uint256 tokenId_
    ) internal pure returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40) // Grab the free memory pointer.
            // Layout the variables and bytecode backwards.
            mstore(add(result, 0xa3), tokenId_)
            mstore(add(result, 0x83), shr(96, shl(96, tokenContract_)))
            mstore(add(result, 0x63), chainId_)
            mstore(add(result, 0x43), salt_)
            mstore(add(result, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(result, 0x14), implementation_)
            mstore(result, 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73)
            result := keccak256(add(result, 0x0c), 0xb7)
        }
    }

    /// @dev Creates an account via the ERC6551 registry.
    function createAccount(
        address implementation_,
        bytes32 salt_,
        uint256 chainId_,
        address tokenContract_,
        uint256 tokenId_
    ) internal returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40)
            mstore(add(m, 0x14), implementation_)
            mstore(add(m, 0x34), salt_)
            mstore(add(m, 0x54), chainId_)
            mstore(add(m, 0x74), shr(96, shl(96, tokenContract_)))
            mstore(add(m, 0x94), tokenId_)
            // `createAccount(address,bytes32,uint256,address,uint256)`.
            mstore(m, 0x8a54c52f000000000000000000000000)
            if iszero(
                and(
                    gt(returndatasize(), 0x1f),
                    call(gas(), REGISTRY, 0, add(m, 0x10), 0xa4, 0x00, 0x20)
                )
            ) {
                mstore(0x00, 0x20188a59) // `AccountCreationFailed()`.
                revert(0x1c, 0x04)
            }
            result := mload(0x00)
        }
    }

    /// @dev Returns the address of the ERC6551 account.
    function account(
        address implementation_,
        bytes32 salt_,
        uint256 chainId_,
        address tokenContract_,
        uint256 tokenId_
    ) internal pure returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := mload(0x40) // Grab the free memory pointer.
            // Layout the variables and bytecode backwards.
            mstore(add(result, 0xa3), tokenId_)
            mstore(add(result, 0x83), shr(96, shl(96, tokenContract_)))
            mstore(add(result, 0x63), chainId_)
            mstore(add(result, 0x43), salt_)
            mstore(add(result, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
            mstore(add(result, 0x14), implementation_)
            mstore(result, 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73)
            // Compute and store the bytecode hash.
            mstore8(0x00, 0xff) // Write the prefix.
            mstore(0x35, keccak256(add(result, 0x0c), 0xb7))
            mstore(0x01, shl(96, REGISTRY))
            mstore(0x15, salt_)
            result := keccak256(0x00, 0x55)
            mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
        }
    }

    /// @dev Returns if `a` is an ERC6551 account with `expectedImplementation`.
    function isERC6551Account(address a, address expectedImplementation)
        internal
        view
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Grab the free memory pointer..
            extcodecopy(a, add(m, 0x20), 0x0a, 0xa3)
            let implementation_ := shr(96, mload(add(m, 0x20)))
            if mul(
                extcodesize(implementation_),
                gt(eq(extcodesize(a), 0xad), shl(96, xor(expectedImplementation, implementation_)))
            ) {
                // Layout the variables and bytecode backwards.
                mstore(add(m, 0x23), 0x5af43d82803e903d91602b57fd5bf3)
                mstore(add(m, 0x14), implementation_)
                mstore(m, 0x3d60ad80600a3d3981f3363d3d373d3d3d363d73)
                // Compute and store the bytecode hash.
                mstore8(0x00, 0xff) // Write the prefix.
                mstore(0x35, keccak256(add(m, 0x0c), 0xb7))
                mstore(0x01, shl(96, REGISTRY))
                mstore(0x15, mload(add(m, 0x43)))
                result := iszero(shl(96, xor(a, keccak256(0x00, 0x55))))
                mstore(0x35, 0) // Restore the overwritten part of the free memory pointer.
            }
        }
    }

    /// @dev Returns the implementation of the ERC6551 account `a`.
    function implementation(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(a, 0x00, 0x0a, 0x14)
            result := shr(96, mload(0x00))
        }
    }

    /// @dev Returns the static variables of the ERC6551 account `a`.
    function context(address a)
        internal
        view
        returns (bytes32 salt_, uint256 chainId_, address tokenContract_, uint256 tokenId_)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let m := mload(0x40) // Cache the free memory pointer.
            extcodecopy(a, 0x00, 0x2d, 0x80)
            salt_ := mload(0x00)
            chainId_ := mload(0x20)
            tokenContract_ := mload(0x40)
            tokenId_ := mload(0x60)
            mstore(0x40, m) // Restore the free memory pointer.
            mstore(0x60, 0) // Restore the zero pointer.
        }
    }

    /// @dev Returns the salt of the ERC6551 account `a`.
    function salt(address a) internal view returns (bytes32 result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(a, 0x00, 0x2d, 0x20)
            result := mload(0x00)
        }
    }

    /// @dev Returns the chain ID of the ERC6551 account `a`.
    function chainId(address a) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(a, 0x00, 0x4d, 0x20)
            result := mload(0x00)
        }
    }

    /// @dev Returns the token contract of the ERC6551 account `a`.
    function tokenContract(address a) internal view returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(a, 0x00, 0x6d, 0x20)
            result := mload(0x00)
        }
    }

    /// @dev Returns the token ID of the ERC6551 account `a`.
    function tokenId(address a) internal view returns (uint256 result) {
        /// @solidity memory-safe-assembly
        assembly {
            extcodecopy(a, 0x00, 0x8d, 0x20)
            result := mload(0x00)
        }
    }
}

File 6 of 8 : LibString.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @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 {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                        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();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         CONSTANTS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The constant returned when the `search` is not found in the string.
    uint256 internal constant NOT_FOUND = type(uint256).max;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     DECIMAL OPERATIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(uint256 value) internal pure returns (string memory str) {
        /// @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.
            str := add(mload(0x40), 0x80)
            // Update the free memory pointer to allocate.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end of the memory to calculate the length later.
            let end := str

            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 {} {
                str := add(str, w) // `sub(str, 1)`.
                // Write the character to the pointer.
                // The ASCII index of the '0' character is 48.
                mstore8(str, add(48, mod(temp, 10)))
                // Keep dividing `temp` until zero.
                temp := div(temp, 10)
                if iszero(temp) { break }
            }

            let length := sub(end, str)
            // Move the pointer 32 bytes leftwards to make room for the length.
            str := sub(str, 0x20)
            // Store the length.
            mstore(str, length)
        }
    }

    /// @dev Returns the base 10 decimal representation of `value`.
    function toString(int256 value) internal pure returns (string memory str) {
        if (value >= 0) {
            return toString(uint256(value));
        }
        unchecked {
            str = 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 length := mload(str) // Load the string length.
            mstore(str, 0x2d) // Store the '-' character.
            str := sub(str, 1) // Move back the string pointer by a byte.
            mstore(str, add(length, 1)) // Update the string length.
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   HEXADECIMAL OPERATIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2 + 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
        str = toHexStringNoPrefix(value, length);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write the length.
        }
    }

    /// @dev Returns the hexadecimal representation of `value`,
    /// left-padded to an input length of `length` bytes.
    /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
    /// giving a total length of `length * 2` bytes.
    /// Reverts if `length` is too small for the output to contain all the digits.
    function toHexStringNoPrefix(uint256 value, uint256 length)
        internal
        pure
        returns (string memory str)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // We need 0x20 bytes for the trailing zeros padding, `length * 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.
            str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let start := sub(str, add(length, length))
            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 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(xor(str, start)) { break }
            }

            if temp {
                mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
                revert(0x1c, 0x04)
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
            str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
            let strLength := mload(str) // Get the length.
            str := add(str, o) // Move the pointer, accounting for leading zero.
            mstore(str, sub(strLength, o)) // Write 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 str) {
        /// @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.
            str := add(mload(0x40), 0x80)
            // Allocate the memory.
            mstore(0x40, add(str, 0x20))
            // Zeroize the slot after the string.
            mstore(str, 0)

            // Cache the end to calculate the length later.
            let end := str
            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            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 {} {
                str := add(str, w) // `sub(str, 2)`.
                mstore8(add(str, 1), mload(and(temp, 15)))
                mstore8(str, mload(and(shr(4, temp), 15)))
                temp := shr(8, temp)
                if iszero(temp) { break }
            }

            // Compute the string's length.
            let strLength := sub(end, str)
            // Move the pointer and write the length.
            str := sub(str, 0x20)
            mstore(str, strLength)
        }
    }

    /// @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 str) {
        str = toHexString(value);
        /// @solidity memory-safe-assembly
        assembly {
            let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
            let o := add(str, 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 str) {
        str = toHexStringNoPrefix(value);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        /// @solidity memory-safe-assembly
        assembly {
            str := mload(0x40)

            // Allocate the 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(str, 0x80))

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            str := add(str, 2)
            mstore(str, 40)

            let o := add(str, 0x20)
            mstore(add(o, 40), 0)

            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 str) {
        str = toHexStringNoPrefix(raw);
        /// @solidity memory-safe-assembly
        assembly {
            let strLength := add(mload(str), 2) // Compute the length.
            mstore(str, 0x3078) // Write the "0x" prefix.
            str := sub(str, 2) // Move the pointer.
            mstore(str, strLength) // Write 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 str) {
        /// @solidity memory-safe-assembly
        assembly {
            let length := mload(raw)
            str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
            mstore(str, add(length, length)) // Store the length of the output.

            // Store "0123456789abcdef" in scratch space.
            mstore(0x0f, 0x30313233343536373839616263646566)

            let o := add(str, 0x20)
            let end := add(raw, length)

            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 the 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 {
            let mask := shl(7, div(not(0), 255))
            result := 1
            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)
            }
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   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 `search` replaced with `replacement`.
    function replace(string memory subject, string memory search, string memory replacement)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)
            let replacementLength := mload(replacement)

            subject := add(subject, 0x20)
            search := add(search, 0x20)
            replacement := add(replacement, 0x20)
            result := add(mload(0x40), 0x20)

            let subjectEnd := add(subject, subjectLength)
            if iszero(gt(searchLength, subjectLength)) {
                let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                mstore(result, t)
                                result := add(result, 1)
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Copy the `replacement` one word at a time.
                        for { let o := 0 } 1 {} {
                            mstore(add(result, o), mload(add(replacement, o)))
                            o := add(o, 0x20)
                            if iszero(lt(o, replacementLength)) { break }
                        }
                        result := add(result, replacementLength)
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    mstore(result, t)
                    result := add(result, 1)
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
            }

            let resultRemainder := result
            result := add(mload(0x40), 0x20)
            let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
            // Copy the rest of the string one word at a time.
            for {} lt(subject, subjectEnd) {} {
                mstore(resultRemainder, mload(subject))
                resultRemainder := add(resultRemainder, 0x20)
                subject := add(subject, 0x20)
            }
            result := sub(result, 0x20)
            let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
            mstore(last, 0)
            mstore(0x40, add(last, 0x20)) // Allocate the memory.
            mstore(result, k) // Store the length.
        }
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from left to right, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for { let subjectLength := mload(subject) } 1 {} {
                if iszero(mload(search)) {
                    if iszero(gt(from, subjectLength)) {
                        result := from
                        break
                    }
                    result := subjectLength
                    break
                }
                let searchLength := mload(search)
                let subjectStart := add(subject, 0x20)

                result := not(0) // Initialize to `NOT_FOUND`.

                subject := add(subjectStart, from)
                let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)

                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(add(search, 0x20))

                if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }

                if iszero(lt(searchLength, 0x20)) {
                    for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
                        if iszero(shr(m, xor(mload(subject), s))) {
                            if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
    /// searching from left to right.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function indexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = indexOf(subject, search, 0);
    }

    /// @dev Returns the byte index of the first location of `search` in `subject`,
    /// searching from right to left, starting from `from`.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search, uint256 from)
        internal
        pure
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            for {} 1 {} {
                result := not(0) // Initialize to `NOT_FOUND`.
                let searchLength := mload(search)
                if gt(searchLength, mload(subject)) { break }
                let w := result

                let fromMax := sub(mload(subject), searchLength)
                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(search, 0x20), searchLength) } 1 {} {
                    if eq(keccak256(subject, searchLength), 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 `search` in `subject`,
    /// searching from right to left.
    /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
    function lastIndexOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256 result)
    {
        result = lastIndexOf(subject, search, uint256(int256(-1)));
    }

    /// @dev Returns true if `search` is found in `subject`, false otherwise.
    function contains(string memory subject, string memory search) internal pure returns (bool) {
        return indexOf(subject, search) != NOT_FOUND;
    }

    /// @dev Returns whether `subject` starts with `search`.
    function startsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                iszero(gt(searchLength, mload(subject))),
                eq(
                    keccak256(add(subject, 0x20), searchLength),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns whether `subject` ends with `search`.
    function endsWith(string memory subject, string memory search)
        internal
        pure
        returns (bool result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let searchLength := mload(search)
            let subjectLength := mload(subject)
            // Whether `search` is not longer than `subject`.
            let withinRange := iszero(gt(searchLength, subjectLength))
            // Just using keccak256 directly is actually cheaper.
            // forgefmt: disable-next-item
            result := and(
                withinRange,
                eq(
                    keccak256(
                        // `subject + 0x20 + max(subjectLength - searchLength, 0)`.
                        add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
                        searchLength
                    ),
                    keccak256(add(search, 0x20), searchLength)
                )
            )
        }
    }

    /// @dev Returns `subject` repeated `times`.
    function repeat(string memory subject, uint256 times)
        internal
        pure
        returns (string memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(or(iszero(times), iszero(subjectLength))) {
                subject := add(subject, 0x20)
                result := mload(0x40)
                let output := add(result, 0x20)
                for {} 1 {} {
                    // Copy the `subject` one word at a time.
                    for { let o := 0 } 1 {} {
                        mstore(add(output, o), mload(add(subject, o)))
                        o := add(o, 0x20)
                        if iszero(lt(o, subjectLength)) { break }
                    }
                    output := add(output, subjectLength)
                    times := sub(times, 1)
                    if iszero(times) { break }
                }
                mstore(output, 0) // Zeroize the slot after the string.
                let resultLength := sub(output, add(result, 0x20))
                mstore(result, resultLength) // Store the length.
                // Allocate the memory.
                mstore(0x40, add(result, add(resultLength, 0x20)))
            }
        }
    }

    /// @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 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            if iszero(gt(subjectLength, end)) { end := subjectLength }
            if iszero(gt(subjectLength, start)) { start := subjectLength }
            if lt(start, end) {
                result := mload(0x40)
                let resultLength := sub(end, start)
                mstore(result, resultLength)
                subject := add(subject, start)
                let w := not(0x1f)
                // Copy the `subject` one word at a time, backwards.
                for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
                    mstore(add(result, o), mload(add(subject, o)))
                    o := add(o, w) // `sub(o, 0x20)`.
                    if iszero(o) { break }
                }
                // Zeroize the slot after the string.
                mstore(add(add(result, 0x20), resultLength), 0)
                // Allocate memory for the length and the bytes,
                // rounded up to a multiple of 32.
                mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
            }
        }
    }

    /// @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 result)
    {
        result = slice(subject, start, uint256(int256(-1)));
    }

    /// @dev Returns all the indices of `search` in `subject`.
    /// The indices are byte offsets.
    function indicesOf(string memory subject, string memory search)
        internal
        pure
        returns (uint256[] memory result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let subjectLength := mload(subject)
            let searchLength := mload(search)

            if iszero(gt(searchLength, subjectLength)) {
                subject := add(subject, 0x20)
                search := add(search, 0x20)
                result := add(mload(0x40), 0x20)

                let subjectStart := subject
                let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
                let h := 0
                if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
                let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
                let s := mload(search)
                for {} 1 {} {
                    let t := mload(subject)
                    // Whether the first `searchLength % 32` bytes of
                    // `subject` and `search` matches.
                    if iszero(shr(m, xor(t, s))) {
                        if h {
                            if iszero(eq(keccak256(subject, searchLength), h)) {
                                subject := add(subject, 1)
                                if iszero(lt(subject, subjectSearchEnd)) { break }
                                continue
                            }
                        }
                        // Append to `result`.
                        mstore(result, sub(subject, subjectStart))
                        result := add(result, 0x20)
                        // Advance `subject` by `searchLength`.
                        subject := add(subject, searchLength)
                        if searchLength {
                            if iszero(lt(subject, subjectSearchEnd)) { break }
                            continue
                        }
                    }
                    subject := add(subject, 1)
                    if iszero(lt(subject, subjectSearchEnd)) { break }
                }
                let resultEnd := result
                // Assign `result` to the free memory pointer.
                result := mload(0x40)
                // Store the length of `result`.
                mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
                // Allocate memory for result.
                // We allocate one more word, so this array can be recycled for {split}.
                mstore(0x40, add(resultEnd, 0x20))
            }
        }
    }

    /// @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)
    {
        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))
            let prevIndex := 0
            for {} 1 {} {
                let index := mload(indexPtr)
                mstore(indexPtr, 0x60)
                if iszero(eq(index, prevIndex)) {
                    let element := mload(0x40)
                    let elementLength := sub(index, prevIndex)
                    mstore(element, elementLength)
                    // Copy the `subject` one word at a time, backwards.
                    for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
                        mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
                        o := add(o, w) // `sub(o, 0x20)`.
                        if iszero(o) { break }
                    }
                    // Zeroize the slot after the string.
                    mstore(add(add(element, 0x20), elementLength), 0)
                    // Allocate memory for the length and the bytes,
                    // rounded up to a multiple of 32.
                    mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
                    // Store the `element` into the array.
                    mstore(indexPtr, element)
                }
                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 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 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            let w := not(0x1f)
            result := mload(0x40)
            let aLength := mload(a)
            // Copy `a` one word at a time, backwards.
            for { let o := and(add(aLength, 0x20), w) } 1 {} {
                mstore(add(result, o), mload(add(a, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let bLength := mload(b)
            let output := add(result, aLength)
            // Copy `b` one word at a time, backwards.
            for { let o := and(add(bLength, 0x20), w) } 1 {} {
                mstore(add(output, o), mload(add(b, o)))
                o := add(o, w) // `sub(o, 0x20)`.
                if iszero(o) { break }
            }
            let totalLength := add(aLength, bLength)
            let last := add(add(result, 0x20), totalLength)
            // Zeroize the slot after the string.
            mstore(last, 0)
            // Stores the length.
            mstore(result, totalLength)
            // Allocate memory for the length and the bytes,
            // rounded up to a multiple of 32.
            mstore(0x40, and(add(last, 0x1f), w))
        }
    }

    /// @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 length := mload(subject)
            if length {
                result := add(mload(0x40), 0x20)
                subject := add(subject, 1)
                let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
                let w := not(0)
                for { let o := length } 1 {} {
                    o := add(o, w)
                    let b := and(0xff, mload(add(subject, o)))
                    mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
                    if iszero(o) { break }
                }
                result := mload(0x40)
                mstore(result, length) // Store the length.
                let last := add(add(result, 0x20), length)
                mstore(last, 0) // Zeroize the slot after the string.
                mstore(0x40, add(last, 0x20)) // Allocate the 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)
            let o := add(result, 0x20)
            mstore(o, s)
            mstore(add(o, n), 0)
            mstore(0x40, add(result, 0x40))
        }
    }

    /// @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 {
            let end := add(s, mload(s))
            result := add(mload(0x40), 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(result, c)
                    result := add(result, 1)
                    continue
                }
                let t := shr(248, mload(c))
                mstore(result, mload(and(t, 0x1f)))
                result := add(result, shr(5, t))
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the 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 {
            let end := add(s, mload(s))
            result := add(mload(0x40), 0x20)
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            // 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 {} 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(result, c)
                        result := add(result, 1)
                        continue
                    }
                    mstore8(result, 0x5c) // "\\".
                    mstore8(add(result, 1), c)
                    result := add(result, 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(result, mload(0x19)) // "\\u00XX".
                    result := add(result, 6)
                    continue
                }
                mstore8(result, 0x5c) // "\\".
                mstore8(add(result, 1), mload(add(c, 8)))
                result := add(result, 2)
            }
            if addDoubleQuotes {
                mstore8(result, 34)
                result := add(1, result)
            }
            let last := result
            mstore(last, 0) // Zeroize the slot after the string.
            result := mload(0x40)
            mstore(result, sub(last, add(result, 0x20))) // Store the length.
            mstore(0x40, add(last, 0x20)) // Allocate the 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 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 {
            // Grab the free memory pointer.
            result := mload(0x40)
            // Allocate 2 words (1 for the length, 1 for the bytes).
            mstore(0x40, add(result, 0x40))
            // Zeroize the length slot.
            mstore(result, 0)
            // Store the length and bytes.
            mstore(add(result, 0x1f), packed)
            // Right pad with zeroes.
            mstore(add(add(result, 0x20), mload(result)), 0)
        }
    }

    /// @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 aLength := mload(a)
            // We don't need to zero right pad the strings,
            // since this is our own custom non-standard packing scheme.
            result :=
                mul(
                    // Load the length and the bytes of `a` and `b`.
                    or(
                        shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
                        mload(sub(add(b, 0x1e), aLength))
                    ),
                    // `totalLength != 0 && totalLength < 31`. Abuses underflow.
                    // Assumes that the lengths are valid and within the block gas limit.
                    lt(sub(add(aLength, 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 {
            // Grab the free memory pointer.
            resultA := mload(0x40)
            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 retSize := 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, retSize), 0)
            // Store the return offset.
            mstore(retStart, 0x20)
            // End the transaction, returning the string.
            return(retStart, retSize)
        }
    }
}

File 7 of 8 : ReentrancyGuard.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;

/// @notice Reentrancy guard mixin.
/// @author Soledge (https://github.com/vectorized/soledge/blob/main/src/utils/ReentrancyGuard.sol)
///
/// Note: This implementation utilizes the `TSTORE` and `TLOAD` opcodes.
/// Please ensure that the chain you are deploying on supports them.
abstract contract ReentrancyGuard {
    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                       CUSTOM ERRORS                        */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Unauthorized reentrant call.
    error Reentrancy();

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                          STORAGE                           */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
    /// 9 bytes is large enough to avoid collisions in practice,
    /// but not too large to result in excessive bytecode bloat.
    uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;

    /*«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-«-*/
    /*                      REENTRANCY GUARD                      */
    /*-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»-»*/

    /// @dev Guards a function from reentrancy.
    modifier nonReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
            tstore(_REENTRANCY_GUARD_SLOT, address())
        }
        _;
        /// @solidity memory-safe-assembly
        assembly {
            tstore(_REENTRANCY_GUARD_SLOT, 0)
        }
    }

    /// @dev Guards a view function from read-only reentrancy.
    modifier nonReadReentrant() virtual {
        /// @solidity memory-safe-assembly
        assembly {
            if tload(_REENTRANCY_GUARD_SLOT) {
                mstore(0x00, 0xab143c06) // `Reentrancy()`.
                revert(0x1c, 0x04)
            }
        }
        _;
    }
}

File 8 of 8 : Ownable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                       CUSTOM ERRORS                        */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The caller is not authorized to call the function.
    error Unauthorized();

    /// @dev The `newOwner` cannot be the zero address.
    error NewOwnerIsZeroAddress();

    /// @dev The `pendingOwner` does not have a valid handover request.
    error NoHandoverRequest();

    /// @dev Cannot double-initialize.
    error AlreadyInitialized();

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                           EVENTS                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The ownership is transferred from `oldOwner` to `newOwner`.
    /// This event is intentionally kept the same as OpenZeppelin's Ownable to be
    /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
    /// despite it not being as lightweight as a single argument event.
    event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);

    /// @dev An ownership handover to `pendingOwner` has been requested.
    event OwnershipHandoverRequested(address indexed pendingOwner);

    /// @dev The ownership handover to `pendingOwner` has been canceled.
    event OwnershipHandoverCanceled(address indexed pendingOwner);

    /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
    uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
        0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;

    /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
        0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;

    /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
    uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
        0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                          STORAGE                           */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev The owner slot is given by:
    /// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
    /// It is intentionally chosen to be a high value
    /// to avoid collision with lower slots.
    /// The choice of manual storage layout is to enable compatibility
    /// with both regular and upgradeable contracts.
    bytes32 internal constant _OWNER_SLOT =
        0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;

    /// The ownership handover slot of `newOwner` is given by:
    /// ```
    ///     mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
    ///     let handoverSlot := keccak256(0x00, 0x20)
    /// ```
    /// It stores the expiry timestamp of the two-step ownership handover.
    uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                     INTERNAL FUNCTIONS                     */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
    function _guardInitializeOwner() internal pure virtual returns (bool guard) {}

    /// @dev Initializes the owner directly without authorization guard.
    /// This function must be called upon initialization,
    /// regardless of whether the contract is upgradeable or not.
    /// This is to enable generalization to both regular and upgradeable contracts,
    /// and to save gas in case the initial owner is not the caller.
    /// For performance reasons, this function will not check if there
    /// is an existing owner.
    function _initializeOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                if sload(ownerSlot) {
                    mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
                    revert(0x1c, 0x04)
                }
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Store the new value.
                sstore(_OWNER_SLOT, newOwner)
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
            }
        }
    }

    /// @dev Sets the owner directly without authorization guard.
    function _setOwner(address newOwner) internal virtual {
        if (_guardInitializeOwner()) {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
            }
        } else {
            /// @solidity memory-safe-assembly
            assembly {
                let ownerSlot := _OWNER_SLOT
                // Clean the upper 96 bits.
                newOwner := shr(96, shl(96, newOwner))
                // Emit the {OwnershipTransferred} event.
                log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
                // Store the new value.
                sstore(ownerSlot, newOwner)
            }
        }
    }

    /// @dev Throws if the sender is not the owner.
    function _checkOwner() internal view virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // If the caller is not the stored owner, revert.
            if iszero(eq(caller(), sload(_OWNER_SLOT))) {
                mstore(0x00, 0x82b42900) // `Unauthorized()`.
                revert(0x1c, 0x04)
            }
        }
    }

    /// @dev Returns how long a two-step ownership handover is valid for in seconds.
    /// Override to return a different value if needed.
    /// Made internal to conserve bytecode. Wrap it in a public function if needed.
    function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
        return 48 * 3600;
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                  PUBLIC UPDATE FUNCTIONS                   */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Allows the owner to transfer the ownership to `newOwner`.
    function transferOwnership(address newOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            if iszero(shl(96, newOwner)) {
                mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
                revert(0x1c, 0x04)
            }
        }
        _setOwner(newOwner);
    }

    /// @dev Allows the owner to renounce their ownership.
    function renounceOwnership() public payable virtual onlyOwner {
        _setOwner(address(0));
    }

    /// @dev Request a two-step ownership handover to the caller.
    /// The request will automatically expire in 48 hours (172800 seconds) by default.
    function requestOwnershipHandover() public payable virtual {
        unchecked {
            uint256 expires = block.timestamp + _ownershipHandoverValidFor();
            /// @solidity memory-safe-assembly
            assembly {
                // Compute and set the handover slot to `expires`.
                mstore(0x0c, _HANDOVER_SLOT_SEED)
                mstore(0x00, caller())
                sstore(keccak256(0x0c, 0x20), expires)
                // Emit the {OwnershipHandoverRequested} event.
                log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
            }
        }
    }

    /// @dev Cancels the two-step ownership handover to the caller, if any.
    function cancelOwnershipHandover() public payable virtual {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, caller())
            sstore(keccak256(0x0c, 0x20), 0)
            // Emit the {OwnershipHandoverCanceled} event.
            log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
        }
    }

    /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
    /// Reverts if there is no existing ownership handover requested by `pendingOwner`.
    function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute and set the handover slot to 0.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            let handoverSlot := keccak256(0x0c, 0x20)
            // If the handover does not exist, or has expired.
            if gt(timestamp(), sload(handoverSlot)) {
                mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
                revert(0x1c, 0x04)
            }
            // Set the handover slot to 0.
            sstore(handoverSlot, 0)
        }
        _setOwner(pendingOwner);
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                   PUBLIC READ FUNCTIONS                    */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Returns the owner of the contract.
    function owner() public view virtual returns (address result) {
        /// @solidity memory-safe-assembly
        assembly {
            result := sload(_OWNER_SLOT)
        }
    }

    /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
    function ownershipHandoverExpiresAt(address pendingOwner)
        public
        view
        virtual
        returns (uint256 result)
    {
        /// @solidity memory-safe-assembly
        assembly {
            // Compute the handover slot.
            mstore(0x0c, _HANDOVER_SLOT_SEED)
            mstore(0x00, pendingOwner)
            // Load the handover slot.
            result := sload(keccak256(0x0c, 0x20))
        }
    }

    /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
    /*                         MODIFIERS                          */
    /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/

    /// @dev Marks a function as only callable by the owner.
    modifier onlyOwner() virtual {
        _checkOwner();
        _;
    }
}

Settings
{
  "remappings": [
    "forge-std/=test/utils/forge-std/",
    "murky/=lib/murky/",
    "dn404/=lib/dn404/src/",
    "solady/=lib/solady/src/",
    "ds-test/=lib/murky/lib/forge-std/lib/ds-test/src/",
    "forge-std/=lib/murky/lib/forge-std/src/",
    "murky/=lib/murky/",
    "openzeppelin-contracts/=lib/murky/lib/openzeppelin-contracts/",
    "solady/=lib/solady/src/",
    "soledge/=lib/soledge/src/"
  ],
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "metadata": {
    "useLiteralContent": false,
    "bytecodeHash": "ipfs",
    "appendCBOR": true
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "abi"
      ]
    }
  },
  "evmVersion": "cancun",
  "viaIR": false,
  "libraries": {}
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"OnlyOneVaultPerAccount","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SingleTransferNotEnabled","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"VaultHasNotBeenCreated","type":"error"},{"inputs":[],"name":"VaultManagerAlreadyInitialized","type":"error"},{"inputs":[],"name":"VaultProxyIsZeroAddress","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"SingleTransferEnabledSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"vault","type":"address"}],"name":"VaultCreated","type":"event"},{"inputs":[],"name":"ASTERIX","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ASTERIX_MIRROR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"METADATA_SETTER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"createVault","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"createVaultFor","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositAsterixERC20","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"depositAsterixERC20For","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"depositAsterixMirrorERC721","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"depositAsterixMirrorERC721For","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockVaultProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"holder","type":"address"}],"name":"maxAsterixERC20WithdrawableWithoutBurningERC721s","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"}],"name":"setNameAndSymbol","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setSingleTransferEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"renderer","type":"address"}],"name":"setTokenURIRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"proxy","type":"address"}],"name":"setVaultProxy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"singleTransferEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"result","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalVaults","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"vaultAt","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"vaultOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"vaultOwner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultProxy","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"vaultProxyLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"vault","type":"address"}],"name":"vaultTokenId","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawAsterixERC20","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"withdrawAsterixERC20To","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"withdrawAsterixMirrorERC721","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"withdrawAsterixMirrorERC721To","outputs":[{"internalType":"address","name":"vault","type":"address"}],"stateMutability":"nonpayable","type":"function"}]

608060405234801561000f575f80fd5b506100356effe8b47b3e2130213b802212439497331461002f573361003a565b3261003a565b610113565b61004381610054565b6100518163800000006100ac565b50565b638b78c6d81980541561006e57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6100b8828260016100bc565b5050565b638b78c6d8600c52825f526020600c208054838117836100dd575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3505050505050565b612204806101205f395ff3fe608060405260043610610341575f3560e01c80636352211e116101bd578063aeb84f24116100f2578063cf70698a11610092578063f2fde38b1161006d578063f2fde38b1461098a578063fbcd21591461099d578063fee81cf4146109bc578063ff87a5f5146109ed575f80fd5b8063cf70698a14610924578063e985e9c514610943578063f04e283e14610977575f80fd5b8063b69e0643116100cd578063b69e0643146108bf578063b88d4fde146108d3578063c5975788146108e6578063c87b56dd14610905575f80fd5b8063aeb84f2414610862578063b19c3ca314610881578063b50fd681146108a0575f80fd5b8063905e34411161015d578063983525bf11610138578063983525bf146107c7578063a22cb465146107e6578063a6caeb4b14610805578063a7e76d4814610842575f80fd5b8063905e34411461076f57806394a7c3ef1461079157806395d89b41146107b3575f80fd5b8063893a537211610198578063893a5372146106db5780638c13a453146107015780638d654023146107205780638da5cb5b14610757575f80fd5b80636352211e1461069557806370a08231146106b4578063715018a6146106d3575f80fd5b806329a4927a116102935780634a4ee7b11161023357806354d1f13d1161020e57806354d1f13d1461063b57806355f804b3146106435780635a446215146106625780635d12928b14610681575f80fd5b80634a4ee7b1146105d457806350a534c7146105e7578063514e62fc14610606575f80fd5b806336fe3cb81161026e57806336fe3cb814610564578063397bfe5514610583578063398e6cb7146105a257806342842e0e146105c1575f80fd5b806329a4927a146104fd5780632de948071461051c578063302ad53a1461054d575f80fd5b806318160ddd116102fe5780631c10893f116102d95780631c10893f1461049a5780631cd64df4146104ad57806323b872dd146104e257806325692962146104f5575f80fd5b806318160ddd14610441578063183a4f6e146104685780631a966d701461047b575f80fd5b806301ffc9a71461034557806306fdde03146103965780630709df45146103b7578063081812fc146103ee578063095ea7b31461040d57806310a96a0114610422575b5f80fd5b348015610350575f80fd5b5061038161035f366004611cf6565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156103a1575f80fd5b506103aa610a0c565b60405161038d9190611d1d565b3480156103c2575f80fd5b506103d66103d1366004611d68565b610a9c565b6040516001600160a01b03909116815260200161038d565b3480156103f9575f80fd5b506103d6610408366004611d81565b610aac565b61042061041b366004611d98565b610ae7565b005b34801561042d575f80fd5b506103d661043c366004611e07565b610af6565b34801561044c575f80fd5b506004546001600160401b03165b60405190815260200161038d565b610420610476366004611d81565b610b9b565b348015610486575f80fd5b506103d6610495366004611d68565b610ba8565b6104206104a8366004611d98565b610bee565b3480156104b8575f80fd5b506103816104c7366004611d98565b638b78c6d8600c9081525f9290925260209091205481161490565b6104206104f0366004611e55565b610c00565b610420610d05565b348015610508575f80fd5b506103d6610517366004611e07565b610d51565b348015610527575f80fd5b5061045a610536366004611d68565b638b78c6d8600c9081525f91909152602090205490565b348015610558575f80fd5b5061045a638000000081565b34801561056f575f80fd5b5061045a61057e366004611d68565b610dc0565b34801561058e575f80fd5b5061042061059d366004611d68565b610e05565b3480156105ad575f80fd5b506103d66105bc366004611d81565b610e69565b6104206105cf366004611e55565b610e74565b6104206105e2366004611d98565b610ea0565b3480156105f2575f80fd5b5061045a610601366004611d68565b610eb2565b348015610611575f80fd5b50610381610620366004611d98565b638b78c6d8600c9081525f9290925260209091205416151590565b610420610f19565b34801561064e575f80fd5b5061042061065d366004611ecb565b610f52565b34801561066d575f80fd5b5061042061067c366004611f09565b610f73565b34801561068c575f80fd5b506103d6610fa4565b3480156106a0575f80fd5b506103d66106af366004611d81565b610fb3565b3480156106bf575f80fd5b5061045a6106ce366004611d68565b610fd6565b61042061100e565b3480156106e6575f80fd5b506004546103d690600160401b90046001600160a01b031681565b34801561070c575f80fd5b506103d661071b366004611d81565b611021565b34801561072b575f80fd5b5060045461073f906001600160401b031681565b6040516001600160401b03909116815260200161038d565b348015610762575f80fd5b50638b78c6d819546103d6565b34801561077a575f80fd5b506103d66eca73a6df4c58b84c5b4b847fe8ff3981565b34801561079c575f80fd5b506103d66ec26fabfe894d13233d5ec73f61cc7281565b3480156107be575f80fd5b506103aa611033565b3480156107d2575f80fd5b506103d66107e1366004611d98565b611042565b3480156107f1575f80fd5b50610420610800366004611f7e565b6110cb565b348015610810575f80fd5b5061038161081f366004611d81565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c151590565b34801561084d575f80fd5b5060045461038190600160e01b900460ff1681565b34801561086d575f80fd5b506103d661087c366004611faf565b61111e565b34801561088c575f80fd5b5061042061089b366004611fe1565b611131565b3480156108ab575f80fd5b506103d66108ba366004611d81565b6111f2565b3480156108ca575f80fd5b506104206111fd565b6104206108e1366004611ffa565b61121a565b3480156108f1575f80fd5b506103d6610900366004611d68565b611274565b348015610910575f80fd5b506103aa61091f366004611d81565b6112b5565b34801561092f575f80fd5b506103d661093e366004611faf565b611433565b34801561094e575f80fd5b5061038161095d366004612063565b601c52670a5a2e7a000000006008525f526030600c205490565b610420610985366004611d68565b61143f565b610420610998366004611d68565b611479565b3480156109a8575f80fd5b506103d66109b7366004611d98565b61149f565b3480156109c7575f80fd5b5061045a6109d6366004611d68565b63389a75e1600c9081525f91909152602090205490565b3480156109f8575f80fd5b50610420610a07366004611d68565b6114f4565b606060018054610a1b9061208b565b80601f0160208091040260200160405190810160405280929190818152602001828054610a479061208b565b8015610a925780601f10610a6957610100808354040283529160200191610a92565b820191905f5260205f20905b815481529060010190602001808311610a7557829003601f168201915b5050505050905090565b5f610aa682611524565b92915050565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610add5763ceea21b65f526004601cfd5b6001015492915050565b610af2338383611544565b5050565b5f68929eee149b4bd212685c15610b145763ab143c065f526004601cfd5b3068929eee149b4bd212685d610b2933610a9c565b90506001600160a01b038116610b525760405163425ef92760e01b815260040160405180910390fd5b5f5b82811015610b8657610b7e826ec26fabfe894d13233d5ec73f61cc7287600585901b8801356115de565b600101610b54565b505b5f68929eee149b4bd212685d9392505050565b610ba53382611602565b50565b5f68929eee149b4bd212685c15610bc65763ab143c065f526004601cfd5b3068929eee149b4bd212685d610bdb8261160d565b90505f68929eee149b4bd212685d919050565b610bf66116f1565b610af2828261170b565b610c0b838383611717565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302610c5c5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417610c88576030600c2054610c8857634b6e7f185f526004601cfd5b8215610c95575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402610cd65767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f68929eee149b4bd212685c15610d6f5763ab143c065f526004601cfd5b3068929eee149b4bd212685d610d848461160d565b90505f5b82811015610dba57610db2826ec26fabfe894d13233d5ec73f61cc7233600585901b8801356117ba565b600101610d88565b50610b88565b5f80610dcb836117fb565b90505f610dd78261180a565b9050836001600160a01b0316610dec82610a9c565b6001600160a01b031603610dfe578192505b5050919050565b610e0d6116f1565b600454600160e01b900460ff1615610e38576040516303cb96db60e21b815260040160405180910390fd5b600480546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b5f610aa63383611042565b610e7f838383610c00565b813b15610d0057610d0083838360405180602001604052805f815250611831565b610ea86116f1565b610af28282611602565b5f80610ebd83610a9c565b90506001600160a01b038116610ed557505f92915050565b670de0b6b3a7640000610ef76ec26fabfe894d13233d5ec73f61cc72836118b2565b02610f116eca73a6df4c58b84c5b4b847fe8ff39836118b2565b039392505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b6380000000610f60816118dc565b6003610f6d838583612115565b50505050565b6380000000610f81816118dc565b6001610f8e858783612115565b506002610f9c838583612115565b505050505050565b5f610fae33610ba8565b905090565b5f610fbd8261180a565b905080610fd15763ceea21b65f526004601cfd5b919050565b5f81610fe957638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b6110166116f1565b61101f5f61190d565b565b5f610aa661102e8361180a565b611524565b606060028054610a1b9061208b565b5f68929eee149b4bd212685c156110605763ab143c065f526004601cfd5b3068929eee149b4bd212685d61107533610a9c565b90506001600160a01b03811661109e5760405163425ef92760e01b815260040160405180910390fd5b6110b9816eca73a6df4c58b84c5b4b847fe8ff398585611953565b5f68929eee149b4bd212685d92915050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b5f61112a338484610af6565b9392505050565b68929eee149b4bd212685c1561114e5763ab143c065f526004601cfd5b3068929eee149b4bd212685d5f61116433610a9c565b90506001600160a01b03811661118d5760405163425ef92760e01b815260040160405180910390fd5b5f611197826117fb565b90506111a581841515611977565b807ffaa8d8eedc81dcb9ee1d63753820c60f27794f91eb8d0725891f0e0b4e4730c1846040516111d9911515815260200190565b60405180910390a250505f68929eee149b4bd212685d50565b5f610aa6338361149f565b6112056116f1565b6004805460ff60e01b1916600160e01b179055565b611225858585610c00565b833b1561126d5761126d85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061183192505050565b5050505050565b5f8061127f836117fb565b90505f61128b8261180a565b9050836001600160a01b03166112a082610a9c565b6001600160a01b031603610dfe579392505050565b60606112de825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6112fb5760405163677510db60e11b815260040160405180910390fd5b5f546001600160a01b0316801561135f57604051915063c87b56dd5f52826020525f806024601c845afa611331573d5f833e3d82fd5b60205f803e60205f51833e815160205f5101602084013e815160208301015f8152602081016040525061142d565b6003805461136c9061208b565b15905061142d5761142a600380546113839061208b565b80601f01602080910402602001604051908101604052809291908181526020018280546113af9061208b565b80156113fa5780601f106113d1576101008083540402835291602001916113fa565b820191905f5260205f20905b8154815290600101906020018083116113dd57829003601f168201915b5050505050604051806040016040528060048152602001637b69647d60e01b815250611425866119a6565b6119e8565b91505b50919050565b5f61112a338484610d51565b6114476116f1565b63389a75e1600c52805f526020600c20805442111561146d57636f5e88185f526004601cfd5b5f9055610ba58161190d565b6114816116f1565b8060601b61149657637448fbae5f526004601cfd5b610ba58161190d565b5f68929eee149b4bd212685c156114bd5763ab143c065f526004601cfd5b3068929eee149b4bd212685d6114d28361160d565b90506114ef816eca73a6df4c58b84c5b4b847fe8ff3933856117ba565b6110b9565b6380000000611502816118dc565b505f80546001600160a01b0319166001600160a01b0392909216919091179055565b673ec412a9852d173d60c11b601c9081525f91909152600c205460201c90565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816115875763ceea21b65f526004601cfd5b8185148515176115ab57815f526030600c20546115ab57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b610f6d84846323b872dd876001600160a01b0316866001600160a01b031686611b08565b610af282825f611b6f565b5f61161782611524565b90506001600160a01b0381161561162d57919050565b600454600160401b90046001600160a01b03168061165e57604051630873153160e11b815260040160405180910390fd5b600480546001600160401b038082166001011667ffffffffffffffff19909116811790915561168e84825f611bc6565b61169b825f463085611c58565b9250826001600160a01b031681856001600160a01b03167f019b61d9140f8784f4eed1e66569335630452af2d974ceb13d3e706c0786729660405160405180910390a4610dfe84846001600160a01b0316611cca565b638b78c6d81954331461101f576382b429005f526004601cfd5b610af282826001611b6f565b61172082611524565b6001600160e01b0316156117475760405163759be05b60e11b815260040160405180910390fd5b6001600160a01b03831615610d00575f818152673ec412a9852d173d60c11b601c5260208120820182015460a01c90036117945760405163768a0e2b60e01b815260040160405180910390fd5b61179e815f611977565b6117b0826117ab85611524565b611cca565b610d00835f611cca565b60405181606052846040528260601b602c526323b872dd60601b600c5260205f6064601c5f885af16117ee573d5f823e3d81fd5b5f60605260405250505050565b5f6020608d5f843c50505f5190565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611878578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611899573d15611899573d5f843e3d83fd5b508060e01b825114610f9c5763d1a57ed65f526004601cfd5b5f816014526370a0823160601b5f5260208060246010865afa601f3d111660205102905092915050565b638b78c6d819543314610ba557638b78c6d8600c52335f52806020600c205416610ba5576382b429005f526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b610f6d848463a9059cbb856001600160a01b0316856001600160a01b03165f611b08565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a9004806119bf575050819003601f19909101908152919050565b60608351835183516020870196506020860195506020850194506020604051019350828701838311611ab8576001838203015f60208510611a2857508388205b601f851660200360031b89515b8b51818118831c611a9f578315611a6f5783888e2014611a6f57808a5260019c8d019c90990198848d10611a695750611ab3565b50611a35565b5f5b8b8101518b820152602001878110611a7157509b87019b988601988715611a9f57848d10611a695750611ab3565b895260019b8c019b90980197838c10611a35575b505050505b84935060206040510194508781038585030192505b80881015611ae8578751845260209788019790930192611acd565b50505f818401908152602001604052601f19909201918252509392505050565b604051856014820152635194544760601b81525f6034820152608060548201525f60748201528460988201528360b88201528260d88201528160f8820152606460948201525f38610124601084015f8b5af1611b66573d5f823e3d81fd5b50505050505050565b638b78c6d8600c52825f526020600c20805483811783611b90575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3505050505050565b611bd15f8484611717565b8260601b60601c9250815f52673ec412a9852d173d60c11b601c52828160a01b1760205f208301830155825f52601c600c20600181540163ffffffff81168502611c2a5767ea553b3401336cea851560021b526004601cfd5b905581835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a4505050565b5f6040518660148201528560348201528460548201528360601b60601c6074820152826094820152638a54c52f60601b815260205f60a4601084015f6f6551c19487814612e58fe068137757585af1601f3d1116611cbd576320188a595f526004601cfd5b50505f5195945050505050565b673ec412a9852d173d60c11b601c52815f52601c600c2080548060201c831860201b8118825550505050565b5f60208284031215611d06575f80fd5b81356001600160e01b03198116811461112a575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b0381168114610fd1575f80fd5b5f60208284031215611d78575f80fd5b61112a82611d52565b5f60208284031215611d91575f80fd5b5035919050565b5f8060408385031215611da9575f80fd5b611db283611d52565b946020939093013593505050565b5f8083601f840112611dd0575f80fd5b5081356001600160401b03811115611de6575f80fd5b6020830191508360208260051b8501011115611e00575f80fd5b9250929050565b5f805f60408486031215611e19575f80fd5b611e2284611d52565b925060208401356001600160401b03811115611e3c575f80fd5b611e4886828701611dc0565b9497909650939450505050565b5f805f60608486031215611e67575f80fd5b611e7084611d52565b9250611e7e60208501611d52565b9150604084013590509250925092565b5f8083601f840112611e9e575f80fd5b5081356001600160401b03811115611eb4575f80fd5b602083019150836020828501011115611e00575f80fd5b5f8060208385031215611edc575f80fd5b82356001600160401b03811115611ef1575f80fd5b611efd85828601611e8e565b90969095509350505050565b5f805f8060408587031215611f1c575f80fd5b84356001600160401b0380821115611f32575f80fd5b611f3e88838901611e8e565b90965094506020870135915080821115611f56575f80fd5b50611f6387828801611e8e565b95989497509550505050565b80358015158114610fd1575f80fd5b5f8060408385031215611f8f575f80fd5b611f9883611d52565b9150611fa660208401611f6f565b90509250929050565b5f8060208385031215611fc0575f80fd5b82356001600160401b03811115611fd5575f80fd5b611efd85828601611dc0565b5f60208284031215611ff1575f80fd5b61112a82611f6f565b5f805f805f6080868803121561200e575f80fd5b61201786611d52565b945061202560208701611d52565b93506040860135925060608601356001600160401b03811115612046575f80fd5b61205288828901611e8e565b969995985093965092949392505050565b5f8060408385031215612074575f80fd5b61207d83611d52565b9150611fa660208401611d52565b600181811c9082168061209f57607f821691505b60208210810361142d57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b601f821115610d0057805f5260205f20601f840160051c810160208510156120f65750805b601f840160051c820191505b8181101561126d575f8155600101612102565b6001600160401b0383111561212c5761212c6120bd565b6121408361213a835461208b565b836120d1565b5f601f841160018114612171575f851561215a5750838201355b5f19600387901b1c1916600186901b17835561126d565b5f83815260208120601f198716915b828110156121a05786850135825560209485019460019092019101612180565b50868210156121bc575f1960f88860031b161c19848701351681555b505060018560011b018355505050505056fea26469706673582212207b184e74ca114f5efbf54d0fbe4087ef6dba4ce52b7914fe01c91add502a40dc64736f6c63430008190033

Deployed Bytecode

0x608060405260043610610341575f3560e01c80636352211e116101bd578063aeb84f24116100f2578063cf70698a11610092578063f2fde38b1161006d578063f2fde38b1461098a578063fbcd21591461099d578063fee81cf4146109bc578063ff87a5f5146109ed575f80fd5b8063cf70698a14610924578063e985e9c514610943578063f04e283e14610977575f80fd5b8063b69e0643116100cd578063b69e0643146108bf578063b88d4fde146108d3578063c5975788146108e6578063c87b56dd14610905575f80fd5b8063aeb84f2414610862578063b19c3ca314610881578063b50fd681146108a0575f80fd5b8063905e34411161015d578063983525bf11610138578063983525bf146107c7578063a22cb465146107e6578063a6caeb4b14610805578063a7e76d4814610842575f80fd5b8063905e34411461076f57806394a7c3ef1461079157806395d89b41146107b3575f80fd5b8063893a537211610198578063893a5372146106db5780638c13a453146107015780638d654023146107205780638da5cb5b14610757575f80fd5b80636352211e1461069557806370a08231146106b4578063715018a6146106d3575f80fd5b806329a4927a116102935780634a4ee7b11161023357806354d1f13d1161020e57806354d1f13d1461063b57806355f804b3146106435780635a446215146106625780635d12928b14610681575f80fd5b80634a4ee7b1146105d457806350a534c7146105e7578063514e62fc14610606575f80fd5b806336fe3cb81161026e57806336fe3cb814610564578063397bfe5514610583578063398e6cb7146105a257806342842e0e146105c1575f80fd5b806329a4927a146104fd5780632de948071461051c578063302ad53a1461054d575f80fd5b806318160ddd116102fe5780631c10893f116102d95780631c10893f1461049a5780631cd64df4146104ad57806323b872dd146104e257806325692962146104f5575f80fd5b806318160ddd14610441578063183a4f6e146104685780631a966d701461047b575f80fd5b806301ffc9a71461034557806306fdde03146103965780630709df45146103b7578063081812fc146103ee578063095ea7b31461040d57806310a96a0114610422575b5f80fd5b348015610350575f80fd5b5061038161035f366004611cf6565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156103a1575f80fd5b506103aa610a0c565b60405161038d9190611d1d565b3480156103c2575f80fd5b506103d66103d1366004611d68565b610a9c565b6040516001600160a01b03909116815260200161038d565b3480156103f9575f80fd5b506103d6610408366004611d81565b610aac565b61042061041b366004611d98565b610ae7565b005b34801561042d575f80fd5b506103d661043c366004611e07565b610af6565b34801561044c575f80fd5b506004546001600160401b03165b60405190815260200161038d565b610420610476366004611d81565b610b9b565b348015610486575f80fd5b506103d6610495366004611d68565b610ba8565b6104206104a8366004611d98565b610bee565b3480156104b8575f80fd5b506103816104c7366004611d98565b638b78c6d8600c9081525f9290925260209091205481161490565b6104206104f0366004611e55565b610c00565b610420610d05565b348015610508575f80fd5b506103d6610517366004611e07565b610d51565b348015610527575f80fd5b5061045a610536366004611d68565b638b78c6d8600c9081525f91909152602090205490565b348015610558575f80fd5b5061045a638000000081565b34801561056f575f80fd5b5061045a61057e366004611d68565b610dc0565b34801561058e575f80fd5b5061042061059d366004611d68565b610e05565b3480156105ad575f80fd5b506103d66105bc366004611d81565b610e69565b6104206105cf366004611e55565b610e74565b6104206105e2366004611d98565b610ea0565b3480156105f2575f80fd5b5061045a610601366004611d68565b610eb2565b348015610611575f80fd5b50610381610620366004611d98565b638b78c6d8600c9081525f9290925260209091205416151590565b610420610f19565b34801561064e575f80fd5b5061042061065d366004611ecb565b610f52565b34801561066d575f80fd5b5061042061067c366004611f09565b610f73565b34801561068c575f80fd5b506103d6610fa4565b3480156106a0575f80fd5b506103d66106af366004611d81565b610fb3565b3480156106bf575f80fd5b5061045a6106ce366004611d68565b610fd6565b61042061100e565b3480156106e6575f80fd5b506004546103d690600160401b90046001600160a01b031681565b34801561070c575f80fd5b506103d661071b366004611d81565b611021565b34801561072b575f80fd5b5060045461073f906001600160401b031681565b6040516001600160401b03909116815260200161038d565b348015610762575f80fd5b50638b78c6d819546103d6565b34801561077a575f80fd5b506103d66eca73a6df4c58b84c5b4b847fe8ff3981565b34801561079c575f80fd5b506103d66ec26fabfe894d13233d5ec73f61cc7281565b3480156107be575f80fd5b506103aa611033565b3480156107d2575f80fd5b506103d66107e1366004611d98565b611042565b3480156107f1575f80fd5b50610420610800366004611f7e565b6110cb565b348015610810575f80fd5b5061038161081f366004611d81565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c151590565b34801561084d575f80fd5b5060045461038190600160e01b900460ff1681565b34801561086d575f80fd5b506103d661087c366004611faf565b61111e565b34801561088c575f80fd5b5061042061089b366004611fe1565b611131565b3480156108ab575f80fd5b506103d66108ba366004611d81565b6111f2565b3480156108ca575f80fd5b506104206111fd565b6104206108e1366004611ffa565b61121a565b3480156108f1575f80fd5b506103d6610900366004611d68565b611274565b348015610910575f80fd5b506103aa61091f366004611d81565b6112b5565b34801561092f575f80fd5b506103d661093e366004611faf565b611433565b34801561094e575f80fd5b5061038161095d366004612063565b601c52670a5a2e7a000000006008525f526030600c205490565b610420610985366004611d68565b61143f565b610420610998366004611d68565b611479565b3480156109a8575f80fd5b506103d66109b7366004611d98565b61149f565b3480156109c7575f80fd5b5061045a6109d6366004611d68565b63389a75e1600c9081525f91909152602090205490565b3480156109f8575f80fd5b50610420610a07366004611d68565b6114f4565b606060018054610a1b9061208b565b80601f0160208091040260200160405190810160405280929190818152602001828054610a479061208b565b8015610a925780601f10610a6957610100808354040283529160200191610a92565b820191905f5260205f20905b815481529060010190602001808311610a7557829003601f168201915b5050505050905090565b5f610aa682611524565b92915050565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610add5763ceea21b65f526004601cfd5b6001015492915050565b610af2338383611544565b5050565b5f68929eee149b4bd212685c15610b145763ab143c065f526004601cfd5b3068929eee149b4bd212685d610b2933610a9c565b90506001600160a01b038116610b525760405163425ef92760e01b815260040160405180910390fd5b5f5b82811015610b8657610b7e826ec26fabfe894d13233d5ec73f61cc7287600585901b8801356115de565b600101610b54565b505b5f68929eee149b4bd212685d9392505050565b610ba53382611602565b50565b5f68929eee149b4bd212685c15610bc65763ab143c065f526004601cfd5b3068929eee149b4bd212685d610bdb8261160d565b90505f68929eee149b4bd212685d919050565b610bf66116f1565b610af2828261170b565b610c0b838383611717565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302610c5c5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417610c88576030600c2054610c8857634b6e7f185f526004601cfd5b8215610c95575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402610cd65767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b5f68929eee149b4bd212685c15610d6f5763ab143c065f526004601cfd5b3068929eee149b4bd212685d610d848461160d565b90505f5b82811015610dba57610db2826ec26fabfe894d13233d5ec73f61cc7233600585901b8801356117ba565b600101610d88565b50610b88565b5f80610dcb836117fb565b90505f610dd78261180a565b9050836001600160a01b0316610dec82610a9c565b6001600160a01b031603610dfe578192505b5050919050565b610e0d6116f1565b600454600160e01b900460ff1615610e38576040516303cb96db60e21b815260040160405180910390fd5b600480546001600160a01b03909216600160401b0268010000000000000000600160e01b0319909216919091179055565b5f610aa63383611042565b610e7f838383610c00565b813b15610d0057610d0083838360405180602001604052805f815250611831565b610ea86116f1565b610af28282611602565b5f80610ebd83610a9c565b90506001600160a01b038116610ed557505f92915050565b670de0b6b3a7640000610ef76ec26fabfe894d13233d5ec73f61cc72836118b2565b02610f116eca73a6df4c58b84c5b4b847fe8ff39836118b2565b039392505050565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b6380000000610f60816118dc565b6003610f6d838583612115565b50505050565b6380000000610f81816118dc565b6001610f8e858783612115565b506002610f9c838583612115565b505050505050565b5f610fae33610ba8565b905090565b5f610fbd8261180a565b905080610fd15763ceea21b65f526004601cfd5b919050565b5f81610fe957638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b6110166116f1565b61101f5f61190d565b565b5f610aa661102e8361180a565b611524565b606060028054610a1b9061208b565b5f68929eee149b4bd212685c156110605763ab143c065f526004601cfd5b3068929eee149b4bd212685d61107533610a9c565b90506001600160a01b03811661109e5760405163425ef92760e01b815260040160405180910390fd5b6110b9816eca73a6df4c58b84c5b4b847fe8ff398585611953565b5f68929eee149b4bd212685d92915050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b5f61112a338484610af6565b9392505050565b68929eee149b4bd212685c1561114e5763ab143c065f526004601cfd5b3068929eee149b4bd212685d5f61116433610a9c565b90506001600160a01b03811661118d5760405163425ef92760e01b815260040160405180910390fd5b5f611197826117fb565b90506111a581841515611977565b807ffaa8d8eedc81dcb9ee1d63753820c60f27794f91eb8d0725891f0e0b4e4730c1846040516111d9911515815260200190565b60405180910390a250505f68929eee149b4bd212685d50565b5f610aa6338361149f565b6112056116f1565b6004805460ff60e01b1916600160e01b179055565b611225858585610c00565b833b1561126d5761126d85858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f9201919091525061183192505050565b5050505050565b5f8061127f836117fb565b90505f61128b8261180a565b9050836001600160a01b03166112a082610a9c565b6001600160a01b031603610dfe579392505050565b60606112de825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6112fb5760405163677510db60e11b815260040160405180910390fd5b5f546001600160a01b0316801561135f57604051915063c87b56dd5f52826020525f806024601c845afa611331573d5f833e3d82fd5b60205f803e60205f51833e815160205f5101602084013e815160208301015f8152602081016040525061142d565b6003805461136c9061208b565b15905061142d5761142a600380546113839061208b565b80601f01602080910402602001604051908101604052809291908181526020018280546113af9061208b565b80156113fa5780601f106113d1576101008083540402835291602001916113fa565b820191905f5260205f20905b8154815290600101906020018083116113dd57829003601f168201915b5050505050604051806040016040528060048152602001637b69647d60e01b815250611425866119a6565b6119e8565b91505b50919050565b5f61112a338484610d51565b6114476116f1565b63389a75e1600c52805f526020600c20805442111561146d57636f5e88185f526004601cfd5b5f9055610ba58161190d565b6114816116f1565b8060601b61149657637448fbae5f526004601cfd5b610ba58161190d565b5f68929eee149b4bd212685c156114bd5763ab143c065f526004601cfd5b3068929eee149b4bd212685d6114d28361160d565b90506114ef816eca73a6df4c58b84c5b4b847fe8ff3933856117ba565b6110b9565b6380000000611502816118dc565b505f80546001600160a01b0319166001600160a01b0392909216919091179055565b673ec412a9852d173d60c11b601c9081525f91909152600c205460201c90565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816115875763ceea21b65f526004601cfd5b8185148515176115ab57815f526030600c20546115ab57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b610f6d84846323b872dd876001600160a01b0316866001600160a01b031686611b08565b610af282825f611b6f565b5f61161782611524565b90506001600160a01b0381161561162d57919050565b600454600160401b90046001600160a01b03168061165e57604051630873153160e11b815260040160405180910390fd5b600480546001600160401b038082166001011667ffffffffffffffff19909116811790915561168e84825f611bc6565b61169b825f463085611c58565b9250826001600160a01b031681856001600160a01b03167f019b61d9140f8784f4eed1e66569335630452af2d974ceb13d3e706c0786729660405160405180910390a4610dfe84846001600160a01b0316611cca565b638b78c6d81954331461101f576382b429005f526004601cfd5b610af282826001611b6f565b61172082611524565b6001600160e01b0316156117475760405163759be05b60e11b815260040160405180910390fd5b6001600160a01b03831615610d00575f818152673ec412a9852d173d60c11b601c5260208120820182015460a01c90036117945760405163768a0e2b60e01b815260040160405180910390fd5b61179e815f611977565b6117b0826117ab85611524565b611cca565b610d00835f611cca565b60405181606052846040528260601b602c526323b872dd60601b600c5260205f6064601c5f885af16117ee573d5f823e3d81fd5b5f60605260405250505050565b5f6020608d5f843c50505f5190565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611878578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611899573d15611899573d5f843e3d83fd5b508060e01b825114610f9c5763d1a57ed65f526004601cfd5b5f816014526370a0823160601b5f5260208060246010865afa601f3d111660205102905092915050565b638b78c6d819543314610ba557638b78c6d8600c52335f52806020600c205416610ba5576382b429005f526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b610f6d848463a9059cbb856001600160a01b0316856001600160a01b03165f611b08565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a9004806119bf575050819003601f19909101908152919050565b60608351835183516020870196506020860195506020850194506020604051019350828701838311611ab8576001838203015f60208510611a2857508388205b601f851660200360031b89515b8b51818118831c611a9f578315611a6f5783888e2014611a6f57808a5260019c8d019c90990198848d10611a695750611ab3565b50611a35565b5f5b8b8101518b820152602001878110611a7157509b87019b988601988715611a9f57848d10611a695750611ab3565b895260019b8c019b90980197838c10611a35575b505050505b84935060206040510194508781038585030192505b80881015611ae8578751845260209788019790930192611acd565b50505f818401908152602001604052601f19909201918252509392505050565b604051856014820152635194544760601b81525f6034820152608060548201525f60748201528460988201528360b88201528260d88201528160f8820152606460948201525f38610124601084015f8b5af1611b66573d5f823e3d81fd5b50505050505050565b638b78c6d8600c52825f526020600c20805483811783611b90575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f80a3505050505050565b611bd15f8484611717565b8260601b60601c9250815f52673ec412a9852d173d60c11b601c52828160a01b1760205f208301830155825f52601c600c20600181540163ffffffff81168502611c2a5767ea553b3401336cea851560021b526004601cfd5b905581835f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a4505050565b5f6040518660148201528560348201528460548201528360601b60601c6074820152826094820152638a54c52f60601b815260205f60a4601084015f6f6551c19487814612e58fe068137757585af1601f3d1116611cbd576320188a595f526004601cfd5b50505f5195945050505050565b673ec412a9852d173d60c11b601c52815f52601c600c2080548060201c831860201b8118825550505050565b5f60208284031215611d06575f80fd5b81356001600160e01b03198116811461112a575f80fd5b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b80356001600160a01b0381168114610fd1575f80fd5b5f60208284031215611d78575f80fd5b61112a82611d52565b5f60208284031215611d91575f80fd5b5035919050565b5f8060408385031215611da9575f80fd5b611db283611d52565b946020939093013593505050565b5f8083601f840112611dd0575f80fd5b5081356001600160401b03811115611de6575f80fd5b6020830191508360208260051b8501011115611e00575f80fd5b9250929050565b5f805f60408486031215611e19575f80fd5b611e2284611d52565b925060208401356001600160401b03811115611e3c575f80fd5b611e4886828701611dc0565b9497909650939450505050565b5f805f60608486031215611e67575f80fd5b611e7084611d52565b9250611e7e60208501611d52565b9150604084013590509250925092565b5f8083601f840112611e9e575f80fd5b5081356001600160401b03811115611eb4575f80fd5b602083019150836020828501011115611e00575f80fd5b5f8060208385031215611edc575f80fd5b82356001600160401b03811115611ef1575f80fd5b611efd85828601611e8e565b90969095509350505050565b5f805f8060408587031215611f1c575f80fd5b84356001600160401b0380821115611f32575f80fd5b611f3e88838901611e8e565b90965094506020870135915080821115611f56575f80fd5b50611f6387828801611e8e565b95989497509550505050565b80358015158114610fd1575f80fd5b5f8060408385031215611f8f575f80fd5b611f9883611d52565b9150611fa660208401611f6f565b90509250929050565b5f8060208385031215611fc0575f80fd5b82356001600160401b03811115611fd5575f80fd5b611efd85828601611dc0565b5f60208284031215611ff1575f80fd5b61112a82611f6f565b5f805f805f6080868803121561200e575f80fd5b61201786611d52565b945061202560208701611d52565b93506040860135925060608601356001600160401b03811115612046575f80fd5b61205288828901611e8e565b969995985093965092949392505050565b5f8060408385031215612074575f80fd5b61207d83611d52565b9150611fa660208401611d52565b600181811c9082168061209f57607f821691505b60208210810361142d57634e487b7160e01b5f52602260045260245ffd5b634e487b7160e01b5f52604160045260245ffd5b601f821115610d0057805f5260205f20601f840160051c810160208510156120f65750805b601f840160051c820191505b8181101561126d575f8155600101612102565b6001600160401b0383111561212c5761212c6120bd565b6121408361213a835461208b565b836120d1565b5f601f841160018114612171575f851561215a5750838201355b5f19600387901b1c1916600186901b17835561126d565b5f83815260208120601f198716915b828110156121a05786850135825560209485019460019092019101612180565b50868210156121bc575f1960f88860031b161c19848701351681555b505060018560011b018355505050505056fea26469706673582212207b184e74ca114f5efbf54d0fbe4087ef6dba4ce52b7914fe01c91add502a40dc64736f6c63430008190033

Deployed Bytecode Sourcemap

163:2287:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14864:380:3;;;;;;;;;;-1:-1:-1;14864:380:3;;;;;:::i;:::-;15177:10;15042:3;15038:21;;;;15171:17;;;15196:10;15190:17;;15168:40;15216:10;15210:17;;;15165:63;;14864:380;;;;470:14:8;;463:22;445:41;;433:2;418:18;14864:380:3;;;;;;;;4010:98:7;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;20241:126::-;;;;;;;;;;-1:-1:-1;20241:126:7;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1453:32:8;;;1435:51;;1423:2;1408:18;20241:126:7;1289:203:8;8099:532:3;;;;;;;;;;-1:-1:-1;8099:532:3;;;;;:::i;:::-;;:::i;8925:119::-;;;;;;:::i;:::-;;:::i;:::-;;10759:489:7;;;;;;;;;;-1:-1:-1;10759:489:7;;;;;:::i;:::-;;:::i;5772:96::-;;;;;;;;;;-1:-1:-1;5850:11:7;;-1:-1:-1;;;;;5850:11:7;5772:96;;;2975:25:8;;;2963:2;2948:18;5772:96:7;2829:177:8;10127:109:2;;;;;;:::i;:::-;;:::i;7842:137:7:-;;;;;;;;;;-1:-1:-1;7842:137:7;;;;;:::i;:::-;;:::i;9588:123:2:-;;;;;;:::i;:::-;;:::i;11178:139::-;;;;;;;;;;-1:-1:-1;11178:139:2;;;;;:::i;:::-;10769:15;10763:4;10756:29;;;11257:4;10798:18;;;;10898:4;10882:21;;;10876:28;11280:21;;:30;;11178:139;10748:2886:3;;;;;;:::i;:::-;;:::i;9021:617:1:-;;;:::i;9138:415:7:-;;;;;;;;;;-1:-1:-1;9138:415:7;;;;;:::i;:::-;;:::i;10567:353:2:-;;;;;;;;;;-1:-1:-1;10567:353:2;;;;;:::i;:::-;10769:15;10763:4;10756:29;;;10627:13;10798:18;;;;10898:4;10882:21;;10876:28;;10567:353;1064:55:7;;;;;;;;;;;;14166:7:2;1064:55:7;;21010:407;;;;;;;;;;-1:-1:-1;21010:407:7;;;;;:::i;:::-;;:::i;2303:145:6:-;;;;;;;;;;-1:-1:-1;2303:145:6;;;;;:::i;:::-;;:::i;10512:152:7:-;;;;;;;;;;-1:-1:-1;10512:152:7;;;;;:::i;:::-;;:::i;13705:198:3:-;;;;;;:::i;:::-;;:::i;9856:125:2:-;;;;;;:::i;:::-;;:::i;11786:359:7:-;;;;;;;;;;-1:-1:-1;11786:359:7;;;;;:::i;:::-;;:::i;10982:134:2:-;;;;;;;;;;-1:-1:-1;10982:134:2;;;;;:::i;:::-;10769:15;10763:4;10756:29;;;11060:4;10798:18;;;;10898:4;10882:21;;;10876:28;11083:21;:26;;;10982:134;9720:456:1;;;:::i;6199:118:7:-;;;;;;;;;;-1:-1:-1;6199:118:7;;;;;:::i;:::-;;:::i;6564:197::-;;;;;;;;;;-1:-1:-1;6564:197:7;;;;;:::i;:::-;;:::i;8035:113::-;;;;;;;;;;;;;:::i;6957:332:3:-;;;;;;;;;;-1:-1:-1;6957:332:3;;;;;:::i;:::-;;:::i;7433:533::-;;;;;;;;;;-1:-1:-1;7433:533:3;;;;;:::i;:::-;;:::i;8762:100:1:-;;;:::i;848:25:6:-;;;;;;;;;;-1:-1:-1;848:25:6;;;;-1:-1:-1;;;848:25:6;;-1:-1:-1;;;;;848:25:6;;;21536:140:7;;;;;;;;;;-1:-1:-1;21536:140:7;;;;;:::i;:::-;;:::i;3183:25::-;;;;;;;;;;-1:-1:-1;3183:25:7;;;;-1:-1:-1;;;;;3183:25:7;;;;;;-1:-1:-1;;;;;5001:31:8;;;4983:50;;4971:2;4956:18;3183:25:7;4839:200:8;11408:182:1;;;;;;;;;;-1:-1:-1;;;11556:18:1;11408:182;;790:76:7;;;;;;;;;;;;824:42;790:76;;924:83;;;;;;;;;;;;965:42;924:83;;4142:102;;;;;;;;;;;;;:::i;10032:382::-;;;;;;;;;;-1:-1:-1;10032:382:7;;;;;:::i;:::-;;:::i;9667:726:3:-;;;;;;;;;;-1:-1:-1;9667:726:3;;;;;:::i;:::-;;:::i;21760:134:7:-;;;;;;;;;;-1:-1:-1;21760:134:7;;;;;:::i;:::-;21837:4;18323:16:3;;;-1:-1:-1;;;18359:4:3;18352:38;18460:4;18444:21;;18436:30;;18428:39;18422:46;18417:3;18413:56;21860:27:7;;;21760:134;930:28:6;;;;;;;;;;-1:-1:-1;930:28:6;;;;-1:-1:-1;;;930:28:6;;;;;;11349:209:7;;;;;;;;;;-1:-1:-1;11349:209:7;;;;;:::i;:::-;;:::i;21962:571::-;;;;;;;;;;-1:-1:-1;21962:571:7;;;;;:::i;:::-;;:::i;8807:151::-;;;;;;;;;;-1:-1:-1;8807:151:7;;;;;:::i;:::-;;:::i;2171:91:6:-;;;;;;;;;;;;;:::i;14406:249:3:-;;;;;;:::i;:::-;;:::i;20488:411:7:-;;;;;;;;;;-1:-1:-1;20488:411:7;;;;;:::i;:::-;;:::i;4350:1382::-;;;;;;;;;;-1:-1:-1;4350:1382:7;;;;;:::i;:::-;;:::i;9732:208::-;;;;;;;;;;-1:-1:-1;9732:208:7;;;;;:::i;:::-;;:::i;9135:392:3:-;;;;;;;;;;-1:-1:-1;9135:392:3;;;;;:::i;:::-;9355:4;9348:22;9396:31;9390:4;9383:45;9255:11;9441:19;9505:4;9499;9489:21;9483:28;;9135:392;10363:708:1;;;;;;:::i;:::-;;:::i;8348:349::-;;;;;;:::i;:::-;;:::i;8325:308:7:-;;;;;;;;;;-1:-1:-1;8325:308:7;;;;;:::i;:::-;;:::i;11693:435:1:-;;;;;;;;;;-1:-1:-1;11693:435:1;;;;;:::i;:::-;11963:19;11957:4;11950:33;;;11812:14;11996:26;;;;12106:4;12090:21;;12084:28;;11693:435;6374:138:7;;;;;;;;;;-1:-1:-1;6374:138:7;;;;;:::i;:::-;;:::i;4010:98::-;4064:13;4096:5;4089:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;4010:98;:::o;20241:126::-;20302:7;20344:14;20352:5;20344:7;:14::i;:::-;20321:39;20241:126;-1:-1:-1;;20241:126:7:o;8099:532:3:-;8161:14;8266:2;8260:4;8253:16;-1:-1:-1;;;8289:4:3;8282:38;8386:4;8380;8370:21;8366:2;8362:30;8358:2;8354:39;8430:13;8424:20;8420:2;8416:29;8406:158;;8478:10;8472:4;8465:24;8545:4;8539;8532:18;8406:158;8597:1;8593:21;8587:28;;8099:532;-1:-1:-1;;8099:532:3:o;8925:119::-;9004:33;9013:10;9025:7;9034:2;9004:8;:33::i;:::-;8925:119;;:::o;10759:489:7:-;10908:13;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;10945:19:7::1;10953:10;10945:7;:19::i;:::-;10937:27:::0;-1:-1:-1;;;;;;11004:19:7;::::1;11000:56;;11032:24;;-1:-1:-1::0;;;11032:24:7::1;;;;;;;;;;;11000:56;11071:9;11066:143;11082:19:::0;;::::1;11066:143;;;11122:76;11153:5:::0;965:42:::1;11176:2:::0;24939:1;24935:9;;;24921:24;;24908:38;11122:30:::1;:76::i;:::-;11103:3;;11066:143;;;;11218:23;2021:1:5::0;1997:22;1990:33;10759:489:7;;;;;:::o;10127:109:2:-;10198:31;10211:10;10223:5;10198:12;:31::i;:::-;10127:109;:::o;7842:137:7:-;7919:13;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;7952:20:7::1;7965:6;7952:12;:20::i;:::-;7944:28;;2021:1:5::0;1997:22;1990:33;7842:137:7;;;:::o;9588:123:2:-;12517:13:1;:11;:13::i;:::-;9680:24:2::1;9692:4;9698:5;9680:11;:24::i;10748:2886:3:-:0;10841:34;10862:4;10868:2;10872;10841:20;:34::i;:::-;11025:1;11169:16;;;-1:-1:-1;;;11240:8:3;11211:38;11205:4;11198:52;11316:4;11300:21;;11292:30;;11284:39;;11359:20;;-1:-1:-1;;;;;11049:25:3;;;;11093:23;;;;11405:36;;;11284:39;11557:15;;;11546:27;;11536:229;;11697:18;11688:5;11681:13;11678:1;11674:21;11667:49;11746:4;11740;11733:18;11536:229;11868:4;11862;11855:18;11926:13;11923:1;11919:21;11913:28;11890:51;;12076:15;12066:8;12063:29;12056:4;12046:8;12043:18;12040:53;12030:288;;12149:4;12143;12133:21;12127:28;12117:183;;12196:10;12190:4;12183:24;12273:4;12267;12260:18;12117:183;12393:15;12390:55;;;12441:1;12425:13;12422:1;12418:21;12411:32;12390:55;12557:13;;;12536:35;12514:58;;-1:-1:-1;12690:4:3;12684;12674:21;;;12740:22;;-1:-1:-1;;12736:30:3;12712:55;;-1:-1:-1;12858:16:3;;;12912:21;12981:20;;12764:1;12977:28;13157:20;13132:46;;13124:55;;13114:270;;13308:18;13302:2;13295:10;13292:1;13288:18;13281:46;13361:4;13355;13348:18;13114:270;13401:42;;13572:2;13568;13562:4;13535:25;13529:4;13517:10;13512:63;13594:33;10748:2886;;;:::o;9021:617:1:-;9114:15;7972:9;-1:-1:-1;;;;;9132:46:1;:15;:46;9114:64;;9346:19;9340:4;9333:33;9396:8;9390:4;9383:22;9452:7;9445:4;9439;9429:21;9422:38;9599:8;9552:45;9549:1;9546;9541:67;9248:374;9021:617::o;9138:415:7:-;9291:13;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;9328:20:7::1;9341:6;9328:12;:20::i;:::-;9320:28;;9363:9;9358:148;9374:19:::0;;::::1;9358:148;;;9414:81;9442:5:::0;965:42:::1;9465:10;24939:1:::0;24935:9;;;24921:24;;24908:38;9414:27:::1;:81::i;:::-;9395:3;;9358:148;;;;9515:31;10127:109:2::0;21010:407:7;21076:14;21165:15;21183:25;21202:5;21183:18;:25::i;:::-;21165:43;;21218:21;21242:17;21251:7;21242:8;:17::i;:::-;21218:41;;21387:5;-1:-1:-1;;;;;21361:31:7;:22;21369:13;21361:7;:22::i;:::-;-1:-1:-1;;;;;21361:31:7;;21357:53;;21403:7;21394:16;;21357:53;21092:325;;21010:407;;;:::o;2303:145:6:-;12517:13:1;:11;:13::i;:::-;2380:16:6::1;::::0;-1:-1:-1;;;2380:16:6;::::1;;;2376:37;;;2405:8;;-1:-1:-1::0;;;2405:8:6::1;;;;;;;;;;;2376:37;2423:10;:18:::0;;-1:-1:-1;;;;;2423:18:6;;::::1;-1:-1:-1::0;;;2423:18:6::1;-1:-1:-1::0;;;;;;2423:18:6;;::::1;::::0;;;::::1;::::0;;2303:145::o;10512:152:7:-;10582:13;10615:42;10638:10;10650:6;10615:22;:42::i;13705:198:3:-;13802:26;13815:4;13821:2;13825;13802:12;:26::i;:::-;38367:14;;13838:58;;;13856:40;13879:4;13885:2;13889;13856:40;;;;;;;;;;;;:22;:40::i;9856:125:2:-;12517:13:1;:11;:13::i;:::-;9949:25:2::1;9962:4;9968:5;9949:12;:25::i;11786:359:7:-:0;11921:7;11944:13;11960:15;11968:6;11960:7;:15::i;:::-;11944:31;-1:-1:-1;;;;;;11989:19:7;;11985:33;;-1:-1:-1;12017:1:7;;11786:359;-1:-1:-1;;11786:359:7:o;11985:33::-;1207:8;12088:33;965:42;12115:5;12088:10;:33::i;:::-;:40;12059:26;824:42;12079:5;12059:10;:26::i;:::-;:69;;11786:359;-1:-1:-1;;;11786:359:7:o;9720:456:1:-;9922:19;9916:4;9909:33;9968:8;9962:4;9955:22;10020:1;10013:4;10007;9997:21;9990:32;10151:8;10105:44;10102:1;10099;10094:66;9720:456::o;6199:118:7:-;14166:7:2;11991:25;12010:5;11991:18;:25::i;:::-;6296:8:7::1;:14;6307:3:::0;;6296:8;:14:::1;:::i;:::-;;6199:118:::0;;;:::o;6564:197::-;14166:7:2;11991:25;12010:5;11991:18;:25::i;:::-;6714:5:7::1;:13;6722:5:::0;;6714;:13:::1;:::i;:::-;-1:-1:-1::0;6737:7:7::1;:17;6747:7:::0;;6737;:17:::1;:::i;:::-;;6564:197:::0;;;;;:::o;8035:113::-;8082:13;8115:26;8130:10;8115:14;:26::i;:::-;8107:34;;8035:113;:::o;6957:332:3:-;7015:14;7050:12;7059:2;7050:8;:12::i;:::-;7041:21;;7148:6;7138:135;;7187:10;7181:4;7174:24;7254:4;7248;7241:18;7138:135;6957:332;;;:::o;7433:533::-;7496:14;7656:5;7646:143;;7694:10;7688:4;7681:24;7770:4;7764;7757:18;7646:143;-1:-1:-1;;;7809:4:3;7802:38;7866:5;7860:4;7853:19;7929:20;7921:4;7915;7905:21;7899:28;7895:55;7885:65;;7433:533;;;:::o;8762:100:1:-;12517:13;:11;:13::i;:::-;8834:21:::1;8852:1;8834:9;:21::i;:::-;8762:100::o:0;21536:140:7:-;21599:7;21641:26;21649:17;21658:7;21649:8;:17::i;:::-;21641:7;:26::i;4142:102::-;4198:13;4230:7;4223:14;;;;;:::i;10032:382::-;10161:13;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;10198:19:7::1;10206:10;10198:7;:19::i;:::-;10190:27:::0;-1:-1:-1;;;;;;10257:19:7;::::1;10253:56;;10285:24;;-1:-1:-1::0;;;10285:24:7::1;;;;;;;;;;;10253:56;10319:55;10347:5;824:42;10363:2;10367:6;10319:27;:55::i;:::-;2021:1:5::0;1997:22;1990:33;10032:382:7;;;;:::o;9667:726:3:-;9882:10;9875:18;9868:26;9854:40;;9991:8;9985:4;9978:22;10026:31;10020:4;10013:45;10084:8;10078:4;10071:22;10136:10;10129:4;10123;10113:21;10106:41;10221:10;10215:4;10208:24;10366:8;10362:2;10358:17;10354:2;10350:26;10340:8;10305:33;10299:4;10293;10288:89;9667:726;;:::o;11349:209:7:-;11463:13;11500:51;11530:10;11542:8;;11500:29;:51::i;:::-;11492:59;11349:209;-1:-1:-1;;;11349:209:7:o;21962:571::-;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;22048:13:7::1;22064:19;22072:10;22064:7;:19::i;:::-;22048:35:::0;-1:-1:-1;;;;;;22097:19:7;::::1;22093:56;;22125:24;;-1:-1:-1::0;;;22125:24:7::1;;;;;;;;;;;22093:56;22293:15;22311:25;22330:5;22311:18;:25::i;:::-;22293:43:::0;-1:-1:-1;22421:48:7::1;22293:43:::0;24180:9;;24173:17;22421:13:::1;:48::i;:::-;22509:7;22484:42;22518:7;22484:42;;;;470:14:8::0;463:22;445:41;;433:2;418:18;;305:187;22484:42:7::1;;;;;;;;22038:495;;2021:1:5::0;1997:22;1990:33;21962:571:7;:::o;8807:151::-;8876:13;8909:42;8932:10;8944:6;8909:22;:42::i;2171:91:6:-;12517:13:1;:11;:13::i;:::-;2232:16:6::1;:23:::0;;-1:-1:-1;;;;2232:23:6::1;-1:-1:-1::0;;;2232:23:6::1;::::0;;2171:91::o;14406:249:3:-;14552:26;14565:4;14571:2;14575;14552:12;:26::i;:::-;38367:14;;14588:60;;;14606:42;14629:4;14635:2;14639;14643:4;;14606:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14606:22:3;;-1:-1:-1;;;14606:42:3:i;:::-;14406:249;;;;;:::o;20488:411:7:-;20552:14;20641:15;20659:25;20678:5;20659:18;:25::i;:::-;20641:43;;20694:21;20718:17;20727:7;20718:8;:17::i;:::-;20694:41;;20863:5;-1:-1:-1;;;;;20837:31:7;:22;20845:13;20837:7;:22::i;:::-;-1:-1:-1;;;;;20837:31:7;;20833:59;;20879:13;20488:411;-1:-1:-1;;;20488:411:7:o;4350:1382::-;4418:20;4455:11;4463:2;15636:11:3;15725:16;;;-1:-1:-1;;;15761:4:3;15754:38;15875:4;15859:21;;15851:30;;15843:39;15837:46;15833:2;15829:55;15822:63;15815:71;;15576:326;4455:11:7;4450:44;;4475:19;;-1:-1:-1;;;4475:19:7;;;;;;;;;;;4450:44;4505:16;4524:17;-1:-1:-1;;;;;4524:17:7;4623:22;;4619:1107;;4751:4;4745:11;4735:21;;4786:10;4780:4;4773:24;4851:2;4845:4;4838:16;4927:4;4921;4915;4909;4899:8;4892:5;4881:51;4871:202;;4985:16;4979:4;4971:6;4956:46;5038:16;5030:6;5023:32;4871:202;5117:4;5111;5105;5090:32;5223:4;5216;5210:11;5202:6;5187:41;5343:6;5337:13;5330:4;5323;5317:11;5313:22;5306:4;5298:6;5294:17;5279:72;5428:6;5422:13;5415:4;5407:6;5403:17;5399:37;5465:1;5460:3;5453:14;5544:4;5539:3;5535:14;5529:4;5522:28;;4619:1107;;;5610:8;5604:22;;;;;:::i;:::-;:27;;-1:-1:-1;5600:126:7;;5656:59;5674:8;5656:59;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;;5656:59:7;;;5692:22;5711:2;5692:18;:22::i;:::-;5656:17;:59::i;:::-;5647:68;;5600:126;4440:1292;4350:1382;;;:::o;9732:208::-;9845:13;9882:51;9912:10;9924:8;;9882:29;:51::i;10363:708:1:-;12517:13;:11;:13::i;:::-;10597:19:::1;10591:4;10584:33;10643:12;10637:4;10630:26;10705:4;10699;10689:21;10811:12;10805:19;10792:11;10789:36;10786:157;;;10857:10;10851:4;10844:24;10924:4;10918;10911:18;10786:157;11020:1;10999:23:::0;;11041::::1;11051:12:::0;11041:9:::1;:23::i;8348:349::-:0;12517:13;:11;:13::i;:::-;8520:8:::1;8516:2;8512:17;8502:150;;8562:10;8556:4;8549:24;8633:4;8627;8620:18;8502:150;8671:19;8681:8;8671:9;:19::i;8325:308:7:-:0;8458:13;1706:22:5;1700:29;1697:143;;;1761:10;1755:4;1748:24;1821:4;1815;1808:18;1697:143;1884:9;1860:22;1853:41;8495:20:7::1;8508:6;8495:12;:20::i;:::-;8487:28;;8525:60;8550:5;824:42;8566:10;8578:6;8525:24;:60::i;:::-;8595:31;10127:109:2::0;6374:138:7;14166:7:2;11991:25;12010:5;11991:18;:25::i;:::-;-1:-1:-1;6477:17:7::1;:28:::0;;-1:-1:-1;;;;;;6477:28:7::1;-1:-1:-1::0;;;;;6477:28:7;;;::::1;::::0;;;::::1;::::0;;6374:138::o;17011:301:3:-;-1:-1:-1;;;17173:4:3;17166:38;;;17074:14;17217:19;;;;17283:4;17273:21;17267:28;17263:2;17259:37;;17011:301::o;29039:1442::-;29222:1;29218:6;29214:2;29210:15;29269:7;29253:14;29249:28;29238:39;;29316:2;29300:14;29296:23;29290:29;;29389:2;29383:4;29376:16;29447:2;-1:-1:-1;;;29418:32:3;29412:4;29405:46;29517:4;29511;29501:21;29497:2;29493:30;29489:2;29485:39;29576:13;29570:20;29554:14;29550:41;29537:54;;29665:5;29655:134;;29703:10;29697:4;29690:24;29770:4;29764;29757:18;29655:134;29972:5;29968:2;29965:13;29960:2;29953:10;29950:29;29940:280;;30012:5;30006:4;29999:19;30067:4;30061;30051:21;30045:28;30035:171;;30110:10;30104:4;30097:24;30183:4;30177;30170:18;30035:171;30314:1;30310:21;30303:38;;;30462:2;30333:7;30446:5;30419:25;30413:4;30401:10;30396:69;;29039:1442;;;:::o;17773:309:7:-;17996:79;18005:5;18012:12;18026:10;18046:5;-1:-1:-1;;;;;17996:79:7;18062:2;-1:-1:-1;;;;;17996:79:7;18067:7;17996:8;:79::i;4304:117:2:-;4382:32;4395:4;4401:5;4408;4382:12;:32::i;12689:1254:7:-;12752:13;12801:14;12809:5;12801:7;:14::i;:::-;12777:40;-1:-1:-1;;;;;;12831:19:7;;;12827:37;;12689:1254;;;:::o;12827:37::-;1844:10:6;;-1:-1:-1;;;1844:10:6;;-1:-1:-1;;;;;1844:10:6;;12941:57:7;;12973:25;;-1:-1:-1;;;12973:25:7;;;;;;;;;;;12941:57;13032:11;13030:13;;-1:-1:-1;;;;;13030:13:7;;;;;;-1:-1:-1;;13030:13:7;;;;;;;;13095:48;13125:5;13030:13;13012:15;13095:29;:48::i;:::-;13402:334;13444:5;13545:1;13605:13;13658:4;13701:7;13402:24;:334::i;:::-;13394:342;;13784:5;-1:-1:-1;;;;;13755:35:7;13775:7;13768:5;-1:-1:-1;;;;;13755:35:7;;;;;;;;;;;13896:30;13904:5;13919;-1:-1:-1;;;;;13896:30:7;:7;:30::i;7292:355:1:-;-1:-1:-1;;7498:18:1;7488:8;7485:32;7475:156;;7550:10;7544:4;7537:24;7612:4;7606;7599:18;4053:115:2;4130:31;4143:4;4149:5;4156:4;4130:12;:31::i;22976:554:7:-;23125:11;23133:2;23125:7;:11::i;:::-;-1:-1:-1;;;;;23125:16:7;;23121:53;;23150:24;;-1:-1:-1;;;23150:24:7;;;;;;;;;;;23121:53;-1:-1:-1;;;;;23188:18:7;;;23184:340;;18232:13:3;18323:16;;;-1:-1:-1;;;18359:4:3;18352:38;18460:4;18444:21;;18436:30;;18428:39;;18422:46;18417:3;18413:56;23226:27:7;;23222:66;;23262:26;;-1:-1:-1;;;23262:26:7;;;;;;;;;;;23222:66;23302:25;23316:7;23325:1;23302:13;:25::i;:::-;23385:26;23393:2;23397:13;23405:4;23397:7;:13::i;:::-;23385:7;:26::i;:::-;23460:16;23468:4;23474:1;23460:7;:16::i;16623:989::-;16874:4;16868:11;16939:7;16933:4;16926:21;17006:5;17000:4;16993:19;17074:4;17070:2;17066:13;17060:4;17053:27;-1:-1:-1;;;17130:4:7;17123:48;17346:4;17340;17334;17328;17325:1;17311:12;17304:5;17299:52;17289:181;;17395:16;17389:4;17386:1;17371:41;17439:16;17436:1;17429:27;17289:181;17496:1;17490:4;17483:15;17552:4;17545:15;-1:-1:-1;;;;16623:989:7:o;10486:225:0:-;10537:14;10656:4;10650;10644;10641:1;10629:32;-1:-1:-1;;10690:4:0;10684:11;;10486:225::o;16037:323:3:-;16098:14;16190:16;;;-1:-1:-1;;;16226:4:3;16219:38;16334:4;16318:21;;16310:30;;16302:39;16296:46;-1:-1:-1;;;;;16280:64:3;;16037:323::o;38588:1370::-;38825:4;38819:11;38875:10;38908:24;38905:1;38898:35;38967:8;38960:4;38957:1;38953:12;38946:30;39075:4;39071:2;39067:13;39063:2;39059:22;39052:4;39049:1;39045:12;39038:44;39116:2;39109:4;39106:1;39102:12;39095:24;39153:4;39146;39143:1;39139:12;39132:26;39186:4;39180:11;39225:1;39218:4;39215:1;39211:12;39204:23;39243:1;39240:71;;;39306:1;39299:4;39296:1;39292:12;39289:1;39282:4;39276;39272:15;39269:1;39262:5;39251:57;39247:62;39240:71;39427:4;39424:1;39417:4;39414:1;39410:12;39403:4;39400:1;39396:12;39393:1;39389:2;39382:5;39377:55;39367:313;;39455:16;39452:214;;;39583:16;39577:4;39574:1;39559:41;39631:16;39628:1;39621:27;39452:214;39367:313;39776:24;39771:3;39767:34;39763:1;39757:8;39754:48;39744:198;;39835:10;39829:4;39822:24;39923:4;39917;39910:18;19383:740:7;19458:14;19563:7;19557:4;19550:21;-1:-1:-1;;;19624:4:7;19617:48;20062:4;20056;20050;20044;20037:5;20030;20019:48;19957:4;19939:16;19936:26;19847:242;19820:4;19814:11;19729:378;19703:404;;19383:740;;;;:::o;5219:802:2:-;-1:-1:-1;;5507:27:2;5497:8;5494:41;5484:521;;5610:15;5604:4;5597:29;5656:8;5650:4;5643:22;5859:5;5851:4;5845;5835:21;5829:28;5825:40;5815:176;;5902:10;5896:4;5889:24;5968:4;5962;5955:18;6145:1089:1;-1:-1:-1;;6579:16:1;;-1:-1:-1;;;;;6427:26:1;;;;;;6539:38;6536:1;;6528:78;6703:16;;6698:3;6694:26;6681:40;;6663:59;;10127:109:2;:::o;15928:282:7:-;16132:71;16141:5;16148:9;16159:10;16179:2;-1:-1:-1;;;;;16132:71:7;16192:6;-1:-1:-1;;;;;16132:71:7;16201:1;16132:8;:71::i;18689:432:3:-;18844:2;18838:4;18831:16;-1:-1:-1;;;18867:4:3;18860:38;18964:4;18958;18948:21;18944:2;18940:30;18936:2;18932:39;19004:13;18998:20;19094:6;19089:3;19085:16;19078:5;19074:28;19069:3;19065:38;19057:6;19053:51;19038:13;19031:74;;;18689:432;;:::o;1946:1641:4:-;2002:17;2447:4;2440;2434:11;2430:22;2423:29;;2546:4;2541:3;2537:14;2531:4;2524:28;2627:1;2622:3;2615:14;2728:3;2758:1;2754:6;2967:5;2949:402;3005:11;;;;3186:2;3200;3190:13;;3182:22;3005:11;3169:36;3292:2;3282:13;;3312:25;2949:402;3312:25;-1:-1:-1;;3379:13:4;;;-1:-1:-1;;3492:14:4;;;3552:19;;;3492:14;1946:1641;-1:-1:-1;1946:1641:4:o;19186:3338::-;19322:20;19451:7;19445:14;19498:6;19492:13;19549:11;19543:18;19599:4;19590:7;19586:18;19575:29;;19639:4;19631:6;19627:17;19617:27;;19689:4;19676:11;19672:22;19657:37;;19734:4;19727;19721:11;19717:22;19707:32;;19784:13;19775:7;19771:27;19838:13;19824:12;19821:31;19811:1966;;19931:1;19916:12;19904:10;19900:29;19896:37;19959:1;20004:4;19990:12;19987:22;19977:74;;-1:-1:-1;20018:31:4;;;19977:74;20112:4;20098:12;20094:23;20088:4;20084:34;20081:1;20077:42;20151:6;20145:13;20175:1588;20224:7;20218:14;20402:1;20399;20395:9;20392:1;20388:17;20378:1166;;20436:1;20433:433;;;20515:1;20500:12;20491:7;20481:32;20478:39;20468:372;;20553:17;;;20625:1;20671:15;;;;20613:14;;;;20729:29;;;20719:50;;20762:5;;;20719:50;20802:8;20175:1588;;20468:372;20976:1;20961:250;21044:19;;;21038:26;21022:14;;;21015:50;21106:4;21099:12;21150:24;;;20961:250;21140:45;-1:-1:-1;21312:26:4;;;;21246:30;;;;21363:159;;;;21431:16;21422:7;21419:29;21409:50;;21452:5;;;21363:159;21565:17;;21625:1;21659:15;;;;21613:14;;;;21705:29;;;20175:1588;21695:50;20175:1588;20179:2;;;;19811:1966;21814:6;21791:29;;21860:4;21853;21847:11;21843:22;21833:32;;21937:7;21925:10;21921:24;21912:6;21895:15;21891:28;21887:59;21878:68;;22022:213;22041:10;22032:7;22029:23;22022:213;;;22098:14;;22074:39;;22170:4;22203:18;;;;22149:26;;;;22022:213;;;-1:-1:-1;;22304:17:4;22300:25;;;22376:15;;;22270:4;22417:15;22411:4;22404:29;-1:-1:-1;;22258:17:4;;;22470;;;-1:-1:-1;22258:17:4;19186:3338;-1:-1:-1;;;19186:3338:4:o;18229:1017:7:-;18502:4;18496:11;18541:6;18534:4;18531:1;18527:12;18520:28;-1:-1:-1;;;18568:1:7;18561:45;18683:1;18676:4;18673:1;18669:12;18662:23;18731:4;18724;18721:1;18717:12;18710:26;18791:1;18784:4;18781:1;18777:12;18770:23;18843:10;18836:4;18833:1;18829:12;18822:32;18888:4;18881;18878:1;18874:12;18867:26;18927:4;18920;18917:1;18913:12;18906:26;18966:4;18959;18956:1;18952:12;18945:26;19005:4;18998;18995:1;18991:12;18984:26;19106:4;19094:10;19087:5;19080:4;19077:1;19073:12;19070:1;19063:5;19056;19051:60;19041:189;;19155:16;19149:4;19146:1;19131:41;19199:16;19196:1;19189:27;19041:189;;18229:1017;;;;;;:::o;2952:967:2:-;3118:15;3112:4;3105:29;3160:4;3154;3147:18;3210:4;3204;3194:21;3288:8;3282:15;3395:5;3386:7;3383:18;3639:2;3629:62;;-1:-1:-1;3669:19:2;;;3656:33;;3629:62;3763:7;3753:8;3746:25;3895:7;3887:4;3881:11;3877:2;3873:20;3841:30;3838:1;3835;3830:73;;;;2952:967;;;:::o;21573:1353:3:-;21677:40;21706:1;21710:2;21714;21677:20;:40::i;:::-;21855:2;21851;21847:11;21843:2;21839:20;21833:26;;21938:2;21932:4;21925:16;-1:-1:-1;;;21961:4:3;21954:38;22073:2;22065:5;22060:3;22056:15;22053:23;22044:4;22038;22028:21;22024:2;22020:30;22016:2;22012:39;22005:72;22172:2;22166:4;22159:16;22227:4;22221;22211:21;22298:1;22284:11;22278:18;22274:26;22450:20;22431:17;22427:44;22423:2;22419:53;22409:268;;22601:18;22595:2;22588:10;22585:1;22581:18;22574:46;22654:4;22648;22641:18;22409:268;22694:38;;22858:2;22854;22851:1;22824:25;22851:1;22806:10;22801:60;10748:2886;;;:::o;4854:1046:0:-;5041:14;5148:4;5142:11;5187:15;5180:4;5177:1;5173:12;5166:37;5237:5;5230:4;5227:1;5223:12;5216:27;5277:8;5270:4;5267:1;5263:12;5256:30;5336:14;5332:2;5328:23;5324:2;5320:32;5313:4;5310:1;5306:12;5299:54;5387:8;5380:4;5377:1;5373:12;5366:30;-1:-1:-1;;;5489:1:0;5482:45;5691:4;5685;5679;5672;5669:1;5665:12;5662:1;5652:8;5645:5;5640:56;5613:4;5595:16;5592:26;5567:147;5540:310;;5760:10;5754:4;5747:24;5831:4;5825;5818:18;5540:310;-1:-1:-1;;5879:4:0;5873:11;;4854:1046;-1:-1:-1;;;;;4854:1046:0:o;17563:407:3:-;-1:-1:-1;;;17710:4:3;17703:38;17767:5;17761:4;17754:19;17821:4;17815;17805:21;17859:11;17853:18;17943:6;17939:2;17935:15;17928:5;17924:27;17920:2;17916:36;17908:6;17904:49;17891:11;17884:70;;;17563:407;;:::o;14:286:8:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:8;;209:43;;199:71;;266:1;263;256:12;497:418;646:2;635:9;628:21;609:4;678:6;672:13;721:6;716:2;705:9;701:18;694:34;780:6;775:2;767:6;763:15;758:2;747:9;743:18;737:50;836:1;831:2;822:6;811:9;807:22;803:31;796:42;906:2;899;895:7;890:2;882:6;878:15;874:29;863:9;859:45;855:54;847:62;;;497:418;;;;:::o;920:173::-;988:20;;-1:-1:-1;;;;;1037:31:8;;1027:42;;1017:70;;1083:1;1080;1073:12;1098:186;1157:6;1210:2;1198:9;1189:7;1185:23;1181:32;1178:52;;;1226:1;1223;1216:12;1178:52;1249:29;1268:9;1249:29;:::i;1497:180::-;1556:6;1609:2;1597:9;1588:7;1584:23;1580:32;1577:52;;;1625:1;1622;1615:12;1577:52;-1:-1:-1;1648:23:8;;1497:180;-1:-1:-1;1497:180:8:o;1682:254::-;1750:6;1758;1811:2;1799:9;1790:7;1786:23;1782:32;1779:52;;;1827:1;1824;1817:12;1779:52;1850:29;1869:9;1850:29;:::i;:::-;1840:39;1926:2;1911:18;;;;1898:32;;-1:-1:-1;;;1682:254:8:o;1941:367::-;2004:8;2014:6;2068:3;2061:4;2053:6;2049:17;2045:27;2035:55;;2086:1;2083;2076:12;2035:55;-1:-1:-1;2109:20:8;;-1:-1:-1;;;;;2141:30:8;;2138:50;;;2184:1;2181;2174:12;2138:50;2221:4;2213:6;2209:17;2197:29;;2281:3;2274:4;2264:6;2261:1;2257:14;2249:6;2245:27;2241:38;2238:47;2235:67;;;2298:1;2295;2288:12;2235:67;1941:367;;;;;:::o;2313:511::-;2408:6;2416;2424;2477:2;2465:9;2456:7;2452:23;2448:32;2445:52;;;2493:1;2490;2483:12;2445:52;2516:29;2535:9;2516:29;:::i;:::-;2506:39;;2596:2;2585:9;2581:18;2568:32;-1:-1:-1;;;;;2615:6:8;2612:30;2609:50;;;2655:1;2652;2645:12;2609:50;2694:70;2756:7;2747:6;2736:9;2732:22;2694:70;:::i;:::-;2313:511;;2783:8;;-1:-1:-1;2668:96:8;;-1:-1:-1;;;;2313:511:8:o;3011:328::-;3088:6;3096;3104;3157:2;3145:9;3136:7;3132:23;3128:32;3125:52;;;3173:1;3170;3163:12;3125:52;3196:29;3215:9;3196:29;:::i;:::-;3186:39;;3244:38;3278:2;3267:9;3263:18;3244:38;:::i;:::-;3234:48;;3329:2;3318:9;3314:18;3301:32;3291:42;;3011:328;;;;;:::o;3344:348::-;3396:8;3406:6;3460:3;3453:4;3445:6;3441:17;3437:27;3427:55;;3478:1;3475;3468:12;3427:55;-1:-1:-1;3501:20:8;;-1:-1:-1;;;;;3533:30:8;;3530:50;;;3576:1;3573;3566:12;3530:50;3613:4;3605:6;3601:17;3589:29;;3665:3;3658:4;3649:6;3641;3637:19;3633:30;3630:39;3627:59;;;3682:1;3679;3672:12;3697:411;3768:6;3776;3829:2;3817:9;3808:7;3804:23;3800:32;3797:52;;;3845:1;3842;3835:12;3797:52;3885:9;3872:23;-1:-1:-1;;;;;3910:6:8;3907:30;3904:50;;;3950:1;3947;3940:12;3904:50;3989:59;4040:7;4031:6;4020:9;4016:22;3989:59;:::i;:::-;4067:8;;3963:85;;-1:-1:-1;3697:411:8;-1:-1:-1;;;;3697:411:8:o;4113:721::-;4205:6;4213;4221;4229;4282:2;4270:9;4261:7;4257:23;4253:32;4250:52;;;4298:1;4295;4288:12;4250:52;4338:9;4325:23;-1:-1:-1;;;;;4408:2:8;4400:6;4397:14;4394:34;;;4424:1;4421;4414:12;4394:34;4463:59;4514:7;4505:6;4494:9;4490:22;4463:59;:::i;:::-;4541:8;;-1:-1:-1;4437:85:8;-1:-1:-1;4629:2:8;4614:18;;4601:32;;-1:-1:-1;4645:16:8;;;4642:36;;;4674:1;4671;4664:12;4642:36;;4713:61;4766:7;4755:8;4744:9;4740:24;4713:61;:::i;:::-;4113:721;;;;-1:-1:-1;4793:8:8;-1:-1:-1;;;;4113:721:8:o;5044:160::-;5109:20;;5165:13;;5158:21;5148:32;;5138:60;;5194:1;5191;5184:12;5209:254;5274:6;5282;5335:2;5323:9;5314:7;5310:23;5306:32;5303:52;;;5351:1;5348;5341:12;5303:52;5374:29;5393:9;5374:29;:::i;:::-;5364:39;;5422:35;5453:2;5442:9;5438:18;5422:35;:::i;:::-;5412:45;;5209:254;;;;;:::o;5468:437::-;5554:6;5562;5615:2;5603:9;5594:7;5590:23;5586:32;5583:52;;;5631:1;5628;5621:12;5583:52;5671:9;5658:23;-1:-1:-1;;;;;5696:6:8;5693:30;5690:50;;;5736:1;5733;5726:12;5690:50;5775:70;5837:7;5828:6;5817:9;5813:22;5775:70;:::i;5910:180::-;5966:6;6019:2;6007:9;5998:7;5994:23;5990:32;5987:52;;;6035:1;6032;6025:12;5987:52;6058:26;6074:9;6058:26;:::i;6095:627::-;6192:6;6200;6208;6216;6224;6277:3;6265:9;6256:7;6252:23;6248:33;6245:53;;;6294:1;6291;6284:12;6245:53;6317:29;6336:9;6317:29;:::i;:::-;6307:39;;6365:38;6399:2;6388:9;6384:18;6365:38;:::i;:::-;6355:48;;6450:2;6439:9;6435:18;6422:32;6412:42;;6505:2;6494:9;6490:18;6477:32;-1:-1:-1;;;;;6524:6:8;6521:30;6518:50;;;6564:1;6561;6554:12;6518:50;6603:59;6654:7;6645:6;6634:9;6630:22;6603:59;:::i;:::-;6095:627;;;;-1:-1:-1;6095:627:8;;-1:-1:-1;6681:8:8;;6577:85;6095:627;-1:-1:-1;;;6095:627:8:o;6727:260::-;6795:6;6803;6856:2;6844:9;6835:7;6831:23;6827:32;6824:52;;;6872:1;6869;6862:12;6824:52;6895:29;6914:9;6895:29;:::i;:::-;6885:39;;6943:38;6977:2;6966:9;6962:18;6943:38;:::i;6992:380::-;7071:1;7067:12;;;;7114;;;7135:61;;7189:4;7181:6;7177:17;7167:27;;7135:61;7242:2;7234:6;7231:14;7211:18;7208:38;7205:161;;7288:10;7283:3;7279:20;7276:1;7269:31;7323:4;7320:1;7313:15;7351:4;7348:1;7341:15;7377:127;7438:10;7433:3;7429:20;7426:1;7419:31;7469:4;7466:1;7459:15;7493:4;7490:1;7483:15;7635:518;7737:2;7732:3;7729:11;7726:421;;;7773:5;7770:1;7763:16;7817:4;7814:1;7804:18;7887:2;7875:10;7871:19;7868:1;7864:27;7858:4;7854:38;7923:4;7911:10;7908:20;7905:47;;;-1:-1:-1;7946:4:8;7905:47;8001:2;7996:3;7992:12;7989:1;7985:20;7979:4;7975:31;7965:41;;8056:81;8074:2;8067:5;8064:13;8056:81;;;8133:1;8119:16;;8100:1;8089:13;8056:81;;8329:1198;-1:-1:-1;;;;;8448:3:8;8445:27;8442:53;;;8475:18;;:::i;:::-;8504:94;8594:3;8554:38;8586:4;8580:11;8554:38;:::i;:::-;8548:4;8504:94;:::i;:::-;8624:1;8649:2;8644:3;8641:11;8666:1;8661:608;;;;9313:1;9330:3;9327:93;;;-1:-1:-1;9386:19:8;;;9373:33;9327:93;-1:-1:-1;;8286:1:8;8282:11;;;8278:24;8274:29;8264:40;8310:1;8306:11;;;8261:57;9433:78;;8634:887;;8661:608;7582:1;7575:14;;;7619:4;7606:18;;-1:-1:-1;;8697:17:8;;;8812:229;8826:7;8823:1;8820:14;8812:229;;;8915:19;;;8902:33;8887:49;;9022:4;9007:20;;;;8975:1;8963:14;;;;8842:12;8812:229;;;8816:3;9069;9060:7;9057:16;9054:159;;;9193:1;9189:6;9183:3;9177;9174:1;9170:11;9166:21;9162:34;9158:39;9145:9;9140:3;9136:19;9123:33;9119:79;9111:6;9104:95;9054:159;;;9256:1;9250:3;9247:1;9243:11;9239:19;9233:4;9226:33;8634:887;;8329:1198;;;:::o

Swarm Source

ipfs://7b184e74ca114f5efbf54d0fbe4087ef6dba4ce52b7914fe01c91add502a40dc
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.