ERC-721
Overview
Max Total Supply
122 PRIME
Holders
117
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 PRIMELoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
Prime
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity 0.8.20; import "solady/src/tokens/ERC721.sol"; import "solady/src/auth/Ownable.sol"; import "solady/src/utils/ECDSA.sol"; import "solady/src/utils/LibString.sol"; contract Prime is ERC721, Ownable { using ECDSA for bytes; error InvalidValue(); error MismatchLength(uint256 expecting); error NameUsed(); error InvalidReferral(); error FailedToSendFee(); error NothingToClaim(); error ClaimsClosed(); error ContractDepleted(); error QueryForNonexistantToken(); error InvalidWhitelistClaim(); error AlreadyClaimed(); error InvalidDiscountValue(); error MustUseSameRefCode(string code); error MintIsNotLive(); uint256 public PRICE = 0.018777 * 1 ether; uint256 public DISCOUNT_PRICE = 0.0169 * 1 ether; uint256 public WHITELIST_PRICE = 0.0142 * 1 ether; uint256 public totalSupply = 0; uint256 public totalRefClaims = 0; string public baseURI = "https://app.sukuri.io/api/"; bool public IS_LIVE = false; bool public CLAIMS_LIVE = false; address signer; mapping(uint256 tokenID => string name) public namespace; mapping(string name => address owner) public nameOwner; mapping(address referee => string referral) public usedRefs; mapping(address owner => uint256 balance) refClaim; mapping(address whitelistee => uint256 claimed) public wlClaim; constructor(address signer_) { _initializeOwner(msg.sender); signer = signer_; } function whitelistMint( string calldata _name, string memory referral, bytes calldata signature ) external payable { if (!IS_LIVE) { revert MintIsNotLive(); } if (msg.value != WHITELIST_PRICE) { revert InvalidValue(); } if (wlClaim[msg.sender] != 0) { revert AlreadyClaimed(); } bytes32 message = keccak256(abi.encode(msg.sender, _name, referral)); if ( ECDSA.recover(ECDSA.toEthSignedMessageHash(message), signature) != signer ) { revert InvalidWhitelistClaim(); } if (nameOwner[_name] != address(0)) { revert NameUsed(); } _checkAndUpdateRefClaims(referral); uint256 tokenId = ++totalSupply; namespace[tokenId] = _name; nameOwner[_name] = msg.sender; wlClaim[msg.sender]++; _mint(msg.sender, tokenId); } function mint( string calldata _name, string memory referral ) external payable { if (!IS_LIVE) { revert MintIsNotLive(); } bytes memory refTmp = bytes(referral); if (refTmp.length > 0 && msg.value != DISCOUNT_PRICE) { revert InvalidDiscountValue(); } else if (refTmp.length == 0 && msg.value != PRICE) { revert InvalidValue(); } if (nameOwner[_name] != address(0)) { revert NameUsed(); } _checkAndUpdateRefClaims(referral); uint256 tokenId = ++totalSupply; namespace[tokenId] = _name; nameOwner[_name] = msg.sender; _mint(msg.sender, tokenId); } function _afterTokenTransfer( address from, address to, uint256 id ) internal override { if (to == address(0)) { revert TransferToZeroAddress(); } nameOwner[namespace[id]] = to; } function claimFees() external { if (!CLAIMS_LIVE) { revert ClaimsClosed(); } uint256 claim = refClaim[msg.sender]; if (claim == 0) { revert NothingToClaim(); } if (address(this).balance < claim) { revert ContractDepleted(); } refClaim[msg.sender] = 0; totalRefClaims -= claim; (bool success, ) = address(msg.sender).call{value: claim}(""); if (!success) { revert FailedToSendFee(); } } function adminMint( address[] calldata tos, string[] calldata names ) external onlyOwner { if (tos.length != names.length) { revert MismatchLength({expecting: tos.length}); } uint256 tokenId = totalSupply; for (uint i; i < tos.length; ) { tokenId++; _mint(tos[i], tokenId); namespace[tokenId] = names[i]; nameOwner[names[i]] = tos[i]; unchecked { i++; } } totalSupply += tos.length; } function withdraw() external onlyOwner { if (address(this).balance < totalRefClaims) { revert ContractDepleted(); } (bool success, ) = address(owner()).call{ value: address(this).balance - totalRefClaims }(""); if (!success) { revert FailedToSendFee(); } } // This should never be called unless nobody is claiming, the claim balances are extremely low // and we need to get the ETH out of the contract so it's not burned. Claim periods will be live // for a long time so this should not happen. function forceWithdrawl() external onlyOwner { (bool success, ) = address(owner()).call{value: address(this).balance}( "" ); if (!success) { revert FailedToSendFee(); } } function setIsLive(bool status) external onlyOwner { IS_LIVE = status; } function setClaimLive(bool status) external onlyOwner { CLAIMS_LIVE = status; } function setSigner(address _signer) external onlyOwner { signer = _signer; } function setBaseURI(string calldata _baseURI) external onlyOwner { baseURI = _baseURI; } function setMintPrice(uint256 price) external onlyOwner { PRICE = price; } function checkClaim(address ref) public view returns (uint256) { return refClaim[ref]; } function contractBalance() external view returns (uint256) { return address(this).balance - totalRefClaims; } function name() public pure override returns (string memory) { return "Sukuri Prime"; } function symbol() public pure override returns (string memory) { return "PRIME"; } function contractURI() public view returns (string memory) { return LibString.concat(baseURI, "contractURI"); } function tokenURI(uint256 id) public view override returns (string memory) { if (id > totalSupply || id == 0) { revert QueryForNonexistantToken(); } return LibString.concat( LibString.concat(baseURI, "tokenURI/"), LibString.toString(id) ); } function _checkAndUpdateRefClaims(string memory referral) internal { bytes memory refTmp = bytes(referral); if (refTmp.length > 0) { address ref = nameOwner[referral]; if ( LibString.packOne(usedRefs[msg.sender]) != bytes32(0) && !LibString.eq(usedRefs[msg.sender], referral) ) { revert MustUseSameRefCode({code: usedRefs[msg.sender]}); } if (ref == address(0)) { revert InvalidReferral(); } usedRefs[msg.sender] = referral; bool refHasRef = LibString.packOne(usedRefs[ref]) != bytes32(0); uint256 refFee = (msg.value * 5) / 100; uint256 refRefFee = refHasRef ? (msg.value * 5) / 1000 : 0; unchecked { refClaim[nameOwner[usedRefs[ref]]] += refRefFee; refClaim[ref] += refFee; totalRefClaims += (refFee + refRefFee); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. 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) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(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)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST be always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) 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 := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // 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 manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {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 an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `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()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized ECDSA wrapper. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) /// /// @dev Note: /// - The recovery functions use the ecrecover precompile (0x1). /// /// WARNING! Do NOT use signatures as unique identifiers. /// Please use EIP712 with a nonce included in the digest to prevent replay attacks. /// This implementation does NOT check if a signature is non-malleable. library ECDSA { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The signature is invalid. error InvalidSignature(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RECOVERY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: as of Solady version 0.0.68, these functions will // revert upon recovery failure for more safety by default. /// @dev Recovers the signer's address from a message digest `hash`, /// and the `signature`. /// /// This function does NOT accept EIP-2098 short form signatures. /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 /// short form signatures instead. function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let signatureLength := mload(signature) mstore(0x00, hash) mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x40, mload(add(signature, 0x20))) // `r`. mstore(0x60, mload(add(signature, 0x40))) // `s`. result := mload( staticcall( gas(), // Amount of gas left for the transaction. eq(signatureLength, 65), // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the `signature`. /// /// This function does NOT accept EIP-2098 short form signatures. /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 /// short form signatures instead. function recoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. result := mload( staticcall( gas(), // Amount of gas left for the transaction. eq(signature.length, 65), // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. /// /// This function only accepts EIP-2098 short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. result := mload( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) result := mload( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* TRY-RECOVER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // WARNING! // These functions will NOT revert upon recovery failure. // Instead, they will return the zero address upon recovery failure. // It is critical that the returned address is NEVER compared against // a zero address (e.g. an uninitialized address variable). /// @dev Recovers the signer's address from a message digest `hash`, /// and the `signature`. /// /// This function does NOT accept EIP-2098 short form signatures. /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 /// short form signatures instead. function tryRecover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. let signatureLength := mload(signature) mstore(0x00, hash) mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x40, mload(add(signature, 0x20))) // `r`. mstore(0x60, mload(add(signature, 0x40))) // `s`. pop( staticcall( gas(), // Amount of gas left for the transaction. eq(signatureLength, 65), // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the `signature`. /// /// This function does NOT accept EIP-2098 short form signatures. /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 /// short form signatures instead. function tryRecoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. pop( staticcall( gas(), // Amount of gas left for the transaction. eq(signature.length, 65), // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. /// /// This function only accepts EIP-2098 short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. pop( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) pop( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 {} { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) 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 prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, 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(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`. For short strings up to 32 bytes. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let x := and(b, add(not(b), 1)) let r := or(shl(8, iszero(b)), shl(7, iszero(iszero(shr(128, x))))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) result := gt(eq(mload(a), sub(32, shr(3, r))), shr(r, xor(b, mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output 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) } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "evmVersion": "paris", "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"signer_","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyClaimed","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"ClaimsClosed","type":"error"},{"inputs":[],"name":"ContractDepleted","type":"error"},{"inputs":[],"name":"FailedToSendFee","type":"error"},{"inputs":[],"name":"InvalidDiscountValue","type":"error"},{"inputs":[],"name":"InvalidReferral","type":"error"},{"inputs":[],"name":"InvalidValue","type":"error"},{"inputs":[],"name":"InvalidWhitelistClaim","type":"error"},{"inputs":[],"name":"MintIsNotLive","type":"error"},{"inputs":[{"internalType":"uint256","name":"expecting","type":"uint256"}],"name":"MismatchLength","type":"error"},{"inputs":[{"internalType":"string","name":"code","type":"string"}],"name":"MustUseSameRefCode","type":"error"},{"inputs":[],"name":"NameUsed","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NothingToClaim","type":"error"},{"inputs":[],"name":"QueryForNonexistantToken","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":"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":"CLAIMS_LIVE","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DISCOUNT_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"IS_LIVE","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"WHITELIST_PRICE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address[]","name":"tos","type":"address[]"},{"internalType":"string[]","name":"names","type":"string[]"}],"name":"adminMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"ref","type":"address"}],"name":"checkClaim","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"forceWithdrawl","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":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"referral","type":"string"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"string","name":"name","type":"string"}],"name":"nameOwner","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"namespace","outputs":[{"internalType":"string","name":"name","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","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":"_baseURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setClaimLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"status","type":"bool"}],"name":"setIsLive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_signer","type":"address"}],"name":"setSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalRefClaims","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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"},{"inputs":[{"internalType":"address","name":"referee","type":"address"}],"name":"usedRefs","outputs":[{"internalType":"string","name":"referral","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"referral","type":"string"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"whitelistMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"whitelistee","type":"address"}],"name":"wlClaim","outputs":[{"internalType":"uint256","name":"claimed","type":"uint256"}],"stateMutability":"view","type":"function"}]
Contract Creation Code
6642b594fef290006000908155663c0a75e0b44000600155663272d323cf8000600255600381905560045560c0604052601a60809081527f68747470733a2f2f6170702e73756b7572692e696f2f6170692f00000000000060a052600590620000699082620001bf565b506006805461ffff191690553480156200008257600080fd5b506040516200297338038062002973833981016040819052620000a5916200028b565b620000b033620000de565b600680546001600160a01b03909216620100000262010000600160b01b0319909216919091179055620002bd565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200014557607f821691505b6020821081036200016657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001ba57600081815260208120601f850160051c81016020861015620001955750805b601f850160051c820191505b81811015620001b657828155600101620001a1565b5050505b505050565b81516001600160401b03811115620001db57620001db6200011a565b620001f381620001ec845462000130565b846200016c565b602080601f8311600181146200022b5760008415620002125750858301515b600019600386901b1c1916600185901b178555620001b6565b600085815260208120601f198616915b828110156200025c578886015182559484019460019091019084016200023b565b50858210156200027b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6000602082840312156200029e57600080fd5b81516001600160a01b0381168114620002b657600080fd5b9392505050565b6126a680620002cd6000396000f3fe60806040526004361061027d5760003560e01c80637d20a41d1161014f578063b88d4fde116100c1578063e8a3d4851161007a578063e8a3d4851461073f578063e985e9c514610754578063f04e283e1461078a578063f2fde38b1461079d578063f4a0a528146107b0578063fee81cf4146107d057600080fd5b8063b88d4fde14610681578063c87b56dd14610694578063d294f093146106b4578063da32abac146106c9578063db228051146106de578063e18c3a06146106fe57600080fd5b80638d859f3e116101135780638d859f3e146105c45780638da5cb5b146105da5780638f4e41d5146105f357806395d89b4114610613578063a22cb46514610641578063b1d1dfbd1461066157600080fd5b80637d20a41d1461054c57806382dd832314610566578063870bf62f146105865780638aa0fdad1461059c5780638b7afe2e146105af57600080fd5b806325692962116101f35780636352211e116101ac5780636352211e146104af5780636c0360eb146104cf5780636c19e783146104e457806370a0823114610504578063715018a614610524578063783e1bab1461052c57600080fd5b8063256929621461042a5780633ccfd60b1461043257806342842e0e146104475780634337bb261461045a57806354d1f13d1461048757806355f804b31461048f57600080fd5b8063095ea7b311610245578063095ea7b3146103a45780630eff0a38146103b957806317e7f295146103cc57806318160ddd146103e25780631c6cd2fa146103f857806323b872dd1461041757600080fd5b806301ffc9a7146102825780630426212c146102d4578063057707a01461031857806306fdde031461032e578063081812fc1461036c575b600080fd5b34801561028e57600080fd5b506102bf61029d366004611cc6565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156102e057600080fd5b5061030a6102ef366004611d0e565b6001600160a01b03166000908152600a602052604090205490565b6040519081526020016102cb565b34801561032457600080fd5b5061030a60015481565b34801561033a57600080fd5b5060408051808201909152600c81526b53756b757269205072696d6560a01b60208201525b6040516102cb9190611d79565b34801561037857600080fd5b5061038c610387366004611d8c565b610803565b6040516001600160a01b0390911681526020016102cb565b6103b76103b2366004611da5565b610842565b005b6103b76103c7366004611eb9565b610851565b3480156103d857600080fd5b5061030a60025481565b3480156103ee57600080fd5b5061030a60035481565b34801561040457600080fd5b506006546102bf90610100900460ff1681565b6103b7610425366004611f4d565b610aa5565b6103b7610bc6565b34801561043e57600080fd5b506103b7610c15565b6103b7610455366004611f4d565b610cd0565b34801561046657600080fd5b5061030a610475366004611d0e565b600b6020526000908152604090205481565b6103b7610cfd565b34801561049b57600080fd5b506103b76104aa366004611f89565b610d39565b3480156104bb57600080fd5b5061038c6104ca366004611d8c565b610d4e565b3480156104db57600080fd5b5061035f610d8c565b3480156104f057600080fd5b506103b76104ff366004611d0e565b610e1a565b34801561051057600080fd5b5061030a61051f366004611d0e565b610e4c565b6103b7610e87565b34801561053857600080fd5b506103b7610547366004611fda565b610e9b565b34801561055857600080fd5b506006546102bf9060ff1681565b34801561057257600080fd5b506103b7610581366004611fda565b610ebd565b34801561059257600080fd5b5061030a60045481565b6103b76105aa366004611ff5565b610ed8565b3480156105bb57600080fd5b5061030a61103f565b3480156105d057600080fd5b5061030a60005481565b3480156105e657600080fd5b50638b78c6d8195461038c565b3480156105ff57600080fd5b5061035f61060e366004611d0e565b611054565b34801561061f57600080fd5b506040805180820190915260058152645052494d4560d81b602082015261035f565b34801561064d57600080fd5b506103b761065c36600461205d565b61106d565b34801561066d57600080fd5b506103b761067c3660046120d4565b6110c3565b6103b761068f36600461213f565b611231565b3480156106a057600080fd5b5061035f6106af366004611d8c565b611285565b3480156106c057600080fd5b506103b761137f565b3480156106d557600080fd5b506103b761148a565b3480156106ea57600080fd5b5061035f6106f9366004611d8c565b6114b3565b34801561070a57600080fd5b5061038c61071936600461219c565b80516020818301810180516008825292820191909301209152546001600160a01b031681565b34801561074b57600080fd5b5061035f6114cc565b34801561076057600080fd5b506102bf61076f3660046121d8565b601c52670a5a2e7a000000006008526000526030600c205490565b6103b7610798366004611d0e565b611585565b6103b76107ab366004611d0e565b6115c2565b3480156107bc57600080fd5b506103b76107cb366004611d8c565b6115e9565b3480156107dc57600080fd5b5061030a6107eb366004611d0e565b63389a75e1600c908152600091909152602090205490565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6108385763ceea21b66000526004601cfd5b6001015492915050565b61084d3383836115f6565b5050565b60065460ff16610874576040516303eaac9360e01b815260040160405180910390fd5b600254341461089657604051632a9ffab760e21b815260040160405180910390fd5b336000908152600b6020526040902054156108c457604051630c8d9eab60e31b815260040160405180910390fd5b6000338686866040516020016108dd9493929190612202565b60408051601f1981840301815291905280516020909101206006549091506001600160a01b03620100009091041661097961093d836020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061169792505050565b6001600160a01b0316146109a057604051634825ec7b60e01b815260040160405180910390fd5b60006001600160a01b0316600887876040516109bd92919061225b565b908152604051908190036020019020546001600160a01b0316146109f45760405163568d5a9f60e01b815260040160405180910390fd5b6109fd846116f0565b6000600360008154610a0e90612281565b91829055506000818152600760205260409020909150610a2f87898361231a565b503360088888604051610a4392919061225b565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600b909152908120805491610a8d83612281565b9190505550610a9c3382611a11565b50505050505050565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302610b035782610af55763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b84610b165763ea553b346000526004601cfd5b856000528160010154925082331486331417610b44576030600c2054610b4457634b6e7f186000526004601cfd5b8215610b5257600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff8116610b8c576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4610bc1838383611ac3565b505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610c1d611b41565b600454471015610c3f57604051624898d760e71b815260040160405180910390fd5b6000610c4e638b78c6d8195490565b6001600160a01b031660045447610c6591906123d9565b6040515b60006040518083038185875af1925050503d8060008114610ca6576040519150601f19603f3d011682016040523d82523d6000602084013e610cab565b606091505b5050905080610ccd57604051638b3dac3760e01b815260040160405180910390fd5b50565b610cdb838383610aa5565b813b15610bc157610bc183838360405180602001604052806000815250611b5c565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610d41611b41565b6005610bc182848361231a565b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b031680610d875763ceea21b66000526004601cfd5b919050565b60058054610d999061229a565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc59061229a565b8015610e125780601f10610de757610100808354040283529160200191610e12565b820191906000526020600020905b815481529060010190602001808311610df557829003601f168201915b505050505081565b610e22611b41565b600680546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b600081610e6157638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b610e8f611b41565b610e996000611be9565b565b610ea3611b41565b600680549115156101000261ff0019909216919091179055565b610ec5611b41565b6006805460ff1916911515919091179055565b60065460ff16610efb576040516303eaac9360e01b815260040160405180910390fd5b8051819015801590610f0f57506001543414155b15610f2d576040516312689ab760e11b815260040160405180910390fd5b8051158015610f3e57506000543414155b15610f5c57604051632a9ffab760e21b815260040160405180910390fd5b60006001600160a01b031660088585604051610f7992919061225b565b908152604051908190036020019020546001600160a01b031614610fb05760405163568d5a9f60e01b815260040160405180910390fd5b610fb9826116f0565b6000600360008154610fca90612281565b91829055506000818152600760205260409020909150610feb85878361231a565b503360088686604051610fff92919061225b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b03199092169190911790556110383382611a11565b5050505050565b60006004544761104f91906123d9565b905090565b60096020526000908152604090208054610d999061229a565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b6110cb611b41565b8281146110f35760405163a73e819d60e01b8152600481018490526024015b60405180910390fd5b60035460005b8481101561120f578161110b81612281565b92505061113e868683818110611123576111236123ec565b90506020020160208101906111389190611d0e565b83611a11565b838382818110611150576111506123ec565b90506020028101906111629190612402565b60008481526007602052604090209161117c91908361231a565b5085858281811061118f5761118f6123ec565b90506020020160208101906111a49190611d0e565b60088585848181106111b8576111b86123ec565b90506020028101906111ca9190612402565b6040516111d892919061225b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b03199092169190911790556001016110f9565b5084849050600360008282546112259190612448565b90915550505050505050565b61123c858585610aa5565b833b156110385761103885858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b5c92505050565b6060600354821180611295575081155b156112b35760405163199c280360e01b815260040160405180910390fd5b61137961136b600580546112c69061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546112f29061229a565b801561133f5780601f106113145761010080835404028352916020019161133f565b820191906000526020600020905b81548152906001019060200180831161132257829003601f168201915b505050505060405180604001604052806009815260200168746f6b656e5552492f60b81b815250611c27565b61137484611c82565b611c27565b92915050565b600654610100900460ff166113a757604051637087773560e11b815260040160405180910390fd5b336000908152600a6020526040812054908190036113d8576040516312d37ee560e31b815260040160405180910390fd5b804710156113f857604051624898d760e71b815260040160405180910390fd5b336000908152600a602052604081208190556004805483929061141c9084906123d9565b9091555050604051600090339083908381818185875af1925050503d8060008114611463576040519150601f19603f3d011682016040523d82523d6000602084013e611468565b606091505b505090508061084d57604051638b3dac3760e01b815260040160405180910390fd5b611492611b41565b60006114a1638b78c6d8195490565b6001600160a01b031647604051610c69565b60076020526000908152604090208054610d999061229a565b606061104f600580546114de9061229a565b80601f016020809104026020016040519081016040528092919081815260200182805461150a9061229a565b80156115575780601f1061152c57610100808354040283529160200191611557565b820191906000526020600020905b81548152906001019060200180831161153a57829003601f168201915b50505050506040518060400160405280600b81526020016a636f6e747261637455524960a81b815250611c27565b61158d611b41565b63389a75e1600c52806000526020600c2080544211156115b557636f5e88186000526004601cfd5b60009055610ccd81611be9565b6115ca611b41565b8060601b6115e057637448fbae6000526004601cfd5b610ccd81611be9565b6115f1611b41565b600055565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c526020600020820182018054821691508161163d5763ceea21b66000526004601cfd5b81851485151761166357816000526030600c205461166357634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a450505050565b6000604051825184600052606084015160001a602052602084015160405260408401516060526020600160806000604185145afa519250503d6116e257638baa579f6000526004601cfd5b600060605260405292915050565b805181901561084d57600060088360405161170b919061245b565b908152604080516020928190038301902054336000908152600990935290822080546001600160a01b0390921693506117dc916117479061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546117739061229a565b80156117c05780601f10611795576101008083540402835291602001916117c0565b820191906000526020600020905b8154815290600101906020018083116117a357829003601f168201915b50505050506000601f600183510310601f830151029050919050565b1415801561189b5750336000908152600960205260409020805461189991906118049061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546118309061229a565b801561187d5780601f106118525761010080835404028352916020019161187d565b820191906000526020600020905b81548152906001019060200180831161186057829003601f168201915b5050505050848051602091820120825192909101919091201490565b155b156118ca573360009081526009602052604090819020905163028895ef60e51b81526110ea9190600401612477565b6001600160a01b0381166118f15760405163119833d760e11b815260040160405180910390fd5b33600090815260096020526040902061190a8482612502565b506001600160a01b038116600090815260096020526040812080548291611934916117479061229a565b14159050600060646119473460056125c1565b61195191906125d8565b9050600082611961576000611979565b6103e861196f3460056125c1565b61197991906125d8565b905080600a6000600860096000896001600160a01b03166001600160a01b031681526020019081526020016000206040516119b491906125fa565b9081526040805160209281900383019020546001600160a01b039081168452838301949094529182016000908120805495909501909455969091168252600a90955293909320805482019055600480549190930101909155505050565b6001600160a01b039091169081611a305763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b15611a655763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116611a91576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461084d600083835b6001600160a01b038216611aea57604051633a954ecd60e21b815260040160405180910390fd5b81600860076000848152602001908152602001600020604051611b0d91906125fa565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b638b78c6d819543314610e99576382b429006000526004601cfd5b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611ba3578060c08401826020870160045afa505b60208360a48301601c860160008a5af1611bc7573d15611bc7573d6000803e3d6000fd5b508060e01b825114611be15763d1a57ed66000526004601cfd5b505050505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6040518251601f19906020810182165b8581015184820152820180611c37575083518184018360208301165b8681015182820152840180611c535750506000910183810160208101929092528352603f011660405292915050565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611c9d575050819003601f19909101908152919050565b600060208284031215611cd857600080fd5b81356001600160e01b031981168114611cf057600080fd5b9392505050565b80356001600160a01b0381168114610d8757600080fd5b600060208284031215611d2057600080fd5b611cf082611cf7565b60005b83811015611d44578181015183820152602001611d2c565b50506000910152565b60008151808452611d65816020860160208601611d29565b601f01601f19169290920160200192915050565b602081526000611cf06020830184611d4d565b600060208284031215611d9e57600080fd5b5035919050565b60008060408385031215611db857600080fd5b611dc183611cf7565b946020939093013593505050565b60008083601f840112611de157600080fd5b5081356001600160401b03811115611df857600080fd5b602083019150836020828501011115611e1057600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112611e3e57600080fd5b81356001600160401b0380821115611e5857611e58611e17565b604051601f8301601f19908116603f01168101908282118183101715611e8057611e80611e17565b81604052838152866020858801011115611e9957600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060608688031215611ed157600080fd5b85356001600160401b0380821115611ee857600080fd5b611ef489838a01611dcf565b90975095506020880135915080821115611f0d57600080fd5b611f1989838a01611e2d565b94506040880135915080821115611f2f57600080fd5b50611f3c88828901611dcf565b969995985093965092949392505050565b600080600060608486031215611f6257600080fd5b611f6b84611cf7565b9250611f7960208501611cf7565b9150604084013590509250925092565b60008060208385031215611f9c57600080fd5b82356001600160401b03811115611fb257600080fd5b611fbe85828601611dcf565b90969095509350505050565b80358015158114610d8757600080fd5b600060208284031215611fec57600080fd5b611cf082611fca565b60008060006040848603121561200a57600080fd5b83356001600160401b038082111561202157600080fd5b61202d87838801611dcf565b9095509350602086013591508082111561204657600080fd5b5061205386828701611e2d565b9150509250925092565b6000806040838503121561207057600080fd5b61207983611cf7565b915061208760208401611fca565b90509250929050565b60008083601f8401126120a257600080fd5b5081356001600160401b038111156120b957600080fd5b6020830191508360208260051b8501011115611e1057600080fd5b600080600080604085870312156120ea57600080fd5b84356001600160401b038082111561210157600080fd5b61210d88838901612090565b9096509450602087013591508082111561212657600080fd5b5061213387828801612090565b95989497509550505050565b60008060008060006080868803121561215757600080fd5b61216086611cf7565b945061216e60208701611cf7565b93506040860135925060608601356001600160401b0381111561219057600080fd5b611f3c88828901611dcf565b6000602082840312156121ae57600080fd5b81356001600160401b038111156121c457600080fd5b6121d084828501611e2d565b949350505050565b600080604083850312156121eb57600080fd5b6121f483611cf7565b915061208760208401611cf7565b6001600160a01b03851681526060602082018190528101839052828460808301376000608084830101526000601f19601f850116820160808382030160408401526122506080820185611d4d565b979650505050505050565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016122935761229361226b565b5060010190565b600181811c908216806122ae57607f821691505b6020821081036122ce57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610bc157600081815260208120601f850160051c810160208610156122fb5750805b601f850160051c820191505b81811015611be157828155600101612307565b6001600160401b0383111561233157612331611e17565b6123458361233f835461229a565b836122d4565b6000601f84116001811461237957600085156123615750838201355b600019600387901b1c1916600186901b178355611038565b600083815260209020601f19861690835b828110156123aa578685013582556020948501946001909201910161238a565b50868210156123c75760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b818103818111156113795761137961226b565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261241957600080fd5b8301803591506001600160401b0382111561243357600080fd5b602001915036819003821315611e1057600080fd5b808201808211156113795761137961226b565b6000825161246d818460208701611d29565b9190910192915050565b600060208083526000845461248b8161229a565b808487015260406001808416600081146124ac57600181146124c6576124f4565b60ff1985168984015283151560051b8901830195506124f4565b896000528660002060005b858110156124ec5781548b82018601529083019088016124d1565b8a0184019650505b509398975050505050505050565b81516001600160401b0381111561251b5761251b611e17565b61252f81612529845461229a565b846122d4565b602080601f831160018114612564576000841561254c5750858301515b600019600386901b1c1916600185901b178555611be1565b600085815260208120601f198616915b8281101561259357888601518255948401946001909101908401612574565b50858210156125b15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80820281158282048414176113795761137961226b565b6000826125f557634e487b7160e01b600052601260045260246000fd5b500490565b60008083546126088161229a565b60018281168015612620576001811461263557612664565b60ff1984168752821515830287019450612664565b8760005260208060002060005b8581101561265b5781548a820152908401908201612642565b50505082870194505b5092969550505050505056fea26469706673582212207addfedf96e6111dd4ed0e3577cb158ff519e53fabe5fb93f0a9d67621fa7be864736f6c63430008140033000000000000000000000000a45c900f51d7d78567068ac4876264bd881e675f
Deployed Bytecode
0x60806040526004361061027d5760003560e01c80637d20a41d1161014f578063b88d4fde116100c1578063e8a3d4851161007a578063e8a3d4851461073f578063e985e9c514610754578063f04e283e1461078a578063f2fde38b1461079d578063f4a0a528146107b0578063fee81cf4146107d057600080fd5b8063b88d4fde14610681578063c87b56dd14610694578063d294f093146106b4578063da32abac146106c9578063db228051146106de578063e18c3a06146106fe57600080fd5b80638d859f3e116101135780638d859f3e146105c45780638da5cb5b146105da5780638f4e41d5146105f357806395d89b4114610613578063a22cb46514610641578063b1d1dfbd1461066157600080fd5b80637d20a41d1461054c57806382dd832314610566578063870bf62f146105865780638aa0fdad1461059c5780638b7afe2e146105af57600080fd5b806325692962116101f35780636352211e116101ac5780636352211e146104af5780636c0360eb146104cf5780636c19e783146104e457806370a0823114610504578063715018a614610524578063783e1bab1461052c57600080fd5b8063256929621461042a5780633ccfd60b1461043257806342842e0e146104475780634337bb261461045a57806354d1f13d1461048757806355f804b31461048f57600080fd5b8063095ea7b311610245578063095ea7b3146103a45780630eff0a38146103b957806317e7f295146103cc57806318160ddd146103e25780631c6cd2fa146103f857806323b872dd1461041757600080fd5b806301ffc9a7146102825780630426212c146102d4578063057707a01461031857806306fdde031461032e578063081812fc1461036c575b600080fd5b34801561028e57600080fd5b506102bf61029d366004611cc6565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b3480156102e057600080fd5b5061030a6102ef366004611d0e565b6001600160a01b03166000908152600a602052604090205490565b6040519081526020016102cb565b34801561032457600080fd5b5061030a60015481565b34801561033a57600080fd5b5060408051808201909152600c81526b53756b757269205072696d6560a01b60208201525b6040516102cb9190611d79565b34801561037857600080fd5b5061038c610387366004611d8c565b610803565b6040516001600160a01b0390911681526020016102cb565b6103b76103b2366004611da5565b610842565b005b6103b76103c7366004611eb9565b610851565b3480156103d857600080fd5b5061030a60025481565b3480156103ee57600080fd5b5061030a60035481565b34801561040457600080fd5b506006546102bf90610100900460ff1681565b6103b7610425366004611f4d565b610aa5565b6103b7610bc6565b34801561043e57600080fd5b506103b7610c15565b6103b7610455366004611f4d565b610cd0565b34801561046657600080fd5b5061030a610475366004611d0e565b600b6020526000908152604090205481565b6103b7610cfd565b34801561049b57600080fd5b506103b76104aa366004611f89565b610d39565b3480156104bb57600080fd5b5061038c6104ca366004611d8c565b610d4e565b3480156104db57600080fd5b5061035f610d8c565b3480156104f057600080fd5b506103b76104ff366004611d0e565b610e1a565b34801561051057600080fd5b5061030a61051f366004611d0e565b610e4c565b6103b7610e87565b34801561053857600080fd5b506103b7610547366004611fda565b610e9b565b34801561055857600080fd5b506006546102bf9060ff1681565b34801561057257600080fd5b506103b7610581366004611fda565b610ebd565b34801561059257600080fd5b5061030a60045481565b6103b76105aa366004611ff5565b610ed8565b3480156105bb57600080fd5b5061030a61103f565b3480156105d057600080fd5b5061030a60005481565b3480156105e657600080fd5b50638b78c6d8195461038c565b3480156105ff57600080fd5b5061035f61060e366004611d0e565b611054565b34801561061f57600080fd5b506040805180820190915260058152645052494d4560d81b602082015261035f565b34801561064d57600080fd5b506103b761065c36600461205d565b61106d565b34801561066d57600080fd5b506103b761067c3660046120d4565b6110c3565b6103b761068f36600461213f565b611231565b3480156106a057600080fd5b5061035f6106af366004611d8c565b611285565b3480156106c057600080fd5b506103b761137f565b3480156106d557600080fd5b506103b761148a565b3480156106ea57600080fd5b5061035f6106f9366004611d8c565b6114b3565b34801561070a57600080fd5b5061038c61071936600461219c565b80516020818301810180516008825292820191909301209152546001600160a01b031681565b34801561074b57600080fd5b5061035f6114cc565b34801561076057600080fd5b506102bf61076f3660046121d8565b601c52670a5a2e7a000000006008526000526030600c205490565b6103b7610798366004611d0e565b611585565b6103b76107ab366004611d0e565b6115c2565b3480156107bc57600080fd5b506103b76107cb366004611d8c565b6115e9565b3480156107dc57600080fd5b5061030a6107eb366004611d0e565b63389a75e1600c908152600091909152602090205490565b600081600052673ec412a9852d173d60c11b601c52602060002082018201805460601b6108385763ceea21b66000526004601cfd5b6001015492915050565b61084d3383836115f6565b5050565b60065460ff16610874576040516303eaac9360e01b815260040160405180910390fd5b600254341461089657604051632a9ffab760e21b815260040160405180910390fd5b336000908152600b6020526040902054156108c457604051630c8d9eab60e31b815260040160405180910390fd5b6000338686866040516020016108dd9493929190612202565b60408051601f1981840301815291905280516020909101206006549091506001600160a01b03620100009091041661097961093d836020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b85858080601f01602080910402602001604051908101604052809392919081815260200183838082843760009201919091525061169792505050565b6001600160a01b0316146109a057604051634825ec7b60e01b815260040160405180910390fd5b60006001600160a01b0316600887876040516109bd92919061225b565b908152604051908190036020019020546001600160a01b0316146109f45760405163568d5a9f60e01b815260040160405180910390fd5b6109fd846116f0565b6000600360008154610a0e90612281565b91829055506000818152600760205260409020909150610a2f87898361231a565b503360088888604051610a4392919061225b565b908152604080516020928190038301902080546001600160a01b0319166001600160a01b039490941693909317909255336000908152600b909152908120805491610a8d83612281565b9190505550610a9c3382611a11565b50505050505050565b6000818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b039485169493841693811691908286148302610b035782610af55763ceea21b66000526004601cfd5b63a11481006000526004601cfd5b84610b165763ea553b346000526004601cfd5b856000528160010154925082331486331417610b44576030600c2054610b4457634b6e7f186000526004601cfd5b8215610b5257600082600101555b85851818905550601c600c8181208054600019019055600084905220805460010163ffffffff8116610b8c576301336cea6000526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600080a4610bc1838383611ac3565b505050565b60006202a3006001600160401b03164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610c1d611b41565b600454471015610c3f57604051624898d760e71b815260040160405180910390fd5b6000610c4e638b78c6d8195490565b6001600160a01b031660045447610c6591906123d9565b6040515b60006040518083038185875af1925050503d8060008114610ca6576040519150601f19603f3d011682016040523d82523d6000602084013e610cab565b606091505b5050905080610ccd57604051638b3dac3760e01b815260040160405180910390fd5b50565b610cdb838383610aa5565b813b15610bc157610bc183838360405180602001604052806000815250611b5c565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b610d41611b41565b6005610bc182848361231a565b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b031680610d875763ceea21b66000526004601cfd5b919050565b60058054610d999061229a565b80601f0160208091040260200160405190810160405280929190818152602001828054610dc59061229a565b8015610e125780601f10610de757610100808354040283529160200191610e12565b820191906000526020600020905b815481529060010190602001808311610df557829003601f168201915b505050505081565b610e22611b41565b600680546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b600081610e6157638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b610e8f611b41565b610e996000611be9565b565b610ea3611b41565b600680549115156101000261ff0019909216919091179055565b610ec5611b41565b6006805460ff1916911515919091179055565b60065460ff16610efb576040516303eaac9360e01b815260040160405180910390fd5b8051819015801590610f0f57506001543414155b15610f2d576040516312689ab760e11b815260040160405180910390fd5b8051158015610f3e57506000543414155b15610f5c57604051632a9ffab760e21b815260040160405180910390fd5b60006001600160a01b031660088585604051610f7992919061225b565b908152604051908190036020019020546001600160a01b031614610fb05760405163568d5a9f60e01b815260040160405180910390fd5b610fb9826116f0565b6000600360008154610fca90612281565b91829055506000818152600760205260409020909150610feb85878361231a565b503360088686604051610fff92919061225b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b03199092169190911790556110383382611a11565b5050505050565b60006004544761104f91906123d9565b905090565b60096020526000908152604090208054610d999061229a565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b6110cb611b41565b8281146110f35760405163a73e819d60e01b8152600481018490526024015b60405180910390fd5b60035460005b8481101561120f578161110b81612281565b92505061113e868683818110611123576111236123ec565b90506020020160208101906111389190611d0e565b83611a11565b838382818110611150576111506123ec565b90506020028101906111629190612402565b60008481526007602052604090209161117c91908361231a565b5085858281811061118f5761118f6123ec565b90506020020160208101906111a49190611d0e565b60088585848181106111b8576111b86123ec565b90506020028101906111ca9190612402565b6040516111d892919061225b565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b03199092169190911790556001016110f9565b5084849050600360008282546112259190612448565b90915550505050505050565b61123c858585610aa5565b833b156110385761103885858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611b5c92505050565b6060600354821180611295575081155b156112b35760405163199c280360e01b815260040160405180910390fd5b61137961136b600580546112c69061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546112f29061229a565b801561133f5780601f106113145761010080835404028352916020019161133f565b820191906000526020600020905b81548152906001019060200180831161132257829003601f168201915b505050505060405180604001604052806009815260200168746f6b656e5552492f60b81b815250611c27565b61137484611c82565b611c27565b92915050565b600654610100900460ff166113a757604051637087773560e11b815260040160405180910390fd5b336000908152600a6020526040812054908190036113d8576040516312d37ee560e31b815260040160405180910390fd5b804710156113f857604051624898d760e71b815260040160405180910390fd5b336000908152600a602052604081208190556004805483929061141c9084906123d9565b9091555050604051600090339083908381818185875af1925050503d8060008114611463576040519150601f19603f3d011682016040523d82523d6000602084013e611468565b606091505b505090508061084d57604051638b3dac3760e01b815260040160405180910390fd5b611492611b41565b60006114a1638b78c6d8195490565b6001600160a01b031647604051610c69565b60076020526000908152604090208054610d999061229a565b606061104f600580546114de9061229a565b80601f016020809104026020016040519081016040528092919081815260200182805461150a9061229a565b80156115575780601f1061152c57610100808354040283529160200191611557565b820191906000526020600020905b81548152906001019060200180831161153a57829003601f168201915b50505050506040518060400160405280600b81526020016a636f6e747261637455524960a81b815250611c27565b61158d611b41565b63389a75e1600c52806000526020600c2080544211156115b557636f5e88186000526004601cfd5b60009055610ccd81611be9565b6115ca611b41565b8060601b6115e057637448fbae6000526004601cfd5b610ccd81611be9565b6115f1611b41565b600055565b60001960601c828116925083811693508160005283673ec412a9852d173d60c11b17601c526020600020820182018054821691508161163d5763ceea21b66000526004601cfd5b81851485151761166357816000526030600c205461166357634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600080a450505050565b6000604051825184600052606084015160001a602052602084015160405260408401516060526020600160806000604185145afa519250503d6116e257638baa579f6000526004601cfd5b600060605260405292915050565b805181901561084d57600060088360405161170b919061245b565b908152604080516020928190038301902054336000908152600990935290822080546001600160a01b0390921693506117dc916117479061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546117739061229a565b80156117c05780601f10611795576101008083540402835291602001916117c0565b820191906000526020600020905b8154815290600101906020018083116117a357829003601f168201915b50505050506000601f600183510310601f830151029050919050565b1415801561189b5750336000908152600960205260409020805461189991906118049061229a565b80601f01602080910402602001604051908101604052809291908181526020018280546118309061229a565b801561187d5780601f106118525761010080835404028352916020019161187d565b820191906000526020600020905b81548152906001019060200180831161186057829003601f168201915b5050505050848051602091820120825192909101919091201490565b155b156118ca573360009081526009602052604090819020905163028895ef60e51b81526110ea9190600401612477565b6001600160a01b0381166118f15760405163119833d760e11b815260040160405180910390fd5b33600090815260096020526040902061190a8482612502565b506001600160a01b038116600090815260096020526040812080548291611934916117479061229a565b14159050600060646119473460056125c1565b61195191906125d8565b9050600082611961576000611979565b6103e861196f3460056125c1565b61197991906125d8565b905080600a6000600860096000896001600160a01b03166001600160a01b031681526020019081526020016000206040516119b491906125fa565b9081526040805160209281900383019020546001600160a01b039081168452838301949094529182016000908120805495909501909455969091168252600a90955293909320805482019055600480549190930101909155505050565b6001600160a01b039091169081611a305763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b15611a655763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116611a91576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461084d600083835b6001600160a01b038216611aea57604051633a954ecd60e21b815260040160405180910390fd5b81600860076000848152602001908152602001600020604051611b0d91906125fa565b90815260405190819003602001902080546001600160a01b03929092166001600160a01b0319909216919091179055505050565b638b78c6d819543314610e99576382b429006000526004601cfd5b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611ba3578060c08401826020870160045afa505b60208360a48301601c860160008a5af1611bc7573d15611bc7573d6000803e3d6000fd5b508060e01b825114611be15763d1a57ed66000526004601cfd5b505050505050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6040518251601f19906020810182165b8581015184820152820180611c37575083518184018360208301165b8681015182820152840180611c535750506000910183810160208101929092528352603f011660405292915050565b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611c9d575050819003601f19909101908152919050565b600060208284031215611cd857600080fd5b81356001600160e01b031981168114611cf057600080fd5b9392505050565b80356001600160a01b0381168114610d8757600080fd5b600060208284031215611d2057600080fd5b611cf082611cf7565b60005b83811015611d44578181015183820152602001611d2c565b50506000910152565b60008151808452611d65816020860160208601611d29565b601f01601f19169290920160200192915050565b602081526000611cf06020830184611d4d565b600060208284031215611d9e57600080fd5b5035919050565b60008060408385031215611db857600080fd5b611dc183611cf7565b946020939093013593505050565b60008083601f840112611de157600080fd5b5081356001600160401b03811115611df857600080fd5b602083019150836020828501011115611e1057600080fd5b9250929050565b634e487b7160e01b600052604160045260246000fd5b600082601f830112611e3e57600080fd5b81356001600160401b0380821115611e5857611e58611e17565b604051601f8301601f19908116603f01168101908282118183101715611e8057611e80611e17565b81604052838152866020858801011115611e9957600080fd5b836020870160208301376000602085830101528094505050505092915050565b600080600080600060608688031215611ed157600080fd5b85356001600160401b0380821115611ee857600080fd5b611ef489838a01611dcf565b90975095506020880135915080821115611f0d57600080fd5b611f1989838a01611e2d565b94506040880135915080821115611f2f57600080fd5b50611f3c88828901611dcf565b969995985093965092949392505050565b600080600060608486031215611f6257600080fd5b611f6b84611cf7565b9250611f7960208501611cf7565b9150604084013590509250925092565b60008060208385031215611f9c57600080fd5b82356001600160401b03811115611fb257600080fd5b611fbe85828601611dcf565b90969095509350505050565b80358015158114610d8757600080fd5b600060208284031215611fec57600080fd5b611cf082611fca565b60008060006040848603121561200a57600080fd5b83356001600160401b038082111561202157600080fd5b61202d87838801611dcf565b9095509350602086013591508082111561204657600080fd5b5061205386828701611e2d565b9150509250925092565b6000806040838503121561207057600080fd5b61207983611cf7565b915061208760208401611fca565b90509250929050565b60008083601f8401126120a257600080fd5b5081356001600160401b038111156120b957600080fd5b6020830191508360208260051b8501011115611e1057600080fd5b600080600080604085870312156120ea57600080fd5b84356001600160401b038082111561210157600080fd5b61210d88838901612090565b9096509450602087013591508082111561212657600080fd5b5061213387828801612090565b95989497509550505050565b60008060008060006080868803121561215757600080fd5b61216086611cf7565b945061216e60208701611cf7565b93506040860135925060608601356001600160401b0381111561219057600080fd5b611f3c88828901611dcf565b6000602082840312156121ae57600080fd5b81356001600160401b038111156121c457600080fd5b6121d084828501611e2d565b949350505050565b600080604083850312156121eb57600080fd5b6121f483611cf7565b915061208760208401611cf7565b6001600160a01b03851681526060602082018190528101839052828460808301376000608084830101526000601f19601f850116820160808382030160408401526122506080820185611d4d565b979650505050505050565b8183823760009101908152919050565b634e487b7160e01b600052601160045260246000fd5b6000600182016122935761229361226b565b5060010190565b600181811c908216806122ae57607f821691505b6020821081036122ce57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115610bc157600081815260208120601f850160051c810160208610156122fb5750805b601f850160051c820191505b81811015611be157828155600101612307565b6001600160401b0383111561233157612331611e17565b6123458361233f835461229a565b836122d4565b6000601f84116001811461237957600085156123615750838201355b600019600387901b1c1916600186901b178355611038565b600083815260209020601f19861690835b828110156123aa578685013582556020948501946001909201910161238a565b50868210156123c75760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b818103818111156113795761137961226b565b634e487b7160e01b600052603260045260246000fd5b6000808335601e1984360301811261241957600080fd5b8301803591506001600160401b0382111561243357600080fd5b602001915036819003821315611e1057600080fd5b808201808211156113795761137961226b565b6000825161246d818460208701611d29565b9190910192915050565b600060208083526000845461248b8161229a565b808487015260406001808416600081146124ac57600181146124c6576124f4565b60ff1985168984015283151560051b8901830195506124f4565b896000528660002060005b858110156124ec5781548b82018601529083019088016124d1565b8a0184019650505b509398975050505050505050565b81516001600160401b0381111561251b5761251b611e17565b61252f81612529845461229a565b846122d4565b602080601f831160018114612564576000841561254c5750858301515b600019600386901b1c1916600185901b178555611be1565b600085815260208120601f198616915b8281101561259357888601518255948401946001909101908401612574565b50858210156125b15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b80820281158282048414176113795761137961226b565b6000826125f557634e487b7160e01b600052601260045260246000fd5b500490565b60008083546126088161229a565b60018281168015612620576001811461263557612664565b60ff1984168752821515830287019450612664565b8760005260208060002060005b8581101561265b5781548a820152908401908201612642565b50505082870194505b5092969550505050505056fea26469706673582212207addfedf96e6111dd4ed0e3577cb158ff519e53fabe5fb93f0a9d67621fa7be864736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000a45c900f51d7d78567068ac4876264bd881e675f
-----Decoded View---------------
Arg [0] : signer_ (address): 0xA45C900f51D7D78567068Ac4876264BD881E675f
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000a45c900f51d7d78567068ac4876264bd881e675f
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.