ERC-20
Overview
Max Total Supply
4 QWS
Holders
0
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract (WITH 0 Decimals)
Balance
1 QWSValue
$0.00Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
SheepNft
Compiler Version
v0.8.19+commit.7dd6d404
Optimization Enabled:
Yes with 1000000 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
/// SPDX-License-Identifier: MIT pragma solidity 0.8.19; // OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol) // OpenZeppelin Contracts (last updated v4.6.0) (interfaces/IERC2981.sol) // OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol) /** * @dev Interface of the ERC165 standard, as defined in the * https://eips.ethereum.org/EIPS/eip-165[EIP]. * * Implementers can declare support of contract interfaces, which can then be * queried by others ({ERC165Checker}). * * For an implementation, see {ERC165}. */ interface IERC165 { /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section] * to learn more about how these ids are created. * * This function call must use less than 30 000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); } /** * @dev Interface for the NFT Royalty Standard. * * A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal * support for royalty payments across all NFT marketplaces and ecosystem participants. * * _Available since v4.5._ */ interface IERC2981 is IERC165 { /** * @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of * exchange. The royalty amount is denominated and should be paid in that same unit of exchange. */ function royaltyInfo(uint256 tokenId, uint256 salePrice) external view returns (address receiver, uint256 royaltyAmount); } // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol) /** * @dev Implementation of the {IERC165} interface. * * Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check * for the additional interface id that will be supported. For example: * * ```solidity * function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { * return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId); * } * ``` * * Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation. */ abstract contract ERC165 is IERC165 { /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return interfaceId == type(IERC165).interfaceId; } } /** * @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information. * * Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for * specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first. * * Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the * fee is specified in basis points by default. * * IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See * https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to * voluntarily pay royalties together with sales, but note that this standard is not yet widely supported. * * _Available since v4.5._ */ abstract contract ERC2981 is IERC2981, ERC165 { struct RoyaltyInfo { address receiver; uint96 royaltyFraction; } RoyaltyInfo private _defaultRoyaltyInfo; mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) { return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId); } /** * @inheritdoc IERC2981 */ function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) { RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId]; if (royalty.receiver == address(0)) { royalty = _defaultRoyaltyInfo; } uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator(); return (royalty.receiver, royaltyAmount); } /** * @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a * fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an * override. */ function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /** * @dev Sets the royalty information that all ids in this contract will default to. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: invalid receiver"); _defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Removes default royalty information. */ function _deleteDefaultRoyalty() internal virtual { delete _defaultRoyaltyInfo; } /** * @dev Sets the royalty information for a specific token id, overriding the global default. * * Requirements: * * - `receiver` cannot be the zero address. * - `feeNumerator` cannot be greater than the fee denominator. */ function _setTokenRoyalty( uint256 tokenId, address receiver, uint96 feeNumerator ) internal virtual { require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice"); require(receiver != address(0), "ERC2981: Invalid parameters"); _tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator); } /** * @dev Resets royalty information for the token id back to the global default. */ function _resetTokenRoyalty(uint256 tokenId) internal virtual { delete _tokenRoyaltyInfo[tokenId]; } } // OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165Storage.sol) /** * @dev Storage based implementation of the {IERC165} interface. * * Contracts may inherit from this and call {_registerInterface} to declare * their support of an interface. */ abstract contract ERC165Storage is ERC165 { /** * @dev Mapping of interface ids to whether or not it's supported. */ mapping(bytes4 => bool) private _supportedInterfaces; /** * @dev See {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { return super.supportsInterface(interfaceId) || _supportedInterfaces[interfaceId]; } /** * @dev Registers the contract as an implementer of the interface defined by * `interfaceId`. Support of the actual ERC165 interface is automatic and * registering its interface id is not required. * * See {IERC165-supportsInterface}. * * Requirements: * * - `interfaceId` cannot be the ERC165 invalid interface (`0xffffffff`). */ function _registerInterface(bytes4 interfaceId) internal virtual { require(interfaceId != 0xffffffff, "ERC165: invalid interface id"); _supportedInterfaces[interfaceId] = true; } } /// @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) /// 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. 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..223] `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..225] `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 managed 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(shr(96, 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 a {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 a {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) 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 `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. 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) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 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 := 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 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @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)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // 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) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 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(0x00, 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 managed 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 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 {Transfer} 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(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits a {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 `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. 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) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 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(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } } /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover /// 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(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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: `not(_OWNER_SLOT_NOT)`. /// It is intentionally choosen 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. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// 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 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 { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), 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 { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // 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(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 be 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(not(_OWNER_SLOT_NOT)) } } /// @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)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } } /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles is Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. /// /// Note: This is equal to `_OWNER_SLOT_NOT` in for gas efficiency. uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @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 { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value and `or` it with `roles`. roles := or(sload(roleSlot), roles) // Store the new value. sstore(roleSlot, roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @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 { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) let roleSlot := keccak256(0x0c, 0x20) // Load the current value. let currentRoles := sload(roleSlot) // Use `and` to compute the intersection of `currentRoles` and `roles`, // `xor` it with `currentRoles` to flip the bits in the intersection. roles := xor(currentRoles, and(currentRoles, roles)) // Then, store the new value. sstore(roleSlot, roles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles) } } /// @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) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Load the stored value, and set the result to whether the // `and` intersection of the value and `roles` is not zero. result := iszero(iszero(and(sload(keccak256(0x0c, 0x20)), roles))) } } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x0c, _ROLE_SLOT_SEED) mstore(0x00, user) // Whether the stored value is contains all the set bits in `roles`. result := eq(and(sload(keccak256(0x0c, 0x20)), roles), roles) } } /// @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 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. function rolesFromOrdinals(uint8[] memory ordinals) public 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. function ordinalsFromRoles(uint256 roles) public 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) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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; } // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol) /** * @dev Interface of the ERC20 standard as defined in the EIP. */ interface IERC20 { /** * @dev Emitted when `value` tokens are moved from one account (`from`) to * another (`to`). * * Note that `value` may be zero. */ event Transfer(address indexed from, address indexed to, uint256 value); /** * @dev Emitted when the allowance of a `spender` for an `owner` is set by * a call to {approve}. `value` is the new allowance. */ event Approval(address indexed owner, address indexed spender, uint256 value); /** * @dev Returns the amount of tokens in existence. */ function totalSupply() external view returns (uint256); /** * @dev Returns the amount of tokens owned by `account`. */ function balanceOf(address account) external view returns (uint256); /** * @dev Moves `amount` tokens from the caller's account to `to`. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transfer(address to, uint256 amount) external returns (bool); /** * @dev Returns the remaining number of tokens that `spender` will be * allowed to spend on behalf of `owner` through {transferFrom}. This is * zero by default. * * This value changes when {approve} or {transferFrom} are called. */ function allowance(address owner, address spender) external view returns (uint256); /** * @dev Sets `amount` as the allowance of `spender` over the caller's tokens. * * Returns a boolean value indicating whether the operation succeeded. * * IMPORTANT: Beware that changing an allowance with this method brings the risk * that someone may use both the old and the new allowance by unfortunate * transaction ordering. One possible solution to mitigate this race * condition is to first reduce the spender's allowance to 0 and set the * desired value afterwards: * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729 * * Emits an {Approval} event. */ function approve(address spender, uint256 amount) external returns (bool); /** * @dev Moves `amount` tokens from `from` to `to` using the * allowance mechanism. `amount` is then deducted from the caller's * allowance. * * Returns a boolean value indicating whether the operation succeeded. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 amount ) external returns (bool); } interface AggregatorV3Interface { function decimals() external view returns (uint8); function description() external view returns (string memory); function version() external view returns (uint256); function getRoundData(uint80 _roundId) external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); function latestRoundData() external view returns ( uint80 roundId, int256 answer, uint256 startedAt, uint256 updatedAt, uint80 answeredInRound ); } // OpenZeppelin Contracts (last updated v4.8.0) (security/ReentrancyGuard.sol) /** * @dev Contract module that helps prevent reentrant calls to a function. * * Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier * available, which can be applied to functions to make sure there are no nested * (reentrant) calls to them. * * Note that because there is a single `nonReentrant` guard, functions marked as * `nonReentrant` may not call one another. This can be worked around by making * those functions `private`, and then adding `external` `nonReentrant` entry * points to them. * * TIP: If you would like to learn more about reentrancy and alternative ways * to protect against it, check out our blog post * https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul]. */ abstract contract ReentrancyGuard { // Booleans are more expensive than uint256 or any type that takes up a full // word because each write operation emits an extra SLOAD to first read the // slot's contents, replace the bits taken up by the boolean, and then write // back. This is the compiler's defense against contract upgrades and // pointer aliasing, and it cannot be disabled. // The values being non-zero value makes deployment a bit more expensive, // but in exchange the refund on every call to nonReentrant will be lower in // amount. Since refunds are capped to a percentage of the total // transaction's gas, it is best to keep them low in cases like this one, to // increase the likelihood of the full refund coming into effect. uint256 private constant _NOT_ENTERED = 1; uint256 private constant _ENTERED = 2; uint256 private _status; constructor() { _status = _NOT_ENTERED; } /** * @dev Prevents a contract from calling itself, directly or indirectly. * Calling a `nonReentrant` function from another `nonReentrant` * function is not supported. It is possible to prevent this from happening * by making the `nonReentrant` function external, and making it call a * `private` function that does the actual work. */ modifier nonReentrant() { _nonReentrantBefore(); _; _nonReentrantAfter(); } function _nonReentrantBefore() private { // On the first call to nonReentrant, _status will be _NOT_ENTERED require(_status != _ENTERED, "ReentrancyGuard: reentrant call"); // Any calls to nonReentrant after this point will fail _status = _ENTERED; } function _nonReentrantAfter() private { // By storing the original value once again, a refund is triggered (see // https://eips.ethereum.org/EIPS/eip-2200) _status = _NOT_ENTERED; } } // OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol) /** * @title ERC721 token receiver interface * @dev Interface for any contract that wants to support safeTransfers * from ERC721 asset contracts. */ interface IERC721Receiver { /** * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom} * by `operator` from `from`, this function is called. * * It must return its Solidity selector to confirm the token transfer. * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted. * * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`. */ function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /// @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) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(uint256(-value)); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksumed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(mload(a), 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, mload(a)) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a 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 { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // 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)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @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 behaviour is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behaviour is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } } /// @title SheepNft /// @notice This is the main contract of SheepNft, NFT with Islamic DeFi got explored contract SheepNft is ERC721, IERC721Receiver, OwnableRoles, ERC165Storage, ERC2981, ReentrancyGuard { IERC20 immutable _usdcToken; AggregatorV3Interface immutable _priceFeedUSDC; AggregatorV3Interface immutable _priceFeedETH; uint256 public _usdPrice; // Token name string private _name; // Token symbol string private _symbol; // Enable Trading bool public publicMintingEnabled = false; bool public ngoUsdcDistributed = false; bool public ngoEthDistributed = false; // max supply cap uint256 private constant MAX_SUPPLY = 2001; uint256 private constant MAX_PUBLIC = 6; address public devWallet = address(0x405DEF8C9FeaFd40a2a591c3Ee0118A27Aa43F0f); address public ischainWallet = address(0x6A07F68a60eB5890947A5af40F3eA928447d5527); // base URI string private _baseNftURI = "url/"; string private _ending = ".json"; // Mapping from owner to list of owned token IDs mapping(address => mapping(uint256 => uint256)) private _ownedTokens; // Mapping from token ID to index of the owner tokens list mapping(uint256 => uint256) private _ownedTokensIndex; // Array with all token ids, used for enumeration uint256[] private _allTokens; // Mapping from token id to position in the allTokens array mapping(uint256 => uint256) private _allTokensIndex; constructor(address _usdc, address _feedUsdc, address _feedEth) ERC721() { _usdcToken = IERC20(_usdc); _priceFeedUSDC = AggregatorV3Interface(_feedUsdc); _priceFeedETH = AggregatorV3Interface(_feedEth); _usdPrice = 199; // 199 USD by default _name = "SheepNft"; _symbol = "QWS"; _initializeOwner(msg.sender); _setDefaultRoyalty(msg.sender, 250); } /// @dev Returns the token collection name. function name() public view virtual override returns (string memory) { return _name; } /// @dev Returns the token collection symbol. function symbol() public view virtual override returns (string memory) { return _symbol; } /// @notice Minting the NFT publicly /// @dev _type 1 is for USDC and 0 is for ETH function publicMint(uint256 _tokenId, uint256 _type) external payable { require(msg.sender == tx.origin, "sheep: bot is not allowed"); require(totalSupply() < MAX_SUPPLY, "sheep: supply exceeded"); require(publicMintingEnabled, "sheep: minting is not enabled"); if (_type == 1) { uint256 price = getCurrentUsdcPrice(); _transferIn(price); } else { uint256 price = getCurrentEthPrice(); require(msg.value >= price, "sheep: insufficient ether"); } _safeMint(msg.sender, _tokenId); } /// @dev See {IERC165-supportsInterface}. function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721, ERC2981, ERC165Storage) returns (bool) { return interfaceId == type(IERC20).interfaceId || interfaceId == type(ERC2981).interfaceId || interfaceId == type(ERC165Storage).interfaceId || super.supportsInterface(interfaceId); } function renounceOwnership() public payable virtual override onlyOwner { require(false, "cannot renounce"); } function _transferIn(uint256 _amount) internal { require( _usdcToken.allowance(msg.sender, address(this)) >= _amount, "transferIn: insufficient allowance" ); require( _usdcToken.transferFrom(msg.sender, address(this), _amount), "transferFrom: cannot transfer token" ); } function enablePublicMinting() external onlyOwner { publicMintingEnabled = true; } function disablePublicMinting() external onlyOwner { publicMintingEnabled = false; } function distributeTeam(uint256 _type) external onlyOwner { if (_type == 1) { _distributeUSDC(); } else { require(_type == 0, "token type is wrong"); _distributeETH(); } } function distributeNGO(address _to, uint256 _amount, uint256 _type) external onlyOwner { if (_type == 1) { require(ngoUsdcDistributed == false, "please distribute USDC to the team first"); require(_usdcToken.balanceOf(address(this)) > _amount, "No USDC to distribute"); _distributeUsdcNGO(_to, _amount); } else { require(ngoEthDistributed == false, "please distribute ETH to the team first"); require(address(this).balance > _amount, "No Ether to distribute"); _distributeEthNGO(_to, _amount); } } /// @notice Distribution of USDC received from minting to NGO. function _distributeUsdcNGO(address _to, uint256 _amount) private { _usdcToken.transfer(_to, _amount); ngoUsdcDistributed = true; } /// @notice Distribution of ETH received from minting to NGO. function _distributeEthNGO(address _to, uint256 _amount) private { (bool successNGOEth,) = _to.call{value: _amount}(""); require(successNGOEth, "Transfer to NGO failed"); ngoEthDistributed = true; } /// @notice Distribution of USDC received from minting. /// The _distribute should be called after the revenue is calculated. function _distributeUSDC() private { require(ngoUsdcDistributed == true, "please distribute USDC to the NGO first"); uint256 usdcBalance = _usdcToken.balanceOf(address(this)); require(usdcBalance > 0, "No USDC to distribute"); uint256 forDevsUsdc = usdcBalance / 2; uint256 forIschainUsdc = usdcBalance / 2; _usdcToken.transfer(devWallet, forDevsUsdc); _usdcToken.transfer(ischainWallet, forIschainUsdc); ngoUsdcDistributed = false; } /// @notice Distribution of ETH received from minting. /// The _distribute should be called after the revenue is calculated. function _distributeETH() private { require(ngoEthDistributed == true, "please distribute ETH to the NGO first"); uint256 ethBalance = address(this).balance; require(ethBalance > 0, "No Ether to distribute"); uint256 forDevsEth = ethBalance / 2; uint256 forIschainEth = ethBalance - forDevsEth; (bool successDevsEth,) = devWallet.call{value: forDevsEth}(""); require(successDevsEth, "Transfer to DEVS failed"); (bool successIschainEth,) = ischainWallet.call{value: forIschainEth}(""); require(successIschainEth, "Transfer to OFFCHAIN failed"); ngoEthDistributed = false; } function getCurrentUsdcPrice() public view returns (uint256) { (, int256 price,, uint256 updatedAt,) = _priceFeedUSDC.latestRoundData(); require(price > 0, "Feed price should be greater than 0"); require(updatedAt > block.timestamp - 3600, "Stale Price"); uint256 usdcPrice = _usdPrice * 10 ** _priceFeedUSDC.decimals() / uint256(price); return usdcPrice * 10 ** 6; } function getCurrentEthPrice() public view returns (uint256) { (, int256 price,, uint256 updatedAt,) = _priceFeedETH.latestRoundData(); require(price > 0, "Feed price should be greater than 0"); require(updatedAt > block.timestamp - 3600, "Stale Price"); uint256 weiPerUsd = (1 ether * _priceFeedETH.decimals()) / uint256(price); uint256 usdcPrice = (_usdPrice * weiPerUsd * 10 ** _priceFeedETH.decimals() / _priceFeedETH.decimals()); return usdcPrice; } function setUSDPrice(uint256 _newPrice) external onlyOwner { _usdPrice = _newPrice; } function ownerMint(address to, uint256 tokenId) external onlyOwner { // mint NFTs _safeMint(to, tokenId); } function tokenExists(uint256 _id) public view returns (bool) { return _exists(_id); } /// @dev See {ERC721A-tokenURI} function tokenURI(uint256 tokenId) public view virtual override(ERC721) returns (string memory) { if (!_exists(tokenId)) revert TokenDoesNotExist(); string memory baseURI = _baseURI(); return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, LibString.toString(tokenId), _ending)) : ""; } /// @dev @dev See {ERC721A-_baseURI} function _baseURI() internal view virtual returns (string memory) { return _baseNftURI; } function setBaseURI(string calldata newURI) external onlyOwner { _baseNftURI = newURI; } function setURIExtention(string calldata newExtention) external onlyOwner { _ending = newExtention; } function setDevWallet(address _newDevWallet) external onlyOwner { devWallet = _newDevWallet; } function setIschainWallet(address _newIschainWallet) external onlyOwner { ischainWallet = _newIschainWallet; } function burn(uint256 tokenId) public virtual { //solhint-disable-next-line max-line-length require( _isApprovedOrOwner(msg.sender, tokenId), "ERC721: caller is not token owner or approved" ); _burn(tokenId); } /** * @dev See {IERC721Enumerable-tokenOfOwnerByIndex}. */ function tokenOfOwnerByIndex( address owner, uint256 index ) public view virtual returns (uint256) { require(index < ERC721.balanceOf(owner), "ERC721Enumerable: owner index out of bounds"); return _ownedTokens[owner][index]; } /** * @dev See {IERC721Enumerable-totalSupply}. */ function totalSupply() public view virtual returns (uint256) { return _allTokens.length; } /** * @dev See {IERC721Enumerable-tokenByIndex}. */ function tokenByIndex(uint256 index) public view virtual returns (uint256) { require(index < this.totalSupply(), "ERC721Enumerable: global index out of bounds"); return _allTokens[index]; } /** * @dev See {ERC721-_beforeTokenTransfer}. */ function _beforeTokenTransfer( address from, address to, uint256 id ) internal virtual override { uint256 tokenId = id; if (from == address(0)) { _addTokenToAllTokensEnumeration(tokenId); } else if (from != to) { _removeTokenFromOwnerEnumeration(from, tokenId); } if (to == address(0)) { _removeTokenFromAllTokensEnumeration(tokenId); } else if (to != from) { _addTokenToOwnerEnumeration(to, tokenId); } } /** * @dev Private function to add a token to this extension's ownership-tracking data * structures. * @param to address representing the new owner of the given token ID * @param tokenId uint256 ID of the token to be added to the tokens list of the given address */ function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private { uint256 length = ERC721.balanceOf(to); _ownedTokens[to][length] = tokenId; _ownedTokensIndex[tokenId] = length; } /** * @dev Private function to add a token to this extension's token tracking data structures. * @param tokenId uint256 ID of the token to be added to the tokens list */ function _addTokenToAllTokensEnumeration(uint256 tokenId) private { _allTokensIndex[tokenId] = _allTokens.length; _allTokens.push(tokenId); } /** * @dev Private function to remove a token from this extension's ownership-tracking data * structures. Note that * while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ * updated: this allows for * gas optimizations e.g. when performing a transfer operation (avoiding double writes). * This has O(1) time complexity, but alters the order of the _ownedTokens array. * @param from address representing the previous owner of the given token ID * @param tokenId uint256 ID of the token to be removed from the tokens list of the given * address */ function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private { // To prevent a gap in from's tokens array, we store the last token in the index of the // token to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = ERC721.balanceOf(from) - 1; uint256 tokenIndex = _ownedTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary if (tokenIndex != lastTokenIndex) { uint256 lastTokenId = _ownedTokens[from][lastTokenIndex]; _ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the // to-delete token _ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index } // This also deletes the contents at the last position of the array delete _ownedTokensIndex[tokenId]; delete _ownedTokens[from][lastTokenIndex]; } /** * @dev Private function to remove a token from this extension's token tracking data * structures. * This has O(1) time complexity, but alters the order of the _allTokens array. * @param tokenId uint256 ID of the token to be removed from the tokens list */ function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private { // To prevent a gap in the tokens array, we store the last token in the index of the token // to delete, and // then delete the last slot (swap and pop). uint256 lastTokenIndex = _allTokens.length - 1; uint256 tokenIndex = _allTokensIndex[tokenId]; // When the token to delete is the last token, the swap operation is unnecessary. However, // since this occurs so // rarely (when the last minted token is burnt) that we still do the swap here to avoid the // gas cost of adding // an 'if' statement (like in _removeTokenFromOwnerEnumeration) uint256 lastTokenId = _allTokens[lastTokenIndex]; _allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete // token _allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index // This also deletes the contents at the last position of the array delete _allTokensIndex[tokenId]; _allTokens.pop(); } function onERC721Received( address, address, uint256, bytes memory ) public virtual override returns (bytes4) { return this.onERC721Received.selector; } }
{ "remappings": [ "@chainlink/=lib/chainlink/contracts/src/", "@erc721A/=lib/ERC721A/", "@murky/=lib/murky/", "@openzeppelin/=lib/openzeppelin-contracts/", "@solady/=lib/solady/src/", "ERC721A/=lib/ERC721A/contracts/", "chainlink/=lib/chainlink/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/src/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/" ], "optimizer": { "enabled": true, "runs": 1000000 }, "metadata": { "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"_usdc","type":"address"},{"internalType":"address","name":"_feedUsdc","type":"address"},{"internalType":"address","name":"_feedEth","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"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"},{"inputs":[],"name":"_usdPrice","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":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"devWallet","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"disablePublicMinting","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"},{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"distributeNGO","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"distributeTeam","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"enablePublicMinting","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":"getCurrentEthPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getCurrentUsdcPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"result","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":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ischainWallet","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":"ngoEthDistributed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ngoUsdcDistributed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"bytes","name":"","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"ordinalsFromRoles","outputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"uint256","name":"_type","type":"uint256"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"publicMintingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"name":"rolesFromOrdinals","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"pure","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":"","type":"address"},{"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":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newDevWallet","type":"address"}],"name":"setDevWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_newIschainWallet","type":"address"}],"name":"setIschainWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newExtention","type":"string"}],"name":"setURIExtention","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newPrice","type":"uint256"}],"name":"setUSDPrice","outputs":[],"stateMutability":"nonpayable","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":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_id","type":"uint256"}],"name":"tokenExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","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":"id","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
6007805476405def8c9feafd40a2a591c3ee0118a27aa43f0f0000006001600160b81b0319909116179055600880546001600160a01b031916736a07f68a60eb5890947a5af40f3ea928447d5527179055610120604052600460e09081526375726c2f60e01b6101005260099062000078908262000358565b50604080518082019091526005815264173539b7b760d91b6020820152600a90620000a4908262000358565b50348015620000b257600080fd5b506040516200479938038062004799833981016040819052620000d59162000441565b60016003556001600160a01b0380841660805282811660a052811660c05260c760045560408051808201909152600881526714da19595c13999d60c21b602082015260059062000126908262000358565b5060408051808201909152600381526251575360e81b602082015260069062000150908262000358565b506200015c3362000172565b620001693360fa620001ae565b5050506200048b565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b6127106001600160601b0382161115620002225760405162461bcd60e51b815260206004820152602a60248201527f455243323938313a20726f79616c7479206665652077696c6c206578636565646044820152692073616c65507269636560b01b60648201526084015b60405180910390fd5b6001600160a01b0382166200027a5760405162461bcd60e51b815260206004820152601960248201527f455243323938313a20696e76616c696420726563656976657200000000000000604482015260640162000219565b604080518082019091526001600160a01b039092168083526001600160601b039091166020909201829052600160a01b90910217600155565b634e487b7160e01b600052604160045260246000fd5b600181811c90821680620002de57607f821691505b602082108103620002ff57634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200035357600081815260208120601f850160051c810160208610156200032e5750805b601f850160051c820191505b818110156200034f578281556001016200033a565b5050505b505050565b81516001600160401b03811115620003745762000374620002b3565b6200038c81620003858454620002c9565b8462000305565b602080601f831160018114620003c45760008415620003ab5750858301515b600019600386901b1c1916600185901b1785556200034f565b600085815260208120601f198616915b82811015620003f557888601518255948401946001909101908401620003d4565b5085821015620004145787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80516001600160a01b03811681146200043c57600080fd5b919050565b6000806000606084860312156200045757600080fd5b620004628462000424565b9250620004726020850162000424565b9150620004826040850162000424565b90509250925092565b60805160a05160c051614298620005016000396000818161182e015281816119cb01528181611a870152611b1901526000818161201c01526121b901526000818161162a015281816127970152818161296701528181612ab001528181612c8c01528181612ded0152612eaa01526142986000f3fe60806040526004361061035f5760003560e01c806355f804b3116101c65780639ec3aa01116100f7578063d39f456111610095578063f04e283e1161006f578063f04e283e14610a30578063f2fde38b14610a43578063f7beb98a14610a56578063fee81cf414610a6b57600080fd5b8063d39f4561146109c7578063d7533f02146109dc578063e985e9c5146109fa57600080fd5b8063b6fc7064116100d1578063b6fc706414610948578063b88d4fde14610967578063c87b56dd1461097a578063d2d240431461099a57600080fd5b80639ec3aa01146108e8578063a22cb46514610908578063b57ac9e31461092857600080fd5b80638dde257d116101645780639125009d1161013e5780639125009d146108965780639190ad47146108ab57806395d89b41146108c057806398ae99a8146108d557600080fd5b80638dde257d146108285780638dec9f7a146108485780638ea5220f1461086257600080fd5b8063715018a6116101a0578063715018a61461079f5780637359e41f146107a75780637d031354146107d45780638da5cb5b146107f457600080fd5b806355f804b31461073f5780636352211e1461075f57806370a082311461077f57600080fd5b80631f53ac02116102a057806342966c681161023e5780634a4ee7b1116102185780634a4ee7b1146106cd5780634f6ccce7146106e0578063514e62fc1461070057806354d1f13d1461073757600080fd5b806342966c681461066d5780634408a0461461068d578063484b973c146106ad57600080fd5b80632a55205a1161027a5780632a55205a146105bb5780632de94807146106075780632f745c591461063a57806342842e0e1461065a57600080fd5b80631f53ac021461058057806323b872dd146105a057806325692962146105b357600080fd5b8063147d959a1161030d578063183a4f6e116102e7578063183a4f6e1461050d5780631a16aacd146105205780631c10893f146105365780631cd64df41461054957600080fd5b8063147d959a14610463578063150b7a021461048357806318160ddd146104f857600080fd5b8063081812fc1161033e578063081812fc146103db578063095ea7b31461042057806313a661ed1461043557600080fd5b8062923f9e1461036457806301ffc9a71461039957806306fdde03146103b9575b600080fd5b34801561037057600080fd5b5061038461037f36600461375c565b610a9e565b60405190151581526020015b60405180910390f35b3480156103a557600080fd5b506103846103b4366004613775565b610ada565b3480156103c557600080fd5b506103ce610bc8565b60405161039091906137db565b3480156103e757600080fd5b506103fb6103f636600461375c565b610c5a565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b61043361042e366004613850565b610cbf565b005b34801561044157600080fd5b50610455610450366004613907565b610cce565b604051908152602001610390565b34801561046f57600080fd5b5061043361047e36600461375c565b610d15565b34801561048f57600080fd5b506104c761049e3660046139b9565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610390565b34801561050457600080fd5b50600d54610455565b61043361051b36600461375c565b610d22565b34801561052c57600080fd5b5061045560045481565b610433610544366004613850565b610d2f565b34801561055557600080fd5b50610384610564366004613850565b638b78c6d8600c90815260009290925260209091205481161490565b34801561058c57600080fd5b5061043361059b366004613a97565b610d41565b6104336105ae366004613ab2565b610d97565b610433610ef9565b3480156105c757600080fd5b506105db6105d6366004613aee565b610f49565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610390565b34801561061357600080fd5b50610455610622366004613a97565b638b78c6d8600c908152600091909152602090205490565b34801561064657600080fd5b50610455610655366004613850565b611042565b610433610668366004613ab2565b611116565b34801561067957600080fd5b5061043361068836600461375c565b611143565b34801561069957600080fd5b506104336106a8366004613b52565b6111e2565b3480156106b957600080fd5b506104336106c8366004613850565b6111f7565b6104336106db366004613850565b611209565b3480156106ec57600080fd5b506104556106fb36600461375c565b61121b565b34801561070c57600080fd5b5061038461071b366004613850565b638b78c6d8600c90815260009290925260209091205416151590565b61043361133f565b34801561074b57600080fd5b5061043361075a366004613b52565b61137b565b34801561076b57600080fd5b506103fb61077a36600461375c565b611390565b34801561078b57600080fd5b5061045561079a366004613a97565b6113f0565b610433611440565b3480156107b357600080fd5b506107c76107c236600461375c565b6114ac565b6040516103909190613b94565b3480156107e057600080fd5b506104336107ef366004613a97565b611503565b34801561080057600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103fb565b34801561083457600080fd5b50610433610843366004613bdb565b611552565b34801561085457600080fd5b506007546103849060ff1681565b34801561086e57600080fd5b506007546103fb906301000000900473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108a257600080fd5b50610455611827565b3480156108b757600080fd5b50610433611bdc565b3480156108cc57600080fd5b506103ce611c0e565b6104336108e3366004613aee565b611c1d565b3480156108f457600080fd5b5061043361090336600461375c565b611e0a565b34801561091457600080fd5b50610433610923366004613c1c565b611e92565b34801561093457600080fd5b506007546103849062010000900460ff1681565b34801561095457600080fd5b5060075461038490610100900460ff1681565b610433610975366004613c53565b611ee8565b34801561098657600080fd5b506103ce61099536600461375c565b611f43565b3480156109a657600080fd5b506008546103fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109d357600080fd5b50610455612015565b3480156109e857600080fd5b506040516202a3008152602001610390565b348015610a0657600080fd5b50610384610a15366004613cc2565b601c52670a5a2e7a000000006008526000526030600c205490565b610433610a3e366004613a97565b61227f565b610433610a51366004613a97565b6122bc565b348015610a6257600080fd5b506104336122e3565b348015610a7757600080fd5b50610455610a86366004613a97565b63389a75e1600c908152600091909152602090205490565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260208120820182015460601b5b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f36372b07000000000000000000000000000000000000000000000000000000001480610b6d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f2baae9fd00000000000000000000000000000000000000000000000000000000145b80610bb957507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b80610ad45750610ad482612318565b606060058054610bd790613cf5565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0390613cf5565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020812082018201805473ffffffffffffffffffffffffffffffffffffffff16610cb55763ceea21b66000526004601cfd5b6001015492915050565b610cca33838361236e565b5050565b6000815160051b5b8015610d0f57828101516001901b909117907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001610cd6565b50919050565b610d1d612424565b600455565b610d2c338261245a565b50565b610d37612424565b610cca82826124a9565b610d49612424565b6007805473ffffffffffffffffffffffffffffffffffffffff9092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b610da28383836124f4565b60008181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610e225782610e145763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b84610e355763ea553b346000526004601cfd5b856000528160010154925082331486331417610e63576030600c2054610e6357634b6e7f186000526004601cfd5b8215610e7157600082600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055600084905220805460010163ffffffff8116610ec9576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a45b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600082815260026020908152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1692820192909252829161100457506040805180820190915260015473ffffffffffffffffffffffffffffffffffffffff811682527401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1660208201525b602081015160009061271090611028906bffffffffffffffffffffffff1687613d71565b6110329190613d88565b91519350909150505b9250929050565b600061104d836113f0565b82106110e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e647300000000000000000000000000000000000000000060648201526084015b60405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600b60209081526040808320938352929052205490565b611121838383610d97565b813b15610ef457610ef483838360405180602001604052806000815250612606565b61114d3382612698565b6111d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f7665640000000000000000000000000000000000000060648201526084016110d7565b610d2c81612726565b6111ea612424565b600a610ef4828483613e09565b6111ff612424565b610cca8282612731565b611211612424565b610cca828261245a565b60003073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190613f23565b821061131a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e6473000000000000000000000000000000000000000060648201526084016110d7565b600d828154811061132d5761132d613f3c565b90600052602060002001549050919050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611383612424565b6009610ef4828483613e09565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806113eb5763ceea21b66000526004601cfd5b919050565b60008161140557638f4eb6046000526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c528160005263ffffffff601c600c2054169050919050565b611448612424565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f63616e6e6f742072656e6f756e6365000000000000000000000000000000000060448201526064016110d7565b565b604051602081016000835b81835260051b6020169091019060010183811c806114b75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08282030160051c8252604052919050565b61150b612424565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61155a612424565b8060010361171b57600754610100900460ff16156115fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f706c656173652064697374726962757465205553444320746f2074686520746560448201527f616d20666972737400000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa9190613f23565b11611711576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f205553444320746f2064697374726962757465000000000000000000000060448201526064016110d7565b610ef4838361274b565b60075462010000900460ff16156117b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f706c6561736520646973747269627574652045544820746f207468652074656160448201527f6d2066697273740000000000000000000000000000000000000000000000000060648201526084016110d7565b81471161181d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f20457468657220746f20646973747269627574650000000000000000000060448201526064016110d7565b610ef48383612835565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bb9190613f85565b5093505092505060008213611952576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f466565642070726963652073686f756c6420626520677265617465722074686160448201527f6e2030000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b61195e610e1042613fd5565b81116119c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5374616c6520507269636500000000000000000000000000000000000000000060448201526064016110d7565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a589190613fe8565b611a6d9060ff16670de0b6b3a7640000614005565b67ffffffffffffffff16611a819190613d88565b905060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190613fe8565b60ff167f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba69190613fe8565b611bb190600a614149565b83600454611bbf9190613d71565b611bc99190613d71565b611bd39190613d88565b95945050505050565b611be4612424565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b606060068054610bd790613cf5565b333214611c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f73686565703a20626f74206973206e6f7420616c6c6f7765640000000000000060448201526064016110d7565b6107d1611c92600d5490565b10611cf9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f73686565703a20737570706c792065786365656465640000000000000000000060448201526064016110d7565b60075460ff16611d65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f73686565703a206d696e74696e67206973206e6f7420656e61626c656400000060448201526064016110d7565b80600103611d88576000611d77612015565b9050611d8281612931565b50611e00565b6000611d92611827565b905080341015611dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f73686565703a20696e73756666696369656e742065746865720000000000000060448201526064016110d7565b505b610cca3383612731565b611e12612424565b80600103611e2257610d2c612bbe565b8015611e8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f746f6b656e20747970652069732077726f6e670000000000000000000000000060448201526064016110d7565b610d2c612f47565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b611ef3858585610d97565b833b15611f3c57611f3c85858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061260692505050565b5050505050565b6060611f808260008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b90565b611fb6576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc0613235565b90508051600003611fe0576040518060200160405280600081525061200e565b80611fea84613244565b600a604051602001611ffe93929190614158565b6040516020818303038152906040525b9392505050565b60008060007f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a99190613f85565b5093505092505060008213612140576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f466565642070726963652073686f756c6420626520677265617465722074686160448201527f6e2030000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b61214c610e1042613fd5565b81116121b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5374616c6520507269636500000000000000000000000000000000000000000060448201526064016110d7565b6000827f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122469190613fe8565b61225190600a614149565b60045461225e9190613d71565b6122689190613d88565b905061227781620f4240613d71565b935050505090565b612287612424565b63389a75e1600c52806000526020600c2080544211156122af57636f5e88186000526004601cfd5b60009055610d2c816132a6565b6122c4612424565b8060601b6122da57637448fbae6000526004601cfd5b610d2c816132a6565b6122eb612424565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610ad45750610ad48261330c565b60001960601c8281169250838116935081600052837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c52602060002082018201805482169150816123ca5763ceea21b66000526004601cfd5b8185148515176123f057816000526030600c20546123f057634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a450505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433146114aa576382b429006000526004601cfd5b638b78c6d8600c52816000526020600c20805482811681189250508181555080600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a35050565b638b78c6d8600c52816000526020600c208181541791508181555080600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a35050565b8073ffffffffffffffffffffffffffffffffffffffff841661255d5761255881600d80546000838152600e60205260408120829055600182018355919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50155565b61259a565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461259a5761259a8482613391565b73ffffffffffffffffffffffffffffffffffffffff83166125c3576125be81613448565b612600565b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146126005761260083826134f7565b50505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a0840152801561264d578060c08401826020870160045afa505b60208360a48301601c860160008a5af1612676573d15612671573d6000803e3d6000fd5b600083525b508060e01b8251146126905763d1a57ed66000526004601cfd5b505050505050565b600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c526020909120820182018054919360019216806126ff5763ceea21b66000526004601cfd5b80851461271e57806000526030600c205461271e578160010154851492505b505092915050565b610d2c600082613548565b610cca828260405180602001604052806000815250613662565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af11580156127e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128049190614216565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905550565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461288f576040519150601f19603f3d011682016040523d82523d6000602084013e612894565b606091505b50509050806128ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5472616e7366657220746f204e474f206661696c65640000000000000000000060448201526064016110d7565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff166201000017905550565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015281907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e79190613f23565b1015612a75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f7472616e73666572496e3a20696e73756666696369656e7420616c6c6f77616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614216565b610d2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f7472616e7366657246726f6d3a2063616e6e6f74207472616e7366657220746f60448201527f6b656e000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b60075460ff610100909104161515600114612c5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f706c656173652064697374726962757465205553444320746f20746865204e4760448201527f4f2066697273740000000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000000000000000000000000000000000000000000073ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0c9190613f23565b905060008111612d78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f205553444320746f2064697374726962757465000000000000000000000060448201526064016110d7565b6000612d85600283613d88565b90506000612d94600284613d88565b6007546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff630100000090920482166004820152602481018590529192507f0000000000000000000000000000000000000000000000000000000000000000169063a9059cbb906044016020604051808303816000875af1158015612e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5a9190614216565b506008546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390527f00000000000000000000000000000000000000000000000000000000000000009091169063a9059cbb906044016020604051808303816000875af1158015612ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f199190614216565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b60075462010000900460ff161515600114612fe4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f706c6561736520646973747269627574652045544820746f20746865204e474f60448201527f206669727374000000000000000000000000000000000000000000000000000060648201526084016110d7565b478061304c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f20457468657220746f20646973747269627574650000000000000000000060448201526064016110d7565b6000613059600283613d88565b905060006130678284613fd5565b600754604051919250600091630100000090910473ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d80600081146130cc576040519150601f19603f3d011682016040523d82523d6000602084013e6130d1565b606091505b505090508061313c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5472616e7366657220746f2044455653206661696c656400000000000000000060448201526064016110d7565b60085460405160009173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d8060008114613196576040519150601f19603f3d011682016040523d82523d6000602084013e61319b565b606091505b5050905080613206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5472616e7366657220746f204f4646434841494e206661696c6564000000000060448201526064016110d7565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff169055505050565b606060098054610bd790613cf5565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061325f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610ad45750507fffffffff000000000000000000000000000000000000000000000000000000001660009081526020819052604090205460ff1690565b6000600161339e846113f0565b6133a89190613fd5565b6000838152600c60205260409020549091508082146134085773ffffffffffffffffffffffffffffffffffffffff84166000908152600b602090815260408083208584528252808320548484528184208190558352600c90915290208190555b506000918252600c6020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600b81528383209183525290812055565b600d5460009061345a90600190613fd5565b6000838152600e6020526040812054600d805493945090928490811061348257613482613f3c565b9060005260206000200154905080600d83815481106134a3576134a3613f3c565b6000918252602080832090910192909255828152600e9091526040808220849055858252812055600d8054806134db576134db614233565b6001900381819060005260206000200160009055905550505050565b6000613502836113f0565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600b602090815260408083208684528252808320859055938252600c9052919091209190915550565b600061355382611390565b9050613561816000846124f4565b50600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826135c85763ceea21b66000526004601cfd5b826000528160010154808614848714178615176135f7576030600c20546135f757634b6e7f186000526004601cfd5b801561360557600083600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b61366c8383613680565b823b15610ef457610ef46000848484612606565b61368c600083836124f4565b73ffffffffffffffffffffffffffffffffffffffff90911690816136b85763ea553b346000526004601cfd5b806000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260206000208101810180548060601b156137025763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff811661372e576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b60006020828403121561376e57600080fd5b5035919050565b60006020828403121561378757600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461200e57600080fd5b60005b838110156137d25781810151838201526020016137ba565b50506000910152565b60208152600082518060208401526137fa8160408501602087016137b7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146113eb57600080fd5b6000806040838503121561386357600080fd5b61386c8361382c565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156138f0576138f061387a565b604052919050565b60ff81168114610d2c57600080fd5b6000602080838503121561391a57600080fd5b823567ffffffffffffffff8082111561393257600080fd5b818501915085601f83011261394657600080fd5b8135818111156139585761395861387a565b8060051b91506139698483016138a9565b818152918301840191848101908884111561398357600080fd5b938501935b838510156139ad578435925061399d836138f8565b8282529385019390850190613988565b98975050505050505050565b600080600080608085870312156139cf57600080fd5b6139d88561382c565b935060206139e781870161382c565b935060408601359250606086013567ffffffffffffffff80821115613a0b57600080fd5b818801915088601f830112613a1f57600080fd5b813581811115613a3157613a3161387a565b613a61847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016138a9565b91508082528984828501011115613a7757600080fd5b808484018584013760008482840101525080935050505092959194509250565b600060208284031215613aa957600080fd5b61200e8261382c565b600080600060608486031215613ac757600080fd5b613ad08461382c565b9250613ade6020850161382c565b9150604084013590509250925092565b60008060408385031215613b0157600080fd5b50508035926020909101359150565b60008083601f840112613b2257600080fd5b50813567ffffffffffffffff811115613b3a57600080fd5b60208301915083602082850101111561103b57600080fd5b60008060208385031215613b6557600080fd5b823567ffffffffffffffff811115613b7c57600080fd5b613b8885828601613b10565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015613bcf57835160ff1683529284019291840191600101613bb0565b50909695505050505050565b600080600060608486031215613bf057600080fd5b613bf98461382c565b95602085013595506040909401359392505050565b8015158114610d2c57600080fd5b60008060408385031215613c2f57600080fd5b613c388361382c565b91506020830135613c4881613c0e565b809150509250929050565b600080600080600060808688031215613c6b57600080fd5b613c748661382c565b9450613c826020870161382c565b935060408601359250606086013567ffffffffffffffff811115613ca557600080fd5b613cb188828901613b10565b969995985093965092949392505050565b60008060408385031215613cd557600080fd5b613cde8361382c565b9150613cec6020840161382c565b90509250929050565b600181811c90821680613d0957607f821691505b602082108103610d0f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610ad457610ad4613d42565b600082613dbe577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b601f821115610ef457600081815260208120601f850160051c81016020861015613dea5750805b601f850160051c820191505b8181101561269057828155600101613df6565b67ffffffffffffffff831115613e2157613e2161387a565b613e3583613e2f8354613cf5565b83613dc3565b6000601f841160018114613e875760008515613e515750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611f3c565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613ed65786850135825560209485019460019092019101613eb6565b5086821015613f11577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b600060208284031215613f3557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805169ffffffffffffffffffff811681146113eb57600080fd5b600080600080600060a08688031215613f9d57600080fd5b613fa686613f6b565b9450602086015193506040860151925060608601519150613fc960808701613f6b565b90509295509295909350565b81810381811115610ad457610ad4613d42565b600060208284031215613ffa57600080fd5b815161200e816138f8565b67ffffffffffffffff81811683821602808216919082811461271e5761271e613d42565b600181815b8085111561408257817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561406857614068613d42565b8085161561407557918102915b93841c939080029061402e565b509250929050565b60008261409957506001610ad4565b816140a657506000610ad4565b81600181146140bc57600281146140c6576140e2565b6001915050610ad4565b60ff8411156140d7576140d7613d42565b50506001821b610ad4565b5060208310610133831016604e8410600b8410161715614105575081810a610ad4565b61410f8383614029565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561414157614141613d42565b029392505050565b600061200e60ff84168361408a565b60008451602061416b8285838a016137b7565b85519184019161417e8184848a016137b7565b855492019160009061418f81613cf5565b600182811680156141a757600181146141da57614206565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450614206565b896000528560002060005b848110156141fe578154898201529083019087016141e5565b505082870194505b50929a9950505050505050505050565b60006020828403121561422857600080fd5b815161200e81613c0e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122036dd65208fe2efdb2cea2253227b2ea79565ae1ed62e5e962cfc7358a0ee245c64736f6c63430008130033000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f60000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
Deployed Bytecode
0x60806040526004361061035f5760003560e01c806355f804b3116101c65780639ec3aa01116100f7578063d39f456111610095578063f04e283e1161006f578063f04e283e14610a30578063f2fde38b14610a43578063f7beb98a14610a56578063fee81cf414610a6b57600080fd5b8063d39f4561146109c7578063d7533f02146109dc578063e985e9c5146109fa57600080fd5b8063b6fc7064116100d1578063b6fc706414610948578063b88d4fde14610967578063c87b56dd1461097a578063d2d240431461099a57600080fd5b80639ec3aa01146108e8578063a22cb46514610908578063b57ac9e31461092857600080fd5b80638dde257d116101645780639125009d1161013e5780639125009d146108965780639190ad47146108ab57806395d89b41146108c057806398ae99a8146108d557600080fd5b80638dde257d146108285780638dec9f7a146108485780638ea5220f1461086257600080fd5b8063715018a6116101a0578063715018a61461079f5780637359e41f146107a75780637d031354146107d45780638da5cb5b146107f457600080fd5b806355f804b31461073f5780636352211e1461075f57806370a082311461077f57600080fd5b80631f53ac02116102a057806342966c681161023e5780634a4ee7b1116102185780634a4ee7b1146106cd5780634f6ccce7146106e0578063514e62fc1461070057806354d1f13d1461073757600080fd5b806342966c681461066d5780634408a0461461068d578063484b973c146106ad57600080fd5b80632a55205a1161027a5780632a55205a146105bb5780632de94807146106075780632f745c591461063a57806342842e0e1461065a57600080fd5b80631f53ac021461058057806323b872dd146105a057806325692962146105b357600080fd5b8063147d959a1161030d578063183a4f6e116102e7578063183a4f6e1461050d5780631a16aacd146105205780631c10893f146105365780631cd64df41461054957600080fd5b8063147d959a14610463578063150b7a021461048357806318160ddd146104f857600080fd5b8063081812fc1161033e578063081812fc146103db578063095ea7b31461042057806313a661ed1461043557600080fd5b8062923f9e1461036457806301ffc9a71461039957806306fdde03146103b9575b600080fd5b34801561037057600080fd5b5061038461037f36600461375c565b610a9e565b60405190151581526020015b60405180910390f35b3480156103a557600080fd5b506103846103b4366004613775565b610ada565b3480156103c557600080fd5b506103ce610bc8565b60405161039091906137db565b3480156103e757600080fd5b506103fb6103f636600461375c565b610c5a565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610390565b61043361042e366004613850565b610cbf565b005b34801561044157600080fd5b50610455610450366004613907565b610cce565b604051908152602001610390565b34801561046f57600080fd5b5061043361047e36600461375c565b610d15565b34801561048f57600080fd5b506104c761049e3660046139b9565b7f150b7a0200000000000000000000000000000000000000000000000000000000949350505050565b6040517fffffffff000000000000000000000000000000000000000000000000000000009091168152602001610390565b34801561050457600080fd5b50600d54610455565b61043361051b36600461375c565b610d22565b34801561052c57600080fd5b5061045560045481565b610433610544366004613850565b610d2f565b34801561055557600080fd5b50610384610564366004613850565b638b78c6d8600c90815260009290925260209091205481161490565b34801561058c57600080fd5b5061043361059b366004613a97565b610d41565b6104336105ae366004613ab2565b610d97565b610433610ef9565b3480156105c757600080fd5b506105db6105d6366004613aee565b610f49565b6040805173ffffffffffffffffffffffffffffffffffffffff9093168352602083019190915201610390565b34801561061357600080fd5b50610455610622366004613a97565b638b78c6d8600c908152600091909152602090205490565b34801561064657600080fd5b50610455610655366004613850565b611042565b610433610668366004613ab2565b611116565b34801561067957600080fd5b5061043361068836600461375c565b611143565b34801561069957600080fd5b506104336106a8366004613b52565b6111e2565b3480156106b957600080fd5b506104336106c8366004613850565b6111f7565b6104336106db366004613850565b611209565b3480156106ec57600080fd5b506104556106fb36600461375c565b61121b565b34801561070c57600080fd5b5061038461071b366004613850565b638b78c6d8600c90815260009290925260209091205416151590565b61043361133f565b34801561074b57600080fd5b5061043361075a366004613b52565b61137b565b34801561076b57600080fd5b506103fb61077a36600461375c565b611390565b34801561078b57600080fd5b5061045561079a366004613a97565b6113f0565b610433611440565b3480156107b357600080fd5b506107c76107c236600461375c565b6114ac565b6040516103909190613b94565b3480156107e057600080fd5b506104336107ef366004613a97565b611503565b34801561080057600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927546103fb565b34801561083457600080fd5b50610433610843366004613bdb565b611552565b34801561085457600080fd5b506007546103849060ff1681565b34801561086e57600080fd5b506007546103fb906301000000900473ffffffffffffffffffffffffffffffffffffffff1681565b3480156108a257600080fd5b50610455611827565b3480156108b757600080fd5b50610433611bdc565b3480156108cc57600080fd5b506103ce611c0e565b6104336108e3366004613aee565b611c1d565b3480156108f457600080fd5b5061043361090336600461375c565b611e0a565b34801561091457600080fd5b50610433610923366004613c1c565b611e92565b34801561093457600080fd5b506007546103849062010000900460ff1681565b34801561095457600080fd5b5060075461038490610100900460ff1681565b610433610975366004613c53565b611ee8565b34801561098657600080fd5b506103ce61099536600461375c565b611f43565b3480156109a657600080fd5b506008546103fb9073ffffffffffffffffffffffffffffffffffffffff1681565b3480156109d357600080fd5b50610455612015565b3480156109e857600080fd5b506040516202a3008152602001610390565b348015610a0657600080fd5b50610384610a15366004613cc2565b601c52670a5a2e7a000000006008526000526030600c205490565b610433610a3e366004613a97565b61227f565b610433610a51366004613a97565b6122bc565b348015610a6257600080fd5b506104336122e3565b348015610a7757600080fd5b50610455610a86366004613a97565b63389a75e1600c908152600091909152602090205490565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260208120820182015460601b5b92915050565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f36372b07000000000000000000000000000000000000000000000000000000001480610b6d57507fffffffff0000000000000000000000000000000000000000000000000000000082167f2baae9fd00000000000000000000000000000000000000000000000000000000145b80610bb957507fffffffff0000000000000000000000000000000000000000000000000000000082167f01ffc9a700000000000000000000000000000000000000000000000000000000145b80610ad45750610ad482612318565b606060058054610bd790613cf5565b80601f0160208091040260200160405190810160405280929190818152602001828054610c0390613cf5565b8015610c505780601f10610c2557610100808354040283529160200191610c50565b820191906000526020600020905b815481529060010190602001808311610c3357829003601f168201915b5050505050905090565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c526020812082018201805473ffffffffffffffffffffffffffffffffffffffff16610cb55763ceea21b66000526004601cfd5b6001015492915050565b610cca33838361236e565b5050565b6000815160051b5b8015610d0f57828101516001901b909117907fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe001610cd6565b50919050565b610d1d612424565b600455565b610d2c338261245a565b50565b610d37612424565b610cca82826124a9565b610d49612424565b6007805473ffffffffffffffffffffffffffffffffffffffff9092166301000000027fffffffffffffffffff0000000000000000000000000000000000000000ffffff909216919091179055565b610da28383836124f4565b60008181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610e225782610e145763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b84610e355763ea553b346000526004601cfd5b856000528160010154925082331486331417610e63576030600c2054610e6357634b6e7f186000526004601cfd5b8215610e7157600082600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055600084905220805460010163ffffffff8116610ec9576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a45b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b600082815260026020908152604080832081518083019092525473ffffffffffffffffffffffffffffffffffffffff8116808352740100000000000000000000000000000000000000009091046bffffffffffffffffffffffff1692820192909252829161100457506040805180820190915260015473ffffffffffffffffffffffffffffffffffffffff811682527401000000000000000000000000000000000000000090046bffffffffffffffffffffffff1660208201525b602081015160009061271090611028906bffffffffffffffffffffffff1687613d71565b6110329190613d88565b91519350909150505b9250929050565b600061104d836113f0565b82106110e0576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602b60248201527f455243373231456e756d657261626c653a206f776e657220696e646578206f7560448201527f74206f6620626f756e647300000000000000000000000000000000000000000060648201526084015b60405180910390fd5b5073ffffffffffffffffffffffffffffffffffffffff919091166000908152600b60209081526040808320938352929052205490565b611121838383610d97565b813b15610ef457610ef483838360405180602001604052806000815250612606565b61114d3382612698565b6111d9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602d60248201527f4552433732313a2063616c6c6572206973206e6f7420746f6b656e206f776e6560448201527f72206f7220617070726f7665640000000000000000000000000000000000000060648201526084016110d7565b610d2c81612726565b6111ea612424565b600a610ef4828483613e09565b6111ff612424565b610cca8282612731565b611211612424565b610cca828261245a565b60003073ffffffffffffffffffffffffffffffffffffffff166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611268573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061128c9190613f23565b821061131a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602c60248201527f455243373231456e756d657261626c653a20676c6f62616c20696e646578206f60448201527f7574206f6620626f756e6473000000000000000000000000000000000000000060648201526084016110d7565b600d828154811061132d5761132d613f3c565b90600052602060002001549050919050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611383612424565b6009610ef4828483613e09565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806113eb5763ceea21b66000526004601cfd5b919050565b60008161140557638f4eb6046000526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c528160005263ffffffff601c600c2054169050919050565b611448612424565b6040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600f60248201527f63616e6e6f742072656e6f756e6365000000000000000000000000000000000060448201526064016110d7565b565b604051602081016000835b81835260051b6020169091019060010183811c806114b75750507fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08282030160051c8252604052919050565b61150b612424565b600880547fffffffffffffffffffffffff00000000000000000000000000000000000000001673ffffffffffffffffffffffffffffffffffffffff92909216919091179055565b61155a612424565b8060010361171b57600754610100900460ff16156115fa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602860248201527f706c656173652064697374726962757465205553444320746f2074686520746560448201527f616d20666972737400000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f70a0823100000000000000000000000000000000000000000000000000000000815230600482015282907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015611686573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906116aa9190613f23565b11611711576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f205553444320746f2064697374726962757465000000000000000000000060448201526064016110d7565b610ef4838361274b565b60075462010000900460ff16156117b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f706c6561736520646973747269627574652045544820746f207468652074656160448201527f6d2066697273740000000000000000000000000000000000000000000000000060648201526084016110d7565b81471161181d576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f20457468657220746f20646973747269627574650000000000000000000060448201526064016110d7565b610ef48383612835565b60008060007f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015611897573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906118bb9190613f85565b5093505092505060008213611952576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f466565642070726963652073686f756c6420626520677265617465722074686160448201527f6e2030000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b61195e610e1042613fd5565b81116119c6576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5374616c6520507269636500000000000000000000000000000000000000000060448201526064016110d7565b6000827f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611a34573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611a589190613fe8565b611a6d9060ff16670de0b6b3a7640000614005565b67ffffffffffffffff16611a819190613d88565b905060007f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611af0573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611b149190613fe8565b60ff167f0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b841973ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015611b82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ba69190613fe8565b611bb190600a614149565b83600454611bbf9190613d71565b611bc99190613d71565b611bd39190613d88565b95945050505050565b611be4612424565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00169055565b606060068054610bd790613cf5565b333214611c86576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f73686565703a20626f74206973206e6f7420616c6c6f7765640000000000000060448201526064016110d7565b6107d1611c92600d5490565b10611cf9576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f73686565703a20737570706c792065786365656465640000000000000000000060448201526064016110d7565b60075460ff16611d65576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601d60248201527f73686565703a206d696e74696e67206973206e6f7420656e61626c656400000060448201526064016110d7565b80600103611d88576000611d77612015565b9050611d8281612931565b50611e00565b6000611d92611827565b905080341015611dfe576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601960248201527f73686565703a20696e73756666696369656e742065746865720000000000000060448201526064016110d7565b505b610cca3383612731565b611e12612424565b80600103611e2257610d2c612bbe565b8015611e8a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f746f6b656e20747970652069732077726f6e670000000000000000000000000060448201526064016110d7565b610d2c612f47565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b611ef3858585610d97565b833b15611f3c57611f3c85858585858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061260692505050565b5050505050565b6060611f808260008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b90565b611fb6576040517fceea21b600000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6000611fc0613235565b90508051600003611fe0576040518060200160405280600081525061200e565b80611fea84613244565b600a604051602001611ffe93929190614158565b6040516020818303038152906040525b9392505050565b60008060007f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f673ffffffffffffffffffffffffffffffffffffffff1663feaf968c6040518163ffffffff1660e01b815260040160a060405180830381865afa158015612085573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906120a99190613f85565b5093505092505060008213612140576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f466565642070726963652073686f756c6420626520677265617465722074686160448201527f6e2030000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b61214c610e1042613fd5565b81116121b4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600b60248201527f5374616c6520507269636500000000000000000000000000000000000000000060448201526064016110d7565b6000827f0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f673ffffffffffffffffffffffffffffffffffffffff1663313ce5676040518163ffffffff1660e01b8152600401602060405180830381865afa158015612222573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122469190613fe8565b61225190600a614149565b60045461225e9190613d71565b6122689190613d88565b905061227781620f4240613d71565b935050505090565b612287612424565b63389a75e1600c52806000526020600c2080544211156122af57636f5e88186000526004601cfd5b60009055610d2c816132a6565b6122c4612424565b8060601b6122da57637448fbae6000526004601cfd5b610d2c816132a6565b6122eb612424565b600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00166001179055565b60007fffffffff0000000000000000000000000000000000000000000000000000000082167f2a55205a000000000000000000000000000000000000000000000000000000001480610ad45750610ad48261330c565b60001960601c8281169250838116935081600052837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c52602060002082018201805482169150816123ca5763ceea21b66000526004601cfd5b8185148515176123f057816000526030600c20546123f057634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a450505050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275433146114aa576382b429006000526004601cfd5b638b78c6d8600c52816000526020600c20805482811681189250508181555080600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a35050565b638b78c6d8600c52816000526020600c208181541791508181555080600c5160601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a35050565b8073ffffffffffffffffffffffffffffffffffffffff841661255d5761255881600d80546000838152600e60205260408120829055600182018355919091527fd7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb50155565b61259a565b8273ffffffffffffffffffffffffffffffffffffffff168473ffffffffffffffffffffffffffffffffffffffff161461259a5761259a8482613391565b73ffffffffffffffffffffffffffffffffffffffff83166125c3576125be81613448565b612600565b8373ffffffffffffffffffffffffffffffffffffffff168373ffffffffffffffffffffffffffffffffffffffff16146126005761260083826134f7565b50505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a0840152801561264d578060c08401826020870160045afa505b60208360a48301601c860160008a5af1612676573d15612671573d6000803e3d6000fd5b600083525b508060e01b8251146126905763d1a57ed66000526004601cfd5b505050505050565b600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c526020909120820182018054919360019216806126ff5763ceea21b66000526004601cfd5b80851461271e57806000526030600c205461271e578160010154851492505b505092915050565b610d2c600082613548565b610cca828260405180602001604052806000815250613662565b6040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff8381166004830152602482018390527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169063a9059cbb906044016020604051808303816000875af11580156127e0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906128049190614216565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1661010017905550565b60008273ffffffffffffffffffffffffffffffffffffffff168260405160006040518083038185875af1925050503d806000811461288f576040519150601f19603f3d011682016040523d82523d6000602084013e612894565b606091505b50509050806128ff576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f5472616e7366657220746f204e474f206661696c65640000000000000000000060448201526064016110d7565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff166201000017905550565b6040517fdd62ed3e00000000000000000000000000000000000000000000000000000000815233600482015230602482015281907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff169063dd62ed3e90604401602060405180830381865afa1580156129c3573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906129e79190613f23565b1015612a75576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602260248201527f7472616e73666572496e3a20696e73756666696369656e7420616c6c6f77616e60448201527f636500000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f23b872dd000000000000000000000000000000000000000000000000000000008152336004820152306024820152604481018290527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff16906323b872dd906064016020604051808303816000875af1158015612b0e573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b329190614216565b610d2c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602360248201527f7472616e7366657246726f6d3a2063616e6e6f74207472616e7366657220746f60448201527f6b656e000000000000000000000000000000000000000000000000000000000060648201526084016110d7565b60075460ff610100909104161515600114612c5b576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602760248201527f706c656173652064697374726962757465205553444320746f20746865204e4760448201527f4f2066697273740000000000000000000000000000000000000000000000000060648201526084016110d7565b6040517f70a082310000000000000000000000000000000000000000000000000000000081523060048201526000907f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb4873ffffffffffffffffffffffffffffffffffffffff16906370a0823190602401602060405180830381865afa158015612ce8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612d0c9190613f23565b905060008111612d78576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601560248201527f4e6f205553444320746f2064697374726962757465000000000000000000000060448201526064016110d7565b6000612d85600283613d88565b90506000612d94600284613d88565b6007546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff630100000090920482166004820152602481018590529192507f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48169063a9059cbb906044016020604051808303816000875af1158015612e36573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e5a9190614216565b506008546040517fa9059cbb00000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff9182166004820152602481018390527f000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb489091169063a9059cbb906044016020604051808303816000875af1158015612ef5573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612f199190614216565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff1690555050565b60075462010000900460ff161515600114612fe4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f706c6561736520646973747269627574652045544820746f20746865204e474f60448201527f206669727374000000000000000000000000000000000000000000000000000060648201526084016110d7565b478061304c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601660248201527f4e6f20457468657220746f20646973747269627574650000000000000000000060448201526064016110d7565b6000613059600283613d88565b905060006130678284613fd5565b600754604051919250600091630100000090910473ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d80600081146130cc576040519150601f19603f3d011682016040523d82523d6000602084013e6130d1565b606091505b505090508061313c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5472616e7366657220746f2044455653206661696c656400000000000000000060448201526064016110d7565b60085460405160009173ffffffffffffffffffffffffffffffffffffffff169084908381818185875af1925050503d8060008114613196576040519150601f19603f3d011682016040523d82523d6000602084013e61319b565b606091505b5050905080613206576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601b60248201527f5472616e7366657220746f204f4646434841494e206661696c6564000000000060448201526064016110d7565b5050600780547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff169055505050565b606060098054610bd790613cf5565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a90048061325f5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b60007f01ffc9a7000000000000000000000000000000000000000000000000000000007fffffffff0000000000000000000000000000000000000000000000000000000083161480610ad45750507fffffffff000000000000000000000000000000000000000000000000000000001660009081526020819052604090205460ff1690565b6000600161339e846113f0565b6133a89190613fd5565b6000838152600c60205260409020549091508082146134085773ffffffffffffffffffffffffffffffffffffffff84166000908152600b602090815260408083208584528252808320548484528184208190558352600c90915290208190555b506000918252600c6020908152604080842084905573ffffffffffffffffffffffffffffffffffffffff9094168352600b81528383209183525290812055565b600d5460009061345a90600190613fd5565b6000838152600e6020526040812054600d805493945090928490811061348257613482613f3c565b9060005260206000200154905080600d83815481106134a3576134a3613f3c565b6000918252602080832090910192909255828152600e9091526040808220849055858252812055600d8054806134db576134db614233565b6001900381819060005260206000200160009055905550505050565b6000613502836113f0565b73ffffffffffffffffffffffffffffffffffffffff9093166000908152600b602090815260408083208684528252808320859055938252600c9052919091209190915550565b600061355382611390565b9050613561816000846124f4565b50600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826135c85763ceea21b66000526004601cfd5b826000528160010154808614848714178615176135f7576030600c20546135f757634b6e7f186000526004601cfd5b801561360557600083600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b61366c8383613680565b823b15610ef457610ef46000848484612606565b61368c600083836124f4565b73ffffffffffffffffffffffffffffffffffffffff90911690816136b85763ea553b346000526004601cfd5b806000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260206000208101810180548060601b156137025763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff811661372e576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b60006020828403121561376e57600080fd5b5035919050565b60006020828403121561378757600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461200e57600080fd5b60005b838110156137d25781810151838201526020016137ba565b50506000910152565b60208152600082518060208401526137fa8160408501602087016137b7565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b803573ffffffffffffffffffffffffffffffffffffffff811681146113eb57600080fd5b6000806040838503121561386357600080fd5b61386c8361382c565b946020939093013593505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b604051601f82017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe016810167ffffffffffffffff811182821017156138f0576138f061387a565b604052919050565b60ff81168114610d2c57600080fd5b6000602080838503121561391a57600080fd5b823567ffffffffffffffff8082111561393257600080fd5b818501915085601f83011261394657600080fd5b8135818111156139585761395861387a565b8060051b91506139698483016138a9565b818152918301840191848101908884111561398357600080fd5b938501935b838510156139ad578435925061399d836138f8565b8282529385019390850190613988565b98975050505050505050565b600080600080608085870312156139cf57600080fd5b6139d88561382c565b935060206139e781870161382c565b935060408601359250606086013567ffffffffffffffff80821115613a0b57600080fd5b818801915088601f830112613a1f57600080fd5b813581811115613a3157613a3161387a565b613a61847fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0601f840116016138a9565b91508082528984828501011115613a7757600080fd5b808484018584013760008482840101525080935050505092959194509250565b600060208284031215613aa957600080fd5b61200e8261382c565b600080600060608486031215613ac757600080fd5b613ad08461382c565b9250613ade6020850161382c565b9150604084013590509250925092565b60008060408385031215613b0157600080fd5b50508035926020909101359150565b60008083601f840112613b2257600080fd5b50813567ffffffffffffffff811115613b3a57600080fd5b60208301915083602082850101111561103b57600080fd5b60008060208385031215613b6557600080fd5b823567ffffffffffffffff811115613b7c57600080fd5b613b8885828601613b10565b90969095509350505050565b6020808252825182820181905260009190848201906040850190845b81811015613bcf57835160ff1683529284019291840191600101613bb0565b50909695505050505050565b600080600060608486031215613bf057600080fd5b613bf98461382c565b95602085013595506040909401359392505050565b8015158114610d2c57600080fd5b60008060408385031215613c2f57600080fd5b613c388361382c565b91506020830135613c4881613c0e565b809150509250929050565b600080600080600060808688031215613c6b57600080fd5b613c748661382c565b9450613c826020870161382c565b935060408601359250606086013567ffffffffffffffff811115613ca557600080fd5b613cb188828901613b10565b969995985093965092949392505050565b60008060408385031215613cd557600080fd5b613cde8361382c565b9150613cec6020840161382c565b90509250929050565b600181811c90821680613d0957607f821691505b602082108103610d0f577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082028115828204841417610ad457610ad4613d42565b600082613dbe577f4e487b7100000000000000000000000000000000000000000000000000000000600052601260045260246000fd5b500490565b601f821115610ef457600081815260208120601f850160051c81016020861015613dea5750805b601f850160051c820191505b8181101561269057828155600101613df6565b67ffffffffffffffff831115613e2157613e2161387a565b613e3583613e2f8354613cf5565b83613dc3565b6000601f841160018114613e875760008515613e515750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b178355611f3c565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b82811015613ed65786850135825560209485019460019092019101613eb6565b5086821015613f11577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b600060208284031215613f3557600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b805169ffffffffffffffffffff811681146113eb57600080fd5b600080600080600060a08688031215613f9d57600080fd5b613fa686613f6b565b9450602086015193506040860151925060608601519150613fc960808701613f6b565b90509295509295909350565b81810381811115610ad457610ad4613d42565b600060208284031215613ffa57600080fd5b815161200e816138f8565b67ffffffffffffffff81811683821602808216919082811461271e5761271e613d42565b600181815b8085111561408257817fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561406857614068613d42565b8085161561407557918102915b93841c939080029061402e565b509250929050565b60008261409957506001610ad4565b816140a657506000610ad4565b81600181146140bc57600281146140c6576140e2565b6001915050610ad4565b60ff8411156140d7576140d7613d42565b50506001821b610ad4565b5060208310610133831016604e8410600b8410161715614105575081810a610ad4565b61410f8383614029565b807fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0482111561414157614141613d42565b029392505050565b600061200e60ff84168361408a565b60008451602061416b8285838a016137b7565b85519184019161417e8184848a016137b7565b855492019160009061418f81613cf5565b600182811680156141a757600181146141da57614206565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0084168752821515830287019450614206565b896000528560002060005b848110156141fe578154898201529083019087016141e5565b505082870194505b50929a9950505050505050505050565b60006020828403121561422857600080fd5b815161200e81613c0e565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea264697066735822122036dd65208fe2efdb2cea2253227b2ea79565ae1ed62e5e962cfc7358a0ee245c64736f6c63430008130033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb480000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f60000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
-----Decoded View---------------
Arg [0] : _usdc (address): 0xA0b86991c6218b36c1d19D4a2e9Eb0cE3606eB48
Arg [1] : _feedUsdc (address): 0x8fFfFfd4AfB6115b954Bd326cbe7B4BA576818f6
Arg [2] : _feedEth (address): 0x5f4eC3Df9cbd43714FE2740f5E3616155c5b8419
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000a0b86991c6218b36c1d19d4a2e9eb0ce3606eb48
Arg [1] : 0000000000000000000000008fffffd4afb6115b954bd326cbe7b4ba576818f6
Arg [2] : 0000000000000000000000005f4ec3df9cbd43714fe2740f5e3616155c5b8419
Loading...
Loading
Loading...
Loading
[ 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.