ERC-721
Source Code
Overview
Max Total Supply
2,669 MMO
Holders
2,669
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 MMOLoading...
Loading
Loading...
Loading
Loading...
Loading
Contract Name:
Metamorph
Compiler Version
v0.8.24+commit.e11b9ed9
Contract Source Code (Solidity)
/**
*Submitted for verification at Arbiscan.io on 2024-02-16
*/
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.13;
abstract contract ERC721 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev An account can hold up to 4294967295 tokens.
uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Only the token owner or an approved account can manage the token.
error NotOwnerNorApproved();
/// @dev The token does not exist.
error TokenDoesNotExist();
/// @dev The token already exists.
error TokenAlreadyExists();
/// @dev Cannot query the balance for the zero address.
error BalanceQueryForZeroAddress();
/// @dev Cannot mint or transfer to the zero address.
error TransferToZeroAddress();
/// @dev The token must be owned by `from`.
error TransferFromIncorrectOwner();
/// @dev The recipient's balance has overflowed.
error AccountBalanceOverflow();
/// @dev Cannot safely transfer to a contract that does not implement
/// the ERC721Receiver interface.
error TransferToNonERC721ReceiverImplementer();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emitted when token `id` is transferred from `from` to `to`.
event Transfer(address indexed from, address indexed to, uint256 indexed id);
/// @dev Emitted when `owner` enables `account` to manage the `id` token.
event Approval(address indexed owner, address indexed account, uint256 indexed id);
/// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens.
event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved);
/// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`.
uint256 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
/// @dev `keccak256(bytes("Approval(address,address,uint256)"))`.
uint256 private constant _APPROVAL_EVENT_SIGNATURE =
0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925;
/// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`.
uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE =
0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership data slot of `id` is given by:
/// ```
/// mstore(0x00, id)
/// mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
/// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
/// ```
/// Bits Layout:
/// - [0..159] `addr`
/// - [160..255] `extraData`
///
/// The approved address slot is given by: `add(1, ownershipSlot)`.
///
/// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip
///
/// The balance slot of `owner` is given by:
/// ```
/// mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
/// mstore(0x00, owner)
/// let balanceSlot := keccak256(0x0c, 0x1c)
/// ```
/// Bits Layout:
/// - [0..31] `balance`
/// - [32..255] `aux`
///
/// The `operator` approval slot of `owner` is given by:
/// ```
/// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
/// mstore(0x00, owner)
/// let operatorApprovalSlot := keccak256(0x0c, 0x30)
/// ```
uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192;
/// @dev Pre-shifted and pre-masked constant.
uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC721 METADATA */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the token collection name.
function name() public view virtual returns (string memory);
/// @dev Returns the token collection symbol.
function symbol() public view virtual returns (string memory);
/// @dev Returns the Uniform Resource Identifier (URI) for token `id`.
function tokenURI(uint256 id) public view virtual returns (string memory);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC721 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of token `id`.
///
/// Requirements:
/// - Token `id` must exist.
function ownerOf(uint256 id) public view virtual returns (address result) {
result = _ownerOf(id);
/// @solidity memory-safe-assembly
assembly {
if iszero(result) {
mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns the number of tokens owned by `owner`.
///
/// Requirements:
/// - `owner` must not be the zero address.
function balanceOf(address owner) public view virtual returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
// Revert if the `owner` is the zero address.
if iszero(owner) {
mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`.
revert(0x1c, 0x04)
}
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE)
}
}
/// @dev Returns the account approved to manage token `id`.
///
/// Requirements:
/// - Token `id` must exist.
function getApproved(uint256 id) public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
if iszero(shl(96, sload(ownershipSlot))) {
mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
revert(0x1c, 0x04)
}
result := sload(add(1, ownershipSlot))
}
}
/// @dev Sets `account` as the approved account to manage token `id`.
///
/// Requirements:
/// - Token `id` must exist.
/// - The caller must be the owner of the token,
/// or an approved operator for the token owner.
///
/// Emits an {Approval} event.
function approve(address account, uint256 id) public payable virtual {
_approve(msg.sender, account, id);
}
/// @dev Returns whether `operator` is approved to manage the tokens of `owner`.
function isApprovedForAll(address owner, address operator)
public
view
virtual
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
mstore(0x1c, operator)
mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
mstore(0x00, owner)
result := sload(keccak256(0x0c, 0x30))
}
}
/// @dev Sets whether `operator` is approved to manage the tokens of the caller.
///
/// Emits an {ApprovalForAll} event.
function setApprovalForAll(address operator, bool isApproved) public virtual {
/// @solidity memory-safe-assembly
assembly {
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`msg.sender`, `operator`).
mstore(0x1c, operator)
mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x30), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
// forgefmt: disable-next-item
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)))
}
}
/// @dev Transfers token `id` from `from` to `to`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - `from` must be the owner of the token.
/// - `to` cannot be the zero address.
/// - The caller must be the owner of the token, or be approved to manage the token.
///
/// Emits a {Transfer} event.
function transferFrom(address from, address to, uint256 id) public payable virtual {
_beforeTokenTransfer(from, to, id);
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
let bitmaskAddress := shr(96, not(0))
from := and(bitmaskAddress, from)
to := and(bitmaskAddress, to)
// Load the ownership data.
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller()))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
let owner := and(bitmaskAddress, ownershipPacked)
// Revert if the token does not exist, or if `from` is not the owner.
if iszero(mul(owner, eq(owner, from))) {
// `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
revert(0x1c, 0x04)
}
// Load, check, and update the token approval.
{
mstore(0x00, from)
let approvedAddress := sload(add(1, ownershipSlot))
// Revert if the caller is not the owner, nor approved.
if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Delete the approved address if any.
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
// Update with the new owner.
sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
// Decrement the balance of `from`.
{
let fromBalanceSlot := keccak256(0x0c, 0x1c)
sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
}
// Increment the balance of `to`.
{
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x1c)
let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
// Revert if `to` is the zero address, or if the account balance overflows.
if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
// `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
mstore(shl(2, iszero(to)), 0xea553b3401336cea)
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceSlotPacked)
}
// Emit the {Transfer} event.
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
}
_afterTokenTransfer(from, to, id);
}
/// @dev Equivalent to `safeTransferFrom(from, to, id, "")`.
function safeTransferFrom(address from, address to, uint256 id) public payable virtual {
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, "");
}
/// @dev Transfers token `id` from `from` to `to`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - `from` must be the owner of the token.
/// - `to` cannot be the zero address.
/// - The caller must be the owner of the token, or be approved to manage the token.
/// - If `to` refers to a smart contract, it must implement
/// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
///
/// Emits a {Transfer} event.
function safeTransferFrom(address from, address to, uint256 id, bytes calldata data)
public
payable
virtual
{
transferFrom(from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
/// See: https://eips.ethereum.org/EIPS/eip-165
/// This function call must use less than 30000 gas.
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let s := shr(224, interfaceId)
// ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f.
result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL QUERY FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns if token `id` exists.
function _exists(uint256 id) internal view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))))
}
}
/// @dev Returns the owner of token `id`.
/// Returns the zero address instead of reverting if the token does not exist.
function _ownerOf(uint256 id) internal view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL DATA HITCHHIKING FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance, no events are emitted for the hitchhiking setters.
// Please emit your own events if required.
/// @dev Returns the auxiliary data for `owner`.
/// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
/// Auxiliary data can be set for any address, even if it does not have any tokens.
function _getAux(address owner) internal view virtual returns (uint224 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
result := shr(32, sload(keccak256(0x0c, 0x1c)))
}
}
/// @dev Set the auxiliary data for `owner` to `value`.
/// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data.
/// Auxiliary data can be set for any address, even if it does not have any tokens.
function _setAux(address owner, uint224 value) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
mstore(0x00, owner)
let balanceSlot := keccak256(0x0c, 0x1c)
let packed := sload(balanceSlot)
sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed)))))
}
}
/// @dev Returns the extra data for token `id`.
/// Minting, transferring, burning a token will not change the extra data.
/// The extra data can be set on a non-existent token.
function _getExtraData(uint256 id) internal view virtual returns (uint96 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20)))))
}
}
/// @dev Sets the extra data for token `id` to `value`.
/// Minting, transferring, burning a token will not change the extra data.
/// The extra data can be set on a non-existent token.
function _setExtraData(uint256 id, uint96 value) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let packed := sload(ownershipSlot)
sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed)))))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL MINT FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Mints token `id` to `to`.
///
/// Requirements:
///
/// - Token `id` must not exist.
/// - `to` cannot be the zero address.
///
/// Emits a {Transfer} event.
function _mint(address to, uint256 id) internal virtual {
_beforeTokenTransfer(address(0), to, id);
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
to := shr(96, shl(96, to))
// Load the ownership data.
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
// Revert if the token already exists.
if shl(96, ownershipPacked) {
mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`.
revert(0x1c, 0x04)
}
// Update with the owner.
sstore(ownershipSlot, or(ownershipPacked, to))
// Increment the balance of the owner.
{
mstore(0x00, to)
let balanceSlot := keccak256(0x0c, 0x1c)
let balanceSlotPacked := add(sload(balanceSlot), 1)
// Revert if `to` is the zero address, or if the account balance overflows.
if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
// `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
mstore(shl(2, iszero(to)), 0xea553b3401336cea)
revert(0x1c, 0x04)
}
sstore(balanceSlot, balanceSlotPacked)
}
// Emit the {Transfer} event.
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
}
_afterTokenTransfer(address(0), to, id);
}
/// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`.
/// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing).
///
/// Requirements:
///
/// - `to` cannot be the zero address.
///
/// Emits a {Transfer} event.
function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual {
_beforeTokenTransfer(address(0), to, id);
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
to := shr(96, shl(96, to))
// Update with the owner and extra data.
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to))
// Increment the balance of the owner.
{
mstore(0x00, to)
let balanceSlot := keccak256(0x0c, 0x1c)
let balanceSlotPacked := add(sload(balanceSlot), 1)
// Revert if `to` is the zero address, or if the account balance overflows.
if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
// `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
mstore(shl(2, iszero(to)), 0xea553b3401336cea)
revert(0x1c, 0x04)
}
sstore(balanceSlot, balanceSlotPacked)
}
// Emit the {Transfer} event.
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id)
}
_afterTokenTransfer(address(0), to, id);
}
/// @dev Equivalent to `_safeMint(to, id, "")`.
function _safeMint(address to, uint256 id) internal virtual {
_safeMint(to, id, "");
}
/// @dev Mints token `id` to `to`.
///
/// Requirements:
///
/// - Token `id` must not exist.
/// - `to` cannot be the zero address.
/// - If `to` refers to a smart contract, it must implement
/// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
///
/// Emits a {Transfer} event.
function _safeMint(address to, uint256 id, bytes memory data) internal virtual {
_mint(to, id);
if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL BURN FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_burn(address(0), id)`.
function _burn(uint256 id) internal virtual {
_burn(address(0), id);
}
/// @dev Destroys token `id`, using `by`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - If `by` is not the zero address,
/// it must be the owner of the token, or be approved to manage the token.
///
/// Emits a {Transfer} event.
function _burn(address by, uint256 id) internal virtual {
address owner = ownerOf(id);
_beforeTokenTransfer(owner, address(0), id);
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
by := shr(96, shl(96, by))
// Load the ownership data.
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
// Reload the owner in case it is changed in `_beforeTokenTransfer`.
owner := shr(96, shl(96, ownershipPacked))
// Revert if the token does not exist.
if iszero(owner) {
mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
revert(0x1c, 0x04)
}
// Load and check the token approval.
{
mstore(0x00, owner)
let approvedAddress := sload(add(1, ownershipSlot))
// If `by` is not the zero address, do the authorization check.
// Revert if the `by` is not the owner, nor approved.
if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Delete the approved address if any.
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
// Clear the owner.
sstore(ownershipSlot, xor(ownershipPacked, owner))
// Decrement the balance of `owner`.
{
let balanceSlot := keccak256(0x0c, 0x1c)
sstore(balanceSlot, sub(sload(balanceSlot), 1))
}
// Emit the {Transfer} event.
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id)
}
_afterTokenTransfer(owner, address(0), id);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL APPROVAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it.
///
/// Requirements:
/// - Token `id` must exist.
function _isApprovedOrOwner(address account, uint256 id)
internal
view
virtual
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
result := 1
// Clear the upper 96 bits.
account := shr(96, shl(96, account))
// Load the ownership data.
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let owner := shr(96, shl(96, sload(ownershipSlot)))
// Revert if the token does not exist.
if iszero(owner) {
mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`.
revert(0x1c, 0x04)
}
// Check if `account` is the `owner`.
if iszero(eq(account, owner)) {
mstore(0x00, owner)
// Check if `account` is approved to manage the token.
if iszero(sload(keccak256(0x0c, 0x30))) {
result := eq(account, sload(add(1, ownershipSlot)))
}
}
}
}
/// @dev Returns the account approved to manage token `id`.
/// Returns the zero address instead of reverting if the token does not exist.
function _getApproved(uint256 id) internal view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, id)
mstore(0x1c, _ERC721_MASTER_SLOT_SEED)
result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20)))))
}
}
/// @dev Equivalent to `_approve(address(0), account, id)`.
function _approve(address account, uint256 id) internal virtual {
_approve(address(0), account, id);
}
/// @dev Sets `account` as the approved account to manage token `id`, using `by`.
///
/// Requirements:
/// - Token `id` must exist.
/// - If `by` is not the zero address, `by` must be the owner
/// or an approved operator for the token owner.
///
/// Emits a {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(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id)
}
}
/// @dev Approve or remove the `operator` as an operator for `by`,
/// without authorization checks.
///
/// Emits an {ApprovalForAll} event.
function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual {
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
by := shr(96, shl(96, by))
operator := shr(96, shl(96, operator))
// Convert to 0 or 1.
isApproved := iszero(iszero(isApproved))
// Update the `isApproved` for (`by`, `operator`).
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator))
mstore(0x00, by)
sstore(keccak256(0x0c, 0x30), isApproved)
// Emit the {ApprovalForAll} event.
mstore(0x00, isApproved)
log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL TRANSFER FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to `_transfer(address(0), from, to, id)`.
function _transfer(address from, address to, uint256 id) internal virtual {
_transfer(address(0), from, to, id);
}
/// @dev Transfers token `id` from `from` to `to`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - `from` must be the owner of the token.
/// - `to` cannot be the zero address.
/// - If `by` is not the zero address,
/// it must be the owner of the token, or be approved to manage the token.
///
/// Emits a {Transfer} event.
function _transfer(address by, address from, address to, uint256 id) internal virtual {
_beforeTokenTransfer(from, to, id);
/// @solidity memory-safe-assembly
assembly {
// Clear the upper 96 bits.
let bitmaskAddress := shr(96, not(0))
from := and(bitmaskAddress, from)
to := and(bitmaskAddress, to)
by := and(bitmaskAddress, by)
// Load the ownership data.
mstore(0x00, id)
mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by))
let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20)))
let ownershipPacked := sload(ownershipSlot)
let owner := and(bitmaskAddress, ownershipPacked)
// Revert if the token does not exist, or if `from` is not the owner.
if iszero(mul(owner, eq(owner, from))) {
// `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`.
mstore(shl(2, iszero(owner)), 0xceea21b6a1148100)
revert(0x1c, 0x04)
}
// Load, check, and update the token approval.
{
mstore(0x00, from)
let approvedAddress := sload(add(1, ownershipSlot))
// If `by` is not the zero address, do the authorization check.
// Revert if the `by` is not the owner, nor approved.
if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) {
if iszero(sload(keccak256(0x0c, 0x30))) {
mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`.
revert(0x1c, 0x04)
}
}
// Delete the approved address if any.
if approvedAddress { sstore(add(1, ownershipSlot), 0) }
}
// Update with the new owner.
sstore(ownershipSlot, xor(ownershipPacked, xor(from, to)))
// Decrement the balance of `from`.
{
let fromBalanceSlot := keccak256(0x0c, 0x1c)
sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1))
}
// Increment the balance of `to`.
{
mstore(0x00, to)
let toBalanceSlot := keccak256(0x0c, 0x1c)
let toBalanceSlotPacked := add(sload(toBalanceSlot), 1)
// Revert if `to` is the zero address, or if the account balance overflows.
if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) {
// `TransferToZeroAddress()`, `AccountBalanceOverflow()`.
mstore(shl(2, iszero(to)), 0xea553b3401336cea)
revert(0x1c, 0x04)
}
sstore(toBalanceSlot, toBalanceSlotPacked)
}
// Emit the {Transfer} event.
log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id)
}
_afterTokenTransfer(from, to, id);
}
/// @dev Equivalent to `_safeTransfer(from, to, id, "")`.
function _safeTransfer(address from, address to, uint256 id) internal virtual {
_safeTransfer(from, to, id, "");
}
/// @dev Transfers token `id` from `from` to `to`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - `from` must be the owner of the token.
/// - `to` cannot be the zero address.
/// - The caller must be the owner of the token, or be approved to manage the token.
/// - If `to` refers to a smart contract, it must implement
/// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
///
/// Emits a {Transfer} event.
function _safeTransfer(address from, address to, uint256 id, bytes memory data)
internal
virtual
{
_transfer(address(0), from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
/// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`.
function _safeTransfer(address by, address from, address to, uint256 id) internal virtual {
_safeTransfer(by, from, to, id, "");
}
/// @dev Transfers token `id` from `from` to `to`.
///
/// Requirements:
///
/// - Token `id` must exist.
/// - `from` must be the owner of the token.
/// - `to` cannot be the zero address.
/// - If `by` is not the zero address,
/// it must be the owner of the token, or be approved to manage the token.
/// - If `to` refers to a smart contract, it must implement
/// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
///
/// Emits a {Transfer} event.
function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data)
internal
virtual
{
_transfer(by, from, to, id);
if (_hasCode(to)) _checkOnERC721Received(from, to, id, data);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HOOKS FOR OVERRIDING */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Hook that is called before any token transfers, including minting and burning.
function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {}
/// @dev Hook that is called after any token transfers, including minting and burning.
function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns if `a` has bytecode of non-zero length.
function _hasCode(address a) private view returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := extcodesize(a) // Can handle dirty upper bits.
}
}
/// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`.
/// Reverts if the target does not support the function correctly.
function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data)
private
{
/// @solidity memory-safe-assembly
assembly {
// Prepare the calldata.
let m := mload(0x40)
let onERC721ReceivedSelector := 0x150b7a02
mstore(m, onERC721ReceivedSelector)
mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`.
mstore(add(m, 0x40), shr(96, shl(96, from)))
mstore(add(m, 0x60), id)
mstore(add(m, 0x80), 0x80)
let n := mload(data)
mstore(add(m, 0xa0), n)
if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) }
// Revert if the call reverts.
if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) {
if returndatasize() {
// Bubble up the revert if the call reverts.
returndatacopy(m, 0x00, returndatasize())
revert(m, returndatasize())
}
}
// Load the returndata and compare it.
if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) {
mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`.
revert(0x1c, 0x04)
}
}
}
}
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}
library LibString {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The length of the output is too small to contain all the hex digits.
error HexLengthInsufficient();
/// @dev The length of the string is more than 32 bytes.
error TooBigForSmallString();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits.
str := add(mload(0x40), 0x80)
// Update the free memory pointer to allocate.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
let w := not(0) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 1)`.
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory str) {
if (value >= 0) {
return toString(uint256(value));
}
unchecked {
str = toString(~uint256(value) + 1);
}
/// @solidity memory-safe-assembly
assembly {
// We still have some spare memory space on the left,
// as we have allocated 3 words (96 bytes) for up to 78 digits.
let length := mload(str) // Load the string length.
mstore(str, 0x2d) // Store the '-' character.
str := sub(str, 1) // Move back the string pointer by a byte.
mstore(str, add(length, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2 + 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value, length);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `length` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `length * 2` bytes.
/// Reverts if `length` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 length)
internal
pure
returns (string memory str)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes
// for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length.
// We add 0x20 to the total and round down to a multiple of 0x20.
// (0x20 + 0x20 + 0x02 + 0x20) = 0x62.
str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f)))
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(str, add(length, length))
let w := not(1) // Tsk.
let temp := value
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for {} 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(str, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2 + 2` bytes.
function toHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x".
/// The output excludes leading "0" from the `toHexString` output.
/// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`.
function toMinimalHexString(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := add(mload(str), 2) // Compute the length.
mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero.
str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output excludes leading "0" from the `toHexStringNoPrefix` output.
/// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`.
function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present.
let strLength := mload(str) // Get the length.
str := add(str, o) // Move the pointer, accounting for leading zero.
mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
/// As address are 20 bytes long, the output will left-padded to have
/// a length of `20 * 2` bytes.
function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x40 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0.
str := add(mload(0x40), 0x80)
// Allocate the memory.
mstore(0x40, add(str, 0x20))
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end to calculate the length later.
let end := str
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let w := not(1) // Tsk.
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let temp := value } 1 {} {
str := add(str, w) // `sub(str, 2)`.
mstore8(add(str, 1), mload(and(temp, 15)))
mstore8(str, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
// Compute the string's length.
let strLength := sub(end, str)
// Move the pointer and write the length.
str := sub(str, 0x20)
mstore(str, strLength)
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte,
/// and the alphabets are capitalized conditionally according to
/// https://eips.ethereum.org/EIPS/eip-55
function toHexStringChecksummed(address value) internal pure returns (string memory str) {
str = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(str, 0x22)
let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... `
let t := shl(240, 136) // `0b10001000 << 240`
for { let i := 0 } 1 {} {
mstore(add(i, i), mul(t, byte(i, hashed)))
i := add(i, 1)
if eq(i, 20) { break }
}
mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask)))))
o := add(o, 0x20)
mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask)))))
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte.
function toHexString(address value) internal pure returns (string memory str) {
str = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hexadecimal representation of `value`.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(address value) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
str := mload(0x40)
// Allocate the memory.
// We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length,
// 0x02 bytes for the prefix, and 0x28 bytes for the digits.
// The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80.
mstore(0x40, add(str, 0x80))
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
str := add(str, 2)
mstore(str, 40)
let o := add(str, 0x20)
mstore(add(o, 40), 0)
value := shl(96, value)
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
for { let i := 0 } 1 {} {
let p := add(o, add(i, i))
let temp := byte(i, value)
mstore8(add(p, 1), mload(and(temp, 15)))
mstore8(p, mload(shr(4, temp)))
i := add(i, 1)
if eq(i, 20) { break }
}
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexString(bytes memory raw) internal pure returns (string memory str) {
str = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let strLength := add(mload(str), 2) // Compute the length.
mstore(str, 0x3078) // Write the "0x" prefix.
str := sub(str, 2) // Move the pointer.
mstore(str, strLength) // Write the length.
}
}
/// @dev Returns the hex encoded string from the raw bytes.
/// The output is encoded using 2 hexadecimal digits per byte.
function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) {
/// @solidity memory-safe-assembly
assembly {
let length := mload(raw)
str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(str, add(length, length)) // Store the length of the output.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let o := add(str, 0x20)
let end := add(raw, length)
for {} iszero(eq(raw, end)) {} {
raw := add(raw, 1)
mstore8(add(o, 1), mload(and(mload(raw), 15)))
mstore8(o, mload(and(shr(4, mload(raw)), 15)))
o := add(o, 2)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate the memory.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* RUNE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the number of UTF characters in the string.
function runeCount(string memory s) internal pure returns (uint256 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
mstore(0x00, div(not(0), 255))
mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506)
let o := add(s, 0x20)
let end := add(o, mload(s))
for { result := 1 } 1 { result := add(result, 1) } {
o := add(o, byte(0, mload(shr(250, mload(o)))))
if iszero(lt(o, end)) { break }
}
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string.
/// (i.e. all characters codes are in [0..127])
function is7BitASCII(string memory s) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let mask := shl(7, div(not(0), 255))
result := 1
let n := mload(s)
if n {
let o := add(s, 0x20)
let end := add(o, n)
let last := mload(end)
mstore(end, 0)
for {} 1 {} {
if and(mask, mload(o)) {
result := 0
break
}
o := add(o, 0x20)
if iszero(lt(o, end)) { break }
}
mstore(end, last)
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STRING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// For performance and bytecode compactness, byte string operations are restricted
// to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets.
// Usage of byte string operations on charsets with runes spanning two or more bytes
// can lead to undefined behavior.
/// @dev Returns `subject` all occurrences of `search` replaced with `replacement`.
function replace(string memory subject, string memory search, string memory replacement)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
let replacementLength := mload(replacement)
subject := add(subject, 0x20)
search := add(search, 0x20)
replacement := add(replacement, 0x20)
result := add(mload(0x40), 0x20)
let subjectEnd := add(subject, subjectLength)
if iszero(gt(searchLength, subjectLength)) {
let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(result, o), mload(add(replacement, o)))
o := add(o, 0x20)
if iszero(lt(o, replacementLength)) { break }
}
result := add(result, replacementLength)
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
mstore(result, t)
result := add(result, 1)
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
}
let resultRemainder := result
result := add(mload(0x40), 0x20)
let k := add(sub(resultRemainder, result), sub(subjectEnd, subject))
// Copy the rest of the string one word at a time.
for {} lt(subject, subjectEnd) {} {
mstore(resultRemainder, mload(subject))
resultRemainder := add(resultRemainder, 0x20)
subject := add(subject, 0x20)
}
result := sub(result, 0x20)
let last := add(add(result, 0x20), k) // Zeroize the slot after the string.
mstore(last, 0)
mstore(0x40, add(last, 0x20)) // Allocate the memory.
mstore(result, k) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for { let subjectLength := mload(subject) } 1 {} {
if iszero(mload(search)) {
if iszero(gt(from, subjectLength)) {
result := from
break
}
result := subjectLength
break
}
let searchLength := mload(search)
let subjectStart := add(subject, 0x20)
result := not(0) // Initialize to `NOT_FOUND`.
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLength), searchLength), 1)
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(add(search, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLength))) { break }
if iszero(lt(searchLength, 0x20)) {
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, subjectStart)
break
}
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
for {} 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
result := sub(subject, subjectStart)
break
}
subject := add(subject, 1)
if iszero(lt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function indexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = indexOf(subject, search, 0);
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let searchLength := mload(search)
if gt(searchLength, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), searchLength)
if iszero(gt(fromMax, from)) { from := fromMax }
let end := add(add(subject, 0x20), w)
subject := add(add(subject, 0x20), from)
if iszero(gt(subject, end)) { break }
// As this function is not too often used,
// we shall simply use keccak256 for smaller bytecode size.
for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} {
if eq(keccak256(subject, searchLength), h) {
result := sub(subject, add(end, 1))
break
}
subject := add(subject, w) // `sub(subject, 1)`.
if iszero(gt(subject, end)) { break }
}
break
}
}
}
/// @dev Returns the byte index of the first location of `search` in `subject`,
/// searching from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found.
function lastIndexOf(string memory subject, string memory search)
internal
pure
returns (uint256 result)
{
result = lastIndexOf(subject, search, uint256(int256(-1)));
}
/// @dev Returns true if `search` is found in `subject`, false otherwise.
function contains(string memory subject, string memory search) internal pure returns (bool) {
return indexOf(subject, search) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `search`.
function startsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
iszero(gt(searchLength, mload(subject))),
eq(
keccak256(add(subject, 0x20), searchLength),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns whether `subject` ends with `search`.
function endsWith(string memory subject, string memory search)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLength := mload(search)
let subjectLength := mload(subject)
// Whether `search` is not longer than `subject`.
let withinRange := iszero(gt(searchLength, subjectLength))
// Just using keccak256 directly is actually cheaper.
// forgefmt: disable-next-item
result := and(
withinRange,
eq(
keccak256(
// `subject + 0x20 + max(subjectLength - searchLength, 0)`.
add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))),
searchLength
),
keccak256(add(search, 0x20), searchLength)
)
)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(or(iszero(times), iszero(subjectLength))) {
subject := add(subject, 0x20)
result := mload(0x40)
let output := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let o := 0 } 1 {} {
mstore(add(output, o), mload(add(subject, o)))
o := add(o, 0x20)
if iszero(lt(o, subjectLength)) { break }
}
output := add(output, subjectLength)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(output, 0) // Zeroize the slot after the string.
let resultLength := sub(output, add(result, 0x20))
mstore(result, resultLength) // Store the length.
// Allocate the memory.
mstore(0x40, add(result, add(resultLength, 0x20)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(string memory subject, uint256 start, uint256 end)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
if iszero(gt(subjectLength, end)) { end := subjectLength }
if iszero(gt(subjectLength, start)) { start := subjectLength }
if lt(start, end) {
result := mload(0x40)
let resultLength := sub(end, start)
mstore(result, resultLength)
subject := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(resultLength, 0x1f), w) } 1 {} {
mstore(add(result, o), mload(add(subject, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(result, 0x20), resultLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(result, and(add(resultLength, 0x3f), w)))
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the string.
/// `start` is a byte offset.
function slice(string memory subject, uint256 start)
internal
pure
returns (string memory result)
{
result = slice(subject, start, uint256(int256(-1)));
}
/// @dev Returns all the indices of `search` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory search)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let subjectLength := mload(subject)
let searchLength := mload(search)
if iszero(gt(searchLength, subjectLength)) {
subject := add(subject, 0x20)
search := add(search, 0x20)
result := add(mload(0x40), 0x20)
let subjectStart := subject
let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1)
let h := 0
if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) }
let m := shl(3, sub(0x20, and(searchLength, 0x1f)))
let s := mload(search)
for {} 1 {} {
let t := mload(subject)
// Whether the first `searchLength % 32` bytes of
// `subject` and `search` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(subject, searchLength), h)) {
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
// Append to `result`.
mstore(result, sub(subject, subjectStart))
result := add(result, 0x20)
// Advance `subject` by `searchLength`.
subject := add(subject, searchLength)
if searchLength {
if iszero(lt(subject, subjectSearchEnd)) { break }
continue
}
}
subject := add(subject, 1)
if iszero(lt(subject, subjectSearchEnd)) { break }
}
let resultEnd := result
// Assign `result` to the free memory pointer.
result := mload(0x40)
// Store the length of `result`.
mstore(result, shr(5, sub(resultEnd, add(result, 0x20))))
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(resultEnd, 0x20))
}
}
}
/// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string.
function split(string memory subject, string memory delimiter)
internal
pure
returns (string[] memory result)
{
uint256[] memory indices = indicesOf(subject, delimiter);
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
let indexPtr := add(indices, 0x20)
let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1)))
mstore(add(indicesEnd, w), mload(subject))
mstore(indices, add(mload(indices), 1))
let prevIndex := 0
for {} 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let elementLength := sub(index, prevIndex)
mstore(element, elementLength)
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(elementLength, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
// Zeroize the slot after the string.
mstore(add(add(element, 0x20), elementLength), 0)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(elementLength, 0x3f), w)))
// Store the `element` into the array.
mstore(indexPtr, element)
}
prevIndex := add(index, mload(delimiter))
indexPtr := add(indexPtr, 0x20)
if iszero(lt(indexPtr, indicesEnd)) { break }
}
result := indices
if iszero(mload(delimiter)) {
result := add(indices, 0x20)
mstore(result, sub(mload(indices), 2))
}
}
}
/// @dev Returns a concatenated string of `a` and `b`.
/// Cheaper than `string.concat()` and does not de-align the free memory pointer.
function concat(string memory a, string memory b)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let w := not(0x1f)
result := mload(0x40)
let aLength := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLength, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLength := mload(b)
let output := add(result, aLength)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLength, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLength := add(aLength, bLength)
let last := add(add(result, 0x20), totalLength)
// Zeroize the slot after the string.
mstore(last, 0)
// Stores the length.
mstore(result, totalLength)
// Allocate memory for the length and the bytes,
// rounded up to a multiple of 32.
mstore(0x40, and(add(last, 0x1f), w))
}
}
/// @dev Returns a copy of the string in either lowercase or UPPERCASE.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function toCase(string memory subject, bool toUpper)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let length := mload(subject)
if length {
result := add(mload(0x40), 0x20)
subject := add(subject, 1)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
let w := not(0)
for { let o := length } 1 {} {
o := add(o, w)
let b := and(0xff, mload(add(subject, o)))
mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20)))
if iszero(o) { break }
}
result := mload(0x40)
mstore(result, length) // Store the length.
let last := add(add(result, 0x20), length)
mstore(last, 0) // Zeroize the slot after the string.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
}
/// @dev Returns a string from a small bytes32 string.
/// `s` must be null-terminated, or behavior will be undefined.
function fromSmallString(bytes32 s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let n := 0
for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'.
mstore(result, n)
let o := add(result, 0x20)
mstore(o, s)
mstore(add(o, n), 0)
mstore(0x40, add(result, 0x40))
}
}
/// @dev Returns the small string, with all bytes after the first null byte zeroized.
function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'.
mstore(0x00, s)
mstore(result, 0x00)
result := mload(0x00)
}
}
/// @dev Returns the string as a normalized null-terminated small string.
function toSmallString(string memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(s)
if iszero(lt(result, 33)) {
mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`.
revert(0x1c, 0x04)
}
result := shl(shl(3, sub(32, result)), mload(add(s, result)))
}
}
/// @dev Returns a lowercased copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function lower(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, false);
}
/// @dev Returns an UPPERCASED copy of the string.
/// WARNING! This function is only compatible with 7-bit ASCII strings.
function upper(string memory subject) internal pure returns (string memory result) {
result = toCase(subject, true);
}
/// @dev Escapes the string to be used within HTML tags.
function escapeHTML(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
// Store the bytes of the packed offsets and strides into the scratch space.
// `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6.
mstore(0x1f, 0x900094)
mstore(0x08, 0xc0000000a6ab)
// Store ""&'<>" into the scratch space.
mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// Not in `["\"","'","&","<",">"]`.
if iszero(and(shl(c, 1), 0x500000c400000000)) {
mstore8(result, c)
result := add(result, 1)
continue
}
let t := shr(248, mload(c))
mstore(result, mload(and(t, 0x1f)))
result := add(result, shr(5, t))
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
/// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes.
function escapeJSON(string memory s, bool addDoubleQuotes)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
let end := add(s, mload(s))
result := add(mload(0x40), 0x20)
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
// Store "\\u0000" in scratch space.
// Store "0123456789abcdef" in scratch space.
// Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`.
// into the scratch space.
mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672)
// Bitmask for detecting `["\"","\\"]`.
let e := or(shl(0x22, 1), shl(0x5c, 1))
for {} iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
if iszero(lt(c, 0x20)) {
if iszero(and(shl(c, 1), e)) {
// Not in `["\"","\\"]`.
mstore8(result, c)
result := add(result, 1)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), c)
result := add(result, 2)
continue
}
if iszero(and(shl(c, 1), 0x3700)) {
// Not in `["\b","\t","\n","\f","\d"]`.
mstore8(0x1d, mload(shr(4, c))) // Hex value.
mstore8(0x1e, mload(and(c, 15))) // Hex value.
mstore(result, mload(0x19)) // "\\u00XX".
result := add(result, 6)
continue
}
mstore8(result, 0x5c) // "\\".
mstore8(add(result, 1), mload(add(c, 8)))
result := add(result, 2)
}
if addDoubleQuotes {
mstore8(result, 34)
result := add(1, result)
}
let last := result
mstore(last, 0) // Zeroize the slot after the string.
result := mload(0x40)
mstore(result, sub(last, add(result, 0x20))) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate the memory.
}
}
/// @dev Escapes the string to be used within double-quotes in a JSON.
function escapeJSON(string memory s) internal pure returns (string memory result) {
result = escapeJSON(s, false);
}
/// @dev Returns whether `a` equals `b`.
function eq(string memory a, string memory b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b)))
}
}
/// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string.
function eqs(string memory a, bytes32 b) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
// These should be evaluated on compile time, as far as possible.
let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`.
let x := not(or(m, or(b, add(m, and(b, m)))))
let r := shl(7, iszero(iszero(shr(128, x))))
r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x))))))
r := or(r, shl(5, lt(0xffffffff, shr(r, x))))
r := or(r, shl(4, lt(0xffff, shr(r, x))))
r := or(r, shl(3, lt(0xff, shr(r, x))))
// forgefmt: disable-next-item
result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))),
xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20)))))
}
}
/// @dev Packs a single string with its length into a single word.
/// Returns `bytes32(0)` if the length is zero or greater than 31.
function packOne(string memory a) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
// We don't need to zero right pad the string,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes.
mload(add(a, 0x1f)),
// `length != 0 && length < 32`. Abuses underflow.
// Assumes that the length is valid and within the block gas limit.
lt(sub(mload(a), 1), 0x1f)
)
}
}
/// @dev Unpacks a string packed using {packOne}.
/// Returns the empty string if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packOne}, the output behavior is undefined.
function unpackOne(bytes32 packed) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
result := mload(0x40)
// Allocate 2 words (1 for the length, 1 for the bytes).
mstore(0x40, add(result, 0x40))
// Zeroize the length slot.
mstore(result, 0)
// Store the length and bytes.
mstore(add(result, 0x1f), packed)
// Right pad with zeroes.
mstore(add(add(result, 0x20), mload(result)), 0)
}
}
/// @dev Packs two strings with their lengths into a single word.
/// Returns `bytes32(0)` if combined length is zero or greater than 30.
function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let aLength := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
// Load the length and the bytes of `a` and `b`.
or(
shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))),
mload(sub(add(b, 0x1e), aLength))
),
// `totalLength != 0 && totalLength < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLength, mload(b)), 1), 0x1e)
)
}
}
/// @dev Unpacks strings packed using {packTwo}.
/// Returns the empty strings if `packed` is `bytes32(0)`.
/// If `packed` is not an output of {packTwo}, the output behavior is undefined.
function unpackTwo(bytes32 packed)
internal
pure
returns (string memory resultA, string memory resultB)
{
/// @solidity memory-safe-assembly
assembly {
// Grab the free memory pointer.
resultA := mload(0x40)
resultB := add(resultA, 0x40)
// Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words.
mstore(0x40, add(resultB, 0x40))
// Zeroize the length slots.
mstore(resultA, 0)
mstore(resultB, 0)
// Store the lengths and bytes.
mstore(add(resultA, 0x1f), packed)
mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA))))
// Right pad with zeroes.
mstore(add(add(resultA, 0x20), mload(resultA)), 0)
mstore(add(add(resultB, 0x20), mload(resultB)), 0)
}
}
/// @dev Directly returns `a` without copying.
function directReturn(string memory a) internal pure {
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the string is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retSize), 0)
// Store the return offset.
mstore(retStart, 0x20)
// End the transaction, returning the string.
return(retStart, retSize)
}
}
}
contract Metamorph is ERC721, Ownable {
using LibString for uint256;
using LibString for string;
error Locked();
error TransferFailed();
error SupplyCapReached();
error InsufficientPayment();
event URILocked();
event MintOpened();
event MintClosed();
event SupplyUpdate(uint16 indexed newMaxSupply);
event UpdateBaseURI(string indexed baseURI_);
event Withdraw(address indexed to, uint256 indexed amount);
string internal _name;
string internal _symbol;
string internal _baseURI;
uint16 internal _mintedSupply;
uint16 public maxSupply;
uint16 public totalSupply;
uint64 public immutable price;
bool mintActive = true;
bool uriLocked;
constructor(
address owner_,
string memory name_,
string memory symbol_,
string memory baseURI_,
uint16 maxSupply_,
uint64 price_
) {
_initializeOwner(owner_);
_name = name_;
_symbol = symbol_;
_baseURI = baseURI_;
maxSupply = maxSupply_;
price = price_;
emit UpdateBaseURI(baseURI_);
}
function name() public view override returns (string memory) {
return _name;
}
function symbol() public view override returns (string memory) {
return _symbol;
}
function contractURI() external view returns (string memory) {
return _baseURI.concat("contract.json");
}
function tokenURI(uint256 tokenId) public view override returns (string memory) {
if (!_exists(tokenId)) return "";
else return _baseURI.concat(tokenId.toString());
}
function __mint(address to, uint16 amount) internal {
uint16 currentSupply = _mintedSupply;
if (!mintActive) revert Locked();
if (msg.value < price) revert InsufficientPayment();
if (currentSupply + amount > maxSupply) revert SupplyCapReached();
for (uint16 i; i < amount;) {
unchecked {
_mint(to, ++currentSupply);
++i;
}
}
unchecked {
totalSupply += amount;
_mintedSupply += amount;
}
}
function airdrop(address to, uint16 amount) external onlyOwner {
uint16 currentSupply = _mintedSupply;
if (!mintActive) revert Locked();
if (currentSupply + amount > maxSupply) revert SupplyCapReached();
for (uint16 i; i < amount;) {
unchecked {
_mint(to, ++currentSupply);
++i;
}
}
unchecked {
totalSupply += amount;
_mintedSupply += amount;
}
}
function burn(uint256 tokenId) external {
if (!_isApprovedOrOwner(msg.sender, tokenId)) revert Unauthorized();
_burn(tokenId);
unchecked {
totalSupply -= 1;
}
}
function openMint() external onlyOwner {
mintActive = true;
emit MintOpened();
}
function closeMint() external onlyOwner {
mintActive = false;
emit MintClosed();
uint16 supply = totalSupply;
if (supply < maxSupply) {
maxSupply = supply;
emit SupplyUpdate(supply);
}
}
function updateBaseURI(string memory baseURI_) external onlyOwner {
if (uriLocked) revert Locked();
_baseURI = baseURI_;
emit UpdateBaseURI(baseURI_);
}
function lockURI() public onlyOwner {
uriLocked = true;
emit URILocked();
}
function withdrawETH(address to) external onlyOwner {
uint256 amount = address(this).balance;
(bool success,) = payable(to).call{value: amount}("");
if (!success) revert TransferFailed();
emit Withdraw(to, amount);
}
function renounceOwnership() public payable override onlyOwner {
if (!uriLocked) lockURI();
super.renounceOwnership();
}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"owner_","type":"address"},{"internalType":"string","name":"name_","type":"string"},{"internalType":"string","name":"symbol_","type":"string"},{"internalType":"string","name":"baseURI_","type":"string"},{"internalType":"uint16","name":"maxSupply_","type":"uint16"},{"internalType":"uint64","name":"price_","type":"uint64"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"Locked","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"SupplyCapReached","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFailed","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":[],"name":"MintClosed","type":"event"},{"anonymous":false,"inputs":[],"name":"MintOpened","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":"uint16","name":"newMaxSupply","type":"uint16"}],"name":"SupplyUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[],"name":"URILocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"string","name":"baseURI_","type":"string"}],"name":"UpdateBaseURI","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"amount","type":"uint256"}],"name":"Withdraw","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint16","name":"amount","type":"uint16"}],"name":"airdrop","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":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"closeMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","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":[],"name":"lockURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"openMint","outputs":[],"stateMutability":"nonpayable","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":"price","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"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":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"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":"string","name":"baseURI_","type":"string"}],"name":"updateBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
60a06040526003805460ff60301b1916660100000000000017905534801562000026575f80fd5b5060405162001be538038062001be583398101604081905262000049916200021f565b6200005486620000f0565b5f62000061868262000377565b50600162000070858262000377565b5060026200007f848262000377565b506003805463ffff000019166201000061ffff8516021790556001600160401b038116608052604051620000b590849062000443565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250505050505062000460565b6001600160a01b0316638b78c6d819819055805f7f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b634e487b7160e01b5f52604160045260245ffd5b5f5b838110156200015b57818101518382015260200162000141565b50505f910152565b5f82601f83011262000173575f80fd5b81516001600160401b03808211156200019057620001906200012b565b604051601f8301601f19908116603f01168101908282118183101715620001bb57620001bb6200012b565b81604052838152866020858801011115620001d4575f80fd5b620001e78460208301602089016200013f565b9695505050505050565b805161ffff8116811462000203575f80fd5b919050565b80516001600160401b038116811462000203575f80fd5b5f805f805f8060c0878903121562000235575f80fd5b86516001600160a01b03811681146200024c575f80fd5b60208801519096506001600160401b038082111562000269575f80fd5b620002778a838b0162000163565b965060408901519150808211156200028d575f80fd5b6200029b8a838b0162000163565b95506060890151915080821115620002b1575f80fd5b50620002c089828a0162000163565b935050620002d160808801620001f1565b9150620002e160a0880162000208565b90509295509295509295565b600181811c908216806200030257607f821691505b6020821081036200032157634e487b7160e01b5f52602260045260245ffd5b50919050565b601f8211156200037257805f5260205f20601f840160051c810160208510156200034e5750805b601f840160051c820191505b818110156200036f575f81556001016200035a565b50505b505050565b81516001600160401b038111156200039357620003936200012b565b620003ab81620003a48454620002ed565b8462000327565b602080601f831160018114620003e1575f8415620003c95750858301515b5f19600386901b1c1916600185901b1785556200043b565b5f85815260208120601f198616915b828110156200041157888601518255948401946001909101908401620003f0565b50858210156200042f57878501515f19600388901b60f8161c191681555b505060018460011b0185555b505050505050565b5f8251620004568184602087016200013f565b9190910192915050565b60805161176c620004795f395f610413015261176c5ff3fe6080604052600436106101d0575f3560e01c80638da5cb5b116100fd578063c87b56dd11610092578063ec8d130b11610062578063ec8d130b1461051b578063f04e283e1461053a578063f2fde38b1461054d578063fee81cf414610560575f80fd5b8063c87b56dd14610494578063d5abeb01146104b3578063e8a3d485146104d3578063e985e9c5146104e7575f80fd5b8063a035b1fe116100cd578063a035b1fe14610402578063a22cb4651461044e578063b88d4fde1461046d578063bce6d67214610480575f80fd5b80638da5cb5b146103a35780638e021c06146103bb578063931688cb146103cf57806395d89b41146103ee575f80fd5b806342842e0e1161017357806364f101f01161014357806364f101f01461033b578063690d83201461034f57806370a082311461036e578063715018a61461039b575f80fd5b806342842e0e146102e257806342966c68146102f557806354d1f13d146103145780636352211e1461031c575f80fd5b8063095ea7b3116101ae578063095ea7b31461027d57806318160ddd1461029257806323b872dd146102c757806325692962146102da575f80fd5b806301ffc9a7146101d457806306fdde0314610225578063081812fc14610246575b5f80fd5b3480156101df575f80fd5b506102106101ee3660046112a0565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b348015610230575f80fd5b50610239610591565b60405161021c91906112f0565b348015610251575f80fd5b50610265610260366004611322565b610620565b6040516001600160a01b03909116815260200161021c565b61029061028b36600461134f565b61065b565b005b34801561029d575f80fd5b506003546102b490640100000000900461ffff1681565b60405161ffff909116815260200161021c565b6102906102d5366004611377565b61066a565b610290610764565b6102906102f0366004611377565b6107b1565b348015610300575f80fd5b5061029061030f366004611322565b6107dd565b610290610837565b348015610327575f80fd5b50610265610336366004611322565b610870565b348015610346575f80fd5b506102906108ac565b34801561035a575f80fd5b506102906103693660046113b0565b610955565b348015610379575f80fd5b5061038d6103883660046113b0565b610a08565b60405190815260200161021c565b610290610a40565b3480156103ae575f80fd5b50638b78c6d81954610265565b3480156103c6575f80fd5b50610290610a6b565b3480156103da575f80fd5b506102906103e93660046113dd565b610ab4565b3480156103f9575f80fd5b50610239610b34565b34801561040d575f80fd5b506104357f000000000000000000000000000000000000000000000000000000000000000081565b60405167ffffffffffffffff909116815260200161021c565b348015610459575f80fd5b50610290610468366004611488565b610b43565b61029061047b3660046114c1565b610b96565b34801561048b575f80fd5b50610290610bf0565b34801561049f575f80fd5b506102396104ae366004611322565b610c3b565b3480156104be575f80fd5b506003546102b49062010000900461ffff1681565b3480156104de575f80fd5b50610239610d24565b3480156104f2575f80fd5b50610210610501366004611554565b601c52670a5a2e7a000000006008525f526030600c205490565b348015610526575f80fd5b50610290610535366004611585565b610d61565b6102906105483660046113b0565b610e44565b61029061055b3660046113b0565b610e7e565b34801561056b575f80fd5b5061038d61057a3660046113b0565b63389a75e1600c9081525f91909152602090205490565b60605f805461059f906115b5565b80601f01602080910402602001604051908101604052809291908181526020018280546105cb906115b5565b80156106165780601f106105ed57610100808354040283529160200191610616565b820191905f5260205f20905b8154815290600101906020018083116105f957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b6106515763ceea21b65f526004601cfd5b6001015492915050565b610666338383610ea4565b5050565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b0394851694938416938116919082861483026106bb5767ceea21b6a1148100831560021b526004601cfd5b855f5281600101549250823314863314176106e7576030600c20546106e757634b6e7f185f526004601cfd5b82156106f4575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff811684026107355767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b6107bc83838361066a565b813b1561075f5761075f83838360405180602001604052805f815250610f3e565b6107e73382610fc7565b610803576040516282b42960e81b815260040160405180910390fd5b61080c81611030565b50600380545f1961ffff640100000000808404821692909201160265ffff0000000019909116179055565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806108a75763ceea21b65f526004601cfd5b919050565b6108b461103a565b6003805466ff000000000000191690556040517f589ed34b6de61e6df418b1c0e5caa881461804657f37544ca23bf0b86d09f1e3905f90a160035461ffff640100000000820481169162010000900416811015610952576003805463ffff000019166201000061ffff8416908102919091179091556040517f52517e69d79a4e16171442bbef42454bad6689798f61eaecf3825e939ccb2367905f90a25b50565b61095d61103a565b60405147905f906001600160a01b0384169083908381818185875af1925050503d805f81146109a7576040519150601f19603f3d011682016040523d82523d5f602084013e6109ac565b606091505b50509050806109ce576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038516907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364905f90a3505050565b5f81610a1b57638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b610a4861103a565b600354600160381b900460ff16610a6157610a61610a6b565b610a69611054565b565b610a7361103a565b6003805467ff000000000000001916600160381b1790556040517f31d1c0a3af6e15844ff9c1bf6201a5cf123137eb2fb3eeb96861a436d49cd25f905f90a1565b610abc61103a565b600354600160381b900460ff1615610ae7576040516303cb96db60e21b815260040160405180910390fd5b6002610af38282611631565b5080604051610b0291906116ed565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250565b60606001805461059f906115b5565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b610ba185858561066a565b833b15610be957610be985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610f3e92505050565b5050505050565b610bf861103a565b6003805466ff000000000000191666010000000000001790556040517f4301b55b3d4fd9018308a6bd66bf37880623a9548566d1b12867ab619a993ca1905f90a1565b6060610c64825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b610c7b57505060408051602081019091525f815290565b610d1e610c8783611065565b60028054610c94906115b5565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc0906115b5565b8015610d0b5780601f10610ce257610100808354040283529160200191610d0b565b820191905f5260205f20905b815481529060010190602001808311610cee57829003601f168201915b50505050506110a790919063ffffffff16565b92915050565b6060610d5c6040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b81525060028054610c94906115b5565b905090565b610d6961103a565b60035461ffff8116906601000000000000900460ff16610d9c576040516303cb96db60e21b815260040160405180910390fd5b60035462010000900461ffff16610db38383611708565b61ffff161115610dd6576040516354db2d5d60e11b815260040160405180910390fd5b5f5b8261ffff168161ffff161015610e0457610dfc848360010193508361ffff16611101565b600101610dd8565b50506003805461ffff64010000000080830482168501821602808216828416179094011661ffff1990931665ffff0000ffff199091161791909117905550565b610e4c61103a565b63389a75e1600c52805f526020600c208054421115610e7257636f5e88185f526004601cfd5b5f90556109528161119d565b610e8661103a565b8060601b610e9b57637448fbae5f526004601cfd5b6109528161119d565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f208201820180548216915081610ee75763ceea21b65f526004601cfd5b818514851517610f0b57815f526030600c2054610f0b57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f85578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1610fa6573d15610fa6573d5f843e3d83fd5b508060e01b825114610fbf5763d1a57ed65f526004601cfd5b505050505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193600192168061100a5763ceea21b65f526004601cfd5b80851461102857805f526030600c2054611028578160010154851492505b505092915050565b6109525f826111da565b638b78c6d819543314610a69576382b429005f526004601cfd5b61105c61103a565b610a695f61119d565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a90048061107e575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806110b7575083518184018360208301165b86810151828201528401806110d35750505f910183810160208101929092528352603f011660405292915050565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b1561113c5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026111705767ea553b3401336cea841560021b526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f6111e482610870565b9050505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112295763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611256576030600c205461125657634b6e7f185f526004601cfd5b8015611263575f83600101555b5082189055601c600c2080545f19019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b5f602082840312156112b0575f80fd5b81356001600160e01b0319811681146112c7575f80fd5b9392505050565b5f5b838110156112e85781810151838201526020016112d0565b50505f910152565b602081525f825180602084015261130e8160408501602087016112ce565b601f01601f19169190910160400192915050565b5f60208284031215611332575f80fd5b5035919050565b80356001600160a01b03811681146108a7575f80fd5b5f8060408385031215611360575f80fd5b61136983611339565b946020939093013593505050565b5f805f60608486031215611389575f80fd5b61139284611339565b92506113a060208501611339565b9150604084013590509250925092565b5f602082840312156113c0575f80fd5b6112c782611339565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156113ed575f80fd5b813567ffffffffffffffff80821115611404575f80fd5b818401915084601f830112611417575f80fd5b813581811115611429576114296113c9565b604051601f8201601f19908116603f01168101908382118183101715611451576114516113c9565b81604052828152876020848701011115611469575f80fd5b826020860160208301375f928101602001929092525095945050505050565b5f8060408385031215611499575f80fd5b6114a283611339565b9150602083013580151581146114b6575f80fd5b809150509250929050565b5f805f805f608086880312156114d5575f80fd5b6114de86611339565b94506114ec60208701611339565b935060408601359250606086013567ffffffffffffffff8082111561150f575f80fd5b818801915088601f830112611522575f80fd5b813581811115611530575f80fd5b896020828501011115611541575f80fd5b9699959850939650602001949392505050565b5f8060408385031215611565575f80fd5b61156e83611339565b915061157c60208401611339565b90509250929050565b5f8060408385031215611596575f80fd5b61159f83611339565b9150602083013561ffff811681146114b6575f80fd5b600181811c908216806115c957607f821691505b6020821081036115e757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561075f57805f5260205f20601f840160051c810160208510156116125750805b601f840160051c820191505b81811015610be9575f815560010161161e565b815167ffffffffffffffff81111561164b5761164b6113c9565b61165f8161165984546115b5565b846115ed565b602080601f831160018114611692575f841561167b5750858301515b5f19600386901b1c1916600185901b178555610fbf565b5f85815260208120601f198616915b828110156116c0578886015182559484019460019091019084016116a1565b50858210156116dd57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82516116fe8184602087016112ce565b9190910192915050565b61ffff81811683821601908082111561172f57634e487b7160e01b5f52601160045260245ffd5b509291505056fea2646970667358221220500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de64736f6c6343000818003300000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e311000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000194d6574616d6f727068204c6162733a20496e63657074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000034d4d4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961766d7363697366626371663779736c6532686664796271366176653637706966767a627a6a62786a3361347270626c626e6a792f0000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x6080604052600436106101d0575f3560e01c80638da5cb5b116100fd578063c87b56dd11610092578063ec8d130b11610062578063ec8d130b1461051b578063f04e283e1461053a578063f2fde38b1461054d578063fee81cf414610560575f80fd5b8063c87b56dd14610494578063d5abeb01146104b3578063e8a3d485146104d3578063e985e9c5146104e7575f80fd5b8063a035b1fe116100cd578063a035b1fe14610402578063a22cb4651461044e578063b88d4fde1461046d578063bce6d67214610480575f80fd5b80638da5cb5b146103a35780638e021c06146103bb578063931688cb146103cf57806395d89b41146103ee575f80fd5b806342842e0e1161017357806364f101f01161014357806364f101f01461033b578063690d83201461034f57806370a082311461036e578063715018a61461039b575f80fd5b806342842e0e146102e257806342966c68146102f557806354d1f13d146103145780636352211e1461031c575f80fd5b8063095ea7b3116101ae578063095ea7b31461027d57806318160ddd1461029257806323b872dd146102c757806325692962146102da575f80fd5b806301ffc9a7146101d457806306fdde0314610225578063081812fc14610246575b5f80fd5b3480156101df575f80fd5b506102106101ee3660046112a0565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b348015610230575f80fd5b50610239610591565b60405161021c91906112f0565b348015610251575f80fd5b50610265610260366004611322565b610620565b6040516001600160a01b03909116815260200161021c565b61029061028b36600461134f565b61065b565b005b34801561029d575f80fd5b506003546102b490640100000000900461ffff1681565b60405161ffff909116815260200161021c565b6102906102d5366004611377565b61066a565b610290610764565b6102906102f0366004611377565b6107b1565b348015610300575f80fd5b5061029061030f366004611322565b6107dd565b610290610837565b348015610327575f80fd5b50610265610336366004611322565b610870565b348015610346575f80fd5b506102906108ac565b34801561035a575f80fd5b506102906103693660046113b0565b610955565b348015610379575f80fd5b5061038d6103883660046113b0565b610a08565b60405190815260200161021c565b610290610a40565b3480156103ae575f80fd5b50638b78c6d81954610265565b3480156103c6575f80fd5b50610290610a6b565b3480156103da575f80fd5b506102906103e93660046113dd565b610ab4565b3480156103f9575f80fd5b50610239610b34565b34801561040d575f80fd5b506104357f000000000000000000000000000000000000000000000000016345785d8a000081565b60405167ffffffffffffffff909116815260200161021c565b348015610459575f80fd5b50610290610468366004611488565b610b43565b61029061047b3660046114c1565b610b96565b34801561048b575f80fd5b50610290610bf0565b34801561049f575f80fd5b506102396104ae366004611322565b610c3b565b3480156104be575f80fd5b506003546102b49062010000900461ffff1681565b3480156104de575f80fd5b50610239610d24565b3480156104f2575f80fd5b50610210610501366004611554565b601c52670a5a2e7a000000006008525f526030600c205490565b348015610526575f80fd5b50610290610535366004611585565b610d61565b6102906105483660046113b0565b610e44565b61029061055b3660046113b0565b610e7e565b34801561056b575f80fd5b5061038d61057a3660046113b0565b63389a75e1600c9081525f91909152602090205490565b60605f805461059f906115b5565b80601f01602080910402602001604051908101604052809291908181526020018280546105cb906115b5565b80156106165780601f106105ed57610100808354040283529160200191610616565b820191905f5260205f20905b8154815290600101906020018083116105f957829003601f168201915b5050505050905090565b5f815f52673ec412a9852d173d60c11b601c5260205f2082018201805460601b6106515763ceea21b65f526004601cfd5b6001015492915050565b610666338383610ea4565b5050565b5f818152673ec412a9852d173d60c11b3317601c52602090208101810180546001600160a01b0394851694938416938116919082861483026106bb5767ceea21b6a1148100831560021b526004601cfd5b855f5281600101549250823314863314176106e7576030600c20546106e757634b6e7f185f526004601cfd5b82156106f4575f82600101555b85851818905550601c600c81812080545f190190555f84905220805460010163ffffffff811684026107355767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f38a45b505050565b5f6202a30067ffffffffffffffff164201905063389a75e1600c52335f52806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d5f80a250565b6107bc83838361066a565b813b1561075f5761075f83838360405180602001604052805f815250610f3e565b6107e73382610fc7565b610803576040516282b42960e81b815260040160405180910390fd5b61080c81611030565b50600380545f1961ffff640100000000808404821692909201160265ffff0000000019909116179055565b63389a75e1600c52335f525f6020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c925f80a2565b5f818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b0316806108a75763ceea21b65f526004601cfd5b919050565b6108b461103a565b6003805466ff000000000000191690556040517f589ed34b6de61e6df418b1c0e5caa881461804657f37544ca23bf0b86d09f1e3905f90a160035461ffff640100000000820481169162010000900416811015610952576003805463ffff000019166201000061ffff8416908102919091179091556040517f52517e69d79a4e16171442bbef42454bad6689798f61eaecf3825e939ccb2367905f90a25b50565b61095d61103a565b60405147905f906001600160a01b0384169083908381818185875af1925050503d805f81146109a7576040519150601f19603f3d011682016040523d82523d5f602084013e6109ac565b606091505b50509050806109ce576040516312171d8360e31b815260040160405180910390fd5b60405182906001600160a01b038516907f884edad9ce6fa2440d8a54cc123490eb96d2768479d49ff9c7366125a9424364905f90a3505050565b5f81610a1b57638f4eb6045f526004601cfd5b673ec412a9852d173d60c11b601c52815f5263ffffffff601c600c2054169050919050565b610a4861103a565b600354600160381b900460ff16610a6157610a61610a6b565b610a69611054565b565b610a7361103a565b6003805467ff000000000000001916600160381b1790556040517f31d1c0a3af6e15844ff9c1bf6201a5cf123137eb2fb3eeb96861a436d49cd25f905f90a1565b610abc61103a565b600354600160381b900460ff1615610ae7576040516303cb96db60e21b815260040160405180910390fd5b6002610af38282611631565b5080604051610b0291906116ed565b604051908190038120907f157d450c8fb1377294d9db75af1de2753efc52d8e5578551d70d2c7d9cd74df9905f90a250565b60606001805461059f906115b5565b801515905081601c52670a5a2e7a00000000600852335f52806030600c2055805f528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160205fa35050565b610ba185858561066a565b833b15610be957610be985858585858080601f0160208091040260200160405190810160405280939291908181526020018383808284375f92019190915250610f3e92505050565b5050505050565b610bf861103a565b6003805466ff000000000000191666010000000000001790556040517f4301b55b3d4fd9018308a6bd66bf37880623a9548566d1b12867ab619a993ca1905f90a1565b6060610c64825f818152673ec412a9852d173d60c11b601c52602090208101015460601b151590565b610c7b57505060408051602081019091525f815290565b610d1e610c8783611065565b60028054610c94906115b5565b80601f0160208091040260200160405190810160405280929190818152602001828054610cc0906115b5565b8015610d0b5780601f10610ce257610100808354040283529160200191610d0b565b820191905f5260205f20905b815481529060010190602001808311610cee57829003601f168201915b50505050506110a790919063ffffffff16565b92915050565b6060610d5c6040518060400160405280600d81526020016c31b7b73a3930b1ba173539b7b760991b81525060028054610c94906115b5565b905090565b610d6961103a565b60035461ffff8116906601000000000000900460ff16610d9c576040516303cb96db60e21b815260040160405180910390fd5b60035462010000900461ffff16610db38383611708565b61ffff161115610dd6576040516354db2d5d60e11b815260040160405180910390fd5b5f5b8261ffff168161ffff161015610e0457610dfc848360010193508361ffff16611101565b600101610dd8565b50506003805461ffff64010000000080830482168501821602808216828416179094011661ffff1990931665ffff0000ffff199091161791909117905550565b610e4c61103a565b63389a75e1600c52805f526020600c208054421115610e7257636f5e88185f526004601cfd5b5f90556109528161119d565b610e8661103a565b8060601b610e9b57637448fbae5f526004601cfd5b6109528161119d565b5f1960601c82811692508381169350815f5283673ec412a9852d173d60c11b17601c5260205f208201820180548216915081610ee75763ceea21b65f526004601cfd5b818514851517610f0b57815f526030600c2054610f0b57634b6e7f185f526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f38a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f85578060c08401826020870160045afa505b60208360a48301601c86015f8a5af1610fa6573d15610fa6573d5f843e3d83fd5b508060e01b825114610fbf5763d1a57ed65f526004601cfd5b505050505050565b5f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193600192168061100a5763ceea21b65f526004601cfd5b80851461102857805f526030600c2054611028578160010154851492505b505092915050565b6109525f826111da565b638b78c6d819543314610a69576382b429005f526004601cfd5b61105c61103a565b610a695f61119d565b60606080604051019050602081016040525f8152805f19835b928101926030600a8206018453600a90048061107e575050819003601f19909101908152919050565b6040518251601f19906020810182165b85810151848201528201806110b7575083518184018360208301165b86810151828201528401806110d35750505f910183810160208101929092528352603f011660405292915050565b8160601b60601c9150805f52673ec412a9852d173d60c11b601c5260205f208101810180548060601b1561113c5763c991cbb15f526004601cfd5b831790555f829052601c600c20805460010163ffffffff811684026111705767ea553b3401336cea841560021b526004601cfd5b905580825f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a355565b5f6111e482610870565b9050505f8181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826112295763ceea21b65f526004601cfd5b825f52816001015480861484871417861517611256576030600c205461125657634b6e7f185f526004601cfd5b8015611263575f83600101555b5082189055601c600c2080545f19019055815f827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b5f602082840312156112b0575f80fd5b81356001600160e01b0319811681146112c7575f80fd5b9392505050565b5f5b838110156112e85781810151838201526020016112d0565b50505f910152565b602081525f825180602084015261130e8160408501602087016112ce565b601f01601f19169190910160400192915050565b5f60208284031215611332575f80fd5b5035919050565b80356001600160a01b03811681146108a7575f80fd5b5f8060408385031215611360575f80fd5b61136983611339565b946020939093013593505050565b5f805f60608486031215611389575f80fd5b61139284611339565b92506113a060208501611339565b9150604084013590509250925092565b5f602082840312156113c0575f80fd5b6112c782611339565b634e487b7160e01b5f52604160045260245ffd5b5f602082840312156113ed575f80fd5b813567ffffffffffffffff80821115611404575f80fd5b818401915084601f830112611417575f80fd5b813581811115611429576114296113c9565b604051601f8201601f19908116603f01168101908382118183101715611451576114516113c9565b81604052828152876020848701011115611469575f80fd5b826020860160208301375f928101602001929092525095945050505050565b5f8060408385031215611499575f80fd5b6114a283611339565b9150602083013580151581146114b6575f80fd5b809150509250929050565b5f805f805f608086880312156114d5575f80fd5b6114de86611339565b94506114ec60208701611339565b935060408601359250606086013567ffffffffffffffff8082111561150f575f80fd5b818801915088601f830112611522575f80fd5b813581811115611530575f80fd5b896020828501011115611541575f80fd5b9699959850939650602001949392505050565b5f8060408385031215611565575f80fd5b61156e83611339565b915061157c60208401611339565b90509250929050565b5f8060408385031215611596575f80fd5b61159f83611339565b9150602083013561ffff811681146114b6575f80fd5b600181811c908216806115c957607f821691505b6020821081036115e757634e487b7160e01b5f52602260045260245ffd5b50919050565b601f82111561075f57805f5260205f20601f840160051c810160208510156116125750805b601f840160051c820191505b81811015610be9575f815560010161161e565b815167ffffffffffffffff81111561164b5761164b6113c9565b61165f8161165984546115b5565b846115ed565b602080601f831160018114611692575f841561167b5750858301515b5f19600386901b1c1916600185901b178555610fbf565b5f85815260208120601f198616915b828110156116c0578886015182559484019460019091019084016116a1565b50858210156116dd57878501515f19600388901b60f8161c191681555b5050505050600190811b01905550565b5f82516116fe8184602087016112ce565b9190910192915050565b61ffff81811683821601908082111561172f57634e487b7160e01b5f52601160045260245ffd5b509291505056fea2646970667358221220500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de64736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e311000000000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000001400000000000000000000000000000000000000000000000000000000000000bb8000000000000000000000000000000000000000000000000016345785d8a000000000000000000000000000000000000000000000000000000000000000000194d6574616d6f727068204c6162733a20496e63657074696f6e0000000000000000000000000000000000000000000000000000000000000000000000000000034d4d4f00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000043697066733a2f2f6261667962656961766d7363697366626371663779736c6532686664796271366176653637706966767a627a6a62786a3361347270626c626e6a792f0000000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : owner_ (address): 0x43c5465b85F55753CddCaa1Df33D28B4A56E3110
Arg [1] : name_ (string): Metamorph Labs: Inception
Arg [2] : symbol_ (string): MMO
Arg [3] : baseURI_ (string): ipfs://bafybeiavmscisfbcqf7ysle2hfdybq6ave67pifvzbzjbxj3a4rpblbnjy/
Arg [4] : maxSupply_ (uint16): 3000
Arg [5] : price_ (uint64): 100000000000000000
-----Encoded View---------------
14 Constructor Arguments found :
Arg [0] : 00000000000000000000000043c5465b85f55753cddcaa1df33d28b4a56e3110
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000100
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000140
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000bb8
Arg [5] : 000000000000000000000000000000000000000000000000016345785d8a0000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [7] : 4d6574616d6f727068204c6162733a20496e63657074696f6e00000000000000
Arg [8] : 0000000000000000000000000000000000000000000000000000000000000003
Arg [9] : 4d4d4f0000000000000000000000000000000000000000000000000000000000
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000043
Arg [11] : 697066733a2f2f6261667962656961766d7363697366626371663779736c6532
Arg [12] : 686664796271366176653637706966767a627a6a62786a3361347270626c626e
Arg [13] : 6a792f0000000000000000000000000000000000000000000000000000000000
Deployed Bytecode Sourcemap
104194:4092:0:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;13801:387;;;;;;;;;;-1:-1:-1;13801:387:0;;;;;:::i;:::-;14119:10;13982:3;13978:21;;;;14113:17;;;14138:10;14132:17;;14110:40;14158:10;14152:17;;;14107:63;;13801:387;;;;470:14:1;;463:22;445:41;;433:2;418:18;13801:387:0;;;;;;;;105367:92;;;;;;;;;;;;;:::i;:::-;;;;;;;:::i;6874:544::-;;;;;;;;;;-1:-1:-1;6874:544:0;;;;;:::i;:::-;;:::i;:::-;;;-1:-1:-1;;;;;1502:32:1;;;1484:51;;1472:2;1457:18;6874:544:0;1338:203:1;7722:121:0;;;;;;:::i;:::-;;:::i;:::-;;104826:25;;;;;;;;;;-1:-1:-1;104826:25:0;;;;;;;;;;;;;;2157:6:1;2145:19;;;2127:38;;2115:2;2100:18;104826:25:0;1983:188:1;9595:2944:0;;;;;;:::i;:::-;;:::i;48099:630::-;;;:::i;12613:201::-;;;;;;:::i;:::-;;:::i;106972:214::-;;;;;;;;;;-1:-1:-1;106972:214:0;;;;;:::i;:::-;;:::i;48814:466::-;;;:::i;5699:341::-;;;;;;;;;;-1:-1:-1;5699:341:0;;;;;:::i;:::-;;:::i;107305:264::-;;;;;;;;;;;;;:::i;107875:257::-;;;;;;;;;;-1:-1:-1;107875:257:0;;;;;:::i;:::-;;:::i;6190:545::-;;;;;;;;;;-1:-1:-1;6190:545:0;;;;;:::i;:::-;;:::i;:::-;;;2846:25:1;;;2834:2;2819:18;6190:545:0;2700:177:1;108140:143:0;;;:::i;50539:187::-;;;;;;;;;;-1:-1:-1;;;50690:18:0;50539:187;;107769:98;;;;;;;;;;;;;:::i;107577:184::-;;;;;;;;;;-1:-1:-1;107577:184:0;;;;;:::i;:::-;;:::i;105467:96::-;;;;;;;;;;;;;:::i;104858:29::-;;;;;;;;;;;;;;;;;;4115:18:1;4103:31;;;4085:50;;4073:2;4058:18;104858:29:0;3941:200:1;8487:741:0;;;;;;;;;;-1:-1:-1;8487:741:0;;;;;:::i;:::-;;:::i;13331:256::-;;;;;;:::i;:::-;;:::i;107194:103::-;;;;;;;;;;;;;:::i;105698:189::-;;;;;;;;;;-1:-1:-1;105698:189:0;;;;;:::i;:::-;;:::i;104796:23::-;;;;;;;;;;-1:-1:-1;104796:23:0;;;;;;;;;;;105571:119;;;;;;;;;;;;;:::i;7937:405::-;;;;;;;;;;-1:-1:-1;7937:405:0;;;;;:::i;:::-;8165:4;8158:22;8207:31;8201:4;8194:45;8061:11;8253:19;8318:4;8312;8302:21;8296:28;;7937:405;106454:510;;;;;;;;;;-1:-1:-1;106454:510:0;;;;;:::i;:::-;;:::i;49471:724::-;;;;;;:::i;:::-;;:::i;47408:358::-;;;;;;:::i;:::-;;:::i;50832:449::-;;;;;;;;;;-1:-1:-1;50832:449:0;;;;;:::i;:::-;51111:19;51105:4;51098:33;;;50955:14;51145:26;;;;51257:4;51241:21;;51235:28;;50832:449;105367:92;105413:13;105446:5;105439:12;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;105367:92;:::o;6874:544::-;6936:14;7044:2;7038:4;7031:16;-1:-1:-1;;;7068:4:0;7061:38;7166:4;7160;7150:21;7146:2;7142:30;7138:2;7134:39;7211:13;7205:20;7201:2;7197:29;7187:161;;7260:10;7254:4;7247:24;7328:4;7322;7315:18;7187:161;7382:1;7378:21;7372:28;;6874:544;-1:-1:-1;;6874:544:0:o;7722:121::-;7802:33;7811:10;7823:7;7832:2;7802:8;:33::i;:::-;7722:121;;:::o;9595:2944::-;9877:1;10025:16;;;-1:-1:-1;;;10097:8:0;10068:38;10062:4;10055:52;10174:4;10158:21;;10150:30;;10142:39;;10218:20;;-1:-1:-1;;;;;9902:25:0;;;;9947:23;;;;10265:36;;;10142:39;10419:15;;;10408:27;;10398:233;;10561:18;10552:5;10545:13;10542:1;10538:21;10531:49;10611:4;10605;10598:18;10398:233;10737:4;10731;10724:18;10796:13;10793:1;10789:21;10783:28;10760:51;;10948:15;10938:8;10935:29;10928:4;10918:8;10915:18;10912:53;10902:293;;11022:4;11016;11006:21;11000:28;10990:186;;11070:10;11064:4;11057:24;11148:4;11142;11135:18;10990:186;11272:15;11269:55;;;11320:1;11304:13;11301:1;11297:21;11290:32;11269:55;11439:13;;;11418:35;11396:58;;-1:-1:-1;11575:4:0;11569;11559:21;;;11626:22;;-1:-1:-1;;11622:30:0;11598:55;;-1:-1:-1;11748:16:0;;;11803:21;11873:20;;11650:1;11869:28;12051:20;12026:46;;12018:55;;12008:274;;12204:18;12198:2;12191:10;12188:1;12184:18;12177:46;12258:4;12252;12245:18;12008:274;12300:42;;12474:2;12470;12464:4;12437:25;12431:4;12419:10;12414:63;12498:33;9595:2944;;;:::o;48099:630::-;48194:15;47024:9;48212:46;;:15;:46;48194:64;;48430:19;48424:4;48417:33;48481:8;48475:4;48468:22;48538:7;48531:4;48525;48515:21;48508:38;48687:8;48640:45;48637:1;48634;48629:67;48330:381;48099:630::o;12613:201::-;12711:26;12724:4;12730:2;12734;12711:12;:26::i;:::-;37837:14;;12748:58;;;12766:40;12789:4;12795:2;12799;12766:40;;;;;;;;;;;;:22;:40::i;106972:214::-;107028:39;107047:10;107059:7;107028:18;:39::i;:::-;107023:67;;107076:14;;-1:-1:-1;;;107076:14:0;;;;;;;;;;;107023:67;107101:14;107107:7;107101:5;:14::i;:::-;-1:-1:-1;107151:11:0;:16;;-1:-1:-1;;107151:16:0;;;;;;;;;;;;;-1:-1:-1;;107151:16:0;;;;;;106972:214::o;48814:466::-;49020:19;49014:4;49007:33;49067:8;49061:4;49054:22;49120:1;49113:4;49107;49097:21;49090:32;49253:8;49207:44;49204:1;49201;49196:66;48814:466::o;5699:341::-;5757:14;15155:16;;;-1:-1:-1;;;15192:4:0;15185:38;15301:4;15285:21;;15277:30;;15269:39;;15263:46;-1:-1:-1;;;;;15247:64:0;;5884:138;;5934:10;5928:4;5921:24;6002:4;5996;5989:18;5884:138;5699:341;;;:::o;107305:264::-;51678:13;:11;:13::i;:::-;107356:10:::1;:18:::0;;-1:-1:-1;;107356:18:0::1;::::0;;107390:12:::1;::::0;::::1;::::0;107369:5:::1;::::0;107390:12:::1;107431:11;::::0;::::1;::::0;;::::1;::::0;::::1;::::0;107466:9;;::::1;;107457:18:::0;::::1;107453:109;;;107492:9;:18:::0;;-1:-1:-1;;107492:18:0::1;::::0;::::1;::::0;::::1;::::0;;::::1;::::0;;;::::1;::::0;;;107530:20:::1;::::0;::::1;::::0;-1:-1:-1;;107530:20:0::1;107453:109;107345:224;107305:264::o:0;107875:257::-;51678:13;:11;:13::i;:::-;108005:35:::1;::::0;107955:21:::1;::::0;107938:14:::1;::::0;-1:-1:-1;;;;;108005:16:0;::::1;::::0;107955:21;;107938:14;108005:35;107938:14;108005:35;107955:21;108005:16;:35:::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;107987:53;;;108056:7;108051:37;;108072:16;;-1:-1:-1::0;;;108072:16:0::1;;;;;;;;;;;108051:37;108104:20;::::0;108117:6;;-1:-1:-1;;;;;108104:20:0;::::1;::::0;::::1;::::0;;;::::1;107927:205;;107875:257:::0;:::o;6190:545::-;6253:14;6417:5;6407:146;;6456:10;6450:4;6443:24;6533:4;6527;6520:18;6407:146;-1:-1:-1;;;6574:4:0;6567:38;6632:5;6626:4;6619:19;6696:20;6688:4;6682;6672:21;6666:28;6662:55;6652:65;;6190:545;;;:::o;108140:143::-;51678:13;:11;:13::i;:::-;108219:9:::1;::::0;-1:-1:-1;;;108219:9:0;::::1;;;108214:25;;108230:9;:7;:9::i;:::-;108250:25;:23;:25::i;:::-;108140:143::o:0;107769:98::-;51678:13;:11;:13::i;:::-;107816:9:::1;:16:::0;;-1:-1:-1;;107816:16:0::1;-1:-1:-1::0;;;107816:16:0::1;::::0;;107848:11:::1;::::0;::::1;::::0;107816:16;;107848:11:::1;107769:98::o:0;107577:184::-;51678:13;:11;:13::i;:::-;107658:9:::1;::::0;-1:-1:-1;;;107658:9:0;::::1;;;107654:30;;;107676:8;;-1:-1:-1::0;;;107676:8:0::1;;;;;;;;;;;107654:30;107695:8;:19;107706:8:::0;107695;:19:::1;:::i;:::-;;107744:8;107730:23;;;;;;:::i;:::-;;::::0;;;;::::1;::::0;;;::::1;::::0;;;::::1;107577:184:::0;:::o;105467:96::-;105515:13;105548:7;105541:14;;;;;:::i;8487:741::-;8706:10;8699:18;8692:26;8678:40;;8817:8;8811:4;8804:22;8853:31;8847:4;8840:45;8912:8;8906:4;8899:22;8965:10;8958:4;8952;8942:21;8935:41;9052:10;9046:4;9039:24;9199:8;9195:2;9191:17;9187:2;9183:26;9173:8;9138:33;9132:4;9126;9121:89;8487:741;;:::o;13331:256::-;13482:26;13495:4;13501:2;13505;13482:12;:26::i;:::-;37837:14;;13519:60;;;13537:42;13560:4;13566:2;13570;13574:4;;13537:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;13537:22:0;;-1:-1:-1;;;13537:42:0:i;:::-;13331:256;;;;;:::o;107194:103::-;51678:13;:11;:13::i;:::-;107244:10:::1;:17:::0;;-1:-1:-1;;107244:17:0::1;::::0;::::1;::::0;;107277:12:::1;::::0;::::1;::::0;107244:17;;107277:12:::1;107194:103::o:0;105698:189::-;105763:13;105794:16;105802:7;14587:11;14679:16;;;-1:-1:-1;;;14716:4:0;14709:38;14831:4;14815:21;;14807:30;;14799:39;14793:46;14789:2;14785:55;14778:63;14771:71;;14527:333;105794:16;105789:90;;-1:-1:-1;;105812:9:0;;;;;;;;;-1:-1:-1;105812:9:0;;;105698:189::o;105789:90::-;105844:35;105860:18;:7;:16;:18::i;:::-;105844:8;:15;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:35;;;;:::i;:::-;105837:42;105698:189;-1:-1:-1;;105698:189:0:o;105571:119::-;105617:13;105650:32;;;;;;;;;;;;;;-1:-1:-1;;;105650:32:0;;;:8;:15;;;;;:::i;:32::-;105643:39;;105571:119;:::o;106454:510::-;51678:13;:11;:13::i;:::-;106561::::1;::::0;::::1;::::0;::::1;::::0;106590:10;;::::1;;;106585:32;;106609:8;;-1:-1:-1::0;;;106609:8:0::1;;;;;;;;;;;106585:32;106657:9;::::0;;;::::1;;;106632:22;106648:6:::0;106632:13;:22:::1;:::i;:::-;:34;;;106628:65;;;106675:18;;-1:-1:-1::0;;;106675:18:0::1;;;;;;;;;;;106628:65;106709:8;106704:147;106723:6;106719:10;;:1;:10;;;106704:147;;;106776:26;106782:2;106786:15;;;;;;106776:26;;:5;:26::i;:::-;106821:3;;106704:147;;;-1:-1:-1::0;;106886:11:0::1;:21:::0;;::::1;::::0;;;::::1;::::0;::::1;::::0;::::1;::::0;::::1;;106922:23:::0;;;;;;;;;::::1;;-1:-1:-1::0;;106922:23:0;;;-1:-1:-1;;106922:23:0;;;;;;;::::1;::::0;;-1:-1:-1;106454:510:0:o;49471:724::-;51678:13;:11;:13::i;:::-;49709:19:::1;49703:4;49696:33;49756:12;49750:4;49743:26;49819:4;49813;49803:21;49927:12;49921:19;49908:11;49905:36;49902:160;;;49974:10;49968:4;49961:24;50042:4;50036;50029:18;49902:160;50141:1;50120:23:::0;;50164::::1;50174:12:::0;50164:9:::1;:23::i;47408:358::-:0;51678:13;:11;:13::i;:::-;47583:8:::1;47579:2;47575:17;47565:153;;47626:10;47620:4;47613:24;47698:4;47692;47685:18;47565:153;47739:19;47749:8;47739:9;:19::i;28304:1472::-:0;28490:1;28486:6;28482:2;28478:15;28538:7;28522:14;28518:28;28507:39;;28586:2;28570:14;28566:23;28560:29;;28661:2;28655:4;28648:16;28720:2;-1:-1:-1;;;28691:32:0;28685:4;28678:46;28791:4;28785;28775:21;28771:2;28767:30;28763:2;28759:39;28851:13;28845:20;28829:14;28825:41;28812:54;;28942:5;28932:137;;28981:10;28975:4;28968:24;29049:4;29043;29036:18;28932:137;29255:5;29251:2;29248:13;29243:2;29236:10;29233:29;29223:286;;29296:5;29290:4;29283:19;29352:4;29346;29336:21;29330:28;29320:174;;29396:10;29390:4;29383:24;29470:4;29464;29457:18;29320:174;29605:1;29601:21;29594:38;;;29755:2;29624:7;29739:5;29712:25;29706:4;29694:10;29689:69;;28304:1472;;;:::o;38064:1400::-;38307:4;38301:11;38358:10;38392:24;38389:1;38382:35;38452:8;38445:4;38442:1;38438:12;38431:30;38561:4;38557:2;38553:13;38549:2;38545:22;38538:4;38535:1;38531:12;38524:44;38603:2;38596:4;38593:1;38589:12;38582:24;38641:4;38634;38631:1;38627:12;38620:26;38675:4;38669:11;38715:1;38708:4;38705:1;38701:12;38694:23;38734:1;38731:71;;;38797:1;38790:4;38787:1;38783:12;38780:1;38773:4;38767;38763:15;38760:1;38753:5;38742:57;38738:62;38731:71;38920:4;38917:1;38910:4;38907:1;38903:12;38896:4;38893:1;38889:12;38886:1;38882:2;38875:5;38870:55;38860:319;;38949:16;38946:218;;;39079:16;39073:4;39070:1;39055:41;39128:16;39125:1;39118:27;38946:218;38860:319;39277:24;39272:3;39268:34;39264:1;39258:8;39255:48;39245:201;;39337:10;39331:4;39324:24;39426:4;39420;39413:18;39245:201;;;38064:1400;;;;:::o;26116:1190::-;26240:11;26494:16;;;-1:-1:-1;;;;;26414:25:0;;;-1:-1:-1;;;26537:37:0;;26531:4;26524:51;26642:4;26626:21;;;26618:30;;26610:39;;26692:20;;26414:25;;26347:1;;26676:38;;26780:137;;26829:10;26823:4;26816:24;26897:4;26891;26884:18;26780:137;27004:5;26995:7;26992:18;26982:306;;27044:5;27038:4;27031:19;27172:4;27166;27156:21;27150:28;27140:133;;27238:13;27235:1;27231:21;27225:28;27216:7;27213:41;27203:51;;27140:133;26982:306;;26116:1190;;;;:::o;23102:84::-;23157:21;23171:1;23175:2;23157:5;:21::i;46329:364::-;-1:-1:-1;;46539:18:0;46529:8;46526:32;46516:159;;46592:10;46586:4;46579:24;46655:4;46649;46642:18;47834:102;51678:13;:11;:13::i;:::-;47907:21:::1;47925:1;47907:9;:21::i;53039:1676::-:0;53095:17;53547:4;53540;53534:11;53530:22;53523:29;;53648:4;53643:3;53639:14;53633:4;53626:28;53731:1;53726:3;53719:14;53835:3;53867:1;53863:6;54079:5;54061:410;54118:11;;;;54302:2;54316;54306:13;;54298:22;54118:11;54285:36;54410:2;54400:13;;54431:25;54061:410;54431:25;-1:-1:-1;;54501:13:0;;;-1:-1:-1;;54616:14:0;;;54678:19;;;54616:14;53039:1676;-1:-1:-1;53039:1676:0:o;89220:1399::-;89474:4;89468:11;89508:8;;-1:-1:-1;;89435:9:0;89618:4;89605:18;;89601:26;;89586:214;89683:9;;;89677:16;89661:14;;;89654:40;89717:9;;89763:22;89586:214;89763:22;89590:39;89835:1;89829:8;89877:7;89869:6;89865:20;89994:1;89987:4;89978:7;89974:18;89970:26;89955:214;90052:9;;;90046:16;90030:14;;;90023:40;90086:9;;90132:22;89955:214;90132:22;-1:-1:-1;;90362:1:0;90202:21;;90249:35;;;90265:4;90249:35;;90349:15;;;;90413:27;;90581:15;;90577:23;90571:4;90564:37;90257:6;89220:1399;-1:-1:-1;;89220:1399:0:o;18651:1688::-;18900:2;18896;18892:11;18888:2;18884:20;18878:26;;18972:2;18966:4;18959:16;-1:-1:-1;;;18996:4:0;18989:38;19094:4;19088;19078:21;19074:2;19070:30;19066:2;19062:39;19144:13;19138:20;19235:15;19231:2;19227:24;19224:149;;;19284:10;19278:4;19271:24;19353:4;19347;19340:18;19224:149;19448:23;;19426:46;;19564:4;19557:16;;;19626:4;19620;19610:21;19678:18;;19698:1;19674:26;19852:20;19829:44;;19821:53;;19811:272;;20005:18;19999:2;19992:10;19989:1;19985:18;19978:46;20059:4;20053;20046:18;19811:272;20101:38;;20268:2;20264;20261:1;20234:25;20261:1;20216:10;20211:60;7722:121;;:::o;45155:1113::-;-1:-1:-1;;46122:16:0;;-1:-1:-1;;;;;45968:26:0;;;;;;46082:38;46079:1;;46071:78;46208:27;45155:1113::o;23486:2172::-;23553:13;23569:11;23577:2;23569:7;:11::i;:::-;23553:27;;-1:-1:-1;23842:4:0;23835:16;;;-1:-1:-1;;;;;23760:20:0;;;-1:-1:-1;;;23878:32:0;;23872:4;23865:46;23978:4;23962:21;;;23954:30;;23946:39;;24022:20;;23760;;24147:33;;;;24246:137;;24295:10;24289:4;24282:24;24363:4;24357;24350:18;24246:137;24480:5;24474:4;24467:19;24540:13;24537:1;24533:21;24527:28;24775:15;24771:2;24768:23;24760:5;24756:2;24753:13;24750:42;24745:2;24738:10;24735:58;24725:298;;24850:4;24844;24834:21;24828:28;24818:186;;24898:10;24892:4;24885:24;24976:4;24970;24963:18;24818:186;25100:15;25097:55;;;25148:1;25132:13;25129:1;25125:21;25118:32;25097:55;-1:-1:-1;25236:27:0;;25214:50;;25382:4;25376;25366:21;25429:18;;-1:-1:-1;;25425:26:0;25405:47;;25584:2;-1:-1:-1;25257:5:0;25547:25;-1:-1:-1;25529:10:0;25524:63;9595:2944;;;:::o;14:286:1:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;167:23;;-1:-1:-1;;;;;;219:32:1;;209:43;;199:71;;266:1;263;256:12;199:71;289:5;14:286;-1:-1:-1;;;14:286:1:o;497:250::-;582:1;592:113;606:6;603:1;600:13;592:113;;;682:11;;;676:18;663:11;;;656:39;628:2;621:10;592:113;;;-1:-1:-1;;739:1:1;721:16;;714:27;497:250::o;752:396::-;901:2;890:9;883:21;864:4;933:6;927:13;976:6;971:2;960:9;956:18;949:34;992:79;1064:6;1059:2;1048:9;1044:18;1039:2;1031:6;1027:15;992:79;:::i;:::-;1132:2;1111:15;-1:-1:-1;;1107:29:1;1092:45;;;;1139:2;1088:54;;752:396;-1:-1:-1;;752:396:1:o;1153:180::-;1212:6;1265:2;1253:9;1244:7;1240:23;1236:32;1233:52;;;1281:1;1278;1271:12;1233:52;-1:-1:-1;1304:23:1;;1153:180;-1:-1:-1;1153:180:1:o;1546:173::-;1614:20;;-1:-1:-1;;;;;1663:31:1;;1653:42;;1643:70;;1709:1;1706;1699:12;1724:254;1792:6;1800;1853:2;1841:9;1832:7;1828:23;1824:32;1821:52;;;1869:1;1866;1859:12;1821:52;1892:29;1911:9;1892:29;:::i;:::-;1882:39;1968:2;1953:18;;;;1940:32;;-1:-1:-1;;;1724:254:1:o;2176:328::-;2253:6;2261;2269;2322:2;2310:9;2301:7;2297:23;2293:32;2290:52;;;2338:1;2335;2328:12;2290:52;2361:29;2380:9;2361:29;:::i;:::-;2351:39;;2409:38;2443:2;2432:9;2428:18;2409:38;:::i;:::-;2399:48;;2494:2;2483:9;2479:18;2466:32;2456:42;;2176:328;;;;;:::o;2509:186::-;2568:6;2621:2;2609:9;2600:7;2596:23;2592:32;2589:52;;;2637:1;2634;2627:12;2589:52;2660:29;2679:9;2660:29;:::i;2882:127::-;2943:10;2938:3;2934:20;2931:1;2924:31;2974:4;2971:1;2964:15;2998:4;2995:1;2988:15;3014:922;3083:6;3136:2;3124:9;3115:7;3111:23;3107:32;3104:52;;;3152:1;3149;3142:12;3104:52;3192:9;3179:23;3221:18;3262:2;3254:6;3251:14;3248:34;;;3278:1;3275;3268:12;3248:34;3316:6;3305:9;3301:22;3291:32;;3361:7;3354:4;3350:2;3346:13;3342:27;3332:55;;3383:1;3380;3373:12;3332:55;3419:2;3406:16;3441:2;3437;3434:10;3431:36;;;3447:18;;:::i;:::-;3522:2;3516:9;3490:2;3576:13;;-1:-1:-1;;3572:22:1;;;3596:2;3568:31;3564:40;3552:53;;;3620:18;;;3640:22;;;3617:46;3614:72;;;3666:18;;:::i;:::-;3706:10;3702:2;3695:22;3741:2;3733:6;3726:18;3781:7;3776:2;3771;3767;3763:11;3759:20;3756:33;3753:53;;;3802:1;3799;3792:12;3753:53;3858:2;3853;3849;3845:11;3840:2;3832:6;3828:15;3815:46;3903:1;3881:15;;;3898:2;3877:24;3870:35;;;;-1:-1:-1;3885:6:1;3014:922;-1:-1:-1;;;;;3014:922:1:o;4146:347::-;4211:6;4219;4272:2;4260:9;4251:7;4247:23;4243:32;4240:52;;;4288:1;4285;4278:12;4240:52;4311:29;4330:9;4311:29;:::i;:::-;4301:39;;4390:2;4379:9;4375:18;4362:32;4437:5;4430:13;4423:21;4416:5;4413:32;4403:60;;4459:1;4456;4449:12;4403:60;4482:5;4472:15;;;4146:347;;;;;:::o;4498:808::-;4595:6;4603;4611;4619;4627;4680:3;4668:9;4659:7;4655:23;4651:33;4648:53;;;4697:1;4694;4687:12;4648:53;4720:29;4739:9;4720:29;:::i;:::-;4710:39;;4768:38;4802:2;4791:9;4787:18;4768:38;:::i;:::-;4758:48;;4853:2;4842:9;4838:18;4825:32;4815:42;;4908:2;4897:9;4893:18;4880:32;4931:18;4972:2;4964:6;4961:14;4958:34;;;4988:1;4985;4978:12;4958:34;5026:6;5015:9;5011:22;5001:32;;5071:7;5064:4;5060:2;5056:13;5052:27;5042:55;;5093:1;5090;5083:12;5042:55;5133:2;5120:16;5159:2;5151:6;5148:14;5145:34;;;5175:1;5172;5165:12;5145:34;5220:7;5215:2;5206:6;5202:2;5198:15;5194:24;5191:37;5188:57;;;5241:1;5238;5231:12;5188:57;4498:808;;;;-1:-1:-1;4498:808:1;;-1:-1:-1;5272:2:1;5264:11;;5294:6;4498:808;-1:-1:-1;;;4498:808:1:o;5311:260::-;5379:6;5387;5440:2;5428:9;5419:7;5415:23;5411:32;5408:52;;;5456:1;5453;5446:12;5408:52;5479:29;5498:9;5479:29;:::i;:::-;5469:39;;5527:38;5561:2;5550:9;5546:18;5527:38;:::i;:::-;5517:48;;5311:260;;;;;:::o;5576:346::-;5643:6;5651;5704:2;5692:9;5683:7;5679:23;5675:32;5672:52;;;5720:1;5717;5710:12;5672:52;5743:29;5762:9;5743:29;:::i;:::-;5733:39;;5822:2;5811:9;5807:18;5794:32;5866:6;5859:5;5855:18;5848:5;5845:29;5835:57;;5888:1;5885;5878:12;5927:380;6006:1;6002:12;;;;6049;;;6070:61;;6124:4;6116:6;6112:17;6102:27;;6070:61;6177:2;6169:6;6166:14;6146:18;6143:38;6140:161;;6223:10;6218:3;6214:20;6211:1;6204:31;6258:4;6255:1;6248:15;6286:4;6283:1;6276:15;6140:161;;5927:380;;;:::o;6648:518::-;6750:2;6745:3;6742:11;6739:421;;;6786:5;6783:1;6776:16;6830:4;6827:1;6817:18;6900:2;6888:10;6884:19;6881:1;6877:27;6871:4;6867:38;6936:4;6924:10;6921:20;6918:47;;;-1:-1:-1;6959:4:1;6918:47;7014:2;7009:3;7005:12;7002:1;6998:20;6992:4;6988:31;6978:41;;7069:81;7087:2;7080:5;7077:13;7069:81;;;7146:1;7132:16;;7113:1;7102:13;7069:81;;7342:1345;7468:3;7462:10;7495:18;7487:6;7484:30;7481:56;;;7517:18;;:::i;:::-;7546:97;7636:6;7596:38;7628:4;7622:11;7596:38;:::i;:::-;7590:4;7546:97;:::i;:::-;7698:4;;7755:2;7744:14;;7772:1;7767:663;;;;8474:1;8491:6;8488:89;;;-1:-1:-1;8543:19:1;;;8537:26;8488:89;-1:-1:-1;;7299:1:1;7295:11;;;7291:24;7287:29;7277:40;7323:1;7319:11;;;7274:57;8590:81;;7737:944;;7767:663;6595:1;6588:14;;;6632:4;6619:18;;-1:-1:-1;;7803:20:1;;;7921:236;7935:7;7932:1;7929:14;7921:236;;;8024:19;;;8018:26;8003:42;;8116:27;;;;8084:1;8072:14;;;;7951:19;;7921:236;;;7925:3;8185:6;8176:7;8173:19;8170:201;;;8246:19;;;8240:26;-1:-1:-1;;8329:1:1;8325:14;;;8341:3;8321:24;8317:37;8313:42;8298:58;8283:74;;8170:201;-1:-1:-1;;;;;8417:1:1;8401:14;;;8397:22;8384:36;;-1:-1:-1;7342:1345:1:o;8692:289::-;8823:3;8861:6;8855:13;8877:66;8936:6;8931:3;8924:4;8916:6;8912:17;8877:66;:::i;:::-;8959:16;;;;;8692:289;-1:-1:-1;;8692:289:1:o;8986:265::-;9053:6;9079:10;;;9091;;;9075:27;;9114:11;;;9111:134;;;9167:10;9162:3;9158:20;9155:1;9148:31;9202:4;9199:1;9192:15;9230:4;9227:1;9220:15;9111:134;;8986:265;;;;:::o
Swarm Source
ipfs://500fde9c56c8adefa71c29ebc86171864593204c7095d654172f186f073212de
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.