ERC-721
Overview
Max Total Supply
0 q00tants
Holders
5
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
4 q00tantsLoading...
Loading
Loading...
Loading
Loading...
Loading
Contract Source Code Verified (Exact Match)
Contract Name:
Q00tantShadow
Compiler Version
v0.8.28+commit.7893614a
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; import {NFTShadow} from "../NFTShadow.sol"; /** * @title Q00tantShadow */ contract Q00tantShadow is NFTShadow { constructor() NFTShadow(0x000000000000F87b8230c9233b00474eda1E1b3b) { initialize( 0xe880c31C8118103aB49B604E281283E489a69780, "Q00tants", "q00tants", "", 0x7Df5c32827f0Fa448392Ce58231Ce4f378ce56e5, address(0), 0 ); } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; import {ERC721} from "solady/tokens/ERC721.sol"; import {LibString} from "solady/utils/LibString.sol"; import {OwnableRoles} from "solady/auth/OwnableRoles.sol"; import {ERC2981} from "solady/tokens/ERC2981.sol"; import {IERC5192} from "./interfaces/IERC5192.sol"; import {IBeacon} from "./interfaces/IBeacon.sol"; import {ICreatorToken} from "./interfaces/ICreatorToken.sol"; import {ITransferValidator} from "./interfaces/ITransferValidator.sol"; import {IShadowCallbackReceiver} from "./interfaces/IShadowCallbackReceiver.sol"; /** * @title NFTShadow * @author @0xQuit * @notice A contract for soulbound Shadow NFTs that follow ownership on a remote chain. * @notice This contract is designed to be used with a Beacon contract (see IBeacon.sol) to maintain ownership records * through LayerZero's lzRead protocol. * @notice Soulbound tokens can be unlocked by locking them on their source chain. * @notice Contracts have shadow mode disabled by default. In this state, they function very much like a typical oNFT. They * can be minted by locking the native asset, and the native asset can be unlocked by burning the Shadow NFT. * @notice When tokens are locked, ONLY the Beacon contract can transfer them. They will follow the canonical owner, * as resolved by the ExclusiveDelegateResolver (the "Resolver") contract. Users should only issue Resolver compatible * delegations for assets if they own the delegatee. Though the delegatee can not claim ownership of the underlying asset, * they may be able to claim airdrops, participate in activations, or otherwise interact with the asset using the Shadow NFT. */ contract NFTShadow is ERC721, ERC2981, IERC5192, ICreatorToken, OwnableRoles { // Only the Beacon contract can perform admin actions when a token is in Shadow mode error CallerNotBeacon(); // ERC-4906 BatchMetadataUpdate event event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); // The token is currently in Shadow mode error TokenLocked(); // The token is not in Shadow mode error TokenNotLocked(); // The function selector is not recognized error FnSelectorNotRecognized(); // Emitted when a new metadata renderer is set event MetadataRendererSet(address indexed metadataRenderer); // Emitted when shadow mode is enabled event ShadowModeEnabled(); // The address of the Beacon contract address public immutable BEACON_CONTRACT_ADDRESS; // Admin management roles uint256 public constant SHADOW_MODE_MANAGER_ROLE = _ROLE_13; uint256 public constant METADATA_MANAGER_ROLE = _ROLE_42; uint256 public constant TRANSFER_VALIDATOR_MANAGER_ROLE = _ROLE_69; uint256 public constant ROYALTY_MANAGER_ROLE = _ROLE_88; // The address of the ERC721C transfer validator, address(0) for none address public transferValidator; // Mapping to store callback target for each GUID mapping(bytes32 guid => address callbackTarget) public callbacks; // _extraData flags to indicate if a token is in Shadow mode (locked) or not (unlocked) uint96 private constant LOCKED = 0; uint96 private constant UNLOCKED = 1; // The base URI for the token metadata string private _baseTokenUri; // The name of the collection string private _name; // The symbol of the collection string private _symbol; // The address of the MetadataRenderer contract (address(0) if not set) address public metadataRenderer; // If false, the token can only be minted by locking it on the source chain bool public shadowModeEnabled; /** * @param _beaconContract The address of the Beacon contract */ constructor(address _beaconContract) { BEACON_CONTRACT_ADDRESS = _beaconContract; } /// @dev Fallback function for calls from Beacon contract. fallback() external { _shadowFallback(); } /** * @notice Initializes the NFTShadow contract. * @param _initialOwner The address of the initial owner. * @param _collectionName The name of the collection. * @param _collectionSymbol The symbol of the collection. * @param _baseTokenURI The base URI for the token metadata. * @param _metadataRenderer The address of the MetadataRenderer contract. * @param _transferValidator The address of the transfer validator. * @param _royaltyFeeNumerator The ERC2981 royalty fee numerator. */ function initialize( address _initialOwner, string memory _collectionName, string memory _collectionSymbol, string memory _baseTokenURI, // can be left empty if metadataRenderer is set address _metadataRenderer, // address(0) if not set address _transferValidator, uint96 _royaltyFeeNumerator ) public { _baseTokenUri = _baseTokenURI; _name = _collectionName; _symbol = _collectionSymbol; metadataRenderer = _metadataRenderer; _initializeOwner(_initialOwner); transferValidator = _transferValidator; _setDefaultRoyalty(_initialOwner, _royaltyFeeNumerator); } /** * @notice Transfers a token from one address to another. * @param from The address of the sender. * @param to The address of the recipient. * @param tokenId The token ID to transfer. * @dev If the token is locked, only the Beacon contract can transfer it. * @dev If the token is unlocked, only the owner or approved address can transfer it. */ function transferFrom(address from, address to, uint256 tokenId) public payable override { if (msg.sender == BEACON_CONTRACT_ADDRESS) { if (_getExtraData(tokenId) == UNLOCKED) revert TokenNotLocked(); _transfer(address(0), from, to, tokenId); } else { super.transferFrom(from, to, tokenId); } } /** * @notice Triggers an ownership update for the tokens. * @param tokenIds The token IDs to update ownership for. * @param eids The EIDs to read ownership from. If token is locked on the provided EID, no update will occur. */ function read(uint256[] calldata tokenIds, uint32[] calldata eids) public payable returns (bytes32) { return _read(tokenIds, eids, 0); } /** * @notice Triggers an ownership update with custom options. Helpful if a component of the update or callback is particularly expensive. * @param tokenIds The token IDs to update ownership for. * @param eids The EIDs to read ownership from. If token is locked on the provided EID, no update will occur. * @param callbackGasLimit The gas limit for the callback. * @return guid The GUID of the callback. * @dev Any excess fees provided to LayerZero will be returned to the caller. Potential callers are responsible for ensuring * that they are able to receive native tokens. */ function readWithCallback(uint256[] calldata tokenIds, uint32[] calldata eids, uint128 callbackGasLimit) external payable returns (bytes32) { bytes32 guid = _read(tokenIds, eids, callbackGasLimit); callbacks[guid] = msg.sender; return guid; } /** * @notice Unlocks and sends tokens to the beneficiary on the specified EID. * @param dstEid The EID to unlock and send the tokens on. * @param tokenIds The token IDs to unlock and send. * @param beneficiary The address of the recipient on the target chain. * @param refundRecipient The address to refund the native fee to. * @param supplementalGasLimit The gas limit for the callback. * @dev Must be owner or approved, and the token must be unlocked (not in Shadow mode). Tokens released on the target chain will be locked on this chain. */ function send( uint32 dstEid, uint256[] calldata tokenIds, address beneficiary, address refundRecipient, uint128 supplementalGasLimit ) external payable { for (uint256 i = 0; i < tokenIds.length; i++) { if (!_isApprovedOrOwner(msg.sender, tokenIds[i])) revert NotOwnerNorApproved(); if (_locked(tokenIds[i])) revert TokenLocked(); if (!shadowModeEnabled) { _burn(tokenIds[i]); } _setExtraData(tokenIds[i], LOCKED); emit Locked(tokenIds[i]); } address baseCollectionAddress = IBeacon(BEACON_CONTRACT_ADDRESS).shadowToBase(address(this)); IBeacon(BEACON_CONTRACT_ADDRESS).send{value: msg.value}( dstEid, baseCollectionAddress, tokenIds, beneficiary, refundRecipient, supplementalGasLimit ); } /** * @notice Enables shadow mode for the token. * @dev If shadow mode is enabled, shadows can be minted by the Beacon contract. * @dev Once enabled, shadow mode cannot be disabled. */ function enableShadowMode() external onlyRoles(SHADOW_MODE_MANAGER_ROLE) { shadowModeEnabled = true; } /** * @notice Sets the base URI for the token metadata. * @param uri The base URI for the token metadata. * emits BatchMetadataUpdate event */ function setTokenURI(string memory uri) external onlyRoles(METADATA_MANAGER_ROLE) { _baseTokenUri = uri; emit BatchMetadataUpdate(0, type(uint256).max); } /** * @notice Sets the metadata renderer for the collection. * @param _metadataRenderer The address of the metadata renderer. */ function setMetadataRenderer(address _metadataRenderer) external onlyRoles(METADATA_MANAGER_ROLE) { metadataRenderer = _metadataRenderer; emit MetadataRendererSet(_metadataRenderer); emit BatchMetadataUpdate(0, type(uint256).max); } /** * @notice Sets the transfer validator for the collection. * @param transferValidator_ The address of the transfer validator. * @dev address(0) to disable validation. */ function setTransferValidator(address transferValidator_) external onlyRoles(TRANSFER_VALIDATOR_MANAGER_ROLE) { address oldValidator = transferValidator; transferValidator = transferValidator_; emit TransferValidatorUpdated(oldValidator, transferValidator_); } /** * @dev Sets the ERC2981 royalty information for the token collection. * @param receiver The address of the royalty recipient. * @param feeNumerator The royalty fee numerator. */ function setRoyaltyInfo(address receiver, uint96 feeNumerator) external onlyRoles(ROYALTY_MANAGER_ROLE) { _setDefaultRoyalty(receiver, feeNumerator); } /** * @notice Burns a token. * @param tokenId The token ID. * @dev Only the Beacon contract can burn locked tokens, enforced by _beforeTokenTransfer * @dev If the token is unlocked, the caller must be the owner or approved. */ function burn(uint256 tokenId) external { if (_locked(tokenId)) { _burn(tokenId); } else { _burn(msg.sender, tokenId); } } /** * @notice Executes a callback for the specified GUID. * @param guid The GUID of the callback. */ function executeCallback(bytes32 guid) external { if (msg.sender != BEACON_CONTRACT_ADDRESS) revert CallerNotBeacon(); address callbackTarget = callbacks[guid]; if (callbackTarget == address(0)) return; delete callbacks[guid]; IShadowCallbackReceiver(callbackTarget).executeCallback(guid); } /** * @notice Returns whether the token is locked. * @param tokenId The token ID. * @return bool Whether the token is locked. */ function locked(uint256 tokenId) external view returns (bool) { return _locked(tokenId); } /** * @notice Returns whether the contract supports the specified interface. * @param interfaceId The interface ID. * @return bool Whether the contract supports the interface. * @dev ERC721 and ERC2981 are supported. */ function supportsInterface(bytes4 interfaceId) public view override(ERC721, ERC2981) returns (bool) { return interfaceId == type(IERC5192).interfaceId || ERC721.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId) || interfaceId == bytes4(0x49064906); } /** * @notice Returns the token URI for the specified token ID. * @param id The token ID. * @return The token URI. * @dev If the metadataRenderer is set, it will be used to render the token URI. */ function tokenURI(uint256 id) public view override returns (string memory) { if (!_exists(id)) revert TokenDoesNotExist(); if (metadataRenderer != address(0)) { return ERC721(metadataRenderer).tokenURI(id); } return LibString.concat(_baseTokenUri, LibString.toString(id)); } /** * @notice Returns the name of the collection. * @return _name the name of the collection. */ function name() public view override returns (string memory) { return _name; } /** * @notice Returns the symbol of the collection. * @return _symbol the symbol of the collection. */ function symbol() public view override returns (string memory) { return _symbol; } /** * @notice Returns the token IDs of the tokens owned by the specified owner in a range. * @dev 10k collections should be able to get all their tokens in a single call, larger collections may need pagination. * @dev Intended for offchain use, do not use onchain. * @param owner The address of the owner. * @param start The range start. * @param stop The range stop. * @return array of token IDs owned by the specified owner. */ function tokensOfOwnerIn(address owner, uint256 start, uint256 stop) external view returns (uint256[] memory) { return _tokensOfOwnerIn(owner, start, stop); } /** * @notice Returns the ERC721C transfer validator address. address(0) indicates no validator is set. * @return address The address of the transfer validator. */ function getTransferValidator() external view returns (address) { return transferValidator; } /** * @notice Returns the ERC721C transfer validation function signature and whether it is a view function. * @return functionSignature The 4 byte function signature. * @return isViewFunction Bool indicating if the function is a view function. */ function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) { functionSignature = 0xcaee23ea; isViewFunction = true; } function _read(uint256[] calldata tokenIds, uint32[] calldata dstEids, uint128 callbackGasLimit) internal returns (bytes32) { address baseCollectionAddress = IBeacon(BEACON_CONTRACT_ADDRESS).shadowToBase(address(this)); return IBeacon(BEACON_CONTRACT_ADDRESS).read{value: msg.value}( baseCollectionAddress, tokenIds, dstEids, msg.sender, callbackGasLimit ); } /** * @notice Unlocks the specified token ID. * @param tokenId The token ID to unlock. * @param beneficiary The address of the beneficiary of the unlocked token, in case ownership is stale. * @dev Only the Beacon contract can unlock tokens */ function _unlockToken(uint256 tokenId, address beneficiary) internal { if (_locked(tokenId)) { address owner = _ownerOf(tokenId); // mint if there is no previous owner, otherwise transfer if (owner == address(0)) { _mint(beneficiary, tokenId); } else if (beneficiary != owner) { _transfer(address(0), owner, beneficiary, tokenId); } _setExtraData(tokenId, UNLOCKED); emit Unlocked(tokenId); } else { revert TokenNotLocked(); } } function _tokensOfOwnerIn(address owner, uint256 start, uint256 stop) internal view returns (uint256[] memory) { uint256 numberOfTokens = balanceOf(owner); uint256 tokenIdIdx = 0; uint256[] memory tokenIds = new uint256[](numberOfTokens); for (uint256 i = start; i <= stop; i++) { if (_ownerOf(i) == owner) { tokenIds[tokenIdIdx] = i; unchecked { tokenIdIdx++; } if (tokenIdIdx == numberOfTokens) { return tokenIds; } } } // in case we did not find all the tokens within this start/stop, we need to resize the array uint256[] memory result = new uint256[](tokenIdIdx); for (uint256 i = 0; i < tokenIdIdx; i++) { result[i] = tokenIds[i]; } return result; } // tokens can only be transferred if they are locked on the source chain function _beforeTokenTransfer(address from, address to, uint256 tokenId) internal view override { if (msg.sender != BEACON_CONTRACT_ADDRESS) { if (_locked(tokenId) || from == address(0)) { revert CallerNotBeacon(); } if (transferValidator != address(0)) { ITransferValidator(transferValidator).validateTransfer(msg.sender, from, to, tokenId); } } } function _locked(uint256 tokenId) internal view returns (bool) { return _getExtraData(tokenId) == LOCKED; } function _guardInitializeOwner() internal pure override returns (bool) { return true; } function _calldataload(uint256 offset) internal pure returns (uint256 value) { /// @solidity memory-safe-assembly assembly { value := calldataload(offset) } } function _shadowFallback() internal { uint256 fnSelector = _calldataload(0x00) >> 224; if (fnSelector == 0x40c10f19) { // msg.sender is the Beacon contract, enforced by _beforeTokenTransfer _mint(address(uint160(_calldataload(0x04))), _calldataload(0x24)); } else if (fnSelector == 0x92772833) { if (msg.sender != BEACON_CONTRACT_ADDRESS) revert CallerNotBeacon(); uint256 tokenIdsLength = _calldataload(0x44); address beneficiary = address(uint160(_calldataload(0x24))); for (uint256 i = 0; i < tokenIdsLength; i++) { _unlockToken(_calldataload(0x64 + i * 32), beneficiary); } } else { revert FnSelectorNotRecognized(); } } }
// 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) } } } }
// 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(); /// @dev The input string must be a 7-bit ASCII. error StringNot7BitASCII(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; /// @dev Lookup for '0123456789'. uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; /// @dev Lookup for '0123456789abcdefABCDEF'. uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; /// @dev Lookup for '01234567'. uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; /// @dev Lookup for ' \t\n\r\x0b\x0c'. uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end of the memory to calculate the length later. let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 1)`. // Store the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(result, add(48, mod(temp, 10))) temp := div(temp, 10) // Keep dividing `temp` until zero. if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. mstore(result, n) // Store the length. } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory result) { if (value >= 0) return toString(uint256(value)); unchecked { result = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let n := mload(result) // Load the string length. mstore(result, 0x2d) // Store the '-' character. result := sub(result, 1) // Move back the string pointer by a byte. mstore(result, add(n, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `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 result) { result = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is not prefixed with "0x" and is 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 result) { /// @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. result := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(result, add(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 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(result, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := add(mload(result), 2) // Compute the length. mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := mload(result) // Get the length. result := add(result, o) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory result) { result = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(result, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Allocate memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(result, 0x80)) mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. result := add(result, 2) mstore(result, 40) // Store the length. let o := add(result, 0x20) mstore(add(o, 40), 0) // Zeroize the slot after the string. value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory result) { result = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(raw) result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(result, add(n, n)) // Store the length of the output. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let o := add(result, 0x20) let end := add(raw, n) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 let mask := shl(7, div(not(0), 255)) let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /// @dev Returns if this string is a 7-bit ASCII string, /// AND all characters are in the `allowed` lookup. /// Note: If `s` is empty, returns true regardless of `allowed`. function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if mload(s) { let allowed_ := shr(128, shl(128, allowed)) let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := and(result, shr(byte(0, mload(o)), allowed_)) o := add(o, 1) if iszero(and(result, lt(o, end))) { break } } } } } /// @dev Converts the bytes in the 7-bit ASCII string `s` to /// an allowed lookup for use in `is7BitASCII(s, allowed)`. /// To save runtime gas, you can cache the result in an immutable variable. function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := or(result, shl(byte(0, mload(o)), 1)) o := add(o, 1) if iszero(lt(o, end)) { break } } if shr(128, result) { mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(string memory subject, string memory needle, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let needleLen := mload(needle) let replacementLen := mload(replacement) let d := sub(result, subject) // Memory difference. let i := add(subject, 0x20) // Subject bytes pointer. let end := add(i, mload(subject)) if iszero(gt(needleLen, mload(subject))) { let subjectSearchEnd := add(sub(end, needleLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, needleLen), h)) { mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let j := 0 } 1 {} { mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) j := add(j, 0x20) if iszero(lt(j, replacementLen)) { break } } d := sub(add(d, replacementLen), needleLen) if needleLen { i := add(i, needleLen) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } } let n := add(sub(d, add(result, 0x20)), end) // Copy the rest of the string one word at a time. for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } let o := add(i, d) mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := not(0) // Initialize to `NOT_FOUND`. for { let subjectLen := mload(subject) } 1 {} { if iszero(mload(needle)) { result := from if iszero(gt(from, subjectLen)) { break } result := subjectLen break } let needleLen := mload(needle) let subjectStart := add(subject, 0x20) subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) let m := shl(3, sub(0x20, and(needleLen, 0x1f))) let s := mload(add(needle, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } if iszero(lt(needleLen, 0x20)) { for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, needleLen), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle) internal pure returns (uint256 result) { result = indexOf(subject, needle, 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let needleLen := mload(needle) if gt(needleLen, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), needleLen) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if eq(keccak256(subject, needleLen), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256 result) { result = lastIndexOf(subject, needle, type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(string memory subject, string memory needle) internal pure returns (bool) { return indexOf(subject, needle) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `needle`. function startsWith(string memory subject, string memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let needleLen := mload(needle) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(needleLen, mload(subject))), eq( keccak256(add(subject, 0x20), needleLen), keccak256(add(needle, 0x20), needleLen) ) ) } } /// @dev Returns whether `subject` ends with `needle`. function endsWith(string memory subject, string memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let needleLen := mload(needle) // Whether `needle` is not longer than `subject`. let inRange := iszero(gt(needleLen, mload(subject))) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( eq( keccak256( // `subject + 0x20 + max(subjectLen - needleLen, 0)`. add(add(subject, 0x20), mul(inRange, sub(mload(subject), needleLen))), needleLen ), keccak256(add(needle, 0x20), needleLen) ), inRange ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLen := mload(subject) if iszero(or(iszero(times), iszero(subjectLen))) { result := mload(0x40) subject := add(subject, 0x20) let o := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let j := 0 } 1 {} { mstore(add(o, j), mload(add(subject, j))) j := add(j, 0x20) if iszero(lt(j, subjectLen)) { break } } o := add(o, subjectLen) times := sub(times, 1) if iszero(times) { break } } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, sub(o, add(result, 0x20))) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLen := mload(subject) if iszero(gt(subjectLen, end)) { end := subjectLen } if iszero(gt(subjectLen, start)) { start := subjectLen } if lt(start, end) { result := mload(0x40) let n := sub(end, start) let i := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let j := and(add(n, 0x1f), w) } 1 {} { mstore(add(result, j), mload(add(i, j))) j := add(j, w) // `sub(j, 0x20)`. if iszero(j) { break } } let o := add(add(result, 0x20), n) mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, type(uint256).max); } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let searchLen := mload(needle) if iszero(gt(searchLen, mload(subject))) { result := mload(0x40) let i := add(subject, 0x20) let o := add(result, 0x20) let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, searchLen), h)) { i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. o := add(o, 0x20) i := add(i, searchLen) // Advance `i` by `searchLen`. if searchLen { if iszero(lt(i, subjectSearchEnd)) { break } continue } } i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(o, 0x20)) } } } /// @dev Returns a arrays of 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)) for { let prevIndex := 0 } 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let l := sub(index, prevIndex) mstore(element, l) // Store the length of the element. // Copy the `subject` one word at a time, backwards. for { let o := and(add(l, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the string. // Allocate memory for the length and the bytes, rounded up to a multiple of 32. mstore(0x40, add(element, and(add(l, 0x3f), w))) mstore(indexPtr, element) // Store the `element` into the array. } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated 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 { result := mload(0x40) let w := not(0x1f) let aLen := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLen, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLen := mload(b) let output := add(result, aLen) // Copy `b` one word at a time, backwards. for { let o := and(add(bLen, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLen := add(aLen, bLen) let last := add(add(result, 0x20), totalLen) mstore(last, 0) // Zeroize the slot after the string. mstore(result, totalLen) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate memory. } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(subject) if n { result := mload(0x40) let o := add(result, 0x20) let d := sub(subject, result) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) for { let end := add(o, n) } 1 {} { let b := byte(0, mload(add(d, o))) mstore8(o, xor(and(shr(b, flags), 0x20), b)) o := add(o, 1) if eq(o, end) { break } } mstore(result, n) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) // Store the length. let o := add(result, 0x20) mstore(o, s) // Store the bytes of the string. mstore(add(o, n), 0) // Zeroize the slot after the string. mstore(0x40, add(result, 0x40)) // Allocate memory. } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let end := add(s, mload(s)) let o := add(result, 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(o, c) o := add(o, 1) continue } let t := shr(248, mload(c)) mstore(o, mload(and(t, 0x1f))) o := add(o, shr(5, t)) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(o, c) o := add(o, 1) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), c) o := add(o, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(o, mload(0x19)) // "\\u00XX". o := add(o, 6) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), mload(add(c, 8))) o := add(o, 2) } if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Encodes `s` so that it can be safely used in a URI, /// just like `encodeURIComponent` in JavaScript. /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent /// See: https://datatracker.ietf.org/doc/html/rfc2396 /// See: https://datatracker.ietf.org/doc/html/rfc3986 function encodeURIComponent(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Store "0123456789ABCDEF" in scratch space. // Uppercased to be consistent with JavaScript's implementation. mstore(0x0f, 0x30313233343536373839414243444546) let o := add(result, 0x20) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // If not in `[0-9A-Z-a-z-_.!~*'()]`. if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { mstore8(o, 0x25) // '%'. mstore8(add(o, 1), mload(and(shr(4, c), 15))) mstore8(add(o, 2), mload(and(c, 15))) o := add(o, 3) continue } mstore8(o, c) o := add(o, 1) } mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(result, 0) // Zeroize the length slot. mstore(add(result, 0x1f), packed) // Store the length and bytes. mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( or( // Load the length and the bytes of `a` and `b`. shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), // `totalLen != 0 && totalLen < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLen, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { resultA := mload(0x40) // Grab the free memory pointer. resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
// 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/OwnableRoles.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 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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @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, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } }
// SPDX-License-Identifier: CC0-1.0 pragma solidity ^0.8.0; interface IERC5192 { /// @notice Emitted when the locking status is changed to locked. /// @dev If a token is minted and the status is locked, this event should be emitted. /// @param tokenId The identifier for a token. event Locked(uint256 tokenId); /// @notice Emitted when the locking status is changed to unlocked. /// @dev If a token is minted and the status is unlocked, this event should be emitted. /// @param tokenId The identifier for a token. event Unlocked(uint256 tokenId); /// @notice Returns the locking status of an Soulbound Token /// @dev SBTs assigned to zero address are considered invalid, and queries /// about them do throw. /// @param tokenId The identifier for an SBT. function locked(uint256 tokenId) external view returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {CollectionConfig} from "../structs/CollectionConfig.sol"; interface IBeacon { function read( address contractAddress, uint256[] calldata tokenIds, uint32[] calldata eids, address refundRecipient, uint128 callbackGasLimit ) external payable returns (bytes32); function send( uint32 eid, address collection, uint256[] calldata tokenIds, address beneficiary, address refundRecipient, uint128 supplementalGasLimit ) external payable; function getSendOptions(address collectionAddress, uint256[] calldata tokenIds) external view returns (bytes memory); function getReadOptions(address collectionAddress, uint256[] calldata tokenIds, uint128 callbackGasLimit) external view returns (bytes memory); function quoteSend(uint32 eid, address collectionAddress, uint256[] calldata tokenIds, bytes calldata _options) external view returns (uint256 nativeFee, uint256 lzTokenFee); function quoteRead( address collectionAddress, uint256[] calldata tokenIds, uint32[] calldata eids, bytes calldata _options ) external view returns (uint256 nativeFee, uint256 lzTokenFee); function registerCollection( address _shadowAddress, uint32 _baseCollectionChainId, address _baseCollectionAddress, uint32 _baseCollectionEid, uint32 _baseCollectionPerNftOwnershipUpdateCost ) external; function shadowToBase(address _shadowAddress) external view returns (address); function baseToShadow(address _baseAddress) external view returns (address); function collectionConfigs(address _shadowAddress) external view returns (CollectionConfig memory); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ICreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidator { function validateTransfer(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface IShadowCallbackReceiver { function executeCallback(bytes32 guid) external; }
// 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(); _; } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.28; struct CollectionConfig { uint32 baseCollectionChainId; uint32 baseCollectionEid; uint32 baseCollectionPerNftOwnershipUpdateCost; // cost of transferring an NFT from the base collection. If 0, default of 100_000 is used address shadowAddress; // Local shadow address for this chain }
{ "remappings": [ "solady/=lib/solady/src/", "@layerzerolabs/=node_modules/@layerzerolabs/", "@openzeppelin/=node_modules/@openzeppelin/", "solidity-bytes-utils/=node_modules/solidity-bytes-utils/", "forge-std/=lib/forge-std/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
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CallerNotBeacon","type":"error"},{"inputs":[],"name":"FnSelectorNotRecognized","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenLocked","type":"error"},{"inputs":[],"name":"TokenNotLocked","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"metadataRenderer","type":"address"}],"name":"MetadataRendererSet","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":[],"name":"ShadowModeEnabled","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":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Unlocked","type":"event"},{"stateMutability":"nonpayable","type":"fallback"},{"inputs":[],"name":"BEACON_CONTRACT_ADDRESS","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"METADATA_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ROYALTY_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"SHADOW_MODE_MANAGER_ROLE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TRANSFER_VALIDATOR_MANAGER_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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"callbacks","outputs":[{"internalType":"address","name":"callbackTarget","type":"address"}],"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":"enableShadowMode","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"guid","type":"bytes32"}],"name":"executeCallback","outputs":[],"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":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"","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":"_initialOwner","type":"address"},{"internalType":"string","name":"_collectionName","type":"string"},{"internalType":"string","name":"_collectionSymbol","type":"string"},{"internalType":"string","name":"_baseTokenURI","type":"string"},{"internalType":"address","name":"_metadataRenderer","type":"address"},{"internalType":"address","name":"_transferValidator","type":"address"},{"internalType":"uint96","name":"_royaltyFeeNumerator","type":"uint96"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"locked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"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":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"eids","type":"uint32[]"}],"name":"read","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"uint32[]","name":"eids","type":"uint32[]"},{"internalType":"uint128","name":"callbackGasLimit","type":"uint128"}],"name":"readWithCallback","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"payable","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":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","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":"uint32","name":"dstEid","type":"uint32"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"address","name":"beneficiary","type":"address"},{"internalType":"address","name":"refundRecipient","type":"address"},{"internalType":"uint128","name":"supplementalGasLimit","type":"uint128"}],"name":"send","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":"address","name":"_metadataRenderer","type":"address"}],"name":"setMetadataRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setRoyaltyInfo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri","type":"string"}],"name":"setTokenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"shadowModeEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","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":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"transferValidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
60a060405234801561000f575f5ffd5b506df87b8230c9233b00474eda1e1b3b60805260408051808201825260088082526751303074616e747360c01b602080840191909152835180850185529182526771303074616e747360c01b8282015283519081019093525f8084526100a39373e880c31c8118103ab49b604e281283e489a69780939291737df5c32827f0fa448392ce58231ce4f378ce56e590806100a8565b610313565b60026100b48582610259565b5060036100c18782610259565b5060046100ce8682610259565b50600580546001600160a01b0319166001600160a01b0385161790556100f387610120565b5f80546001600160a01b0319166001600160a01b0384161790556101178782610178565b50505050505050565b638b78c6d81980541561013a57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6001600160601b0316612710808211156101995763350a88b35f526004601cfd5b8260601b806101af5763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b634e487b7160e01b5f52604160045260245ffd5b600181811c908216806101e957607f821691505b60208210810361020757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561025457805f5260205f20601f840160051c810160208510156102325750805b601f840160051c820191505b81811015610251575f815560010161023e565b50505b505050565b81516001600160401b03811115610272576102726101c1565b6102868161028084546101d5565b8461020d565b6020601f8211600181146102b8575f83156102a15750848201515b5f19600385901b1c1916600184901b178455610251565b5f84815260208120601f198516915b828110156102e757878501518255602094850194600190920191016102c7565b508482101561030457868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b608051612ba26103635f395f818161030a0152818161094801528181610ca701528181610d1c01528181610e09015281816111a5015281816118e80152818161195501526120220152612ba25ff3fe6080604052600436106102e3575f3560e01c8063529470e81161018f578063a9fc664e116100db578063e985e9c511610094578063f2fde38b1161006e578063f2fde38b1461089a578063f7dec9b4146108ad578063fd4fe8a8146108c0578063fee81cf4146108df576102e3565b8063e985e9c51461083c578063ed06167814610870578063f04e283e14610887576102e3565b8063a9fc664e1461078e578063b1dae618146107ad578063b45a3c0e146107cc578063b88d4fde146107eb578063c87b56dd146107fe578063e0df5b6f1461081d576102e3565b8063715018a6116101485780638da5cb5b116101225780638da5cb5b1461071757806395d89b411461072f57806399a2557a14610743578063a22cb4651461076f576102e3565b8063715018a6146106d05780637347ebb9146106d85780638528e8d3146106f8576102e3565b8063529470e81461063b57806354d1f13d1461065457806358456fb51461065c5780636352211e14610673578063703199701461069257806370a08231146106b1576102e3565b80631c10893f1161024e57806329e38d5e1161020757806342842e0e116101e157806342842e0e146105c157806342966c68146105d45780634a4ee7b1146105f3578063514e62fc14610606576102e3565b806329e38d5e146105345780632a55205a146105525780632de9480714610590576102e3565b80631c10893f146104895780631cd64df41461049c5780631de26e8e146104d157806321f36509146104e557806323b872dd14610519578063256929621461052c576102e3565b8063098144d4116102a0578063098144d4146103ea5780630a212100146104065780630c756a78146104195780630d705df61461043c578063156c2c3214610463578063183a4f6e14610476576102e3565b806301ddc8bf146102f957806301ffc9a71461034957806302fa7c471461037857806306fdde0314610397578063081812fc146103b8578063095ea7b3146103d7575b3480156102ee575f5ffd5b506102f7610910565b005b348015610304575f5ffd5b5061032c7f000000000000000000000000000000000000000000000000000000000000000081565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610354575f5ffd5b50610368610363366004612150565b6109e3565b6040519015158152602001610340565b348015610383575f5ffd5b506102f76103923660046121ac565b610a63565b3480156103a2575f5ffd5b506103ab610a80565b60405161034091906121df565b3480156103c3575f5ffd5b5061032c6103d2366004612214565b610b10565b6102f76103e536600461222b565b610b4b565b3480156103f5575f5ffd5b505f546001600160a01b031661032c565b6102f76104143660046122c5565b610b5a565b348015610424575f5ffd5b5061042e61200081565b604051908152602001610340565b348015610447575f5ffd5b506040805163657711f560e11b81526001602082015201610340565b61042e610471366004612347565b610daa565b6102f7610484366004612214565b610dc1565b6102f761049736600461222b565b610dcb565b3480156104a7575f5ffd5b506103686104b636600461222b565b638b78c6d8600c9081525f9290925260209091205481161490565b3480156104dc575f5ffd5b506102f7610ddd565b3480156104f0575f5ffd5b5061032c6104ff366004612214565b60016020525f90815260409020546001600160a01b031681565b6102f76105273660046123b1565b610dff565b6102f7610e94565b34801561053f575f5ffd5b505f5461032c906001600160a01b031681565b34801561055d575f5ffd5b5061057161056c3660046123ef565b610ee0565b604080516001600160a01b039093168352602083019190915201610340565b34801561059b575f5ffd5b5061042e6105aa36600461240f565b638b78c6d8600c9081525f91909152602090205490565b6102f76105cf3660046123b1565b610f33565b3480156105df575f5ffd5b506102f76105ee366004612214565b610f5f565b6102f761060136600461222b565b610f80565b348015610611575f5ffd5b5061036861062036600461222b565b638b78c6d8600c9081525f9290925260209091205416151590565b348015610646575f5ffd5b5061042e6504000000000081565b6102f7610f92565b348015610667575f5ffd5b5061042e600160581b81565b34801561067e575f5ffd5b5061032c61068d366004612214565b610fcb565b34801561069d575f5ffd5b5060055461032c906001600160a01b031681565b3480156106bc575f5ffd5b5061042e6106cb36600461240f565b610fee565b6102f7611026565b3480156106e3575f5ffd5b5060055461036890600160a01b900460ff1681565b348015610703575f5ffd5b506102f76107123660046124e6565b611039565b348015610722575f5ffd5b50638b78c6d8195461032c565b34801561073a575f5ffd5b506103ab6110b1565b34801561074e575f5ffd5b5061076261075d3660046125b4565b6110c0565b60405161034091906125e6565b34801561077a575f5ffd5b506102f7610789366004612628565b6110d7565b348015610799575f5ffd5b506102f76107a836600461240f565b61112a565b3480156107b8575f5ffd5b506102f76107c7366004612214565b61119a565b3480156107d7575f5ffd5b506103686107e6366004612214565b611277565b6102f76107f9366004612663565b611281565b348015610809575f5ffd5b506103ab610818366004612214565b6112db565b348015610828575f5ffd5b506102f76108373660046126fa565b611439565b348015610847575f5ffd5b50610368610856366004612733565b601c52670a5a2e7a000000006008525f526030600c205490565b34801561087b575f5ffd5b5061042e600160451b81565b6102f761089536600461240f565b611494565b6102f76108a836600461240f565b6114ce565b61042e6108bb36600461275f565b6114f4565b3480156108cb575f5ffd5b506102f76108da36600461240f565b61152c565b3480156108ea575f5ffd5b5061042e6108f936600461240f565b63389a75e1600c9081525f91909152602090205490565b5f3560e01c6340c10f198190036109325761092f6004356024356115b8565b50565b806392772833036109ca57336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146109865760405163db70dad160e01b815260040160405180910390fd5b6044356024355f5b828110156109c4576109bc6109b66109a78360206127f1565b6109b2906064612808565b3590565b8361164c565b60010161098e565b50505050565b604051631e085ca760e11b815260040160405180910390fd5b5f6001600160e01b03198216635a2d1e0760e11b1480610a245750610a24826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b80610a425750632a55205a60e083901c9081146301ffc9a791909114175b80610a5d57506001600160e01b03198216632483248360e11b145b92915050565b600160581b610a71816116fc565b610a7b8383611720565b505050565b606060038054610a8f9061281b565b80601f0160208091040260200160405190810160405280929190818152602001828054610abb9061281b565b8015610b065780601f10610add57610100808354040283529160200191610b06565b820191905f5260205f20905b815481529060010190602001808311610ae957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610b415763ceea21b65f526004601cfd5b6001015492915050565b610b56338383611769565b5050565b5f5b84811015610c8f57610b8633878784818110610b7a57610b7a612853565b90506020020135611803565b610ba35760405163096dcfe360e31b815260040160405180910390fd5b610bc4868683818110610bb857610bb8612853565b9050602002013561186c565b15610be257604051635a8181f760e01b815260040160405180910390fd5b600554600160a01b900460ff16610c1457610c14868683818110610c0857610c08612853565b9050602002013561188e565b610c36868683818110610c2957610c29612853565b905060200201355f611898565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a1611868683818110610c6957610c69612853565b90506020020135604051610c7f91815260200190565b60405180910390a1600101610b5c565b5060405163f174883560e01b81523060048201525f907f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03169063f174883590602401602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d189190612867565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663c9df81673489848a8a8a8a8a6040518963ffffffff1660e01b8152600401610d7397969594939291906128b2565b5f604051808303818588803b158015610d8a575f5ffd5b505af1158015610d9c573d5f5f3e3d5ffd5b505050505050505050505050565b5f610db8858585855f6118c7565b95945050505050565b61092f33826119f8565b610dd3611a03565b610b568282611a1d565b612000610de9816116fc565b506005805460ff60a01b1916600160a01b179055565b6001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000163303610e89576001610e56825f818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b6001600160601b031603610e7d576040516305b166a360e41b815260040160405180910390fd5b610a7b5f848484611a29565b610a7b838383611b23565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f82815268aa4ec00224afccfdb76020526040812054606081901c91906127109083610f13576020515490508060601c93505b606084901b18845f19829004811182023d3d3e9396930204935090915050565b610f3e838383610dff565b813b15610a7b57610a7b83838360405180602001604052805f815250611c14565b610f688161186c565b15610f765761092f8161188e565b61092f3382611c95565b610f88611a03565b610b5682826119f8565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b5f610fd582611d53565b905080610fe95763ceea21b65f526004601cfd5b919050565b5f8161100157638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b61102e611a03565b6110375f611d7a565b565b6002611045858261295a565b506003611052878261295a565b50600461105f868261295a565b50600580546001600160a01b0319166001600160a01b03851617905561108487611dc0565b5f80546001600160a01b0319166001600160a01b0384161790556110a88782611720565b50505050505050565b606060048054610a8f9061281b565b60606110cd848484611e18565b90505b9392505050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b600160451b611138816116fc565b5f80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91015b60405180910390a1505050565b336001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016146111e35760405163db70dad160e01b815260040160405180910390fd5b5f818152600160205260409020546001600160a01b031680611203575050565b5f828152600160205260409081902080546001600160a01b03191690555163163b5cc360e31b8152600481018390526001600160a01b0382169063b1dae618906024015f604051808303815f87803b15801561125d575f5ffd5b505af115801561126f573d5f5f3e3d5ffd5b505050505050565b5f610a5d8261186c565b61128c858585610dff565b833b156112d4576112d485858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1492505050565b5050505050565b6060611304825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6113215760405163677510db60e11b815260040160405180910390fd5b6005546001600160a01b03161561139f5760055460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd906024015f60405180830381865afa158015611378573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a5d9190810190612a14565b610a5d600280546113af9061281b565b80601f01602080910402602001604051908101604052809291908181526020018280546113db9061281b565b80156114265780601f106113fd57610100808354040283529160200191611426565b820191905f5260205f20905b81548152906001019060200180831161140957829003601f168201915b505050505061143484611f7a565b611fbc565b65040000000000611449816116fc565b6002611455838261295a565b50604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91015b60405180910390a15050565b61149c611a03565b63389a75e1600c52805f526020600c2080544211156114c257636f5e88185f526004601cfd5b5f905561092f81611d7a565b6114d6611a03565b8060601b6114eb57637448fbae5f526004601cfd5b61092f81611d7a565b5f5f61150387878787876118c7565b5f81815260016020526040902080546001600160a01b0319163317905591505095945050505050565b6504000000000061153c816116fc565b600580546001600160a01b0319166001600160a01b0384169081179091556040517faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a03905f90a2604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9101611488565b6115c35f8383612017565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b156115fe5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026116325767ea553b3401336cea841560021b526004601cfd5b905580825f5f516020612b4d5f395f51905f528138a45050565b6116558261186c565b156116e3575f61166483611d53565b90506001600160a01b0381166116835761167e82846115b8565b6116a8565b806001600160a01b0316826001600160a01b0316146116a8576116a85f828486611a29565b6116b3836001611898565b6040518381527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429060200161118d565b6040516305b166a360e41b815260040160405180910390fd5b638b78c6d8600c52335f52806020600c20541661092f576382b429005f526004601cfd5b6001600160601b0316612710808211156117415763350a88b35f526004601cfd5b8260601b806117575763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816117ac5763ceea21b65f526004601cfd5b8185148515176117d057815f526030600c20546117d057634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919360019216806118465763ceea21b65f526004601cfd5b80851461186457805f526030600c2054611864578160010154851492505b505092915050565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b61092f5f82611c95565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60405163f174883560e01b81523060048201525f9081906001600160a01b037f0000000000000000000000000000000000000000000000000000000000000000169063f174883590602401602060405180830381865afa15801561192d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119519190612867565b90507f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031663fe084c8f34838a8a8a8a338b6040518963ffffffff1660e01b81526004016119ac9796959493929190612a88565b60206040518083038185885af11580156119c8573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119ed9190612b1d565b979650505050505050565b610b5682825f6120f9565b638b78c6d819543314611037576382b429005f526004601cfd5b610b56828260016120f9565b611a34838383612017565b5f8181526001600160a01b03948516673ec412a9852d173d60c11b8117601c526020909120820182018054919594851694938416938216918286148302611a8a5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082871486881417871517611ab9576030600c2054611ab957634b6e7f185f526004601cfd5b8215611ac6575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611b075767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a450505050565b611b2e838383612017565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302611b7f5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417611bab576030600c2054611bab57634b6e7f185f526004601cfd5b8215611bb8575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611bf95767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a4505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611c5b578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611c7c573d15611c7c573d5f843e3d83fd5b508060e01b82511461126f5763d1a57ed65f526004601cfd5b5f611c9f82610fcb565b9050611cac815f84612017565b505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919382169182611cef5763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611d1c576030600c2054611d1c57634b6e7f185f526004601cfd5b8015611d29575f83600101555b5082189055601c600c2080545f19019055815f825f516020612b4d5f395f51905f528238a4505050565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b638b78c6d819805415611dda57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60605f611e2485610fee565b90505f80826001600160401b03811115611e4057611e4061242a565b604051908082528060200260200182016040528015611e69578160200160208202803683370190505b509050855b858111611edf57876001600160a01b0316611e8882611d53565b6001600160a01b031603611ecd5780828481518110611ea957611ea9612853565b602090810291909101015260018084019385900301611ecd575092506110d0915050565b80611ed781612b34565b915050611e6e565b505f826001600160401b03811115611ef957611ef961242a565b604051908082528060200260200182016040528015611f22578160200160208202803683370190505b5090505f5b83811015611f6e57828181518110611f4157611f41612853565b6020026020010151828281518110611f5b57611f5b612853565b6020908102919091010152600101611f27565b50979650505050505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a900480611f93575050819003601f19909101908152919050565b6040518251601f19906020810182165b8581015184820152820180611fcc575083518184018360208301165b8681015182820152840180611fe85750505f910183810160208101929092528352604090810190525092915050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614610a7b576120508161186c565b8061206257506001600160a01b038316155b156120805760405163db70dad160e01b815260040160405180910390fd5b5f546001600160a01b031615610a7b575f5460405163657711f560e11b81523360048201526001600160a01b0385811660248301528481166044830152606482018490529091169063caee23ea906084015f6040518083038186803b1580156120e7575f5ffd5b505afa1580156110a8573d5f5f3e3d5ffd5b638b78c6d8600c52825f526020600c2080548381178361211a575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f60208284031215612160575f5ffd5b81356001600160e01b0319811681146110d0575f5ffd5b6001600160a01b038116811461092f575f5ffd5b8035610fe981612177565b80356001600160601b0381168114610fe9575f5ffd5b5f5f604083850312156121bd575f5ffd5b82356121c881612177565b91506121d660208401612196565b90509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f60208284031215612224575f5ffd5b5035919050565b5f5f6040838503121561223c575f5ffd5b823561224781612177565b946020939093013593505050565b803563ffffffff81168114610fe9575f5ffd5b5f5f83601f840112612278575f5ffd5b5081356001600160401b0381111561228e575f5ffd5b6020830191508360208260051b85010111156122a8575f5ffd5b9250929050565b80356001600160801b0381168114610fe9575f5ffd5b5f5f5f5f5f5f60a087890312156122da575f5ffd5b6122e387612255565b955060208701356001600160401b038111156122fd575f5ffd5b61230989828a01612268565b909650945050604087013561231d81612177565b9250606087013561232d81612177565b915061233b608088016122af565b90509295509295509295565b5f5f5f5f6040858703121561235a575f5ffd5b84356001600160401b0381111561236f575f5ffd5b61237b87828801612268565b90955093505060208501356001600160401b03811115612399575f5ffd5b6123a587828801612268565b95989497509550505050565b5f5f5f606084860312156123c3575f5ffd5b83356123ce81612177565b925060208401356123de81612177565b929592945050506040919091013590565b5f5f60408385031215612400575f5ffd5b50508035926020909101359150565b5f6020828403121561241f575f5ffd5b81356110d081612177565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156124665761246661242a565b604052919050565b5f6001600160401b038211156124865761248661242a565b50601f01601f191660200190565b5f82601f8301126124a3575f5ffd5b81356124b66124b18261246e565b61243e565b8181528460208386010111156124ca575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f5f5f60e0888a0312156124fc575f5ffd5b873561250781612177565b965060208801356001600160401b03811115612521575f5ffd5b61252d8a828b01612494565b96505060408801356001600160401b03811115612548575f5ffd5b6125548a828b01612494565b95505060608801356001600160401b0381111561256f575f5ffd5b61257b8a828b01612494565b94505061258a6080890161218b565b925061259860a0890161218b565b91506125a660c08901612196565b905092959891949750929550565b5f5f5f606084860312156125c6575f5ffd5b83356125d181612177565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561261d5783518352602093840193909201916001016125ff565b509095945050505050565b5f5f60408385031215612639575f5ffd5b823561264481612177565b915060208301358015158114612658575f5ffd5b809150509250929050565b5f5f5f5f5f60808688031215612677575f5ffd5b853561268281612177565b9450602086013561269281612177565b93506040860135925060608601356001600160401b038111156126b3575f5ffd5b8601601f810188136126c3575f5ffd5b80356001600160401b038111156126d8575f5ffd5b8860208284010111156126e9575f5ffd5b959894975092955050506020019190565b5f6020828403121561270a575f5ffd5b81356001600160401b0381111561271f575f5ffd5b61272b84828501612494565b949350505050565b5f5f60408385031215612744575f5ffd5b823561274f81612177565b9150602083013561265881612177565b5f5f5f5f5f60608688031215612773575f5ffd5b85356001600160401b03811115612788575f5ffd5b61279488828901612268565b90965094505060208601356001600160401b038111156127b2575f5ffd5b6127be88828901612268565b90945092506127d19050604087016122af565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610a5d57610a5d6127dd565b80820180821115610a5d57610a5d6127dd565b600181811c9082168061282f57607f821691505b60208210810361284d57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612877575f5ffd5b81516110d081612177565b8183525f6001600160fb1b03831115612899575f5ffd5b8260051b80836020870137939093016020019392505050565b63ffffffff881681526001600160a01b038716602082015260c0604082018190525f906128e29083018789612882565b6001600160a01b0395861660608401529390941660808201526001600160801b039190911660a09091015295945050505050565b601f821115610a7b57805f5260205f20601f840160051c8101602085101561293b5750805b601f840160051c820191505b818110156112d4575f8155600101612947565b81516001600160401b038111156129735761297361242a565b61298781612981845461281b565b84612916565b6020601f8211600181146129b9575f83156129a25750848201515b5f19600385901b1c1916600184901b1784556112d4565b5f84815260208120601f198516915b828110156129e857878501518255602094850194600190920191016129c8565b5084821015612a0557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f60208284031215612a24575f5ffd5b81516001600160401b03811115612a39575f5ffd5b8201601f81018413612a49575f5ffd5b8051612a576124b18261246e565b818152856020838501011115612a6b575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b6001600160a01b038816815260a0602082018190525f90612aac908301888a612882565b828103604084015285815286906020015f5b87811015612ae95763ffffffff612ad484612255565b16825260209283019290910190600101612abe565b506001600160a01b03861660608501526001600160801b03851660808501529150612b119050565b98975050505050505050565b5f60208284031215612b2d575f5ffd5b5051919050565b5f60018201612b4557612b456127dd565b506001019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d64736f6c634300081c0033
Deployed Bytecode
0x6080604052600436106102e3575f3560e01c8063529470e81161018f578063a9fc664e116100db578063e985e9c511610094578063f2fde38b1161006e578063f2fde38b1461089a578063f7dec9b4146108ad578063fd4fe8a8146108c0578063fee81cf4146108df576102e3565b8063e985e9c51461083c578063ed06167814610870578063f04e283e14610887576102e3565b8063a9fc664e1461078e578063b1dae618146107ad578063b45a3c0e146107cc578063b88d4fde146107eb578063c87b56dd146107fe578063e0df5b6f1461081d576102e3565b8063715018a6116101485780638da5cb5b116101225780638da5cb5b1461071757806395d89b411461072f57806399a2557a14610743578063a22cb4651461076f576102e3565b8063715018a6146106d05780637347ebb9146106d85780638528e8d3146106f8576102e3565b8063529470e81461063b57806354d1f13d1461065457806358456fb51461065c5780636352211e14610673578063703199701461069257806370a08231146106b1576102e3565b80631c10893f1161024e57806329e38d5e1161020757806342842e0e116101e157806342842e0e146105c157806342966c68146105d45780634a4ee7b1146105f3578063514e62fc14610606576102e3565b806329e38d5e146105345780632a55205a146105525780632de9480714610590576102e3565b80631c10893f146104895780631cd64df41461049c5780631de26e8e146104d157806321f36509146104e557806323b872dd14610519578063256929621461052c576102e3565b8063098144d4116102a0578063098144d4146103ea5780630a212100146104065780630c756a78146104195780630d705df61461043c578063156c2c3214610463578063183a4f6e14610476576102e3565b806301ddc8bf146102f957806301ffc9a71461034957806302fa7c471461037857806306fdde0314610397578063081812fc146103b8578063095ea7b3146103d7575b3480156102ee575f5ffd5b506102f7610910565b005b348015610304575f5ffd5b5061032c7f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b81565b6040516001600160a01b0390911681526020015b60405180910390f35b348015610354575f5ffd5b50610368610363366004612150565b6109e3565b6040519015158152602001610340565b348015610383575f5ffd5b506102f76103923660046121ac565b610a63565b3480156103a2575f5ffd5b506103ab610a80565b60405161034091906121df565b3480156103c3575f5ffd5b5061032c6103d2366004612214565b610b10565b6102f76103e536600461222b565b610b4b565b3480156103f5575f5ffd5b505f546001600160a01b031661032c565b6102f76104143660046122c5565b610b5a565b348015610424575f5ffd5b5061042e61200081565b604051908152602001610340565b348015610447575f5ffd5b506040805163657711f560e11b81526001602082015201610340565b61042e610471366004612347565b610daa565b6102f7610484366004612214565b610dc1565b6102f761049736600461222b565b610dcb565b3480156104a7575f5ffd5b506103686104b636600461222b565b638b78c6d8600c9081525f9290925260209091205481161490565b3480156104dc575f5ffd5b506102f7610ddd565b3480156104f0575f5ffd5b5061032c6104ff366004612214565b60016020525f90815260409020546001600160a01b031681565b6102f76105273660046123b1565b610dff565b6102f7610e94565b34801561053f575f5ffd5b505f5461032c906001600160a01b031681565b34801561055d575f5ffd5b5061057161056c3660046123ef565b610ee0565b604080516001600160a01b039093168352602083019190915201610340565b34801561059b575f5ffd5b5061042e6105aa36600461240f565b638b78c6d8600c9081525f91909152602090205490565b6102f76105cf3660046123b1565b610f33565b3480156105df575f5ffd5b506102f76105ee366004612214565b610f5f565b6102f761060136600461222b565b610f80565b348015610611575f5ffd5b5061036861062036600461222b565b638b78c6d8600c9081525f9290925260209091205416151590565b348015610646575f5ffd5b5061042e6504000000000081565b6102f7610f92565b348015610667575f5ffd5b5061042e600160581b81565b34801561067e575f5ffd5b5061032c61068d366004612214565b610fcb565b34801561069d575f5ffd5b5060055461032c906001600160a01b031681565b3480156106bc575f5ffd5b5061042e6106cb36600461240f565b610fee565b6102f7611026565b3480156106e3575f5ffd5b5060055461036890600160a01b900460ff1681565b348015610703575f5ffd5b506102f76107123660046124e6565b611039565b348015610722575f5ffd5b50638b78c6d8195461032c565b34801561073a575f5ffd5b506103ab6110b1565b34801561074e575f5ffd5b5061076261075d3660046125b4565b6110c0565b60405161034091906125e6565b34801561077a575f5ffd5b506102f7610789366004612628565b6110d7565b348015610799575f5ffd5b506102f76107a836600461240f565b61112a565b3480156107b8575f5ffd5b506102f76107c7366004612214565b61119a565b3480156107d7575f5ffd5b506103686107e6366004612214565b611277565b6102f76107f9366004612663565b611281565b348015610809575f5ffd5b506103ab610818366004612214565b6112db565b348015610828575f5ffd5b506102f76108373660046126fa565b611439565b348015610847575f5ffd5b50610368610856366004612733565b601c52670a5a2e7a000000006008525f526030600c205490565b34801561087b575f5ffd5b5061042e600160451b81565b6102f761089536600461240f565b611494565b6102f76108a836600461240f565b6114ce565b61042e6108bb36600461275f565b6114f4565b3480156108cb575f5ffd5b506102f76108da36600461240f565b61152c565b3480156108ea575f5ffd5b5061042e6108f936600461240f565b63389a75e1600c9081525f91909152602090205490565b5f3560e01c6340c10f198190036109325761092f6004356024356115b8565b50565b806392772833036109ca57336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b16146109865760405163db70dad160e01b815260040160405180910390fd5b6044356024355f5b828110156109c4576109bc6109b66109a78360206127f1565b6109b2906064612808565b3590565b8361164c565b60010161098e565b50505050565b604051631e085ca760e11b815260040160405180910390fd5b5f6001600160e01b03198216635a2d1e0760e11b1480610a245750610a24826301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b80610a425750632a55205a60e083901c9081146301ffc9a791909114175b80610a5d57506001600160e01b03198216632483248360e11b145b92915050565b600160581b610a71816116fc565b610a7b8383611720565b505050565b606060038054610a8f9061281b565b80601f0160208091040260200160405190810160405280929190818152602001828054610abb9061281b565b8015610b065780601f10610add57610100808354040283529160200191610b06565b820191905f5260205f20905b815481529060010190602001808311610ae957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b610b415763ceea21b65f526004601cfd5b6001015492915050565b610b56338383611769565b5050565b5f5b84811015610c8f57610b8633878784818110610b7a57610b7a612853565b90506020020135611803565b610ba35760405163096dcfe360e31b815260040160405180910390fd5b610bc4868683818110610bb857610bb8612853565b9050602002013561186c565b15610be257604051635a8181f760e01b815260040160405180910390fd5b600554600160a01b900460ff16610c1457610c14868683818110610c0857610c08612853565b9050602002013561188e565b610c36868683818110610c2957610c29612853565b905060200201355f611898565b7f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a1611868683818110610c6957610c69612853565b90506020020135604051610c7f91815260200190565b60405180910390a1600101610b5c565b5060405163f174883560e01b81523060048201525f907f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b03169063f174883590602401602060405180830381865afa158015610cf4573d5f5f3e3d5ffd5b505050506040513d601f19601f82011682018060405250810190610d189190612867565b90507f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b031663c9df81673489848a8a8a8a8a6040518963ffffffff1660e01b8152600401610d7397969594939291906128b2565b5f604051808303818588803b158015610d8a575f5ffd5b505af1158015610d9c573d5f5f3e3d5ffd5b505050505050505050505050565b5f610db8858585855f6118c7565b95945050505050565b61092f33826119f8565b610dd3611a03565b610b568282611a1d565b612000610de9816116fc565b506005805460ff60a01b1916600160a01b179055565b6001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b163303610e89576001610e56825f818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b6001600160601b031603610e7d576040516305b166a360e41b815260040160405180910390fd5b610a7b5f848484611a29565b610a7b838383611b23565b5f6202a3006001600160401b03164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f5fa250565b5f82815268aa4ec00224afccfdb76020526040812054606081901c91906127109083610f13576020515490508060601c93505b606084901b18845f19829004811182023d3d3e9396930204935090915050565b610f3e838383610dff565b813b15610a7b57610a7b83838360405180602001604052805f815250611c14565b610f688161186c565b15610f765761092f8161188e565b61092f3382611c95565b610f88611a03565b610b5682826119f8565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f5fa2565b5f610fd582611d53565b905080610fe95763ceea21b65f526004601cfd5b919050565b5f8161100157638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b61102e611a03565b6110375f611d7a565b565b6002611045858261295a565b506003611052878261295a565b50600461105f868261295a565b50600580546001600160a01b0319166001600160a01b03851617905561108487611dc0565b5f80546001600160a01b0319166001600160a01b0384161790556110a88782611720565b50505050505050565b606060048054610a8f9061281b565b60606110cd848484611e18565b90505b9392505050565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b600160451b611138816116fc565b5f80546001600160a01b038481166001600160a01b031983168117909355604080519190921680825260208201939093527fcc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac91015b60405180910390a1505050565b336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b16146111e35760405163db70dad160e01b815260040160405180910390fd5b5f818152600160205260409020546001600160a01b031680611203575050565b5f828152600160205260409081902080546001600160a01b03191690555163163b5cc360e31b8152600481018390526001600160a01b0382169063b1dae618906024015f604051808303815f87803b15801561125d575f5ffd5b505af115801561126f573d5f5f3e3d5ffd5b505050505050565b5f610a5d8261186c565b61128c858585610dff565b833b156112d4576112d485858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250611c1492505050565b5050505050565b6060611304825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b6113215760405163677510db60e11b815260040160405180910390fd5b6005546001600160a01b03161561139f5760055460405163c87b56dd60e01b8152600481018490526001600160a01b039091169063c87b56dd906024015f60405180830381865afa158015611378573d5f5f3e3d5ffd5b505050506040513d5f823e601f3d908101601f19168201604052610a5d9190810190612a14565b610a5d600280546113af9061281b565b80601f01602080910402602001604051908101604052809291908181526020018280546113db9061281b565b80156114265780601f106113fd57610100808354040283529160200191611426565b820191905f5260205f20905b81548152906001019060200180831161140957829003601f168201915b505050505061143484611f7a565b611fbc565b65040000000000611449816116fc565b6002611455838261295a565b50604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c91015b60405180910390a15050565b61149c611a03565b63389a75e1600c52805f526020600c2080544211156114c257636f5e88185f526004601cfd5b5f905561092f81611d7a565b6114d6611a03565b8060601b6114eb57637448fbae5f526004601cfd5b61092f81611d7a565b5f5f61150387878787876118c7565b5f81815260016020526040902080546001600160a01b0319163317905591505095945050505050565b6504000000000061153c816116fc565b600580546001600160a01b0319166001600160a01b0384169081179091556040517faa56f403bb636768e9e1fec12c1968db814767675df6bc4a8c2488fc094c6a03905f90a2604080515f81525f1960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c9101611488565b6115c35f8383612017565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b156115fe5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026116325767ea553b3401336cea841560021b526004601cfd5b905580825f5f516020612b4d5f395f51905f528138a45050565b6116558261186c565b156116e3575f61166483611d53565b90506001600160a01b0381166116835761167e82846115b8565b6116a8565b806001600160a01b0316826001600160a01b0316146116a8576116a85f828486611a29565b6116b3836001611898565b6040518381527ff27b6ce5b2f5e68ddb2fd95a8a909d4ecf1daaac270935fff052feacb24f18429060200161118d565b6040516305b166a360e41b815260040160405180910390fd5b638b78c6d8600c52335f52806020600c20541661092f576382b429005f526004601cfd5b6001600160601b0316612710808211156117415763350a88b35f526004601cfd5b8260601b806117575763b4457eaa5f526004601cfd5b90911768aa4ec00224afccfdb7555050565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f2082018201805482169150816117ac5763ceea21b65f526004601cfd5b8185148515176117d057815f526030600c20546117d057634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919360019216806118465763ceea21b65f526004601cfd5b80851461186457805f526030600c2054611864578160010154851492505b505092915050565b5f818152673ec412a9852d173d60c11b601c52602090208101015460a01c1590565b61092f5f82611c95565b815f52673ec412a9852d173d60c11b601c5260205f208201820180548060a01c831860a01b8118825550505050565b60405163f174883560e01b81523060048201525f9081906001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b169063f174883590602401602060405180830381865afa15801561192d573d5f5f3e3d5ffd5b505050506040513d601f19601f820116820180604052508101906119519190612867565b90507f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b6001600160a01b031663fe084c8f34838a8a8a8a338b6040518963ffffffff1660e01b81526004016119ac9796959493929190612a88565b60206040518083038185885af11580156119c8573d5f5f3e3d5ffd5b50505050506040513d601f19601f820116820180604052508101906119ed9190612b1d565b979650505050505050565b610b5682825f6120f9565b638b78c6d819543314611037576382b429005f526004601cfd5b610b56828260016120f9565b611a34838383612017565b5f8181526001600160a01b03948516673ec412a9852d173d60c11b8117601c526020909120820182018054919594851694938416938216918286148302611a8a5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082871486881417871517611ab9576030600c2054611ab957634b6e7f185f526004601cfd5b8215611ac6575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611b075767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a450505050565b611b2e838383612017565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302611b7f5767ceea21b6a1148100831560021b526004601cfd5b855f528160010154925082331486331417611bab576030600c2054611bab57634b6e7f185f526004601cfd5b8215611bb8575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff81168402611bf95767ea553b3401336cea841560021b526004601cfd5b90558082845f516020612b4d5f395f51905f525f38a4505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611c5b578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1611c7c573d15611c7c573d5f843e3d83fd5b508060e01b82511461126f5763d1a57ed65f526004601cfd5b5f611c9f82610fcb565b9050611cac815f84612017565b505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c526020909120820182018054919382169182611cef5763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611d1c576030600c2054611d1c57634b6e7f185f526004601cfd5b8015611d29575f83600101555b5082189055601c600c2080545f19019055815f825f516020612b4d5f395f51905f528238a4505050565b5f818152673ec412a9852d173d60c11b601c5260209020810101546001600160a01b031690565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3811560ff1b8217905550565b638b78c6d819805415611dda57630dc149f05f526004601cfd5b6001600160a01b03909116801560ff1b8117909155805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60605f611e2485610fee565b90505f80826001600160401b03811115611e4057611e4061242a565b604051908082528060200260200182016040528015611e69578160200160208202803683370190505b509050855b858111611edf57876001600160a01b0316611e8882611d53565b6001600160a01b031603611ecd5780828481518110611ea957611ea9612853565b602090810291909101015260018084019385900301611ecd575092506110d0915050565b80611ed781612b34565b915050611e6e565b505f826001600160401b03811115611ef957611ef961242a565b604051908082528060200260200182016040528015611f22578160200160208202803683370190505b5090505f5b83811015611f6e57828181518110611f4157611f41612853565b6020026020010151828281518110611f5b57611f5b612853565b6020908102919091010152600101611f27565b50979650505050505050565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a900480611f93575050819003601f19909101908152919050565b6040518251601f19906020810182165b8581015184820152820180611fcc575083518184018360208301165b8681015182820152840180611fe85750505f910183810160208101929092528352604090810190525092915050565b336001600160a01b037f000000000000000000000000000000000000f87b8230c9233b00474eda1e1b3b1614610a7b576120508161186c565b8061206257506001600160a01b038316155b156120805760405163db70dad160e01b815260040160405180910390fd5b5f546001600160a01b031615610a7b575f5460405163657711f560e11b81523360048201526001600160a01b0385811660248301528481166044830152606482018490529091169063caee23ea906084015f6040518083038186803b1580156120e7575f5ffd5b505afa1580156110a8573d5f5f3e3d5ffd5b638b78c6d8600c52825f526020600c2080548381178361211a575080841681185b80835580600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe265f5fa3505050505050565b5f60208284031215612160575f5ffd5b81356001600160e01b0319811681146110d0575f5ffd5b6001600160a01b038116811461092f575f5ffd5b8035610fe981612177565b80356001600160601b0381168114610fe9575f5ffd5b5f5f604083850312156121bd575f5ffd5b82356121c881612177565b91506121d660208401612196565b90509250929050565b602081525f82518060208401528060208501604085015e5f604082850101526040601f19601f83011684010191505092915050565b5f60208284031215612224575f5ffd5b5035919050565b5f5f6040838503121561223c575f5ffd5b823561224781612177565b946020939093013593505050565b803563ffffffff81168114610fe9575f5ffd5b5f5f83601f840112612278575f5ffd5b5081356001600160401b0381111561228e575f5ffd5b6020830191508360208260051b85010111156122a8575f5ffd5b9250929050565b80356001600160801b0381168114610fe9575f5ffd5b5f5f5f5f5f5f60a087890312156122da575f5ffd5b6122e387612255565b955060208701356001600160401b038111156122fd575f5ffd5b61230989828a01612268565b909650945050604087013561231d81612177565b9250606087013561232d81612177565b915061233b608088016122af565b90509295509295509295565b5f5f5f5f6040858703121561235a575f5ffd5b84356001600160401b0381111561236f575f5ffd5b61237b87828801612268565b90955093505060208501356001600160401b03811115612399575f5ffd5b6123a587828801612268565b95989497509550505050565b5f5f5f606084860312156123c3575f5ffd5b83356123ce81612177565b925060208401356123de81612177565b929592945050506040919091013590565b5f5f60408385031215612400575f5ffd5b50508035926020909101359150565b5f6020828403121561241f575f5ffd5b81356110d081612177565b634e487b7160e01b5f52604160045260245ffd5b604051601f8201601f191681016001600160401b03811182821017156124665761246661242a565b604052919050565b5f6001600160401b038211156124865761248661242a565b50601f01601f191660200190565b5f82601f8301126124a3575f5ffd5b81356124b66124b18261246e565b61243e565b8181528460208386010111156124ca575f5ffd5b816020850160208301375f918101602001919091529392505050565b5f5f5f5f5f5f5f60e0888a0312156124fc575f5ffd5b873561250781612177565b965060208801356001600160401b03811115612521575f5ffd5b61252d8a828b01612494565b96505060408801356001600160401b03811115612548575f5ffd5b6125548a828b01612494565b95505060608801356001600160401b0381111561256f575f5ffd5b61257b8a828b01612494565b94505061258a6080890161218b565b925061259860a0890161218b565b91506125a660c08901612196565b905092959891949750929550565b5f5f5f606084860312156125c6575f5ffd5b83356125d181612177565b95602085013595506040909401359392505050565b602080825282518282018190525f918401906040840190835b8181101561261d5783518352602093840193909201916001016125ff565b509095945050505050565b5f5f60408385031215612639575f5ffd5b823561264481612177565b915060208301358015158114612658575f5ffd5b809150509250929050565b5f5f5f5f5f60808688031215612677575f5ffd5b853561268281612177565b9450602086013561269281612177565b93506040860135925060608601356001600160401b038111156126b3575f5ffd5b8601601f810188136126c3575f5ffd5b80356001600160401b038111156126d8575f5ffd5b8860208284010111156126e9575f5ffd5b959894975092955050506020019190565b5f6020828403121561270a575f5ffd5b81356001600160401b0381111561271f575f5ffd5b61272b84828501612494565b949350505050565b5f5f60408385031215612744575f5ffd5b823561274f81612177565b9150602083013561265881612177565b5f5f5f5f5f60608688031215612773575f5ffd5b85356001600160401b03811115612788575f5ffd5b61279488828901612268565b90965094505060208601356001600160401b038111156127b2575f5ffd5b6127be88828901612268565b90945092506127d19050604087016122af565b90509295509295909350565b634e487b7160e01b5f52601160045260245ffd5b8082028115828204841417610a5d57610a5d6127dd565b80820180821115610a5d57610a5d6127dd565b600181811c9082168061282f57607f821691505b60208210810361284d57634e487b7160e01b5f52602260045260245ffd5b50919050565b634e487b7160e01b5f52603260045260245ffd5b5f60208284031215612877575f5ffd5b81516110d081612177565b8183525f6001600160fb1b03831115612899575f5ffd5b8260051b80836020870137939093016020019392505050565b63ffffffff881681526001600160a01b038716602082015260c0604082018190525f906128e29083018789612882565b6001600160a01b0395861660608401529390941660808201526001600160801b039190911660a09091015295945050505050565b601f821115610a7b57805f5260205f20601f840160051c8101602085101561293b5750805b601f840160051c820191505b818110156112d4575f8155600101612947565b81516001600160401b038111156129735761297361242a565b61298781612981845461281b565b84612916565b6020601f8211600181146129b9575f83156129a25750848201515b5f19600385901b1c1916600184901b1784556112d4565b5f84815260208120601f198516915b828110156129e857878501518255602094850194600190920191016129c8565b5084821015612a0557868401515f19600387901b60f8161c191681555b50505050600190811b01905550565b5f60208284031215612a24575f5ffd5b81516001600160401b03811115612a39575f5ffd5b8201601f81018413612a49575f5ffd5b8051612a576124b18261246e565b818152856020838501011115612a6b575f5ffd5b8160208401602083015e5f91810160200191909152949350505050565b6001600160a01b038816815260a0602082018190525f90612aac908301888a612882565b828103604084015285815286906020015f5b87811015612ae95763ffffffff612ad484612255565b16825260209283019290910190600101612abe565b506001600160a01b03861660608501526001600160801b03851660808501529150612b119050565b98975050505050505050565b5f60208284031215612b2d575f5ffd5b5051919050565b5f60018201612b4557612b456127dd565b506001019056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d64736f6c634300081c0033
Deployed Bytecode Sourcemap
134:364:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3931:17:5;:15;:17::i;:::-;134:364:6;2463:48:5;;;;;;;;;;;;;;;;;;-1:-1:-1;;;;;178:32:13;;;160:51;;148:2;133:18;2463:48:5;;;;;;;;12113:297;;;;;;;;;;-1:-1:-1;12113:297:5;;;;;:::i;:::-;;:::i;:::-;;;678:14:13;;671:22;653:41;;641:2;626:18;12113:297:5;513:187:13;10534:163:5;;;;;;;;;;-1:-1:-1;10534:163:5;;;;;:::i;:::-;;:::i;13089:90::-;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;8099:532:3:-;;;;;;;;;;-1:-1:-1;8099:532:3;;;;;:::i;:::-;;:::i;8925:119::-;;;;;;:::i;:::-;;:::i;14240:105:5:-;;;;;;;;;;-1:-1:-1;14295:7:5;14321:17;-1:-1:-1;;;;;14321:17:5;14240:105;;7856:882;;;;;;:::i;:::-;;:::i;2548:59::-;;;;;;;;;;;;13430:7:1;2548:59:5;;;;;4259:25:13;;;4247:2;4232:18;2548:59:5;4113:177:13;14622:189:5;;;;;;;;;;-1:-1:-1;14622:189:5;;;-1:-1:-1;;;4461:52:13;;14800:4:5;4544:2:13;4529:18;;4522:50;4434:18;14622:189:5;4295:283:13;6184:148:5;;;;;;:::i;:::-;;:::i;10291:109:1:-;;;;;;:::i;:::-;;:::i;9752:123::-;;;;;;:::i;:::-;;:::i;11342:139::-;;;;;;;;;;-1:-1:-1;11342:139:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;11421:4;10962:18;;;;11062:4;11046:21;;;11040:28;11444:21;;:30;;11342:139;8953:114:5;;;;;;;;;;;;;:::i;2976:64::-;;;;;;;;;;-1:-1:-1;2976:64:5;;;;;:::i;:::-;;;;;;;;;;;;-1:-1:-1;;;;;2976:64:5;;;5567:359;;;;;;:::i;:::-;;:::i;9021:617:0:-;;;:::i;2883:32:5:-;;;;;;;;;;-1:-1:-1;2883:32:5;;;;-1:-1:-1;;;;;2883:32:5;;;3179:1058:2;;;;;;;;;;-1:-1:-1;3179:1058:2;;;;;:::i;:::-;;:::i;:::-;;;;-1:-1:-1;;;;;6778:32:13;;;6760:51;;6842:2;6827:18;;6820:34;;;;6733:18;3179:1058:2;6586:274:13;10731:353:1;;;;;;;;;;-1:-1:-1;10731:353:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;10791:13;10962:18;;;;11062:4;11046:21;;11040:28;;10731:353;13705:198:3;;;;;;:::i;:::-;;:::i;10959:174:5:-;;;;;;;;;;-1:-1:-1;10959:174:5;;;;;:::i;:::-;;:::i;10020:125:1:-;;;;;;:::i;:::-;;:::i;11146:134::-;;;;;;;;;;-1:-1:-1;11146:134:1;;;;;:::i;:::-;10933:15;10927:4;10920:29;;;11224:4;10962:18;;;;11062:4;11046:21;;;11040:28;11247:21;:26;;;11146:134;2613:56:5;;;;;;;;;;;;14880:7:1;2613:56:5;;9720:456:0;;;:::i;2747:55:5:-;;;;;;;;;;;;-1:-1:-1;;;2747:55:5;;6957:332:3;;;;;;;;;;-1:-1:-1;6957:332:3;;;;;:::i;:::-;;:::i;3502:31:5:-;;;;;;;;;;-1:-1:-1;3502:31:5;;;;-1:-1:-1;;;;;3502:31:5;;;7433:533:3;;;;;;;;;;-1:-1:-1;7433:533:3;;;;;:::i;:::-;;:::i;8762:100:0:-;;;:::i;3620:29:5:-;;;;;;;;;;-1:-1:-1;3620:29:5;;;;-1:-1:-1;;;3620:29:5;;;;;;4495:679;;;;;;;;;;-1:-1:-1;4495:679:5;;;;;:::i;:::-;;:::i;11408:182:0:-;;;;;;;;;;-1:-1:-1;;;11556:18:0;11408:182;;13307:94:5;;;;;;;;;;;;;:::i;13881:170::-;;;;;;;;;;-1:-1:-1;13881:170:5;;;;;:::i;:::-;;:::i;:::-;;;;;;;:::i;9667:726:3:-;;;;;;;;;;-1:-1:-1;9667:726:3;;;;;:::i;:::-;;:::i;10033:289:5:-;;;;;;;;;;-1:-1:-1;10033:289:5;;;;;:::i;:::-;;:::i;11259:338::-;;;;;;;;;;-1:-1:-1;11259:338:5;;;;;:::i;:::-;;:::i;11756:102::-;;;;;;;;;;-1:-1:-1;11756:102:5;;;;;:::i;:::-;;:::i;14406:249:3:-;;;;;;:::i;:::-;;:::i;12643:324:5:-;;;;;;;;;;-1:-1:-1;12643:324:5;;;;;:::i;:::-;;:::i;9240:175::-;;;;;;;;;;-1:-1:-1;9240:175:5;;;;;:::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;2675:66:5;;;;;;;;;;;;-1:-1:-1;;;2675:66:5;;10363:708:0;;;;;;:::i;:::-;;:::i;8348:349::-;;;;;;:::i;:::-;;:::i;6961:300:5:-;;;;;;:::i;:::-;;:::i;9569:261::-;;;;;;;;;;-1:-1:-1;9569:261:5;;;;;:::i;:::-;;:::i;11693:435:0:-;;;;;;;;;;-1:-1:-1;11693:435:0;;;;;:::i;:::-;11963:19;11957:4;11950:33;;;11812:14;11996:26;;;;12106:4;12090:21;;12084:28;;11693:435;17979:783:5;18025:18;17937:20;18069:3;18046:26;18101:10;18087:24;;;18083:673;;18210:65;18246:4;17937:20;18269:4;17937:20;18210:5;:65::i;:::-;18015:747;17979:783::o;18083:673::-;18296:10;18310;18296:24;18292:464;;18340:10;-1:-1:-1;;;;;18354:23:5;18340:37;;18336:67;;18386:17;;-1:-1:-1;;;18386:17:5;;;;;;;;;;;18336:67;18457:4;17937:20;18528:4;17937:20;18418:22;18550:133;18574:14;18570:1;:18;18550:133;;;18613:55;18626:28;18647:6;:1;18651:2;18647:6;:::i;:::-;18640:13;;:4;:13;:::i;:::-;17937:20;;17775:198;18626:28;18656:11;18613:12;:55::i;:::-;18590:3;;18550:133;;;;18322:371;;18015:747;17979:783::o;18292:464::-;18720:25;;-1:-1:-1;;;18720:25:5;;;;;;;;;;;12113:297;12207:4;-1:-1:-1;;;;;;12230:41:5;;-1:-1:-1;;;12230:41:5;;:82;;;12275:37;12300:11;15177:10:3;15042:3;15038:21;;;;15171:17;;;15196:10;15190:17;;15168:40;15216:10;15210:17;;;15165:63;;14864:380;12275:37:5;12230:136;;;-1:-1:-1;3054:10:2;2930:3;2926:21;;;3048:17;;;3035:10;3029:17;;;;3026:40;12328:38:5;12230:173;;;-1:-1:-1;;;;;;;12370:33:5;;-1:-1:-1;;;12370:33:5;12230:173;12223:180;12113:297;-1:-1:-1;;12113:297:5:o;10534:163::-;-1:-1:-1;;;11897:18:1;11909:5;11897:11;:18::i;:::-;10648:42:5::1;10667:8;10677:12;10648:18;:42::i;:::-;10534:163:::0;;;:::o;13089:90::-;13135:13;13167:5;13160:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13089:90;:::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;7856:882:5:-;8068:9;8063:386;8083:19;;;8063:386;;;8128:43;8147:10;8159:8;;8168:1;8159:11;;;;;;;:::i;:::-;;;;;;;8128:18;:43::i;:::-;8123:78;;8180:21;;-1:-1:-1;;;8180:21:5;;;;;;;;;;;8123:78;8219:20;8227:8;;8236:1;8227:11;;;;;;;:::i;:::-;;;;;;;8219:7;:20::i;:::-;8215:46;;;8248:13;;-1:-1:-1;;;8248:13:5;;;;;;;;;;;8215:46;8281:17;;-1:-1:-1;;;8281:17:5;;;;8276:75;;8318:18;8324:8;;8333:1;8324:11;;;;;;;:::i;:::-;;;;;;;8318:5;:18::i;:::-;8365:34;8379:8;;8388:1;8379:11;;;;;;;:::i;:::-;;;;;;;3172:1;8365:13;:34::i;:::-;8419:19;8426:8;;8435:1;8426:11;;;;;;;:::i;:::-;;;;;;;8419:19;;;;4259:25:13;;4247:2;4232:18;;4113:177;8419:19:5;;;;;;;;8104:3;;8063:386;;;-1:-1:-1;8491:60:5;;-1:-1:-1;;;8491:60:5;;8545:4;8491:60;;;160:51:13;8459:29:5;;8499:23;-1:-1:-1;;;;;8491:45:5;;;;133:18:13;;8491:60:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;8459:92;;8569:23;-1:-1:-1;;;;;8561:37:5;;8606:9;8630:6;8638:21;8661:8;;8671:11;8684:15;8701:20;8561:170;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;8053:685;7856:882;;;;;;:::o;6184:148::-;6275:7;6301:24;6307:8;;6317:4;;6323:1;6301:5;:24::i;:::-;6294:31;6184:148;-1:-1:-1;;;;;6184:148:5:o;10291:109:1:-;10362:31;10375:10;10387:5;10362:12;:31::i;9752:123::-;12517:13:0;:11;:13::i;:::-;9844:24:1::1;9856:4;9862:5;9844:11;:24::i;8953:114:5:-:0;13430:7:1;11897:18;11909:5;11897:11;:18::i;:::-;-1:-1:-1;9036:17:5::1;:24:::0;;-1:-1:-1;;;;9036:24:5::1;-1:-1:-1::0;;;9036:24:5::1;::::0;;8953:114::o;5567:359::-;-1:-1:-1;;;;;5684:23:5;5670:37;:10;:37;5666:254;;3214:1;5727:22;5741:7;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;;18166:319;5727:22:5;-1:-1:-1;;;;;5727:34:5;;5723:63;;5770:16;;-1:-1:-1;;;5770:16:5;;;;;;;;;;;5723:63;5801:40;5819:1;5823:4;5829:2;5833:7;5801:9;:40::i;5666:254::-;5872:37;5891:4;5897:2;5901:7;5872:18;:37::i;9021:617:0:-;9114:15;7972:9;-1:-1:-1;;;;;9132:46:0;: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;3179:1058:2:-;3297:16;3470:21;;;3517:25;3511:4;3504:39;3592:4;3576:21;;3570:28;3627:2;3623:15;;;;3297:16;2531:5;;3623:15;3651:124;;3711:4;3705:11;3699:18;3689:28;;3754:6;3750:2;3746:15;3734:27;;3651:124;3844:2;3840:17;;;3828:30;3797:9;-1:-1:-1;;4144:14:2;;;4138:21;;4131:29;;4113:16;4095;4080:81;3179:1058;;4195:9;;4191:30;;-1:-1:-1;3179:1058:2;;-1:-1:-1;;3179:1058:2:o;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;10959:174:5:-;11013:16;11021:7;11013;:16::i;:::-;11009:118;;;11045:14;11051:7;11045:5;:14::i;11009:118::-;11090:26;11096:10;11108:7;11090:5;:26::i;10020:125:1:-;12517:13:0;:11;:13::i;:::-;10113:25:1::1;10126:4;10132:5;10113:12;:25::i;9720:456:0:-:0;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;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:0:-;12517:13;:11;:13::i;:::-;8834:21:::1;8852:1;8834:9;:21::i;:::-;8762:100::o:0;4495:679:5:-;4867:13;:29;4883:13;4867;:29;:::i;:::-;-1:-1:-1;4906:5:5;:23;4914:15;4906:5;:23;:::i;:::-;-1:-1:-1;4939:7:5;:27;4949:17;4939:7;:27;:::i;:::-;-1:-1:-1;4976:16:5;:36;;-1:-1:-1;;;;;;4976:36:5;-1:-1:-1;;;;;4976:36:5;;;;;5022:31;5039:13;5022:16;:31::i;:::-;5064:17;:38;;-1:-1:-1;;;;;;5064:38:5;-1:-1:-1;;;;;5064:38:5;;;;;5112:55;5131:13;5146:20;5112:18;:55::i;:::-;4495:679;;;;;;;:::o;13307:94::-;13355:13;13387:7;13380:14;;;;;:::i;13881:170::-;13973:16;14008:36;14025:5;14032;14039:4;14008:16;:36::i;:::-;14001:43;;13881:170;;;;;;:::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;10033:289:5:-;-1:-1:-1;;;11897:18:1;11909:5;11897:11;:18::i;:::-;10153:20:5::1;10176:17:::0;;-1:-1:-1;;;;;10203:38:5;;::::1;-1:-1:-1::0;;;;;;10203:38:5;::::1;::::0;::::1;::::0;;;10257:58:::1;::::0;;10176:17;;;::::1;18147:51:13::0;;;18229:2;18214:18;;18207:60;;;;10257:58:5::1;::::0;18120:18:13;10257:58:5::1;;;;;;;;10143:179;10033:289:::0;;:::o;11259:338::-;11321:10;-1:-1:-1;;;;;11335:23:5;11321:37;;11317:67;;11367:17;;-1:-1:-1;;;11367:17:5;;;;;;;;;;;11317:67;11395:22;11420:15;;;:9;:15;;;;;;-1:-1:-1;;;;;11420:15:5;;11445:41;;11479:7;11259:338;:::o;11445:41::-;11503:15;;;;:9;:15;;;;;;;11496:22;;-1:-1:-1;;;;;;11496:22:5;;;11529:61;-1:-1:-1;;;11529:61:5;;;;;4259:25:13;;;-1:-1:-1;;;;;11529:55:5;;;;;4232:18:13;;11529:61:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;11307:290;11259:338;:::o;11756:102::-;11812:4;11835:16;11843:7;11835;:16::i;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;12643:324:5:-;12703:13;12733:11;12741: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;12733:11:5;12728:44;;12753:19;;-1:-1:-1;;;12753:19:5;;;;;;;;;;;12728:44;12787:16;;-1:-1:-1;;;;;12787:16:5;:30;12783:105;;12847:16;;12840:37;;-1:-1:-1;;;12840:37:5;;;;;4259:25:13;;;-1:-1:-1;;;;;12847:16:5;;;;12840:33;;4232:18:13;;12840:37:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;12840:37:5;;;;;;;;;;;;:::i;12783:105::-;12905:55;12922:13;12905:55;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;12937:22;12956:2;12937:18;:22::i;:::-;12905:16;:55::i;9240:175::-;14880:7:1;11897:18;11909:5;11897:11;:18::i;:::-;9332:13:5::1;:19;9348:3:::0;9332:13;:19:::1;:::i;:::-;-1:-1:-1::0;9367:41:5::1;::::0;;9387:1:::1;19152:25:13::0;;-1:-1:-1;;19208:2:13;19193:18;;19186:34;9367:41:5::1;::::0;19125:18:13;9367:41:5::1;;;;;;;;9240:175:::0;;:::o;10363:708:0:-;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;6961:300:5:-:0;7116:7;7139:12;7154:39;7160:8;;7170:4;;7176:16;7154:5;:39::i;:::-;7204:15;;;;:9;:15;;;;;:28;;-1:-1:-1;;;;;;7204:28:5;7222:10;7204:28;;;7139:54;-1:-1:-1;;6961:300:5;;;;;;;:::o;9569:261::-;14880:7:1;11897:18;11909:5;11897:11;:18::i;:::-;9677:16:5::1;:36:::0;;-1:-1:-1;;;;;;9677:36:5::1;-1:-1:-1::0;;;;;9677:36:5;::::1;::::0;;::::1;::::0;;;9729:38:::1;::::0;::::1;::::0;-1:-1:-1;;9729:38:5::1;9782:41;::::0;;9802:1:::1;19152:25:13::0;;-1:-1:-1;;19208:2:13;19193:18;;19186:34;9782:41:5::1;::::0;19125:18:13;9782:41:5::1;18970:256:13::0;19609:1653:3;19675:40;19704:1;19708:2;19712;19675:20;:40::i;:::-;19853:2;19849;19845:11;19841:2;19837:20;19831:26;;19923:2;19917:4;19910:16;-1:-1:-1;;;19946:4:3;19939:38;20043:4;20037;20027:21;20023:2;20019:30;20015:2;20011:39;20092:13;20086:20;20181:15;20177:2;20173:24;20170:146;;;20229:10;20223:4;20216:24;20297:4;20291;20284:18;20170:146;20389:23;;20367:46;;20502:4;20495:16;;;20563:4;20557;20547:21;20614:18;;20634:1;20610:26;20786:20;20763:44;;20755:53;;20745:268;;20937:18;20931:2;20924:10;20921:1;20917:18;20910:46;20990:4;20984;20977:18;20745:268;21030:38;;21194:2;21190;21187:1;-1:-1:-1;;;;;;;;;;;21187:1:3;21142:10;21137:60;8925:119;;:::o;15514:587:5:-;15597:16;15605:7;15597;:16::i;:::-;15593:502;;;15629:13;15645:17;15654:7;15645:8;:17::i;:::-;15629:33;-1:-1:-1;;;;;;15751:19:5;;15747:200;;15790:27;15796:11;15809:7;15790:5;:27::i;:::-;15747:200;;;15857:5;-1:-1:-1;;;;;15842:20:5;:11;-1:-1:-1;;;;;15842:20:5;;15838:109;;15882:50;15900:1;15904:5;15911:11;15924:7;15882:9;:50::i;:::-;15961:32;15975:7;3214:1;15961:13;:32::i;:::-;16013:17;;4259:25:13;;;16013:17:5;;4247:2:13;4232:18;16013:17:5;4113:177:13;15593:502:5;16068:16;;-1:-1:-1;;;16068:16:5;;;;;;;;;;;4659:554:1;4844:15;4838:4;4831:29;4886:8;4880:4;4873:22;5077:5;5069:4;5063;5053:21;5047:28;5043:40;5033:164;;5116:10;5110:4;5103:24;5178:4;5172;5165:18;4464:715:2;-1:-1:-1;;;;;4692:32:2;2531:5;4740:32;;;4737:151;;;4804:10;4798:4;4791:24;4869:4;4863;4856:18;4737:151;4923:8;4919:2;4915:17;4955:6;4945:146;;4994:10;4988:4;4981:24;5072:4;5066;5059:18;4945:146;5138:24;;;5111:25;5104:59;-1:-1:-1;;4464:715:2:o;29039:1442:3:-;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;26907:1160::-;27027:11;27273:16;;;-1:-1:-1;;;;;27195:25:3;;;-1:-1:-1;;;27315:37:3;;27309:4;27302:51;27419:4;27403:21;;;27395:30;;27387:39;;27468:20;;27195:25;;27130:1;;27452:38;;27554:134;;27602:10;27596:4;27589:24;27669:4;27663;27656:18;27554:134;27773:5;27764:7;27761:18;27751:300;;27812:5;27806:4;27799:19;27938:4;27932;27922:21;27916:28;27906:131;;28003:13;28000:1;27996:21;27990:28;27981:7;27978:41;27968:51;;27906:131;27751:300;;26907:1160;;;;:::o;17545:119:5:-;17602: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;17625:32:5;;17545:119::o;23961:82:3:-;24015:21;24029:1;24033:2;24015:5;:21::i;18689:432::-;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;14817:419:5:-;15003:60;;-1:-1:-1;;;15003:60:5;;15057:4;15003:60;;;160:51:13;14948:7:5;;;;-1:-1:-1;;;;;15011:23:5;15003:45;;;;133:18:13;;15003:60:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;14971:92;;15088:23;-1:-1:-1;;;;;15080:37:5;;15125:9;15149:21;15172:8;;15182:7;;15191:10;15203:16;15080:149;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;15073:156;14817:419;-1:-1:-1;;;;;;;14817:419:5:o;4468:117:1:-;4546:32;4559:4;4565:5;4572;4546:12;:32::i;7292:355:0:-;-1:-1:-1;;7498:18:0;7488:8;7485:32;7475:156;;7550:10;7544:4;7537:24;7612:4;7606;7599:18;4217:115:1;4294:31;4307:4;4313:5;4320:4;4294:12;:31::i;32278:3007:3:-;32374:34;32395:4;32401:2;32405;32374:20;:34::i;:::-;32558:1;32744:16;;;-1:-1:-1;;;;;32668:23:3;;;-1:-1:-1;;;32786:32:3;;32780:4;32773:46;32885:4;32869:21;;;32861:30;;32853:39;;32928:20;;32668:23;;32582:25;;;;32626:23;;;;32974:36;;;33126:15;;;33115:27;;33105:229;;33266:18;33257:5;33250:13;33247:1;33243:21;33236:49;33315:4;33309;33302:18;33105:229;33437:4;33431;33424:18;33495:13;33492:1;33488:21;33482:28;33459:51;;33726:15;33722:2;33719:23;33712:4;33708:2;33705:12;33702:41;33697:2;33690:10;33687:57;33677:292;;33800:4;33794;33784:21;33778:28;33768:183;;33847:10;33841:4;33834:24;33924:4;33918;33911:18;33768:183;34044:15;34041:55;;;34092:1;34076:13;34073:1;34069:21;34062:32;34041:55;34208:13;;;34187:35;34165:58;;-1:-1:-1;34341:4:3;34335;34325:21;;;34391:22;;-1:-1:-1;;34387:30:3;34363:55;;-1:-1:-1;34509:16:3;;;34563:21;34632:20;;34415:1;34628:28;34808:20;34783:46;;34775:55;;34765:270;;34959:18;34953:2;34946:10;34943:1;34939:18;34932:46;35012:4;35006;34999:18;34765:270;35052:42;;35223:2;35219;35213:4;-1:-1:-1;;;;;;;;;;;35180:4:3;35168:10;35163:63;32278:3007;;;;:::o;10748:2886::-;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;-1:-1:-1;;;;;;;;;;;13529:4:3;13517:10;13512:63;10534:163:5;;;:::o;38588:1370:3:-;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;24332:2127;24398:13;24414:11;24422:2;24414:7;:11::i;:::-;24398:27;;24435:43;24456:5;24471:1;24475:2;24435:20;:43::i;:::-;-1:-1:-1;24680:4:3;24673:16;;;-1:-1:-1;;;;;24600:20:3;;;-1:-1:-1;;;24715:32:3;;24709:4;24702:46;24814:4;24798:21;;;24790:30;;24782:39;;24857:20;;24600;;24980:33;;;;25077:134;;25125:10;25119:4;25112:24;25192:4;25186;25179:18;25077:134;25305:5;25299:4;25292:19;25364:13;25361:1;25357:21;25351:28;25596:15;25592:2;25589:23;25581:5;25577:2;25574:13;25571:42;25566:2;25559:10;25556:58;25546:293;;25670:4;25664;25654:21;25648:28;25638:183;;25717:10;25711:4;25704:24;25794:4;25788;25781:18;25638:183;25914:15;25911:55;;;25962:1;25946:13;25943:1;25939:21;25932:32;25911:55;-1:-1:-1;26047:27:3;;26025:50;;26190:4;26184;26174:21;26236:18;;-1:-1:-1;;26232:26:3;26212:47;;26388:2;-1:-1:-1;26068:5:3;-1:-1:-1;;;;;;;;;;;;26333:10:3;26328:63;10534:163:5;;;:::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;6145:1089:0:-;-1:-1:-1;;6579:16:0;;-1:-1:-1;;;;;6427:26:0;;;;;;6539:38;6536:1;;6528:78;6703:16;;6698:3;6694:26;6681:40;;6663:59;;18015:747:5;17979:783::o;4883:1190:0:-;-1:-1:-1;;5125:9:0;5119:16;5116:150;;;5171:10;5165:4;5158:24;5243:4;5237;5230:18;5116:150;-1:-1:-1;;;;;5339:26:0;;;5462:16;;5457:3;5453:26;5440:40;;5422:59;;;5339:26;5607:1;5567:38;5607:1;;5556:63;18015:747:5;17979:783::o;16107:900::-;16200:16;16228:22;16253:16;16263:5;16253:9;:16::i;:::-;16228:41;-1:-1:-1;16279:18:5;;16228:41;-1:-1:-1;;;;;16339:29:5;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16339:29:5;-1:-1:-1;16311:57:5;-1:-1:-1;16396:5:5;16379:336;16408:4;16403:1;:9;16379:336;;16452:5;-1:-1:-1;;;;;16437:20:5;:11;16446:1;16437:8;:11::i;:::-;-1:-1:-1;;;;;16437:20:5;;16433:272;;16500:1;16477:8;16486:10;16477:20;;;;;;;;:::i;:::-;;;;;;;;;;:24;16552:12;;;;;16605:28;;;;16601:90;;-1:-1:-1;16664:8:5;-1:-1:-1;16657:15:5;;-1:-1:-1;;16657:15:5;16601:90;16414:3;;;;:::i;:::-;;;;16379:336;;;;16827:23;16867:10;-1:-1:-1;;;;;16853:25:5;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;16853:25:5;-1:-1:-1;16827:51:5;-1:-1:-1;16893:9:5;16888:89;16912:10;16908:1;:14;16888:89;;;16955:8;16964:1;16955:11;;;;;;;;:::i;:::-;;;;;;;16943:6;16950:1;16943:9;;;;;;;;:::i;:::-;;;;;;;;;;:23;16924:3;;16888:89;;;-1:-1:-1;16994:6:5;16107:900;-1:-1:-1;;;;;;;16107:900:5:o;3513:1560:4:-;3569:20;4020:4;4013;4007:11;4003:22;3993:32;;4063:4;4055:6;4051:17;4045:4;4038:31;4117:1;4109:6;4102:17;4182:6;4276:1;4272:6;4485:5;4467:398;4526:14;;;;4716:2;4730;4720:13;;4712:22;4526:14;4696:39;4770:2;4760:13;;4826:25;4467:398;4826:25;-1:-1:-1;;4887:16:4;;;-1:-1:-1;;4926:17:4;;;5019;;;4926;3513:1560;-1:-1:-1;3513:1560:4:o;38748:1214::-;38963:4;38957:11;39024:8;;-1:-1:-1;;38990:9:4;39129:4;39119:15;;39115:23;;39100:207;39193:9;;;39187:16;39171:14;;;39164:40;39226:9;;39271:22;39100:207;39271:22;39104:36;39338:1;39332:8;39379:4;39371:6;39367:17;39488:1;39481:4;39475;39471:15;39467:23;39452:207;39545:9;;;39539:16;39523:14;;;39516:40;39578:9;;39623:22;39452:207;39623:22;-1:-1:-1;;39786:1:4;39688:15;;39728:32;;;39744:4;39728:32;;39773:15;;;;39839:24;;39910:15;;;;39897:29;;-1:-1:-1;39736:6:4;38748:1214;-1:-1:-1;;38748:1214:4:o;17090:449:5:-;17200:10;-1:-1:-1;;;;;17214:23:5;17200:37;;17196:337;;17257:16;17265:7;17257;:16::i;:::-;:38;;;-1:-1:-1;;;;;;17277:18:5;;;17257:38;17253:101;;;17322:17;;-1:-1:-1;;;17322:17:5;;;;;;;;;;;17253:101;17401:1;17372:17;-1:-1:-1;;;;;17372:17:5;:31;17368:155;;17442:17;;17423:85;;-1:-1:-1;;;17423:85:5;;17478:10;17423:85;;;20878:51:13;-1:-1:-1;;;;;20965:32:13;;;20945:18;;;20938:60;21034:32;;;21014:18;;;21007:60;21083:18;;;21076:34;;;17442:17:5;;;;17423:54;;20850:19:13;;17423:85:5;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3116:967:1;3282:15;3276:4;3269:29;3324:4;3318;3311:18;3374:4;3368;3358:21;3452:8;3446:15;3559:5;3550:7;3547:18;3803:2;3793:62;;-1:-1:-1;3833:19:1;;;3820:33;;3793:62;3927:7;3917:8;3910:25;4059:7;4051:4;4045:11;4041:2;4037:20;4005:30;4002:1;3999;3994:73;;;;3116:967;;;:::o;222:286:13:-;280:6;333:2;321:9;312:7;308:23;304:32;301:52;;;349:1;346;339:12;301:52;375:23;;-1:-1:-1;;;;;;427:32:13;;417:43;;407:71;;474:1;471;464:12;705:131;-1:-1:-1;;;;;780:31:13;;770:42;;760:70;;826:1;823;816:12;841:134;909:20;;938:31;909:20;938:31;:::i;980:179::-;1047:20;;-1:-1:-1;;;;;1096:38:13;;1086:49;;1076:77;;1149:1;1146;1139:12;1164:319;1231:6;1239;1292:2;1280:9;1271:7;1267:23;1263:32;1260:52;;;1308:1;1305;1298:12;1260:52;1347:9;1334:23;1366:31;1391:5;1366:31;:::i;:::-;1416:5;-1:-1:-1;1440:37:13;1473:2;1458:18;;1440:37;:::i;:::-;1430:47;;1164:319;;;;;:::o;1488:418::-;1637:2;1626:9;1619:21;1600:4;1669:6;1663:13;1712:6;1707:2;1696:9;1692:18;1685:34;1771:6;1766:2;1758:6;1754:15;1749:2;1738:9;1734:18;1728:50;1827:1;1822:2;1813:6;1802:9;1798:22;1794:31;1787:42;1897:2;1890;1886:7;1881:2;1873:6;1869:15;1865:29;1854:9;1850:45;1846:54;1838:62;;;1488:418;;;;:::o;1911:226::-;1970:6;2023:2;2011:9;2002:7;1998:23;1994:32;1991:52;;;2039:1;2036;2029:12;1991:52;-1:-1:-1;2084:23:13;;1911:226;-1:-1:-1;1911:226:13:o;2142:367::-;2210:6;2218;2271:2;2259:9;2250:7;2246:23;2242:32;2239:52;;;2287:1;2284;2277:12;2239:52;2326:9;2313:23;2345:31;2370:5;2345:31;:::i;:::-;2395:5;2473:2;2458:18;;;;2445:32;;-1:-1:-1;;;2142:367:13:o;2514:163::-;2581:20;;2641:10;2630:22;;2620:33;;2610:61;;2667:1;2664;2657:12;2682:367;2745:8;2755:6;2809:3;2802:4;2794:6;2790:17;2786:27;2776:55;;2827:1;2824;2817:12;2776:55;-1:-1:-1;2850:20:13;;-1:-1:-1;;;;;2882:30:13;;2879:50;;;2925:1;2922;2915:12;2879:50;2962:4;2954:6;2950:17;2938:29;;3022:3;3015:4;3005:6;3002:1;2998:14;2990:6;2986:27;2982:38;2979:47;2976:67;;;3039:1;3036;3029:12;2976:67;2682:367;;;;;:::o;3054:188::-;3122:20;;-1:-1:-1;;;;;3171:46:13;;3161:57;;3151:85;;3232:1;3229;3222:12;3247:861;3368:6;3376;3384;3392;3400;3408;3461:3;3449:9;3440:7;3436:23;3432:33;3429:53;;;3478:1;3475;3468:12;3429:53;3501:28;3519:9;3501:28;:::i;:::-;3491:38;;3580:2;3569:9;3565:18;3552:32;-1:-1:-1;;;;;3599:6:13;3596:30;3593:50;;;3639:1;3636;3629:12;3593:50;3678:70;3740:7;3731:6;3720:9;3716:22;3678:70;:::i;:::-;3767:8;;-1:-1:-1;3652:96:13;-1:-1:-1;;3852:2:13;3837:18;;3824:32;3865:31;3824:32;3865:31;:::i;:::-;3915:5;-1:-1:-1;3972:2:13;3957:18;;3944:32;3985:33;3944:32;3985:33;:::i;:::-;4037:7;-1:-1:-1;4063:39:13;4097:3;4082:19;;4063:39;:::i;:::-;4053:49;;3247:861;;;;;;;;:::o;4583:767::-;4704:6;4712;4720;4728;4781:2;4769:9;4760:7;4756:23;4752:32;4749:52;;;4797:1;4794;4787:12;4749:52;4837:9;4824:23;-1:-1:-1;;;;;4862:6:13;4859:30;4856:50;;;4902:1;4899;4892:12;4856:50;4941:70;5003:7;4994:6;4983:9;4979:22;4941:70;:::i;:::-;5030:8;;-1:-1:-1;4915:96:13;-1:-1:-1;;5118:2:13;5103:18;;5090:32;-1:-1:-1;;;;;5134:32:13;;5131:52;;;5179:1;5176;5169:12;5131:52;5218:72;5282:7;5271:8;5260:9;5256:24;5218:72;:::i;:::-;4583:767;;;;-1:-1:-1;5309:8:13;-1:-1:-1;;;;4583:767:13:o;5722:508::-;5799:6;5807;5815;5868:2;5856:9;5847:7;5843:23;5839:32;5836:52;;;5884:1;5881;5874:12;5836:52;5923:9;5910:23;5942:31;5967:5;5942:31;:::i;:::-;5992:5;-1:-1:-1;6049:2:13;6034:18;;6021:32;6062:33;6021:32;6062:33;:::i;:::-;5722:508;;6114:7;;-1:-1:-1;;;6194:2:13;6179:18;;;;6166:32;;5722:508::o;6235:346::-;6303:6;6311;6364:2;6352:9;6343:7;6339:23;6335:32;6332:52;;;6380:1;6377;6370:12;6332:52;-1:-1:-1;;6425:23:13;;;6545:2;6530:18;;;6517:32;;-1:-1:-1;6235:346:13:o;6865:247::-;6924:6;6977:2;6965:9;6956:7;6952:23;6948:32;6945:52;;;6993:1;6990;6983:12;6945:52;7032:9;7019:23;7051:31;7076:5;7051:31;:::i;7117:127::-;7178:10;7173:3;7169:20;7166:1;7159:31;7209:4;7206:1;7199:15;7233:4;7230:1;7223:15;7249:275;7320:2;7314:9;7385:2;7366:13;;-1:-1:-1;;7362:27:13;7350:40;;-1:-1:-1;;;;;7405:34:13;;7441:22;;;7402:62;7399:88;;;7467:18;;:::i;:::-;7503:2;7496:22;7249:275;;-1:-1:-1;7249:275:13:o;7529:187::-;7578:4;-1:-1:-1;;;;;7603:6:13;7600:30;7597:56;;;7633:18;;:::i;:::-;-1:-1:-1;7699:2:13;7678:15;-1:-1:-1;;7674:29:13;7705:4;7670:40;;7529:187::o;7721:488::-;7764:5;7817:3;7810:4;7802:6;7798:17;7794:27;7784:55;;7835:1;7832;7825:12;7784:55;7875:6;7862:20;7906:53;7922:36;7951:6;7922:36;:::i;:::-;7906:53;:::i;:::-;7984:6;7975:7;7968:23;8038:3;8031:4;8022:6;8014;8010:19;8006:30;8003:39;8000:59;;;8055:1;8052;8045:12;8000:59;8120:6;8113:4;8105:6;8101:17;8094:4;8085:7;8081:18;8068:59;8176:1;8147:20;;;8169:4;8143:31;8136:42;;;;8151:7;7721:488;-1:-1:-1;;;7721:488:13:o;8214:1113::-;8356:6;8364;8372;8380;8388;8396;8404;8457:3;8445:9;8436:7;8432:23;8428:33;8425:53;;;8474:1;8471;8464:12;8425:53;8513:9;8500:23;8532:31;8557:5;8532:31;:::i;:::-;8582:5;-1:-1:-1;8638:2:13;8623:18;;8610:32;-1:-1:-1;;;;;8654:30:13;;8651:50;;;8697:1;8694;8687:12;8651:50;8720;8762:7;8753:6;8742:9;8738:22;8720:50;:::i;:::-;8710:60;;;8823:2;8812:9;8808:18;8795:32;-1:-1:-1;;;;;8842:8:13;8839:32;8836:52;;;8884:1;8881;8874:12;8836:52;8907;8951:7;8940:8;8929:9;8925:24;8907:52;:::i;:::-;8897:62;;;9012:2;9001:9;8997:18;8984:32;-1:-1:-1;;;;;9031:8:13;9028:32;9025:52;;;9073:1;9070;9063:12;9025:52;9096;9140:7;9129:8;9118:9;9114:24;9096:52;:::i;:::-;9086:62;;;9167:39;9201:3;9190:9;9186:19;9167:39;:::i;:::-;9157:49;;9225:39;9259:3;9248:9;9244:19;9225:39;:::i;:::-;9215:49;;9283:38;9316:3;9305:9;9301:19;9283:38;:::i;:::-;9273:48;;8214:1113;;;;;;;;;;:::o;9332:487::-;9409:6;9417;9425;9478:2;9466:9;9457:7;9453:23;9449:32;9446:52;;;9494:1;9491;9484:12;9446:52;9533:9;9520:23;9552:31;9577:5;9552:31;:::i;:::-;9602:5;9680:2;9665:18;;9652:32;;-1:-1:-1;9783:2:13;9768:18;;;9755:32;;9332:487;-1:-1:-1;;;9332:487:13:o;9824:611::-;10014:2;10026:21;;;10096:13;;9999:18;;;10118:22;;;9966:4;;10197:15;;;10171:2;10156:18;;;9966:4;10240:169;10254:6;10251:1;10248:13;10240:169;;;10315:13;;10303:26;;10358:2;10384:15;;;;10349:12;;;;10276:1;10269:9;10240:169;;;-1:-1:-1;10426:3:13;;9824:611;-1:-1:-1;;;;;9824:611:13:o;10440:416::-;10505:6;10513;10566:2;10554:9;10545:7;10541:23;10537:32;10534:52;;;10582:1;10579;10572:12;10534:52;10621:9;10608:23;10640:31;10665:5;10640:31;:::i;:::-;10690:5;-1:-1:-1;10747:2:13;10732:18;;10719:32;10789:15;;10782:23;10770:36;;10760:64;;10820:1;10817;10810:12;10760:64;10843:7;10833:17;;;10440:416;;;;;:::o;10861:983::-;10958:6;10966;10974;10982;10990;11043:3;11031:9;11022:7;11018:23;11014:33;11011:53;;;11060:1;11057;11050:12;11011:53;11099:9;11086:23;11118:31;11143:5;11118:31;:::i;:::-;11168:5;-1:-1:-1;11225:2:13;11210:18;;11197:32;11238:33;11197:32;11238:33;:::i;:::-;11290:7;-1:-1:-1;11370:2:13;11355:18;;11342:32;;-1:-1:-1;11451:2:13;11436:18;;11423:32;-1:-1:-1;;;;;11467:30:13;;11464:50;;;11510:1;11507;11500:12;11464:50;11533:22;;11586:4;11578:13;;11574:27;-1:-1:-1;11564:55:13;;11615:1;11612;11605:12;11564:55;11655:2;11642:16;-1:-1:-1;;;;;11673:6:13;11670:30;11667:50;;;11713:1;11710;11703:12;11667:50;11758:7;11753:2;11744:6;11740:2;11736:15;11732:24;11729:37;11726:57;;;11779:1;11776;11769:12;11726:57;10861:983;;;;-1:-1:-1;10861:983:13;;-1:-1:-1;;;11810:2:13;11802:11;;11832:6;10861:983::o;11849:322::-;11918:6;11971:2;11959:9;11950:7;11946:23;11942:32;11939:52;;;11987:1;11984;11977:12;11939:52;12027:9;12014:23;-1:-1:-1;;;;;12052:6:13;12049:30;12046:50;;;12092:1;12089;12082:12;12046:50;12115;12157:7;12148:6;12137:9;12133:22;12115:50;:::i;:::-;12105:60;11849:322;-1:-1:-1;;;;11849:322:13:o;12176:388::-;12244:6;12252;12305:2;12293:9;12284:7;12280:23;12276:32;12273:52;;;12321:1;12318;12311:12;12273:52;12360:9;12347:23;12379:31;12404:5;12379:31;:::i;:::-;12429:5;-1:-1:-1;12486:2:13;12471:18;;12458:32;12499:33;12458:32;12499:33;:::i;12569:841::-;12699:6;12707;12715;12723;12731;12784:2;12772:9;12763:7;12759:23;12755:32;12752:52;;;12800:1;12797;12790:12;12752:52;12840:9;12827:23;-1:-1:-1;;;;;12865:6:13;12862:30;12859:50;;;12905:1;12902;12895:12;12859:50;12944:70;13006:7;12997:6;12986:9;12982:22;12944:70;:::i;:::-;13033:8;;-1:-1:-1;12918:96:13;-1:-1:-1;;13121:2:13;13106:18;;13093:32;-1:-1:-1;;;;;13137:32:13;;13134:52;;;13182:1;13179;13172:12;13134:52;13221:72;13285:7;13274:8;13263:9;13259:24;13221:72;:::i;:::-;13312:8;;-1:-1:-1;13195:98:13;-1:-1:-1;13366:38:13;;-1:-1:-1;13400:2:13;13385:18;;13366:38;:::i;:::-;13356:48;;12569:841;;;;;;;;:::o;13415:127::-;13476:10;13471:3;13467:20;13464:1;13457:31;13507:4;13504:1;13497:15;13531:4;13528:1;13521:15;13547:168;13620:9;;;13651;;13668:15;;;13662:22;;13648:37;13638:71;;13689:18;;:::i;13720:125::-;13785:9;;;13806:10;;;13803:36;;;13819:18;;:::i;13850:380::-;13929:1;13925:12;;;;13972;;;13993:61;;14047:4;14039:6;14035:17;14025:27;;13993:61;14100:2;14092:6;14089:14;14069:18;14066:38;14063:161;;14146:10;14141:3;14137:20;14134:1;14127:31;14181:4;14178:1;14171:15;14209:4;14206:1;14199:15;14063:161;;13850:380;;;:::o;14235:127::-;14296:10;14291:3;14287:20;14284:1;14277:31;14327:4;14324:1;14317:15;14351:4;14348:1;14341:15;14367:251;14437:6;14490:2;14478:9;14469:7;14465:23;14461:32;14458:52;;;14506:1;14503;14496:12;14458:52;14538:9;14532:16;14557:31;14582:5;14557:31;:::i;14623:311::-;14711:19;;;14693:3;-1:-1:-1;;;;;14742:31:13;;14739:51;;;14786:1;14783;14776:12;14739:51;14822:6;14819:1;14815:14;14874:8;14867:5;14860:4;14855:3;14851:14;14838:45;14903:18;;;;14923:4;14899:29;;14623:311;-1:-1:-1;;;14623:311:13:o;15063:781::-;15402:10;15390:23;;15372:42;;-1:-1:-1;;;;;15450:32:13;;15445:2;15430:18;;15423:60;15519:3;15514:2;15499:18;;15492:31;;;-1:-1:-1;;15540:74:13;;15594:19;;15586:6;15578;15540:74;:::i;:::-;-1:-1:-1;;;;;15650:32:13;;;15645:2;15630:18;;15623:60;15720:32;;;;15714:3;15699:19;;15692:61;-1:-1:-1;;;;;15790:47:13;;;;15670:3;15769:19;;;15762:76;15720:32;15532:82;-1:-1:-1;;;;;15063:781:13:o;15975:518::-;16077:2;16072:3;16069:11;16066:421;;;16113:5;16110:1;16103:16;16157:4;16154:1;16144:18;16227:2;16215:10;16211:19;16208:1;16204:27;16198:4;16194:38;16263:4;16251:10;16248:20;16245:47;;;-1:-1:-1;16286:4:13;16245:47;16341:2;16336:3;16332:12;16329:1;16325:20;16319:4;16315:31;16305:41;;16396:81;16414:2;16407:5;16404:13;16396:81;;;16473:1;16459:16;;16440:1;16429:13;16396:81;;16669:1299;16795:3;16789:10;-1:-1:-1;;;;;16814:6:13;16811:30;16808:56;;;16844:18;;:::i;:::-;16873:97;16963:6;16923:38;16955:4;16949:11;16923:38;:::i;:::-;16917:4;16873:97;:::i;:::-;17019:4;17050:2;17039:14;;17067:1;17062:649;;;;17755:1;17772:6;17769:89;;;-1:-1:-1;17824:19:13;;;17818:26;17769:89;-1:-1:-1;;16626:1:13;16622:11;;;16618:24;16614:29;16604:40;16650:1;16646:11;;;16601:57;17871:81;;17032:930;;17062:649;15922:1;15915:14;;;15959:4;15946:18;;-1:-1:-1;;17098:20:13;;;17216:222;17230:7;17227:1;17224:14;17216:222;;;17312:19;;;17306:26;17291:42;;17419:4;17404:20;;;;17372:1;17360:14;;;;17246:12;17216:222;;;17220:3;17466:6;17457:7;17454:19;17451:201;;;17527:19;;;17521:26;-1:-1:-1;;17610:1:13;17606:14;;;17622:3;17602:24;17598:37;17594:42;17579:58;17564:74;;17451:201;-1:-1:-1;;;;17698:1:13;17682:14;;;17678:22;17665:36;;-1:-1:-1;16669:1299:13:o;18278:687::-;18358:6;18411:2;18399:9;18390:7;18386:23;18382:32;18379:52;;;18427:1;18424;18417:12;18379:52;18460:9;18454:16;-1:-1:-1;;;;;18485:6:13;18482:30;18479:50;;;18525:1;18522;18515:12;18479:50;18548:22;;18601:4;18593:13;;18589:27;-1:-1:-1;18579:55:13;;18630:1;18627;18620:12;18579:55;18663:2;18657:9;18688:53;18704:36;18733:6;18704:36;:::i;18688:53::-;18764:6;18757:5;18750:21;18812:7;18807:2;18798:6;18794:2;18790:15;18786:24;18783:37;18780:57;;;18833:1;18830;18823:12;18780:57;18881:6;18876:2;18872;18868:11;18863:2;18856:5;18852:14;18846:42;18933:1;18908:18;;;18928:2;18904:27;18897:38;;;;18912:5;18278:687;-1:-1:-1;;;;18278:687:13:o;19231:1082::-;-1:-1:-1;;;;;19590:32:13;;19572:51;;19610:3;19654:2;19639:18;;19632:31;;;-1:-1:-1;;19686:74:13;;19740:19;;19732:6;19724;19686:74;:::i;:::-;19796:22;;;19791:2;19776:18;;19769:50;19854:22;;;19930:6;;19904:2;19892:15;19954:1;19964:198;19978:6;19975:1;19972:13;19964:198;;;20070:10;20043:25;20061:6;20043:25;:::i;:::-;20039:42;20027:55;;20111:2;20137:15;;;;20102:12;;;;20000:1;19993:9;19964:198;;;-1:-1:-1;;;;;;20218:32:13;;20213:2;20198:18;;20191:60;-1:-1:-1;;;;;15005:46:13;;20302:3;20287:19;;14993:59;20179:3;-1:-1:-1;20260:47:13;;-1:-1:-1;14939:119:13;20260:47;19231:1082;;;;;;;;;;:::o;20318:184::-;20388:6;20441:2;20429:9;20420:7;20416:23;20412:32;20409:52;;;20457:1;20454;20447:12;20409:52;-1:-1:-1;20480:16:13;;20318:184;-1:-1:-1;20318:184:13:o;20507:135::-;20546:3;20567:17;;;20564:43;;20587:18;;:::i;:::-;-1:-1:-1;20634:1:13;20623:13;;20507:135::o
Swarm Source
ipfs://612dc5058916d3fa4ed3e1217ccfdeaf8b2b3791dbcb7ba4e6c95b348c2b201d
[ 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.