Source Code
More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 437 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Shuffle Token | 29727382 | 309 days ago | IN | 0 ETH | 0.00000043 | ||||
| Shuffle Token | 29727369 | 309 days ago | IN | 0 ETH | 0.00000044 | ||||
| Shuffle Token | 29727358 | 309 days ago | IN | 0 ETH | 0.00000046 | ||||
| Shuffle Token | 29727303 | 309 days ago | IN | 0 ETH | 0.00000052 | ||||
| Shuffle Token | 29727291 | 309 days ago | IN | 0 ETH | 0.00000053 | ||||
| Shuffle Token | 29727279 | 309 days ago | IN | 0 ETH | 0.00000055 | ||||
| Shuffle Token | 29727264 | 309 days ago | IN | 0 ETH | 0.00000057 | ||||
| Shuffle Token | 29727252 | 309 days ago | IN | 0 ETH | 0.00000065 | ||||
| Shuffle Token | 29727241 | 309 days ago | IN | 0 ETH | 0.00000059 | ||||
| Shuffle Token | 29727219 | 309 days ago | IN | 0 ETH | 0.00000071 | ||||
| Shuffle Token | 29727206 | 309 days ago | IN | 0 ETH | 0.00000062 | ||||
| Shuffle Token | 29727192 | 309 days ago | IN | 0 ETH | 0.00000063 | ||||
| Shuffle Token | 29727180 | 309 days ago | IN | 0 ETH | 0.00000065 | ||||
| Shuffle Token | 29727159 | 309 days ago | IN | 0 ETH | 0.00000065 | ||||
| Shuffle Token | 29727149 | 309 days ago | IN | 0 ETH | 0.00000066 | ||||
| Shuffle Token | 29727137 | 309 days ago | IN | 0 ETH | 0.00000068 | ||||
| Shuffle Token | 29727123 | 309 days ago | IN | 0 ETH | 0.00000066 | ||||
| Shuffle Token | 29727109 | 309 days ago | IN | 0 ETH | 0.00000067 | ||||
| Shuffle Token | 29727097 | 309 days ago | IN | 0 ETH | 0.00000069 | ||||
| Shuffle Token | 29727067 | 309 days ago | IN | 0 ETH | 0.00000075 | ||||
| Shuffle Token | 29727051 | 309 days ago | IN | 0 ETH | 0.00000076 | ||||
| Shuffle Token | 29727038 | 309 days ago | IN | 0 ETH | 0.00000078 | ||||
| Shuffle Token | 29727024 | 309 days ago | IN | 0 ETH | 0.00000079 | ||||
| Shuffle Token | 29727008 | 309 days ago | IN | 0 ETH | 0.00000079 | ||||
| Shuffle Token | 29726994 | 309 days ago | IN | 0 ETH | 0.00000079 |
Cross-Chain Transactions
Loading...
Loading
Contract Name:
Zorbit
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 500 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
/**
/////////////////////////////////////////////////////////////
// mint infinite zorbits to infinite random addresses
// love, ripe
/////////////////////////////////////////////////////////////
@title zorbit
@author ripe
*/
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721Enumerable.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
import 'erc721a-upgradeable/contracts/interfaces/IERC721AUpgradeable.sol';
import 'solady/src/utils/Base64.sol';
import './interfaces/IERC721Drop.sol';
import './interfaces/IZorbitArt.sol';
import './library/Structs.sol';
import './library/NodeArt.sol';
contract Zorbit is ERC721, ERC721Enumerable, Ownable {
address public zorbitArtContract;
Structs.ContractMetadata private _contractMetadata;
Structs.Node[] private _nodes;
error Access_OnlyTokenOwner();
error TokenNotFound();
constructor(
string memory tokenName,
string memory tokenSymbol,
address initialOwner
) ERC721(tokenName, tokenSymbol) Ownable(initialOwner) {
_nodes.push(Structs.Node(new address[](0))); // adds a dummy node to the array to make the tokenId and array index match
}
function contractURI() public view returns (string memory) {
return
string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "',
_contractMetadata.name,
'", "description": "',
_contractMetadata.description,
'", "image": "',
_contractMetadata.contractImage,
'", "seller_fee_basis_points": "',
_contractMetadata.sellerFeeBasisPoints,
'", "seller_fee_recipient": "',
_contractMetadata.sellerFeeRecipient,
'", "animation_url": "',
_contractMetadata.animationUrl,
'"}'
)
)
)
)
)
);
}
function tokenURI(
uint256 tokenId
) public view override returns (string memory) {
if (tokenId < 1 || tokenId > totalSupply()) {
revert TokenNotFound();
}
return constructTokenURI(tokenId);
}
function svgArtwork(uint256 tokenId) public view returns (string memory) {
string memory svgRects = IZorbitArt(zorbitArtContract).emptyZorb();
string memory art = NodeArt.buildZorbs(
svgRects,
tokenId,
_nodes[tokenId].owners
);
return art;
}
function constructTokenURI(
uint256 tokenId
) public view returns (string memory) {
string memory art = svgArtwork(tokenId);
return
string(
abi.encodePacked(
'data:application/json;base64,',
Base64.encode(
bytes(
string(
abi.encodePacked(
'{"name": "',
string(abi.encodePacked(_contractMetadata.name)),
' ',
Strings.toString(tokenId),
'", "image": "data:image/svg+xml;base64,',
Base64.encode(bytes(art)),
'", "description": "',
string(abi.encodePacked(_contractMetadata.description)),
'", "attributes": [',
'{"trait_type": "Transfers", "value": "',
Strings.toString(_nodes[tokenId].owners.length),
'"}]}'
)
)
)
)
)
);
}
/*
⌐◨—————————————————————————————————————————————————————————————◨
utility functions
⌐◨—————————————————————————————————————————————————————————————◨
*/
function randomNum(string memory input) internal view returns (uint256) {
uint hashNumber = uint(
keccak256(abi.encodePacked(block.prevrandao, input))
);
return hashNumber % 100;
}
/// @notice Set the contract URI
/// @param contractMetadata_ the new contract URI to set
function setContractMetadata(
Structs.ContractMetadata memory contractMetadata_
) external onlyOwner {
_contractMetadata.name = contractMetadata_.name;
_contractMetadata.description = contractMetadata_.description;
_contractMetadata.contractImage = contractMetadata_.contractImage;
_contractMetadata.sellerFeeBasisPoints = contractMetadata_
.sellerFeeBasisPoints;
_contractMetadata.sellerFeeRecipient = contractMetadata_.sellerFeeRecipient;
_contractMetadata.externalUrl = contractMetadata_.externalUrl;
_contractMetadata.animationUrl = contractMetadata_.animationUrl;
}
function getRandomAddress(
string memory input
) internal view returns (address) {
return
address(
uint160(
uint(
keccak256(
abi.encodePacked(
randomNum(
Strings.toString(uint256(keccak256(abi.encode(input))))
)
)
)
)
)
);
}
/*
⌐◨—————————————————————————————————————————————————————————————◨
external functions
⌐◨—————————————————————————————————————————————————————————————◨
*/
// @notice Mint a new zorbit token to a random address
function mint() external returns (uint256) {
uint256 tokenId = totalSupply() + 1;
address randomAddress = getRandomAddress(
string(
abi.encode(Strings.toString(tokenId), block.prevrandao, msg.sender)
)
);
_safeMint(randomAddress, tokenId);
// after minting, add the minter and new owners to node storage to generate the artwork from when rendering
address[] memory owners = new address[](2);
owners[0] = msg.sender;
owners[1] = randomAddress;
Structs.Node memory node = Structs.Node(owners);
_nodes.push(node);
return tokenId;
}
/// @notice Send a token to a new random address
/// @param tokenId the token ID to transfer
function shuffleToken(uint256 tokenId) public {
if (tokenId < 1 || tokenId > totalSupply()) {
revert TokenNotFound();
}
address from = ownerOf(tokenId);
address to = getRandomAddress(Strings.toString(tokenId + block.prevrandao));
// use custom safeTransfer override to avoid approval from owner
_safeTransfer(from, to, tokenId, '');
_nodes[tokenId].owners.push(to);
}
function shuffleMany(uint256[] memory tokenIds) external {
for (uint256 i = 0; i < tokenIds.length; i++) {
shuffleToken(tokenIds[i]);
}
}
/// @notice Gets a list of current owner addresses for a given array of token IDs. If no owner is found, the address(0) is returned for that token.
/// @param tokenIds array of token IDs to get owners for
/// @return owners an array of owner addresses
function ownersForTokenIds(
uint256[] memory tokenIds
) external view returns (address[] memory) {
address[] memory owners = new address[](tokenIds.length);
for (uint256 i = 0; i < tokenIds.length; i++) {
if (tokenIds[i] > 0 && tokenIds[i] <= totalSupply()) {
owners[i] = ownerOf(tokenIds[i]);
} else {
owners[i] = address(0);
}
}
return owners;
}
/// @notice Gets the owner history for a given token ID
/// @param tokenId the token ID to get owner history for
/// @return an array of addresses
function zorbitIdOwnerHistory(
uint256 tokenId
) external view returns (address[] memory) {
return _nodes[tokenId].owners;
}
/*
⌐◨—————————————————————————————————————————————————————————————◨
contract owner functions
⌐◨—————————————————————————————————————————————————————————————◨
*/
function setZorbitArtContractAddress(address addr) external onlyOwner {
zorbitArtContract = addr;
}
/*
⌐◨—————————————————————————————————————————————————————————————◨
erc721 override functions
⌐◨—————————————————————————————————————————————————————————————◨
*/
function _update(
address to,
uint256 tokenId,
address auth
) internal override(ERC721, ERC721Enumerable) returns (address) {
return super._update(to, tokenId, auth);
}
function _increaseBalance(
address account,
uint128 value
) internal override(ERC721, ERC721Enumerable) {
super._increaseBalance(account, value);
}
function supportsInterface(
bytes4 interfaceId
) public view override(ERC721, ERC721Enumerable) returns (bool) {
return super.supportsInterface(interfaceId);
}
// overrides standard ERC721 safeTransferFrom to avoid approval from owner
function _safeTransfer(
address from,
address to,
uint256 tokenId,
bytes memory data
) internal override {
_update(to, tokenId, address(0));
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol)
pragma solidity ^0.8.20;
import {Context} from "../utils/Context.sol";
/**
* @dev Contract module which provides a basic access control mechanism, where
* there is an account (an owner) that can be granted exclusive access to
* specific functions.
*
* The initial owner is set to the address provided by the deployer. This can
* later be changed with {transferOwnership}.
*
* This module is used through inheritance. It will make available the modifier
* `onlyOwner`, which can be applied to your functions to restrict their use to
* the owner.
*/
abstract contract Ownable is Context {
address private _owner;
/**
* @dev The caller account is not authorized to perform an operation.
*/
error OwnableUnauthorizedAccount(address account);
/**
* @dev The owner is not a valid owner account. (eg. `address(0)`)
*/
error OwnableInvalidOwner(address owner);
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the address provided by the deployer as the initial owner.
*/
constructor(address initialOwner) {
if (initialOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(initialOwner);
}
/**
* @dev Throws if called by any account other than the owner.
*/
modifier onlyOwner() {
_checkOwner();
_;
}
/**
* @dev Returns the address of the current owner.
*/
function owner() public view virtual returns (address) {
return _owner;
}
/**
* @dev Throws if the sender is not the owner.
*/
function _checkOwner() internal view virtual {
if (owner() != _msgSender()) {
revert OwnableUnauthorizedAccount(_msgSender());
}
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby disabling any functionality that is only available to the owner.
*/
function renounceOwnership() public virtual onlyOwner {
_transferOwnership(address(0));
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Can only be called by the current owner.
*/
function transferOwnership(address newOwner) public virtual onlyOwner {
if (newOwner == address(0)) {
revert OwnableInvalidOwner(address(0));
}
_transferOwnership(newOwner);
}
/**
* @dev Transfers ownership of the contract to a new account (`newOwner`).
* Internal function without access restriction.
*/
function _transferOwnership(address newOwner) internal virtual {
address oldOwner = _owner;
_owner = newOwner;
emit OwnershipTransferred(oldOwner, newOwner);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (interfaces/draft-IERC6093.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard ERC20 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC20 tokens.
*/
interface IERC20Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientBalance(address sender, uint256 balance, uint256 needed);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC20InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC20InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `spender`’s `allowance`. Used in transfers.
* @param spender Address that may be allowed to operate on tokens without being their owner.
* @param allowance Amount of tokens a `spender` is allowed to operate with.
* @param needed Minimum amount required to perform a transfer.
*/
error ERC20InsufficientAllowance(address spender, uint256 allowance, uint256 needed);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC20InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `spender` to be approved. Used in approvals.
* @param spender Address that may be allowed to operate on tokens without being their owner.
*/
error ERC20InvalidSpender(address spender);
}
/**
* @dev Standard ERC721 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC721 tokens.
*/
interface IERC721Errors {
/**
* @dev Indicates that an address can't be an owner. For example, `address(0)` is a forbidden owner in EIP-20.
* Used in balance queries.
* @param owner Address of the current owner of a token.
*/
error ERC721InvalidOwner(address owner);
/**
* @dev Indicates a `tokenId` whose `owner` is the zero address.
* @param tokenId Identifier number of a token.
*/
error ERC721NonexistentToken(uint256 tokenId);
/**
* @dev Indicates an error related to the ownership over a particular token. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param tokenId Identifier number of a token.
* @param owner Address of the current owner of a token.
*/
error ERC721IncorrectOwner(address sender, uint256 tokenId, address owner);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC721InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC721InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param tokenId Identifier number of a token.
*/
error ERC721InsufficientApproval(address operator, uint256 tokenId);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC721InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC721InvalidOperator(address operator);
}
/**
* @dev Standard ERC1155 Errors
* Interface of the https://eips.ethereum.org/EIPS/eip-6093[ERC-6093] custom errors for ERC1155 tokens.
*/
interface IERC1155Errors {
/**
* @dev Indicates an error related to the current `balance` of a `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
* @param balance Current balance for the interacting account.
* @param needed Minimum amount required to perform a transfer.
* @param tokenId Identifier number of a token.
*/
error ERC1155InsufficientBalance(address sender, uint256 balance, uint256 needed, uint256 tokenId);
/**
* @dev Indicates a failure with the token `sender`. Used in transfers.
* @param sender Address whose tokens are being transferred.
*/
error ERC1155InvalidSender(address sender);
/**
* @dev Indicates a failure with the token `receiver`. Used in transfers.
* @param receiver Address to which tokens are being transferred.
*/
error ERC1155InvalidReceiver(address receiver);
/**
* @dev Indicates a failure with the `operator`’s approval. Used in transfers.
* @param operator Address that may be allowed to operate on tokens without being their owner.
* @param owner Address of the current owner of a token.
*/
error ERC1155MissingApprovalForAll(address operator, address owner);
/**
* @dev Indicates a failure with the `approver` of a token to be approved. Used in approvals.
* @param approver Address initiating an approval operation.
*/
error ERC1155InvalidApprover(address approver);
/**
* @dev Indicates a failure with the `operator` to be approved. Used in approvals.
* @param operator Address that may be allowed to operate on tokens without being their owner.
*/
error ERC1155InvalidOperator(address operator);
/**
* @dev Indicates an array length mismatch between ids and values in a safeBatchTransferFrom operation.
* Used in batch transfers.
* @param idsLength Length of the array of token identifiers
* @param valuesLength Length of the array of token amounts
*/
error ERC1155InvalidArrayLength(uint256 idsLength, uint256 valuesLength);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/ERC721.sol)
pragma solidity ^0.8.20;
import {IERC721} from "./IERC721.sol";
import {IERC721Receiver} from "./IERC721Receiver.sol";
import {IERC721Metadata} from "./extensions/IERC721Metadata.sol";
import {Context} from "../../utils/Context.sol";
import {Strings} from "../../utils/Strings.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
import {IERC721Errors} from "../../interfaces/draft-IERC6093.sol";
/**
* @dev Implementation of https://eips.ethereum.org/EIPS/eip-721[ERC721] Non-Fungible Token Standard, including
* the Metadata extension, but not including the Enumerable extension, which is available separately as
* {ERC721Enumerable}.
*/
abstract contract ERC721 is Context, ERC165, IERC721, IERC721Metadata, IERC721Errors {
using Strings for uint256;
// Token name
string private _name;
// Token symbol
string private _symbol;
mapping(uint256 tokenId => address) private _owners;
mapping(address owner => uint256) private _balances;
mapping(uint256 tokenId => address) private _tokenApprovals;
mapping(address owner => mapping(address operator => bool)) private _operatorApprovals;
/**
* @dev Initializes the contract by setting a `name` and a `symbol` to the token collection.
*/
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
}
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC165, IERC165) returns (bool) {
return
interfaceId == type(IERC721).interfaceId ||
interfaceId == type(IERC721Metadata).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721-balanceOf}.
*/
function balanceOf(address owner) public view virtual returns (uint256) {
if (owner == address(0)) {
revert ERC721InvalidOwner(address(0));
}
return _balances[owner];
}
/**
* @dev See {IERC721-ownerOf}.
*/
function ownerOf(uint256 tokenId) public view virtual returns (address) {
return _requireOwned(tokenId);
}
/**
* @dev See {IERC721Metadata-name}.
*/
function name() public view virtual returns (string memory) {
return _name;
}
/**
* @dev See {IERC721Metadata-symbol}.
*/
function symbol() public view virtual returns (string memory) {
return _symbol;
}
/**
* @dev See {IERC721Metadata-tokenURI}.
*/
function tokenURI(uint256 tokenId) public view virtual returns (string memory) {
_requireOwned(tokenId);
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string.concat(baseURI, tokenId.toString()) : "";
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return "";
}
/**
* @dev See {IERC721-approve}.
*/
function approve(address to, uint256 tokenId) public virtual {
_approve(to, tokenId, _msgSender());
}
/**
* @dev See {IERC721-getApproved}.
*/
function getApproved(uint256 tokenId) public view virtual returns (address) {
_requireOwned(tokenId);
return _getApproved(tokenId);
}
/**
* @dev See {IERC721-setApprovalForAll}.
*/
function setApprovalForAll(address operator, bool approved) public virtual {
_setApprovalForAll(_msgSender(), operator, approved);
}
/**
* @dev See {IERC721-isApprovedForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev See {IERC721-transferFrom}.
*/
function transferFrom(address from, address to, uint256 tokenId) public virtual {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
// Setting an "auth" arguments enables the `_isAuthorized` check which verifies that the token exists
// (from != 0). Therefore, it is not needed to verify that the return value is not 0 here.
address previousOwner = _update(to, tokenId, _msgSender());
if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId) public {
safeTransferFrom(from, to, tokenId, "");
}
/**
* @dev See {IERC721-safeTransferFrom}.
*/
function safeTransferFrom(address from, address to, uint256 tokenId, bytes memory data) public virtual {
transferFrom(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Returns the owner of the `tokenId`. Does NOT revert if token doesn't exist
*
* IMPORTANT: Any overrides to this function that add ownership of tokens not tracked by the
* core ERC721 logic MUST be matched with the use of {_increaseBalance} to keep balances
* consistent with ownership. The invariant to preserve is that for any address `a` the value returned by
* `balanceOf(a)` must be equal to the number of tokens such that `_ownerOf(tokenId)` is `a`.
*/
function _ownerOf(uint256 tokenId) internal view virtual returns (address) {
return _owners[tokenId];
}
/**
* @dev Returns the approved address for `tokenId`. Returns 0 if `tokenId` is not minted.
*/
function _getApproved(uint256 tokenId) internal view virtual returns (address) {
return _tokenApprovals[tokenId];
}
/**
* @dev Returns whether `spender` is allowed to manage `owner`'s tokens, or `tokenId` in
* particular (ignoring whether it is owned by `owner`).
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _isAuthorized(address owner, address spender, uint256 tokenId) internal view virtual returns (bool) {
return
spender != address(0) &&
(owner == spender || isApprovedForAll(owner, spender) || _getApproved(tokenId) == spender);
}
/**
* @dev Checks if `spender` can operate on `tokenId`, assuming the provided `owner` is the actual owner.
* Reverts if `spender` does not have approval from the provided `owner` for the given token or for all its assets
* the `spender` for the specific `tokenId`.
*
* WARNING: This function assumes that `owner` is the actual owner of `tokenId` and does not verify this
* assumption.
*/
function _checkAuthorized(address owner, address spender, uint256 tokenId) internal view virtual {
if (!_isAuthorized(owner, spender, tokenId)) {
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else {
revert ERC721InsufficientApproval(spender, tokenId);
}
}
}
/**
* @dev Unsafe write access to the balances, used by extensions that "mint" tokens using an {ownerOf} override.
*
* NOTE: the value is limited to type(uint128).max. This protect against _balance overflow. It is unrealistic that
* a uint256 would ever overflow from increments when these increments are bounded to uint128 values.
*
* WARNING: Increasing an account's balance using this function tends to be paired with an override of the
* {_ownerOf} function to resolve the ownership of the corresponding tokens so that balances and ownership
* remain consistent with one another.
*/
function _increaseBalance(address account, uint128 value) internal virtual {
unchecked {
_balances[account] += value;
}
}
/**
* @dev Transfers `tokenId` from its current owner to `to`, or alternatively mints (or burns) if the current owner
* (or `to`) is the zero address. Returns the owner of the `tokenId` before the update.
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that
* `auth` is either the owner of the token, or approved to operate on the token (by the owner).
*
* Emits a {Transfer} event.
*
* NOTE: If overriding this function in a way that tracks balances, see also {_increaseBalance}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual returns (address) {
address from = _ownerOf(tokenId);
// Perform (optional) operator check
if (auth != address(0)) {
_checkAuthorized(from, auth, tokenId);
}
// Execute the update
if (from != address(0)) {
// Clear approval. No need to re-authorize or emit the Approval event
_approve(address(0), tokenId, address(0), false);
unchecked {
_balances[from] -= 1;
}
}
if (to != address(0)) {
unchecked {
_balances[to] += 1;
}
}
_owners[tokenId] = to;
emit Transfer(from, to, tokenId);
return from;
}
/**
* @dev Mints `tokenId` and transfers it to `to`.
*
* WARNING: Usage of this method is discouraged, use {_safeMint} whenever possible
*
* Requirements:
*
* - `tokenId` must not exist.
* - `to` cannot be the zero address.
*
* Emits a {Transfer} event.
*/
function _mint(address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner != address(0)) {
revert ERC721InvalidSender(address(0));
}
}
/**
* @dev Mints `tokenId`, transfers it to `to` and checks for `to` acceptance.
*
* Requirements:
*
* - `tokenId` must not exist.
* - 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 tokenId) internal {
_safeMint(to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeMint-address-uint256-}[`_safeMint`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeMint(address to, uint256 tokenId, bytes memory data) internal virtual {
_mint(to, tokenId);
_checkOnERC721Received(address(0), to, tokenId, data);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
* This is an internal function that does not check if the sender is authorized to operate on the token.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId) internal {
address previousOwner = _update(address(0), tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
}
/**
* @dev Transfers `tokenId` from `from` to `to`.
* As opposed to {transferFrom}, this imposes no restrictions on msg.sender.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
*
* Emits a {Transfer} event.
*/
function _transfer(address from, address to, uint256 tokenId) internal {
if (to == address(0)) {
revert ERC721InvalidReceiver(address(0));
}
address previousOwner = _update(to, tokenId, address(0));
if (previousOwner == address(0)) {
revert ERC721NonexistentToken(tokenId);
} else if (previousOwner != from) {
revert ERC721IncorrectOwner(from, tokenId, previousOwner);
}
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking that contract recipients
* are aware of the ERC721 standard to prevent tokens from being forever locked.
*
* `data` is additional data, it has no specified format and it is sent in call to `to`.
*
* This internal function is like {safeTransferFrom} in the sense that it invokes
* {IERC721Receiver-onERC721Received} on the receiver, and can be used to e.g.
* implement alternative mechanisms to perform token transfer, such as signature-based.
*
* Requirements:
*
* - `tokenId` token must exist and be owned by `from`.
* - `to` cannot be the zero address.
* - `from` 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 _safeTransfer(address from, address to, uint256 tokenId) internal {
_safeTransfer(from, to, tokenId, "");
}
/**
* @dev Same as {xref-ERC721-_safeTransfer-address-address-uint256-}[`_safeTransfer`], with an additional `data` parameter which is
* forwarded in {IERC721Receiver-onERC721Received} to contract recipients.
*/
function _safeTransfer(address from, address to, uint256 tokenId, bytes memory data) internal virtual {
_transfer(from, to, tokenId);
_checkOnERC721Received(from, to, tokenId, data);
}
/**
* @dev Approve `to` to operate on `tokenId`
*
* The `auth` argument is optional. If the value passed is non 0, then this function will check that `auth` is
* either the owner of the token, or approved to operate on all tokens held by this owner.
*
* Emits an {Approval} event.
*
* Overrides to this logic should be done to the variant with an additional `bool emitEvent` argument.
*/
function _approve(address to, uint256 tokenId, address auth) internal {
_approve(to, tokenId, auth, true);
}
/**
* @dev Variant of `_approve` with an optional flag to enable or disable the {Approval} event. The event is not
* emitted in the context of transfers.
*/
function _approve(address to, uint256 tokenId, address auth, bool emitEvent) internal virtual {
// Avoid reading the owner unless necessary
if (emitEvent || auth != address(0)) {
address owner = _requireOwned(tokenId);
// We do not use _isAuthorized because single-token approvals should not be able to call approve
if (auth != address(0) && owner != auth && !isApprovedForAll(owner, auth)) {
revert ERC721InvalidApprover(auth);
}
if (emitEvent) {
emit Approval(owner, to, tokenId);
}
}
_tokenApprovals[tokenId] = to;
}
/**
* @dev Approve `operator` to operate on all of `owner` tokens
*
* Requirements:
* - operator can't be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function _setApprovalForAll(address owner, address operator, bool approved) internal virtual {
if (operator == address(0)) {
revert ERC721InvalidOperator(operator);
}
_operatorApprovals[owner][operator] = approved;
emit ApprovalForAll(owner, operator, approved);
}
/**
* @dev Reverts if the `tokenId` doesn't have a current owner (it hasn't been minted, or it has been burned).
* Returns the owner.
*
* Overrides to ownership logic should be done to {_ownerOf}.
*/
function _requireOwned(uint256 tokenId) internal view returns (address) {
address owner = _ownerOf(tokenId);
if (owner == address(0)) {
revert ERC721NonexistentToken(tokenId);
}
return owner;
}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target address. This will revert if the
* recipient doesn't accept the token transfer. The call is not executed if the target address is not a contract.
*
* @param from address representing the previous owner of the given token ID
* @param to target address that will receive the tokens
* @param tokenId uint256 ID of the token to be transferred
* @param data bytes optional data to send along with the call
*/
function _checkOnERC721Received(address from, address to, uint256 tokenId, bytes memory data) private {
if (to.code.length > 0) {
try IERC721Receiver(to).onERC721Received(_msgSender(), from, tokenId, data) returns (bytes4 retval) {
if (retval != IERC721Receiver.onERC721Received.selector) {
revert ERC721InvalidReceiver(to);
}
} catch (bytes memory reason) {
if (reason.length == 0) {
revert ERC721InvalidReceiver(to);
} else {
/// @solidity memory-safe-assembly
assembly {
revert(add(32, reason), mload(reason))
}
}
}
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/ERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {ERC721} from "../ERC721.sol";
import {IERC721Enumerable} from "./IERC721Enumerable.sol";
import {IERC165} from "../../../utils/introspection/ERC165.sol";
/**
* @dev This implements an optional extension of {ERC721} defined in the EIP that adds enumerability
* of all the token ids in the contract as well as all token ids owned by each account.
*
* CAUTION: `ERC721` extensions that implement custom `balanceOf` logic, such as `ERC721Consecutive`,
* interfere with enumerability and should not be used together with `ERC721Enumerable`.
*/
abstract contract ERC721Enumerable is ERC721, IERC721Enumerable {
mapping(address owner => mapping(uint256 index => uint256)) private _ownedTokens;
mapping(uint256 tokenId => uint256) private _ownedTokensIndex;
uint256[] private _allTokens;
mapping(uint256 tokenId => uint256) private _allTokensIndex;
/**
* @dev An `owner`'s token query was out of bounds for `index`.
*
* NOTE: The owner being `address(0)` indicates a global out of bounds index.
*/
error ERC721OutOfBoundsIndex(address owner, uint256 index);
/**
* @dev Batch mint is not allowed.
*/
error ERC721EnumerableForbiddenBatchMint();
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC721) returns (bool) {
return interfaceId == type(IERC721Enumerable).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @dev See {IERC721Enumerable-tokenOfOwnerByIndex}.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) public view virtual returns (uint256) {
if (index >= balanceOf(owner)) {
revert ERC721OutOfBoundsIndex(owner, index);
}
return _ownedTokens[owner][index];
}
/**
* @dev See {IERC721Enumerable-totalSupply}.
*/
function totalSupply() public view virtual returns (uint256) {
return _allTokens.length;
}
/**
* @dev See {IERC721Enumerable-tokenByIndex}.
*/
function tokenByIndex(uint256 index) public view virtual returns (uint256) {
if (index >= totalSupply()) {
revert ERC721OutOfBoundsIndex(address(0), index);
}
return _allTokens[index];
}
/**
* @dev See {ERC721-_update}.
*/
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
address previousOwner = super._update(to, tokenId, auth);
if (previousOwner == address(0)) {
_addTokenToAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_removeTokenFromOwnerEnumeration(previousOwner, tokenId);
}
if (to == address(0)) {
_removeTokenFromAllTokensEnumeration(tokenId);
} else if (previousOwner != to) {
_addTokenToOwnerEnumeration(to, tokenId);
}
return previousOwner;
}
/**
* @dev Private function to add a token to this extension's ownership-tracking data structures.
* @param to address representing the new owner of the given token ID
* @param tokenId uint256 ID of the token to be added to the tokens list of the given address
*/
function _addTokenToOwnerEnumeration(address to, uint256 tokenId) private {
uint256 length = balanceOf(to) - 1;
_ownedTokens[to][length] = tokenId;
_ownedTokensIndex[tokenId] = length;
}
/**
* @dev Private function to add a token to this extension's token tracking data structures.
* @param tokenId uint256 ID of the token to be added to the tokens list
*/
function _addTokenToAllTokensEnumeration(uint256 tokenId) private {
_allTokensIndex[tokenId] = _allTokens.length;
_allTokens.push(tokenId);
}
/**
* @dev Private function to remove a token from this extension's ownership-tracking data structures. Note that
* while the token is not assigned a new owner, the `_ownedTokensIndex` mapping is _not_ updated: this allows for
* gas optimizations e.g. when performing a transfer operation (avoiding double writes).
* This has O(1) time complexity, but alters the order of the _ownedTokens array.
* @param from address representing the previous owner of the given token ID
* @param tokenId uint256 ID of the token to be removed from the tokens list of the given address
*/
function _removeTokenFromOwnerEnumeration(address from, uint256 tokenId) private {
// To prevent a gap in from's tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = balanceOf(from);
uint256 tokenIndex = _ownedTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary
if (tokenIndex != lastTokenIndex) {
uint256 lastTokenId = _ownedTokens[from][lastTokenIndex];
_ownedTokens[from][tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_ownedTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
}
// This also deletes the contents at the last position of the array
delete _ownedTokensIndex[tokenId];
delete _ownedTokens[from][lastTokenIndex];
}
/**
* @dev Private function to remove a token from this extension's token tracking data structures.
* This has O(1) time complexity, but alters the order of the _allTokens array.
* @param tokenId uint256 ID of the token to be removed from the tokens list
*/
function _removeTokenFromAllTokensEnumeration(uint256 tokenId) private {
// To prevent a gap in the tokens array, we store the last token in the index of the token to delete, and
// then delete the last slot (swap and pop).
uint256 lastTokenIndex = _allTokens.length - 1;
uint256 tokenIndex = _allTokensIndex[tokenId];
// When the token to delete is the last token, the swap operation is unnecessary. However, since this occurs so
// rarely (when the last minted token is burnt) that we still do the swap here to avoid the gas cost of adding
// an 'if' statement (like in _removeTokenFromOwnerEnumeration)
uint256 lastTokenId = _allTokens[lastTokenIndex];
_allTokens[tokenIndex] = lastTokenId; // Move the last token to the slot of the to-delete token
_allTokensIndex[lastTokenId] = tokenIndex; // Update the moved token's index
// This also deletes the contents at the last position of the array
delete _allTokensIndex[tokenId];
_allTokens.pop();
}
/**
* See {ERC721-_increaseBalance}. We need that to account tokens that were minted in batch
*/
function _increaseBalance(address account, uint128 amount) internal virtual override {
if (amount > 0) {
revert ERC721EnumerableForbiddenBatchMint();
}
super._increaseBalance(account, amount);
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Enumerable.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional enumeration extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Enumerable is IERC721 {
/**
* @dev Returns the total amount of tokens stored by the contract.
*/
function totalSupply() external view returns (uint256);
/**
* @dev Returns a token ID owned by `owner` at a given `index` of its token list.
* Use along with {balanceOf} to enumerate all of ``owner``'s tokens.
*/
function tokenOfOwnerByIndex(address owner, uint256 index) external view returns (uint256);
/**
* @dev Returns a token ID at a given `index` of all the tokens stored by the contract.
* Use along with {totalSupply} to enumerate all tokens.
*/
function tokenByIndex(uint256 index) external view returns (uint256);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/extensions/IERC721Metadata.sol)
pragma solidity ^0.8.20;
import {IERC721} from "../IERC721.sol";
/**
* @title ERC-721 Non-Fungible Token Standard, optional metadata extension
* @dev See https://eips.ethereum.org/EIPS/eip-721
*/
interface IERC721Metadata is IERC721 {
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721.sol)
pragma solidity ^0.8.20;
import {IERC165} from "../../utils/introspection/IERC165.sol";
/**
* @dev Required interface of an ERC721 compliant contract.
*/
interface IERC721 is IERC165 {
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in ``owner``'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
* - 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 tokenId, bytes calldata data) external;
/**
* @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
* are aware of the ERC721 protocol to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must have been allowed to move this token by either {approve} or
* {setApprovalForAll}.
* - 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 tokenId) external;
/**
* @dev Transfers `tokenId` token from `from` to `to`.
*
* WARNING: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
* or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
* understand this adds an external call which potentially creates a reentrancy vulnerability.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(address from, address to, uint256 tokenId) external;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the address zero.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (token/ERC721/IERC721Receiver.sol)
pragma solidity ^0.8.20;
/**
* @title ERC721 token receiver interface
* @dev Interface for any contract that wants to support safeTransfers
* from ERC721 asset contracts.
*/
interface IERC721Receiver {
/**
* @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
* by `operator` from `from`, this function is called.
*
* It must return its Solidity selector to confirm the token transfer.
* If any other value is returned or the interface is not implemented by the recipient, the transfer will be
* reverted.
*
* The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
*/
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol)
pragma solidity ^0.8.20;
/**
* @dev Provides information about the current execution context, including the
* sender of the transaction and its data. While these are generally available
* via msg.sender and msg.data, they should not be accessed in such a direct
* manner, since when dealing with meta-transactions the account sending and
* paying for execution may not be the actual sender (as far as an application
* is concerned).
*
* This contract is only required for intermediate, library-like contracts.
*/
abstract contract Context {
function _msgSender() internal view virtual returns (address) {
return msg.sender;
}
function _msgData() internal view virtual returns (bytes calldata) {
return msg.data;
}
function _contextSuffixLength() internal view virtual returns (uint256) {
return 0;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/ERC165.sol)
pragma solidity ^0.8.20;
import {IERC165} from "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/introspection/IERC165.sol)
pragma solidity ^0.8.20;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/Math.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard math utilities missing in the Solidity language.
*/
library Math {
/**
* @dev Muldiv operation overflow.
*/
error MathOverflowedMulDiv();
enum Rounding {
Floor, // Toward negative infinity
Ceil, // Toward positive infinity
Trunc, // Toward zero
Expand // Away from zero
}
/**
* @dev Returns the addition of two unsigned integers, with an overflow flag.
*/
function tryAdd(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
uint256 c = a + b;
if (c < a) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the subtraction of two unsigned integers, with an overflow flag.
*/
function trySub(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b > a) return (false, 0);
return (true, a - b);
}
}
/**
* @dev Returns the multiplication of two unsigned integers, with an overflow flag.
*/
function tryMul(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
// benefit is lost if 'b' is also tested.
// See: https://github.com/OpenZeppelin/openzeppelin-contracts/pull/522
if (a == 0) return (true, 0);
uint256 c = a * b;
if (c / a != b) return (false, 0);
return (true, c);
}
}
/**
* @dev Returns the division of two unsigned integers, with a division by zero flag.
*/
function tryDiv(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a / b);
}
}
/**
* @dev Returns the remainder of dividing two unsigned integers, with a division by zero flag.
*/
function tryMod(uint256 a, uint256 b) internal pure returns (bool, uint256) {
unchecked {
if (b == 0) return (false, 0);
return (true, a % b);
}
}
/**
* @dev Returns the largest of two numbers.
*/
function max(uint256 a, uint256 b) internal pure returns (uint256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two numbers.
*/
function min(uint256 a, uint256 b) internal pure returns (uint256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two numbers. The result is rounded towards
* zero.
*/
function average(uint256 a, uint256 b) internal pure returns (uint256) {
// (a + b) / 2 can overflow.
return (a & b) + (a ^ b) / 2;
}
/**
* @dev Returns the ceiling of the division of two numbers.
*
* This differs from standard division with `/` in that it rounds towards infinity instead
* of rounding towards zero.
*/
function ceilDiv(uint256 a, uint256 b) internal pure returns (uint256) {
if (b == 0) {
// Guarantee the same behavior as in a regular Solidity division.
return a / b;
}
// (a + b - 1) / b can overflow on addition, so we distribute.
return a == 0 ? 0 : (a - 1) / b + 1;
}
/**
* @notice Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
* denominator == 0.
* @dev Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
* Uniswap Labs also under MIT license.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
unchecked {
// 512-bit multiply [prod1 prod0] = x * y. Compute the product mod 2^256 and mod 2^256 - 1, then use
// use the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
// variables such that product = prod1 * 2^256 + prod0.
uint256 prod0 = x * y; // Least significant 256 bits of the product
uint256 prod1; // Most significant 256 bits of the product
assembly {
let mm := mulmod(x, y, not(0))
prod1 := sub(sub(mm, prod0), lt(mm, prod0))
}
// Handle non-overflow cases, 256 by 256 division.
if (prod1 == 0) {
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
// The surrounding unchecked block does not change this fact.
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
return prod0 / denominator;
}
// Make sure the result is less than 2^256. Also prevents denominator == 0.
if (denominator <= prod1) {
revert MathOverflowedMulDiv();
}
///////////////////////////////////////////////
// 512 by 256 division.
///////////////////////////////////////////////
// Make division exact by subtracting the remainder from [prod1 prod0].
uint256 remainder;
assembly {
// Compute remainder using mulmod.
remainder := mulmod(x, y, denominator)
// Subtract 256 bit number from 512 bit number.
prod1 := sub(prod1, gt(remainder, prod0))
prod0 := sub(prod0, remainder)
}
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
uint256 twos = denominator & (0 - denominator);
assembly {
// Divide denominator by twos.
denominator := div(denominator, twos)
// Divide [prod1 prod0] by twos.
prod0 := div(prod0, twos)
// Flip twos such that it is 2^256 / twos. If twos is zero, then it becomes one.
twos := add(div(sub(0, twos), twos), 1)
}
// Shift in bits from prod1 into prod0.
prod0 |= prod1 * twos;
// Invert denominator mod 2^256. Now that denominator is an odd number, it has an inverse modulo 2^256 such
// that denominator * inv = 1 mod 2^256. Compute the inverse by starting with a seed that is correct for
// four bits. That is, denominator * inv = 1 mod 2^4.
uint256 inverse = (3 * denominator) ^ 2;
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
// works in modular arithmetic, doubling the correct bits in each step.
inverse *= 2 - denominator * inverse; // inverse mod 2^8
inverse *= 2 - denominator * inverse; // inverse mod 2^16
inverse *= 2 - denominator * inverse; // inverse mod 2^32
inverse *= 2 - denominator * inverse; // inverse mod 2^64
inverse *= 2 - denominator * inverse; // inverse mod 2^128
inverse *= 2 - denominator * inverse; // inverse mod 2^256
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
// This will give us the correct result modulo 2^256. Since the preconditions guarantee that the outcome is
// less than 2^256, this is the final result. We don't need to compute the high bits of the result and prod1
// is no longer required.
result = prod0 * inverse;
return result;
}
}
/**
* @notice Calculates x * y / denominator with full precision, following the selected rounding direction.
*/
function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
uint256 result = mulDiv(x, y, denominator);
if (unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0) {
result += 1;
}
return result;
}
/**
* @dev Returns the square root of a number. If the number is not a perfect square, the value is rounded
* towards zero.
*
* Inspired by Henry S. Warren, Jr.'s "Hacker's Delight" (Chapter 11).
*/
function sqrt(uint256 a) internal pure returns (uint256) {
if (a == 0) {
return 0;
}
// For our first guess, we get the biggest power of 2 which is smaller than the square root of the target.
//
// We know that the "msb" (most significant bit) of our target number `a` is a power of 2 such that we have
// `msb(a) <= a < 2*msb(a)`. This value can be written `msb(a)=2**k` with `k=log2(a)`.
//
// This can be rewritten `2**log2(a) <= a < 2**(log2(a) + 1)`
// → `sqrt(2**k) <= sqrt(a) < sqrt(2**(k+1))`
// → `2**(k/2) <= sqrt(a) < 2**((k+1)/2) <= 2**(k/2 + 1)`
//
// Consequently, `2**(log2(a) / 2)` is a good first approximation of `sqrt(a)` with at least 1 correct bit.
uint256 result = 1 << (log2(a) >> 1);
// At this point `result` is an estimation with one bit of precision. We know the true value is a uint128,
// since it is the square root of a uint256. Newton's method converges quadratically (precision doubles at
// every iteration). We thus need at most 7 iteration to turn our partial result with one bit of precision
// into the expected uint128 result.
unchecked {
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
result = (result + a / result) >> 1;
return min(result, a / result);
}
}
/**
* @notice Calculates sqrt(a), following the selected rounding direction.
*/
function sqrt(uint256 a, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = sqrt(a);
return result + (unsignedRoundsUp(rounding) && result * result < a ? 1 : 0);
}
}
/**
* @dev Return the log in base 2 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log2(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 128;
}
if (value >> 64 > 0) {
value >>= 64;
result += 64;
}
if (value >> 32 > 0) {
value >>= 32;
result += 32;
}
if (value >> 16 > 0) {
value >>= 16;
result += 16;
}
if (value >> 8 > 0) {
value >>= 8;
result += 8;
}
if (value >> 4 > 0) {
value >>= 4;
result += 4;
}
if (value >> 2 > 0) {
value >>= 2;
result += 2;
}
if (value >> 1 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 2, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log2(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log2(value);
return result + (unsignedRoundsUp(rounding) && 1 << result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 10 of a positive value rounded towards zero.
* Returns 0 if given 0.
*/
function log10(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >= 10 ** 64) {
value /= 10 ** 64;
result += 64;
}
if (value >= 10 ** 32) {
value /= 10 ** 32;
result += 32;
}
if (value >= 10 ** 16) {
value /= 10 ** 16;
result += 16;
}
if (value >= 10 ** 8) {
value /= 10 ** 8;
result += 8;
}
if (value >= 10 ** 4) {
value /= 10 ** 4;
result += 4;
}
if (value >= 10 ** 2) {
value /= 10 ** 2;
result += 2;
}
if (value >= 10 ** 1) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 10, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log10(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log10(value);
return result + (unsignedRoundsUp(rounding) && 10 ** result < value ? 1 : 0);
}
}
/**
* @dev Return the log in base 256 of a positive value rounded towards zero.
* Returns 0 if given 0.
*
* Adding one to the result gives the number of pairs of hex symbols needed to represent `value` as a hex string.
*/
function log256(uint256 value) internal pure returns (uint256) {
uint256 result = 0;
unchecked {
if (value >> 128 > 0) {
value >>= 128;
result += 16;
}
if (value >> 64 > 0) {
value >>= 64;
result += 8;
}
if (value >> 32 > 0) {
value >>= 32;
result += 4;
}
if (value >> 16 > 0) {
value >>= 16;
result += 2;
}
if (value >> 8 > 0) {
result += 1;
}
}
return result;
}
/**
* @dev Return the log in base 256, following the selected rounding direction, of a positive value.
* Returns 0 if given 0.
*/
function log256(uint256 value, Rounding rounding) internal pure returns (uint256) {
unchecked {
uint256 result = log256(value);
return result + (unsignedRoundsUp(rounding) && 1 << (result << 3) < value ? 1 : 0);
}
}
/**
* @dev Returns whether a provided rounding mode is considered rounding up for unsigned integers.
*/
function unsignedRoundsUp(Rounding rounding) internal pure returns (bool) {
return uint8(rounding) % 2 == 1;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/math/SignedMath.sol)
pragma solidity ^0.8.20;
/**
* @dev Standard signed math utilities missing in the Solidity language.
*/
library SignedMath {
/**
* @dev Returns the largest of two signed numbers.
*/
function max(int256 a, int256 b) internal pure returns (int256) {
return a > b ? a : b;
}
/**
* @dev Returns the smallest of two signed numbers.
*/
function min(int256 a, int256 b) internal pure returns (int256) {
return a < b ? a : b;
}
/**
* @dev Returns the average of two signed numbers without overflow.
* The result is rounded towards zero.
*/
function average(int256 a, int256 b) internal pure returns (int256) {
// Formula from the book "Hacker's Delight"
int256 x = (a & b) + ((a ^ b) >> 1);
return x + (int256(uint256(x) >> 255) & (a ^ b));
}
/**
* @dev Returns the absolute unsigned value of a signed value.
*/
function abs(int256 n) internal pure returns (uint256) {
unchecked {
// must be unchecked in order to support `n = type(int256).min`
return uint256(n >= 0 ? n : -n);
}
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.0.0) (utils/Strings.sol)
pragma solidity ^0.8.20;
import {Math} from "./math/Math.sol";
import {SignedMath} from "./math/SignedMath.sol";
/**
* @dev String operations.
*/
library Strings {
bytes16 private constant HEX_DIGITS = "0123456789abcdef";
uint8 private constant ADDRESS_LENGTH = 20;
/**
* @dev The `value` string doesn't fit in the specified `length`.
*/
error StringsInsufficientHexLength(uint256 value, uint256 length);
/**
* @dev Converts a `uint256` to its ASCII `string` decimal representation.
*/
function toString(uint256 value) internal pure returns (string memory) {
unchecked {
uint256 length = Math.log10(value) + 1;
string memory buffer = new string(length);
uint256 ptr;
/// @solidity memory-safe-assembly
assembly {
ptr := add(buffer, add(32, length))
}
while (true) {
ptr--;
/// @solidity memory-safe-assembly
assembly {
mstore8(ptr, byte(mod(value, 10), HEX_DIGITS))
}
value /= 10;
if (value == 0) break;
}
return buffer;
}
}
/**
* @dev Converts a `int256` to its ASCII `string` decimal representation.
*/
function toStringSigned(int256 value) internal pure returns (string memory) {
return string.concat(value < 0 ? "-" : "", toString(SignedMath.abs(value)));
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation.
*/
function toHexString(uint256 value) internal pure returns (string memory) {
unchecked {
return toHexString(value, Math.log256(value) + 1);
}
}
/**
* @dev Converts a `uint256` to its ASCII `string` hexadecimal representation with fixed length.
*/
function toHexString(uint256 value, uint256 length) internal pure returns (string memory) {
uint256 localValue = value;
bytes memory buffer = new bytes(2 * length + 2);
buffer[0] = "0";
buffer[1] = "x";
for (uint256 i = 2 * length + 1; i > 1; --i) {
buffer[i] = HEX_DIGITS[localValue & 0xf];
localValue >>= 4;
}
if (localValue != 0) {
revert StringsInsufficientHexLength(value, length);
}
return string(buffer);
}
/**
* @dev Converts an `address` with fixed length of 20 bytes to its not checksummed ASCII `string` hexadecimal
* representation.
*/
function toHexString(address addr) internal pure returns (string memory) {
return toHexString(uint256(uint160(addr)), ADDRESS_LENGTH);
}
/**
* @dev Returns true if the two strings are equal.
*/
function equal(string memory a, string memory b) internal pure returns (bool) {
return bytes(a).length == bytes(b).length && keccak256(bytes(a)) == keccak256(bytes(b));
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
import {IMetadataRenderer} from '../interfaces/IMetadataRenderer.sol';
/**
________ _____ ____ ______ ____
/\_____ \ /\ __`\/\ _`\ /\ _ \ /\ _`\
\/____//'/'\ \ \/\ \ \ \L\ \ \ \L\ \ \ \ \/\ \ _ __ ___ _____ ____
//'/' \ \ \ \ \ \ , /\ \ __ \ \ \ \ \ \/\`'__\/ __`\/\ '__`\ /',__\
//'/'___ \ \ \_\ \ \ \\ \\ \ \/\ \ \ \ \_\ \ \ \//\ \L\ \ \ \L\ \/\__, `\
/\_______\\ \_____\ \_\ \_\ \_\ \_\ \ \____/\ \_\\ \____/\ \ ,__/\/\____/
\/_______/ \/_____/\/_/\/ /\/_/\/_/ \/___/ \/_/ \/___/ \ \ \/ \/___/
\ \_\
\/_/
*/
/// @notice Interface for ZORA Drops contract
interface IERC721Drop {
// Access errors
/// @notice Only admin can access this function
error Access_OnlyAdmin();
/// @notice Missing the given role or admin access
error Access_MissingRoleOrAdmin(bytes32 role);
/// @notice Withdraw is not allowed by this user
error Access_WithdrawNotAllowed();
/// @notice Cannot withdraw funds due to ETH send failure.
error Withdraw_FundsSendFailure();
/// @notice Mint fee send failure
error MintFee_FundsSendFailure();
/// @notice Protocol Rewards withdraw failure
error ProtocolRewards_WithdrawSendFailure();
/// @notice Call to external metadata renderer failed.
error ExternalMetadataRenderer_CallFailed();
/// @notice Thrown when the operator for the contract is not allowed
/// @dev Used when strict enforcement of marketplaces for creator royalties is desired.
error OperatorNotAllowed(address operator);
/// @notice Thrown when there is no active market filter DAO address supported for the current chain
/// @dev Used for enabling and disabling filter for the given chain.
error MarketFilterDAOAddressNotSupportedForChain();
/// @notice Used when the operator filter registry external call fails
/// @dev Used for bubbling error up to clients.
error RemoteOperatorFilterRegistryCallFailed();
// Sale/Purchase errors
/// @notice Sale is inactive
error Sale_Inactive();
/// @notice Presale is inactive
error Presale_Inactive();
/// @notice Presale merkle root is invalid
error Presale_MerkleNotApproved();
/// @notice Wrong price for purchase
error Purchase_WrongPrice(uint256 correctPrice);
/// @notice NFT sold out
error Mint_SoldOut();
/// @notice Too many purchase for address
error Purchase_TooManyForAddress();
/// @notice Too many presale for address
error Presale_TooManyForAddress();
// Admin errors
/// @notice Royalty percentage too high
error Setup_RoyaltyPercentageTooHigh(uint16 maxRoyaltyBPS);
/// @notice Invalid admin upgrade address
error Admin_InvalidUpgradeAddress(address proposedAddress);
/// @notice Unable to finalize an edition not marked as open (size set to uint64_max_value)
error Admin_UnableToFinalizeNotOpenEdition();
/// @notice Cannot reserve every mint for admin
error InvalidMintSchedule();
/// @notice Event emitted for mint fee payout
/// @param mintFeeAmount amount of the mint fee
/// @param mintFeeRecipient recipient of the mint fee
/// @param success if the payout succeeded
event MintFeePayout(
uint256 mintFeeAmount,
address mintFeeRecipient,
bool success
);
/// @notice Event emitted for each sale
/// @param to address sale was made to
/// @param quantity quantity of the minted nfts
/// @param pricePerToken price for each token
/// @param firstPurchasedTokenId first purchased token ID (to get range add to quantity for max)
event Sale(
address indexed to,
uint256 indexed quantity,
uint256 indexed pricePerToken,
uint256 firstPurchasedTokenId
);
/// @notice Event emitted for each sale
/// @param sender address sale was made to
/// @param tokenContract address of the token contract
/// @param tokenId first purchased token ID (to get range add to quantity for max)
/// @param quantity quantity of the minted nfts
/// @param comment caller provided comment
event MintComment(
address indexed sender,
address indexed tokenContract,
uint256 indexed tokenId,
uint256 quantity,
string comment
);
/// @notice Sales configuration has been changed
/// @dev To access new sales configuration, use getter function.
/// @param changedBy Changed by user
event SalesConfigChanged(address indexed changedBy);
/// @notice Event emitted when the funds recipient is changed
/// @param newAddress new address for the funds recipient
/// @param changedBy address that the recipient is changed by
event FundsRecipientChanged(
address indexed newAddress,
address indexed changedBy
);
/// @notice Event emitted when the funds are withdrawn from the minting contract
/// @param withdrawnBy address that issued the withdraw
/// @param withdrawnTo address that the funds were withdrawn to
/// @param amount amount that was withdrawn
/// @param feeRecipient user getting withdraw fee (if any)
/// @param feeAmount amount of the fee getting sent (if any)
event FundsWithdrawn(
address indexed withdrawnBy,
address indexed withdrawnTo,
uint256 amount,
address feeRecipient,
uint256 feeAmount
);
/// @notice Event emitted when an open mint is finalized and further minting is closed forever on the contract.
/// @param sender address sending close mint
/// @param numberOfMints number of mints the contract is finalized at
event OpenMintFinalized(address indexed sender, uint256 numberOfMints);
/// @notice Event emitted when metadata renderer is updated.
/// @param sender address of the updater
/// @param renderer new metadata renderer address
event UpdatedMetadataRenderer(address sender, IMetadataRenderer renderer);
/// @notice Admin function to update the sales configuration settings
/// @param publicSalePrice public sale price in ether
/// @param maxSalePurchasePerAddress Max # of purchases (public) per address allowed
/// @param publicSaleStart unix timestamp when the public sale starts
/// @param publicSaleEnd unix timestamp when the public sale ends (set to 0 to disable)
/// @param presaleStart unix timestamp when the presale starts
/// @param presaleEnd unix timestamp when the presale ends
/// @param presaleMerkleRoot merkle root for the presale information
function setSaleConfiguration(
uint104 publicSalePrice,
uint32 maxSalePurchasePerAddress,
uint64 publicSaleStart,
uint64 publicSaleEnd,
uint64 presaleStart,
uint64 presaleEnd,
bytes32 presaleMerkleRoot
) external;
/// @notice General configuration for NFT Minting and bookkeeping
struct Configuration {
/// @dev Metadata renderer (uint160)
IMetadataRenderer metadataRenderer;
/// @dev Total size of edition that can be minted (uint160+64 = 224)
uint64 editionSize;
/// @dev Royalty amount in bps (uint224+16 = 240)
uint16 royaltyBPS;
/// @dev Funds recipient for sale (new slot, uint160)
address payable fundsRecipient;
}
/// @notice Sales states and configuration
/// @dev Uses 3 storage slots
struct SalesConfiguration {
/// @dev Public sale price (max ether value > 1000 ether with this value)
uint104 publicSalePrice;
/// @notice Purchase mint limit per address (if set to 0 === unlimited mints)
/// @dev Max purchase number per txn (90+32 = 122)
uint32 maxSalePurchasePerAddress;
/// @dev uint64 type allows for dates into 292 billion years
/// @notice Public sale start timestamp (136+64 = 186)
uint64 publicSaleStart;
/// @notice Public sale end timestamp (186+64 = 250)
uint64 publicSaleEnd;
/// @notice Presale start timestamp
/// @dev new storage slot
uint64 presaleStart;
/// @notice Presale end timestamp
uint64 presaleEnd;
/// @notice Presale merkle root
bytes32 presaleMerkleRoot;
}
/// @notice Return value for sales details to use with front-ends
struct SaleDetails {
// Synthesized status variables for sale and presale
bool publicSaleActive;
bool presaleActive;
// Price for public sale
uint256 publicSalePrice;
// Timed sale actions for public sale
uint64 publicSaleStart;
uint64 publicSaleEnd;
// Timed sale actions for presale
uint64 presaleStart;
uint64 presaleEnd;
// Merkle root (includes address, quantity, and price data for each entry)
bytes32 presaleMerkleRoot;
// Limit public sale to a specific number of mints per wallet
uint256 maxSalePurchasePerAddress;
// Information about the rest of the supply
// Total that have been minted
uint256 totalMinted;
// The total supply available
uint256 maxSupply;
}
/// @notice Return type of specific mint counts and details per address
struct AddressMintDetails {
/// Number of total mints from the given address
uint256 totalMints;
/// Number of presale mints from the given address
uint256 presaleMints;
/// Number of public mints from the given address
uint256 publicMints;
}
/// @notice External purchase function (payable in eth)
/// @param quantity to purchase
/// @return first minted token ID
function purchase(uint256 quantity) external payable returns (uint256);
/// @notice External purchase presale function (takes a merkle proof and matches to root) (payable in eth)
/// @param quantity to purchase
/// @param maxQuantity can purchase (verified by merkle root)
/// @param pricePerToken price per token allowed (verified by merkle root)
/// @param merkleProof input for merkle proof leaf verified by merkle root
/// @return first minted token ID
function purchasePresale(
uint256 quantity,
uint256 maxQuantity,
uint256 pricePerToken,
bytes32[] memory merkleProof
) external payable returns (uint256);
/// @notice Function to return the global sales details for the given drop
function saleDetails() external view returns (SaleDetails memory);
/// @notice Function to return the specific sales details for a given address
/// @param minter address for minter to return mint information for
function mintedPerAddress(
address minter
) external view returns (AddressMintDetails memory);
/// @notice This is the opensea/public owner setting that can be set by the contract admin
function owner() external view returns (address);
/// @notice Update the metadata renderer
/// @param newRenderer new address for renderer
/// @param setupRenderer data to call to bootstrap data for the new renderer (optional)
function setMetadataRenderer(
IMetadataRenderer newRenderer,
bytes memory setupRenderer
) external;
/// @notice This is an admin mint function to mint a quantity to a specific address
/// @param to address to mint to
/// @param quantity quantity to mint
/// @return the id of the first minted NFT
function adminMint(address to, uint256 quantity) external returns (uint256);
/// @notice This is an admin mint function to mint a single nft each to a list of addresses
/// @param to list of addresses to mint an NFT each to
/// @return the id of the first minted NFT
function adminMintAirdrop(address[] memory to) external returns (uint256);
/// @dev Getter for admin role associated with the contract to handle metadata
/// @return boolean if address is admin
function isAdmin(address user) external view returns (bool);
/// @notice added this manually to the interface to support this function
function finalizeOpenEdition() external;
/// @notice added this manually to the interface to support this function
function ownerOf(uint256 tokenId) external view returns (address);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.10;
interface IMetadataRenderer {
function tokenURI(uint256) external view returns (string memory);
function contractURI() external view returns (string memory);
function initializeWithData(bytes memory initData) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
interface IZorbitArt {
function zorbCoords() external view returns (uint8[] memory, uint8[] memory);
function emptyZorb() external view returns (string memory);
function colorsForHash(
bytes32 blockHash
) external pure returns (bytes[4] memory);
function colorsForAddress(
address addr
) external pure returns (bytes[4] memory);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/utils/Strings.sol';
import './Utilities.sol';
// modified from zora's original zorb art contract 0xCa21d4228cDCc68D4e23807E5e370C07577Dd152
/**
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBB#RROOOOOOOOOOOOOOORR#BBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBROOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZOORBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BB#ROOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZORB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@B#ROOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZORB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@BBRRROOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZO#@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@B#RRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZRB@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@B#RRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOB@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@B#RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOB@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@B#RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZRB@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@B###RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZ#@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@BB####RRRRRRRROOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZO@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@BB#####RRRRRRRROOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOB@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@BB######RRRRRRRROOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZO#@@@@@@@@@@@@@@@
@@@@@@@@@@@@BBB######RRRRRRRROOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZO#@@@@@@@@@@@@@@
@@@@@@@@@@@BBBBB#####RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZR@@@@@@@@@@@@@
@@@@@@@@@@BBBBBB#####RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZO#@@@@@@@@@@@@
@@@@@@@@@BBBBBBB#####RRRRRRRRROOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOB@@@@@@@@@@@
@@@@@@@@BBBBBBBB######RRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOB@@@@@@@@@@
@@@@@@@@BBBBBBBBB#####RRRRRRRRROOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOR@@@@@@@@@@
@@@@@@@BBBBBBBBBB######RRRRRRRROOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOB@@@@@@@@@
@@@@@@@BBBBBBBBBBB#####RRRRRRRRROOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOR@@@@@@@@@
@@@@@@@BBBBBBBBBBB######RRRRRRRRROOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOB@@@@@@@@
@@@@@@BBBBBBBBBBBBB######RRRRRRRRROOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOB@@@@@@@@
@@@@@@BBBBBBBBBBBBBB######RRRRRRRRROOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOOO#@@@@@@@@
@@@@@@BBBBBBBBBBBBBBB######RRRRRRRRROOOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOOOOO#@@@@@@@@
@@@@@@BBBBBBBBBBBBBBB######RRRRRRRRRROOOOOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOOOOOOOR@@@@@@@@
@@@@@@BBBBBBBBBBBBBBBB#######RRRRRRRRRROOOOOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOOOOOOOOOO#@@@@@@@@
@@@@@@BBBBBBBBBBBBBBBBB#######RRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZZOOOOOOOOOOOOOOOOOOOO#@@@@@@@@
@@@@@@BBBBBBBBBBBBBBBBBBB######RRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOZZZZZZZZZZZZZZZZZZZZOOOOOOOOOOOOOOOOOOOOOOOOORB@@@@@@@@
@@@@@@BBBBBBBBBBBBBBBBBBBB#######RRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORB@@@@@@@@
@@@@@@@BBBBBBBBBBBBBBBBBBBBB#######RRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORRRR@@@@@@@@@
@@@@@@@BBBBBBBBBBBBBBBBBBBBBB########RRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORRRRRB@@@@@@@@@
@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBB########RRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORRRRRRR#@@@@@@@@@@
@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBB########RRRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORRRRRRRRRRB@@@@@@@@@@
@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBB########RRRRRRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOORRRRRRRRRRRRRRB@@@@@@@@@@@
@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBB#########RRRRRRRRRRRRRRRRRRROOOOOOOOOOOOOOOOOOOOOOOOOORRRRRRRRRRRRRRRRRR##@@@@@@@@@@@@
@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBB#########RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR###B@@@@@@@@@@@@
@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB###########RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR######B@@@@@@@@@@@@@
@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB#############RRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRRR########BB@@@@@@@@@@@@@@
@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB###############RRRRRRRRRRRRRRRRRRRRRRRRRRR#############BB@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB#################################################BBB@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB#######################################BBBBBBB@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB########################BBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@BBBBBBBBBBBBBBBBBBBBBBBBBBBB@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
*/
/// Color lib is a custom library for handling the math functions required to generate the gradient step colors
/// Originally written in javascript, this is a solidity port.
library ColorLib {
using Strings for string;
struct HSL {
uint256 h;
uint256 s;
uint256 l;
}
/// Lookup table for cubicinout range 0-99
function cubicInOut(uint16 p) internal pure returns (int256) {
if (p < 13) {
return 0;
}
if (p < 17) {
return 1;
}
if (p < 19) {
return 2;
}
if (p < 21) {
return 3;
}
if (p < 23) {
return 4;
}
if (p < 24) {
return 5;
}
if (p < 25) {
return 6;
}
if (p < 27) {
return 7;
}
if (p < 28) {
return 8;
}
if (p < 29) {
return 9;
}
if (p < 30) {
return 10;
}
if (p < 31) {
return 11;
}
if (p < 32) {
return 13;
}
if (p < 33) {
return 14;
}
if (p < 34) {
return 15;
}
if (p < 35) {
return 17;
}
if (p < 36) {
return 18;
}
if (p < 37) {
return 20;
}
if (p < 38) {
return 21;
}
if (p < 39) {
return 23;
}
if (p < 40) {
return 25;
}
if (p < 41) {
return 27;
}
if (p < 42) {
return 29;
}
if (p < 43) {
return 31;
}
if (p < 44) {
return 34;
}
if (p < 45) {
return 36;
}
if (p < 46) {
return 38;
}
if (p < 47) {
return 41;
}
if (p < 48) {
return 44;
}
if (p < 49) {
return 47;
}
if (p < 50) {
return 50;
}
if (p < 51) {
return 52;
}
if (p < 52) {
return 55;
}
if (p < 53) {
return 58;
}
if (p < 54) {
return 61;
}
if (p < 55) {
return 63;
}
if (p < 56) {
return 65;
}
if (p < 57) {
return 68;
}
if (p < 58) {
return 70;
}
if (p < 59) {
return 72;
}
if (p < 60) {
return 74;
}
if (p < 61) {
return 76;
}
if (p < 62) {
return 78;
}
if (p < 63) {
return 79;
}
if (p < 64) {
return 81;
}
if (p < 65) {
return 82;
}
if (p < 66) {
return 84;
}
if (p < 67) {
return 85;
}
if (p < 68) {
return 86;
}
if (p < 69) {
return 88;
}
if (p < 70) {
return 89;
}
if (p < 71) {
return 90;
}
if (p < 72) {
return 91;
}
if (p < 74) {
return 92;
}
if (p < 75) {
return 93;
}
if (p < 76) {
return 94;
}
if (p < 78) {
return 95;
}
if (p < 80) {
return 96;
}
if (p < 82) {
return 97;
}
if (p < 86) {
return 98;
}
return 99;
}
/// Lookup table for cubicid range 0-99
function cubicIn(uint256 p) internal pure returns (uint8) {
if (p < 22) {
return 0;
}
if (p < 28) {
return 1;
}
if (p < 32) {
return 2;
}
if (p < 32) {
return 3;
}
if (p < 34) {
return 3;
}
if (p < 36) {
return 4;
}
if (p < 39) {
return 5;
}
if (p < 41) {
return 6;
}
if (p < 43) {
return 7;
}
if (p < 46) {
return 9;
}
if (p < 47) {
return 10;
}
if (p < 49) {
return 11;
}
if (p < 50) {
return 12;
}
if (p < 51) {
return 13;
}
if (p < 53) {
return 14;
}
if (p < 54) {
return 15;
}
if (p < 55) {
return 16;
}
if (p < 56) {
return 17;
}
if (p < 57) {
return 18;
}
if (p < 58) {
return 19;
}
if (p < 59) {
return 20;
}
if (p < 60) {
return 21;
}
if (p < 61) {
return 22;
}
if (p < 62) {
return 23;
}
if (p < 63) {
return 25;
}
if (p < 64) {
return 26;
}
if (p < 65) {
return 27;
}
if (p < 66) {
return 28;
}
if (p < 67) {
return 30;
}
if (p < 68) {
return 31;
}
if (p < 69) {
return 32;
}
if (p < 70) {
return 34;
}
if (p < 71) {
return 35;
}
if (p < 72) {
return 37;
}
if (p < 73) {
return 38;
}
if (p < 74) {
return 40;
}
if (p < 75) {
return 42;
}
if (p < 76) {
return 43;
}
if (p < 77) {
return 45;
}
if (p < 78) {
return 47;
}
if (p < 79) {
return 49;
}
if (p < 80) {
return 51;
}
if (p < 81) {
return 53;
}
if (p < 82) {
return 55;
}
if (p < 83) {
return 57;
}
if (p < 84) {
return 59;
}
if (p < 85) {
return 61;
}
if (p < 86) {
return 63;
}
if (p < 87) {
return 65;
}
if (p < 88) {
return 68;
}
if (p < 89) {
return 70;
}
if (p < 90) {
return 72;
}
if (p < 91) {
return 75;
}
if (p < 92) {
return 77;
}
if (p < 93) {
return 80;
}
if (p < 94) {
return 83;
}
if (p < 95) {
return 85;
}
if (p < 96) {
return 88;
}
if (p < 97) {
return 91;
}
if (p < 98) {
return 94;
}
return 97;
}
/// Lookup table for quintin range 0-99
function quintIn(uint256 p) internal pure returns (uint8) {
if (p < 39) {
return 0;
}
if (p < 45) {
return 1;
}
if (p < 49) {
return 2;
}
if (p < 52) {
return 3;
}
if (p < 53) {
return 4;
}
if (p < 54) {
return 4;
}
if (p < 55) {
return 5;
}
if (p < 56) {
return 5;
}
if (p < 57) {
return 6;
}
if (p < 58) {
return 6;
}
if (p < 59) {
return 7;
}
if (p < 60) {
return 7;
}
if (p < 61) {
return 8;
}
if (p < 62) {
return 9;
}
if (p < 63) {
return 9;
}
if (p < 64) {
return 10;
}
if (p < 65) {
return 11;
}
if (p < 66) {
return 12;
}
if (p < 67) {
return 13;
}
if (p < 68) {
return 14;
}
if (p < 69) {
return 15;
}
if (p < 70) {
return 16;
}
if (p < 71) {
return 18;
}
if (p < 72) {
return 19;
}
if (p < 73) {
return 20;
}
if (p < 74) {
return 22;
}
if (p < 75) {
return 23;
}
if (p < 76) {
return 25;
}
if (p < 77) {
return 27;
}
if (p < 78) {
return 28;
}
if (p < 79) {
return 30;
}
if (p < 80) {
return 32;
}
if (p < 81) {
return 34;
}
if (p < 82) {
return 37;
}
if (p < 83) {
return 39;
}
if (p < 84) {
return 41;
}
if (p < 85) {
return 44;
}
if (p < 86) {
return 47;
}
if (p < 87) {
return 49;
}
if (p < 88) {
return 52;
}
if (p < 89) {
return 55;
}
if (p < 90) {
return 59;
}
if (p < 91) {
return 62;
}
if (p < 92) {
return 65;
}
if (p < 93) {
return 69;
}
if (p < 94) {
return 73;
}
if (p < 95) {
return 77;
}
if (p < 96) {
return 81;
}
if (p < 97) {
return 85;
}
if (p < 98) {
return 90;
}
return 95;
}
// Util for keeping hue range in 0-360 positive
function clampHue(int256 h) internal pure returns (uint256) {
unchecked {
h /= 100;
if (h >= 0) {
return uint256(h) % 360;
} else {
return (uint256(-1 * h) % 360);
}
}
}
/// find hue within range
function lerpHue(
uint8 optionNum,
uint256 direction,
uint256 uhue,
uint8 pct
) internal pure returns (uint256) {
uint256 option = optionNum % 4;
int256 hue = int256(uhue);
if (option == 0) {
return
clampHue(
(((100 - int256(uint256(pct))) * hue) +
(int256(uint256(pct)) * (direction == 0 ? hue - 0 : hue + 10)))
);
}
if (option == 1) {
return
clampHue(
(((100 - int256(uint256(pct))) * hue) +
(int256(uint256(pct)) * (direction == 0 ? hue - 30 : hue + 30)))
);
}
if (option == 2) {
return
clampHue(
(
(((100 - cubicInOut(pct)) * hue) +
(cubicInOut(pct) * (direction == 0 ? hue - 50 : hue + 50)))
)
);
}
return
clampHue(
((100 - cubicInOut(pct)) * hue) +
(cubicInOut(pct) *
int256(
hue +
((direction == 0 ? int256(-60) : int256(60)) *
int256(uint256(optionNum > 128 ? 1 : 0))) +
30
))
);
}
/// find lightness within range
function lerpLightness(
uint8 optionNum,
uint256 start,
uint256 end,
uint256 pct
) internal pure returns (uint256) {
uint256 lerpPercent;
if (optionNum == 0) {
lerpPercent = quintIn(pct);
} else {
lerpPercent = cubicIn(pct);
}
return 1 + (((100.0 - lerpPercent) * start + (lerpPercent * end)) / 100);
}
/// find saturation within range
function lerpSaturation(
uint8 optionNum,
uint256 start,
uint256 end,
uint256 pct
) internal pure returns (uint256) {
unchecked {
uint256 lerpPercent;
if (optionNum == 0) {
lerpPercent = quintIn(pct);
return 1 + (((100.0 - lerpPercent) * start + lerpPercent * end) / 100);
}
lerpPercent = pct;
return ((100.0 - lerpPercent) * start + lerpPercent * end) / 100;
}
}
/// encode a color string
function encodeStr(
uint256 h,
uint256 s,
uint256 l
) internal pure returns (bytes memory) {
return
abi.encodePacked(
'hsl(',
Strings.toString(h),
', ',
Strings.toString(s),
'%, ',
Strings.toString(l),
'%)'
);
}
function gradientForZeroAddress() internal pure returns (bytes[4] memory) {
return [
encodeStr(0, 0, 15),
encodeStr(0, 0, 25),
encodeStr(0, 0, 60),
encodeStr(0, 0, 90)
];
}
/// get gradient color strings for the given addresss
function gradientForAddress(
address addr
) internal pure returns (bytes[4] memory) {
unchecked {
if (addr == address(0)) {
return gradientForZeroAddress();
}
uint8 addrInt = uint8(uint160(addr)) % 255;
bytes32 addrBytes = bytes32(uint256(uint160(addr)));
uint256 startHue = Utilities.selectRandomInRange(
1,
359,
Strings.toString(uint8(addrBytes[31 - 12]))
);
uint256 hueRange = (addrInt % 25) + 1;
return buildGradient(addrInt, startHue, hueRange);
}
}
function defineMinMaxSL(
uint256 addrInt
) internal pure returns (uint8[4] memory) {
uint8 minSaturation = uint8(
Utilities.selectRandomInRange(
8,
50,
Strings.toString(uint8(addrInt % 255))
)
);
uint8 maxSaturation = uint8(
Utilities.selectRandomInRange(
minSaturation,
100,
Strings.toString(uint8(addrInt % 255))
)
);
uint8 minBrightness = uint8(
Utilities.selectRandomInRange(
10,
20,
Strings.toString(uint8(addrInt % 255))
)
);
uint8 maxBrightness = uint8(
Utilities.selectRandomInRange(
minBrightness,
100,
Strings.toString(uint8(addrInt % 255))
)
);
return [minSaturation, maxSaturation, minBrightness, maxBrightness];
}
function getHue(
uint8 addrInt,
uint8 stepNum,
uint256 startHue,
uint256 hueRange
) internal pure returns (uint256) {
return
lerpHue(
addrInt,
(uint256(addrInt) + uint256(stepNum)) % 2,
stepNum == 1
? startHue
: startHue + ((uint256(addrInt) + uint256(stepNum)) % hueRange),
uint8(
Utilities.selectRandomInRange(
15,
50,
string(abi.encodePacked(addrInt, stepNum, 'hue'))
)
)
);
}
function getSaturation(
uint8 addrInt,
uint8 stepNum
) internal pure returns (uint256) {
uint8 min = uint8(
Utilities.selectRandomInRange(
8,
20,
string(abi.encodePacked(addrInt, 'saturationMin'))
)
);
uint8 max = uint8(
Utilities.selectRandomInRange(
75,
100,
string(abi.encodePacked(addrInt, 'saturationMax'))
)
);
if (stepNum == 1) {
max = 22;
}
if (stepNum == 2) {
max = 40;
}
return
lerpSaturation(
addrInt % 2,
min + (10 * stepNum),
max,
Utilities.selectRandomInRange(
25 * (stepNum - 1),
25 * stepNum,
string(abi.encodePacked(addrInt, stepNum, 'saturation'))
)
);
}
function getLightness(
uint8 addrInt,
uint8 stepNum
) internal pure returns (uint256) {
uint8 min = 8;
uint8 max = 15;
if (stepNum == 2) {
min = 21;
max = 31;
}
if (stepNum == 3) {
min = 35;
max = 47;
}
if (stepNum == 4) {
min = 52;
max = addrInt % 6 == 0 ? 75 : 68;
}
return
lerpLightness(
addrInt % 2,
min,
max,
Utilities.selectRandomInRange(
1,
99,
Strings.toString(uint256(keccak256(abi.encodePacked(addrInt))))
)
);
}
function buildColorStep(
uint8 stepNum,
uint8 addrInt,
uint256 startHue,
uint256 hueRange
) internal pure returns (bytes memory) {
return
encodeStr(
getHue(addrInt, stepNum, startHue, hueRange),
getSaturation(addrInt, stepNum),
getLightness(addrInt, stepNum)
);
}
function buildGradient(
uint8 addrInt,
uint256 startHue,
uint256 hueRange
) internal pure returns (bytes[4] memory) {
unchecked {
return [
buildColorStep(1, addrInt, startHue, hueRange), // darkest
buildColorStep(2, addrInt, startHue, hueRange),
buildColorStep(3, addrInt, startHue, hueRange),
buildColorStep(4, addrInt, startHue, hueRange) // lightest
];
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import '@openzeppelin/contracts/utils/Strings.sol';
import './Structs.sol';
import './Utilities.sol';
library NodeArt {
/*
⌐◨—————————————————————————————————————————————————————————————◨
Constants
⌐◨—————————————————————————————————————————————————————————————◨ */
string constant nodeCanvas =
string(
abi.encodePacked(
'<svg xmlns="http://www.w3.org/2000/svg" width="100%" height="100%" fill="none" viewBox="0 0 116 140" shape-rendering="crispEdges"><path fill="#000" d="M0 0h116v140H0V0Z"/><path fill="#050505" d="M13 14h90v112H13V14Z"/>'
)
);
uint256 constant nodeXPosition = 43;
function animationForAllTokenOwners(
bytes[] memory colors,
uint256 nodeIndex,
uint256 interval
) internal pure returns (string memory) {
string
memory animation = '<animate attributeName="fill" repeatCount="indefinite" values="';
string memory colorStrings;
colorStrings = string(
abi.encodePacked(
colorStrings,
string(abi.encodePacked(colors[nodeIndex])),
';'
)
);
for (uint256 i = 0; i < colors.length; i++) {
colorStrings = string(
abi.encodePacked(colorStrings, string(abi.encodePacked(colors[i])), ';')
);
}
// add the first color to the end to complete the loop
colorStrings = string(
abi.encodePacked(
colorStrings,
string(abi.encodePacked(colors[nodeIndex])),
';'
)
);
animation = string(
abi.encodePacked(
animation,
colorStrings,
'" dur="',
Strings.toString(interval * (colors.length)),
'ms" begin="0.',
Strings.toString((4 - nodeIndex)), // begin animation at different times
's" />'
)
);
return animation;
}
function buildZorbRects(
bytes[] memory colors,
string memory svgRects,
uint256 tokenId,
uint256 nodeIndex
) internal pure returns (string memory) {
uint16[13] memory intervals = [
150,
300,
300,
300,
300,
500,
500,
500,
750,
750,
750,
900,
1200
];
uint256 interval = intervals[
Utilities.randomIndex(
Strings.toString(uint256(keccak256(abi.encodePacked(tokenId)))),
intervals.length
)
];
string memory animColors = animationForAllTokenOwners(
colors,
nodeIndex,
interval
);
string memory svg = string(
abi.encodePacked(
'<g fill="',
string(abi.encodePacked(colors[nodeIndex])),
'">',
animColors,
svgRects,
'</g>'
)
);
return svg;
}
function buildZorbs(
string memory svgRects,
uint256 tokenId,
address[] memory owners
) internal pure returns (string memory) {
string memory canvas = nodeCanvas;
uint8[4] memory nodeYPositions = [32, 48, 64, 80];
bytes[] memory allColors = Utilities.colorsForAddresses(owners, false);
for (uint256 i = 0; i < 4; i++) {
string memory rects = buildZorbRects(allColors, svgRects, tokenId, i);
string memory node = string(
abi.encodePacked(
'<svg x="',
Strings.toString(nodeXPosition),
'" y="',
Strings.toString(nodeYPositions[i]),
'" width="29" height="29" viewBox="0 0 29 29">',
rects,
'</svg>'
)
);
canvas = string(abi.encodePacked(canvas, node));
}
return string(abi.encodePacked(canvas, '</svg>'));
}
}// SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.20;
library Structs {
struct ContractMetadata {
string name;
string description;
string contractImage;
string sellerFeeBasisPoints;
string sellerFeeRecipient;
string externalUrl;
string animationUrl;
}
struct Node {
address[] owners;
}
struct CollectiveZorb {
uint256[] editionIds;
}
}//SPDX-License-Identifier: MIT
import './ColorLib.sol';
import '@openzeppelin/contracts/utils/Strings.sol';
pragma solidity ^0.8.20;
library Utilities {
function randomNum(string memory input) internal pure returns (uint256) {
return uint256(keccak256(abi.encodePacked(input)));
}
function randomNumMax(
string memory input,
uint256 max
) internal pure returns (uint256) {
if (max == 0) {
max = 1;
}
return (randomNum(input) % max) + 1;
}
function randomIndex(
string memory seed,
uint256 arrayLength
) internal pure returns (uint256) {
return (randomNum(seed) % arrayLength);
}
function sortChaosColors(
bytes[] memory input
) internal pure returns (string[] memory) {
uint256 inputLength = input.length;
string[] memory result = new string[](inputLength);
// Create an array of strings, moving the first item to the end for each new string.
for (uint256 i = 0; i < inputLength; i++) {
string memory tempString;
for (uint256 j = 0; j < inputLength; j++) {
uint256 index = (i + j) % inputLength;
tempString = string(abi.encodePacked(tempString, input[index], ';'));
}
// add the first item to the end of the string
result[i] = tempString;
}
return result;
}
function sortMinterColors(
uint256 collectiveZorbId,
bytes[] memory colors,
uint256 rangeAmount
) internal pure returns (string[] memory) {
uint256 animationStyleIndex = collectiveZorbId % 4;
string[] memory ranges = new string[](rangeAmount);
// Create an array of strings, moving the first item to the end for each new string.
uint256 counter;
string memory mainColorHues;
for (uint256 i = 0; i < rangeAmount - 1; i++) {
// loop through each color range
for (uint256 h = 0; h < 4; h++) {
string memory rangeColorsString;
for (uint256 j = 0; j < 4; j++) {
uint256 index;
if ((animationStyleIndex * collectiveZorbId) % 4 == 0) {
index = ((i + h + j) * (collectiveZorbId + h + j)) % colors.length;
}
if ((animationStyleIndex * collectiveZorbId) % 4 == 1) {
index = selectRandomInRange(
4 * h,
(4 * h) + 3,
string(abi.encodePacked(i + h + j + collectiveZorbId))
);
}
if ((animationStyleIndex * collectiveZorbId) % 4 == 2) {
index = selectRandomInRange(
0 * h + 1,
3 * h + 2,
string(abi.encodePacked(i + h + j + collectiveZorbId))
);
}
if ((animationStyleIndex * collectiveZorbId) % 4 == 3) {
index = selectRandomInRange(
(j % 3) * (i % 4),
(4 * (i % 4)) + 3,
string(abi.encodePacked(collectiveZorbId, j, i, h, i % 4))
);
}
rangeColorsString = string(
abi.encodePacked(rangeColorsString, colors[index], ';')
);
}
if (h == 0) {
mainColorHues = rangeColorsString;
} else {
ranges[i] = string(
abi.encodePacked(
ranges[i],
string(abi.encodePacked(rangeColorsString, mainColorHues))
)
);
}
}
counter += 1;
if (counter >= colors.length) {
counter = 0;
}
}
return ranges;
}
function selectRandomInRange(
uint256 min,
uint256 max,
string memory seed
) internal pure returns (uint256) {
return (randomNum(string(abi.encodePacked(seed))) % (max - min + 1)) + min;
}
function colorsForAddresses(
address[] memory owners,
bool stacked
) internal pure returns (bytes[] memory) {
uint256 k = 0;
uint256 arrayLength = 69; // max length of owners to include in gradient.
if (owners.length < arrayLength) {
arrayLength = owners.length;
}
bytes[] memory colorArray = new bytes[](arrayLength * 4); // length * num colors returned for gradient
for (uint256 i = 0; i < arrayLength; i++) {
uint256 ownersIndex = arrayLength - 1 - i;
// reverse order to get latest owners first
if (stacked) {
bytes[4] memory colors = ColorLib.gradientForAddress(
owners[ownersIndex]
);
for (uint256 j = 0; j < colors.length; j++) {
colorArray[k] = colors[j];
k += 1;
}
} else {
bytes[4] memory colors = ColorLib.gradientForAddress(
owners[ownersIndex]
);
for (uint256 j = 0; j < colors.length; j++) {
colorArray[k] = colors[j];
k += 1;
}
}
}
return colorArray;
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721AUpgradeable {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - 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 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.3 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../IERC721AUpgradeable.sol';
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode(bytes memory data, bool fileSafe, bool noPadding) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0670 will turn "-_" into "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, xor("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0670))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8(0, mload(and(shr(18, input), 0x3F))) mstore8(1, mload(and(shr(12, input), 0x3F))) mstore8(2, mload(and(shr(6, input), 0x3F))) mstore8(3, mload(and(input, 0x3F))) mstore(ptr, mload(0x00)) ptr := add(ptr, 4) // Advance 4 bytes. if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. // Equivalent to `o = [0, 2, 1][dataLength % 3]`. let o := div(2, mod(dataLength, 3)) // Offset `ptr` and pad with '='. We can simply write over the end. mstore(sub(ptr, o), shl(240, 0x3d3d)) // Set `o` to zero if there is padding. o := mul(iszero(iszero(noPadding)), o) mstore(sub(ptr, o), 0) // Zeroize the slot after the string. mstore(result, sub(encodedLength, o)) // Store the length. } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Decodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let decodedLength := mul(shr(2, dataLength), 3) for {} 1 {} { // If padded. if iszero(and(dataLength, 3)) { let t := xor(mload(add(data, dataLength)), 0x3d3d) // forgefmt: disable-next-item decodedLength := sub( decodedLength, add(iszero(byte(30, t)), iszero(byte(31, t))) ) break } // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) break } result := mload(0x40) // Write the length of the bytes. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, decodedLength) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. // forgefmt: disable-next-item mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) if iszero(lt(ptr, end)) { break } } mstore(0x40, add(end, 0x20)) // Allocate the memory. mstore(end, 0) // Zeroize the slot after the bytes. mstore(0x60, 0) // Restore the zero slot. } } } }
{
"optimizer": {
"enabled": true,
"runs": 500
},
"evmVersion": "paris",
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"libraries": {}
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"string","name":"tokenName","type":"string"},{"internalType":"string","name":"tokenSymbol","type":"string"},{"internalType":"address","name":"initialOwner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"Access_OnlyTokenOwner","type":"error"},{"inputs":[],"name":"ERC721EnumerableForbiddenBatchMint","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721IncorrectOwner","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721InsufficientApproval","type":"error"},{"inputs":[{"internalType":"address","name":"approver","type":"address"}],"name":"ERC721InvalidApprover","type":"error"},{"inputs":[{"internalType":"address","name":"operator","type":"address"}],"name":"ERC721InvalidOperator","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"ERC721InvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC721InvalidReceiver","type":"error"},{"inputs":[{"internalType":"address","name":"sender","type":"address"}],"name":"ERC721InvalidSender","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ERC721NonexistentToken","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"ERC721OutOfBoundsIndex","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"TokenNotFound","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","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":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"constructTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","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":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"ownersForTokenIds","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"description","type":"string"},{"internalType":"string","name":"contractImage","type":"string"},{"internalType":"string","name":"sellerFeeBasisPoints","type":"string"},{"internalType":"string","name":"sellerFeeRecipient","type":"string"},{"internalType":"string","name":"externalUrl","type":"string"},{"internalType":"string","name":"animationUrl","type":"string"}],"internalType":"struct Structs.ContractMetadata","name":"contractMetadata_","type":"tuple"}],"name":"setContractMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setZorbitArtContractAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"shuffleMany","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"shuffleToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"svgArtwork","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"index","type":"uint256"}],"name":"tokenOfOwnerByIndex","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"zorbitArtContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"zorbitIdOwnerHistory","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"}]Contract Creation Code
60806040523480156200001157600080fd5b5060405162004a4038038062004a40833981016040819052620000349162000293565b8083836000620000458382620003af565b506001620000548282620003af565b5050506001600160a01b0381166200008657604051631e4fbdf760e01b81526000600482015260240160405180910390fd5b6200009181620000fb565b5060408051600060208083018281528385019094529282526013805460018101825591528151805192937f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09090920192620000ef92849201906200014d565b5050505050506200047b565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b828054828255906000526020600020908101928215620001a5579160200282015b82811115620001a557825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906200016e565b50620001b3929150620001b7565b5090565b5b80821115620001b35760008155600101620001b8565b634e487b7160e01b600052604160045260246000fd5b600082601f830112620001f657600080fd5b81516001600160401b0380821115620002135762000213620001ce565b604051601f8301601f19908116603f011681019082821181831017156200023e576200023e620001ce565b816040528381526020925086838588010111156200025b57600080fd5b600091505b838210156200027f578582018301518183018401529082019062000260565b600093810190920192909252949350505050565b600080600060608486031215620002a957600080fd5b83516001600160401b0380821115620002c157600080fd5b620002cf87838801620001e4565b94506020860151915080821115620002e657600080fd5b50620002f586828701620001e4565b604086015190935090506001600160a01b03811681146200031557600080fd5b809150509250925092565b600181811c908216806200033557607f821691505b6020821081036200035657634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620003aa57600081815260208120601f850160051c81016020861015620003855750805b601f850160051c820191505b81811015620003a65782815560010162000391565b5050505b505050565b81516001600160401b03811115620003cb57620003cb620001ce565b620003e381620003dc845462000320565b846200035c565b602080601f8311600181146200041b5760008415620004025750858301515b600019600386901b1c1916600185901b178555620003a6565b600085815260208120601f198616915b828110156200044c578886015182559484019460019091019084016200042b565b50858210156200046b5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6145b5806200048b6000396000f3fe608060405234801561001057600080fd5b50600436106101da5760003560e01c806370a0823111610104578063bf8a7908116100a2578063e8a3d48511610071578063e8a3d485146103eb578063e985e9c5146103f3578063eefd82ae1461042f578063f2fde38b1461044257600080fd5b8063bf8a790814610392578063c87b56dd146103b2578063de5405a3146103c5578063e3356fa9146103d857600080fd5b80638da5cb5b116100de5780638da5cb5b1461035357806395d89b4114610364578063a22cb4651461036c578063b88d4fde1461037f57600080fd5b806370a0823114610325578063715018a614610338578063894b4c2e1461034057600080fd5b806323b872dd1161017c5780634c1e28821161014b5780634c1e2882146102d95780634f6ccce7146102ec5780636352211e146102ff5780636db6b2dd1461031257600080fd5b806323b872dd1461028d5780632f745c59146102a057806342842e0e146102b357806342d48093146102c657600080fd5b8063081812fc116101b8578063081812fc14610231578063095ea7b31461025c5780631249c58b1461026f57806318160ddd1461028557600080fd5b806301ffc9a7146101df57806303893edf1461020757806306fdde031461021c575b600080fd5b6101f26101ed36600461358c565b610455565b60405190151581526020015b60405180910390f35b61021a610215366004613619565b610466565b005b6102246104aa565b6040516101fe919061370f565b61024461023f366004613722565b61053c565b6040516001600160a01b0390911681526020016101fe565b61021a61026a366004613752565b610565565b610277610570565b6040519081526020016101fe565b600854610277565b61021a61029b36600461377c565b6106ae565b6102776102ae366004613752565b61073e565b61021a6102c136600461377c565b6107a3565b61021a6102d43660046137b8565b6107c3565b61021a6102e7366004613859565b6107ed565b6102776102fa366004613722565b610876565b61024461030d366004613722565b6108cf565b610224610320366004613722565b6108da565b6102776103333660046137b8565b6109e0565b61021a610a28565b61022461034e366004613722565b610a3c565b600a546001600160a01b0316610244565b610224610b1b565b61021a61037a36600461399e565b610b2a565b61021a61038d3660046139da565b610b35565b6103a56103a0366004613619565b610b4c565b6040516101fe9190613a56565b6102246103c0366004613722565b610c92565b61021a6103d3366004613722565b610ccb565b6103a56103e6366004613722565b610d90565b610224610e0a565b6101f2610401366004613aa3565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600b54610244906001600160a01b031681565b61021a6104503660046137b8565b610e56565b600061046082610e94565b92915050565b60005b81518110156104a65761049482828151811061048757610487613ad6565b6020026020010151610ccb565b8061049e81613b02565b915050610469565b5050565b6060600080546104b990613b1b565b80601f01602080910402602001604051908101604052809291908181526020018280546104e590613b1b565b80156105325780601f1061050757610100808354040283529160200191610532565b820191906000526020600020905b81548152906001019060200180831161051557829003601f168201915b5050505050905090565b600061054782610eb9565b506000828152600460205260409020546001600160a01b0316610460565b6104a6828233610ef2565b60008061057c60085490565b610587906001613b55565b905060006105bf61059783610eff565b44336040516020016105ab93929190613b68565b604051602081830303815290604052610fa0565b90506105cb818361100c565b604080516002808252606082018352600092602083019080368337019050509050338160008151811061060057610600613ad6565b60200260200101906001600160a01b031690816001600160a01b031681525050818160018151811061063457610634613ad6565b6001600160a01b03909216602092830291909101820152604080518083019091528281526013805460018101825560009190915281518051929384937f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090909301926106a292849201906134d5565b50949695505050505050565b6001600160a01b0382166106dd57604051633250574960e11b8152600060048201526024015b60405180910390fd5b60006106ea838333611026565b9050836001600160a01b0316816001600160a01b031614610738576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016106d4565b50505050565b6000610749836109e0565b821061077a5760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016106d4565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6107be83838360405180602001604052806000815250610b35565b505050565b6107cb611033565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6107f5611033565b8051600c906108049082613be8565b506020810151600d906108179082613be8565b506040810151600e9061082a9082613be8565b506060810151600f9061083d9082613be8565b5060808101516010906108509082613be8565b5060a08101516011906108639082613be8565b5060c08101516012906104a69082613be8565b600061088160085490565b82106108aa5760405163295f44f760e21b815260006004820152602481018390526044016106d4565b600882815481106108bd576108bd613ad6565b90600052602060002001549050919050565b600061046082610eb9565b60606000600b60009054906101000a90046001600160a01b03166001600160a01b0316632d15c0296040518163ffffffff1660e01b8152600401600060405180830381865afa158015610931573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109599190810190613ca8565b905060006109d882856013878154811061097557610975613ad6565b60009182526020918290200180546040805182850281018501909152818152928301828280156109ce57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116109b0575b5050505050611060565b949350505050565b60006001600160a01b038216610a0c576040516322718ad960e21b8152600060048201526024016106d4565b506001600160a01b031660009081526003602052604090205490565b610a30611033565b610a3a600061128b565b565b60606000610a49836108da565b9050610af4600c600001604051602001610a639190613d89565b604051602081830303815290604052610a7b85610eff565b610a84846112dd565b604051610a9690600d90602001613d89565b604051602081830303815290604052610acc60138981548110610abb57610abb613ad6565b600091825260209091200154610eff565b604051602001610ae0959493929190613db1565b6040516020818303038152906040526112dd565b604051602001610b049190613efa565b604051602081830303815290604052915050919050565b6060600180546104b990613b1b565b6104a63383836112eb565b610b408484846106ae565b6107388484848461138a565b60606000825167ffffffffffffffff811115610b6a57610b6a6135a9565b604051908082528060200260200182016040528015610b93578160200160208202803683370190505b50905060005b8351811015610c8b576000848281518110610bb657610bb6613ad6565b6020026020010151118015610be65750600854848281518110610bdb57610bdb613ad6565b602002602001015111155b15610c4457610c0d848281518110610c0057610c00613ad6565b60200260200101516108cf565b828281518110610c1f57610c1f613ad6565b60200260200101906001600160a01b031690816001600160a01b031681525050610c79565b6000828281518110610c5857610c58613ad6565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80610c8381613b02565b915050610b99565b5092915050565b60606001821080610ca4575060085482115b15610cc257604051630cbdb7b360e41b815260040160405180910390fd5b61046082610a3c565b6001811080610cdb575060085481115b15610cf957604051630cbdb7b360e41b815260040160405180910390fd5b6000610d04826108cf565b90506000610d22610d1d610d184486613b55565b610eff565b610fa0565b9050610d3f828285604051806020016040528060008152506114b3565b60138381548110610d5257610d52613ad6565b60009182526020808320909101805460018101825590835291200180546001600160a01b039092166001600160a01b03199092169190911790555050565b606060138281548110610da557610da5613ad6565b6000918252602091829020018054604080518285028101850190915281815292830182828015610dfe57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610de0575b50505050509050919050565b604051606090610e3290610ae090600c90600d90600e90600f90601090601290602001613f3f565b604051602001610e429190613efa565b604051602081830303815290604052905090565b610e5e611033565b6001600160a01b038116610e8857604051631e4fbdf760e01b8152600060048201526024016106d4565b610e918161128b565b50565b60006001600160e01b0319821663780e9d6360e01b14806104605750610460826114bf565b6000818152600260205260408120546001600160a01b03168061046057604051637e27328960e01b8152600481018490526024016106d4565b6107be838383600161150f565b60606000610f0c83611634565b600101905060008167ffffffffffffffff811115610f2c57610f2c6135a9565b6040519080825280601f01601f191660200182016040528015610f56576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084610f60575b509392505050565b6000610fdc610fd783604051602001610fb9919061370f565b6040516020818303038152906040528051906020012060001c610eff565b611716565b604051602001610fee91815260200190565b60408051601f19818403018152919052805160209091012092915050565b6104a6828260405180602001604052806000815250611758565b60006109d884848461176f565b600a546001600160a01b03163314610a3a5760405163118cdaa760e01b81523360048201526024016106d4565b6060600060405160200161117b907f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222077696474683d223130302522206865696768743d2231303060208201527f25222066696c6c3d226e6f6e65222076696577426f783d22302030203131362060408201527f313430222073686170652d72656e646572696e673d226372697370456467657360608201527f223e3c706174682066696c6c3d22233030302220643d224d302030683131367660808201527f313430483056305a222f3e3c706174682066696c6c3d2223303530353035222060a08201527f643d224d3133203134683930763131324831335631345a222f3e00000000000060c082015260da0190565b60408051601f1981840301815260808301825260208084526030908401528282019190915260506060830152915060006111b5858261183c565b905060005b600481101561125e5760006111d1838a8a856119fc565b905060006111df602b610eff565b6112018685600481106111f4576111f4613ad6565b602002015160ff16610eff565b836040516020016112149392919061406a565b60405160208183030381529060405290508581604051602001611238929190614127565b60405160208183030381529060405295505050808061125690613b02565b9150506111ba565b50826040516020016112709190614156565b60405160208183030381529060405293505050509392505050565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606061046082600080611b25565b6001600160a01b03821661131d57604051630b61174360e31b81526001600160a01b03831660048201526024016106d4565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561073857604051630a85bd0160e11b81526001600160a01b0384169063150b7a02906113cc903390889087908790600401614180565b6020604051808303816000875af1925050508015611407575060408051601f3d908101601f19168201909252611404918101906141b2565b60015b611470573d808015611435576040519150601f19603f3d011682016040523d82523d6000602084013e61143a565b606091505b50805160000361146857604051633250574960e11b81526001600160a01b03851660048201526024016106d4565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146114ac57604051633250574960e11b81526001600160a01b03851660048201526024016106d4565b5050505050565b6114ac83836000611026565b60006001600160e01b031982166380ac58cd60e01b14806114f057506001600160e01b03198216635b5e139f60e01b145b8061046057506301ffc9a760e01b6001600160e01b0319831614610460565b808061152357506001600160a01b03821615155b1561160457600061153384610eb9565b90506001600160a01b0383161580159061155f5750826001600160a01b0316816001600160a01b031614155b801561159157506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b156115ba5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016106d4565b81156116025783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061167d577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106116a9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106116c757662386f26fc10000830492506010015b6305f5e10083106116df576305f5e100830492506008015b61271083106116f357612710830492506004015b60648310611705576064830492506002015b600a83106104605760010192915050565b600080448360405160200161172c9291906141cf565b60408051601f19818403018152919052805160209091012090506117516064826141f5565b9392505050565b6117628383611c0c565b6107be600084848461138a565b60008061177d858585611c71565b90506001600160a01b0381166117da576117d584600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6117fd565b846001600160a01b0316816001600160a01b0316146117fd576117fd8185611d6a565b6001600160a01b0385166118195761181484611dfb565b6109d8565b846001600160a01b0316816001600160a01b0316146109d8576109d88585611eaa565b6060600080604590508085511015611852575083515b600061185f826004614209565b67ffffffffffffffff811115611877576118776135a9565b6040519080825280602002602001820160405280156118aa57816020015b60608152602001906001900390816118955790505b50905060005b828110156119f2576000816118c6600186614220565b6118d09190614220565b905086156119645760006118fc8983815181106118ef576118ef613ad6565b6020026020010151611efa565b905060005b600481101561195d5781816004811061191c5761191c613ad6565b602002015185888151811061193357611933613ad6565b6020908102919091010152611949600188613b55565b96508061195581613b02565b915050611901565b50506119df565b600061197b8983815181106118ef576118ef613ad6565b905060005b60048110156119dc5781816004811061199b5761199b613ad6565b60200201518588815181106119b2576119b2613ad6565b60209081029190910101526119c8600188613b55565b9650806119d481613b02565b915050611980565b50505b50806119ea81613b02565b9150506118b0565b5095945050505050565b604080516101a0810182526096815261012c6020808301829052828401829052606080840183905260808401929092526101f460a0840181905260c0840181905260e08401526102ee610100840181905261012084018190526101408401526103846101608401526104b0610180840152835190810186905290926000918391611a9191611a8a9101610fb9565b600d611f6c565b600d8110611aa157611aa1613ad6565b602002015161ffff1690506000611ab9888684611f82565b90506000888681518110611acf57611acf613ad6565b6020026020010151604051602001611ae79190614233565b60408051601f1981840301815290829052611b089184908b9060200161424f565b60408051808303601f190181529190529998505050505050505050565b606083518015610f98576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611b9557602001604052613d3d60f01b60038406600204808303919091526000861515909102918290035290038252509392505050565b6001600160a01b038216611c3657604051633250574960e11b8152600060048201526024016106d4565b6000611c4483836000611026565b90506001600160a01b038116156107be576040516339e3563760e11b8152600060048201526024016106d4565b6000828152600260205260408120546001600160a01b0390811690831615611c9e57611c9e81848661211e565b6001600160a01b03811615611cdc57611cbb60008560008061150f565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615611d0b576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000611d75836109e0565b600083815260076020526040902054909150808214611dc8576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090611e0d90600190614220565b60008381526009602052604081205460088054939450909284908110611e3557611e35613ad6565b906000526020600020015490508060088381548110611e5657611e56613ad6565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611e8e57611e8e6142ca565b6001900381819060005260206000200160009055905550505050565b60006001611eb7846109e0565b611ec19190614220565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b611f0261353a565b6001600160a01b038216611f1857610460612182565b60ff828116066001600160a01b0383166000611f446001610167611f3f601386901a610eff565b6121df565b90506000601960ff85160660010160ff169050611f62848383612233565b9695505050505050565b600081611f7884612293565b61175191906141f5565b606060006040518060600160405280603f8152602001614541603f91399050606080868681518110611fb657611fb6613ad6565b6020026020010151604051602001611fce9190614233565b60408051601f1981840301815290829052611fec92916020016142e0565b604051602081830303815290604052905060005b8651811015612076578187828151811061201c5761201c613ad6565b60200260200101516040516020016120349190614233565b60408051601f198184030181529082905261205292916020016142e0565b6040516020818303038152906040529150808061206e90613b02565b915050612000565b508086868151811061208a5761208a613ad6565b60200260200101516040516020016120a29190614233565b60408051601f19818403018152908290526120c092916020016142e0565b604051602081830303815290604052905081816120e3885187610d189190614209565b6120f1610d18896004614220565b604051602001612104949392919061431b565b60408051808303601f190181529190529695505050505050565b6121298383836122a6565b6107be576001600160a01b03831661215757604051637e27328960e01b8152600481018290526024016106d4565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016106d4565b61218a61353a565b60405180608001604052806121a2600080600f612329565b81526020016121b46000806019612329565b81526020016121c6600080603c612329565b81526020016121d8600080605a612329565b9052919050565b6000836121ec8185614220565b6121f7906001613b55565b61221f8460405160200161220b9190614233565b604051602081830303815290604052612293565b61222991906141f5565b6109d89190613b55565b61223b61353a565b60405180608001604052806122536001878787612370565b81526020016122656002878787612370565b81526020016122776003878787612370565b81526020016122896004878787612370565b9052949350505050565b600081604051602001610fee9190614233565b60006001600160a01b038316158015906109d85750826001600160a01b0316846001600160a01b0316148061230057506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b806109d85750506000908152600460205260409020546001600160a01b03908116911614919050565b606061233484610eff565b61233d84610eff565b61234684610eff565b604051602001612358939291906143c3565b60405160208183030381529060405290509392505050565b606061239a612381858786866123a3565b61238b8688612450565b6123958789612594565b612329565b95945050505050565b600061239a8560026123bb60ff808916908416613b55565b6123c591906141f5565b8660ff166001146123fa57846123e160ff808a16908b16613b55565b6123eb91906141f5565b6123f59087613b55565b6123fc565b855b6040516001600160f81b031960f88b811b821660208401528a901b1660218201526268756560e81b602282015261244b90600f906032906025015b6040516020818303038152906040526121df565b612638565b6000806124946008601486604051602001612437919060f89190911b6001600160f81b03191681526c39b0ba3ab930ba34b7b726b4b760991b6001820152600e0190565b905060006124d9604b606487604051602001612437919060f89190911b6001600160f81b03191681526c0e6c2e8eae4c2e8d2dedc9ac2f609b1b6001820152600e0190565b90508360ff166001036124ea575060165b8360ff166002036124f9575060285b61239a612507600287614444565b61251286600a614466565b61251c9085614482565b60ff168360ff1661258f600189612533919061449b565b61253e906019614466565b60ff1661254c8a6019614466565b6040516001600160f81b031960f88e811b821660208401528d901b1660218201526939b0ba3ab930ba34b7b760b11b602282015260ff9190911690602c01612437565b61278e565b60006008600f60ff84166002036125ad575060159050601f5b8360ff166003036125c0575060239050602f5b8360ff166004036125ef57603491506125da600686614444565b60ff16156125e95760446125ec565b604b5b90505b61239a6125fd600287614444565b8360ff168360ff1661263360016063611f3f8c604051602001610fb9919060f89190911b6001600160f81b031916815260010190565b6127d9565b600080612646600487614444565b60ff1690508360008290036126b7576126ae861561266e5761266982600a6144b4565b612679565b6126796000836144dc565b6126869060ff87166144fc565b8261269560ff881660646144dc565b61269f91906144fc565b6126a991906144b4565b61284a565b925050506109d8565b816001036126de576126ae86156126d35761266982601e6144b4565b612679601e836144dc565b81600203612738576126ae86156126ff576126fa8260326144b4565b61270a565b61270a6032836144dc565b6127168660ff1661287d565b61272091906144fc565b8261272d8760ff1661287d565b6126959060646144dc565b61278360808860ff161161274d576000612750565b60015b60ff16871561276057603c612764565b603b195b61276e91906144fc565b61277890836144b4565b61270a90601e6144b4565b979650505050505050565b6000808560ff166000036127c1576127a583612d73565b60ff1690506064818103860285830201046001019150506109d8565b50816064818103860285830201049695505050505050565b6000808560ff166000036127fa576127f083612d73565b60ff169050612809565b612803836130cf565b60ff1690505b60646128158583614209565b86612821846064614220565b61282b9190614209565b6128359190613b55565b61283f919061452c565b611f62906001613b55565b60649005600080821261286357610168825b0692915050565b61016882600019028161285c5761285c614054565b919050565b6000600d8261ffff16101561289457506000919050565b60118261ffff1610156128a957506001919050565b60138261ffff1610156128be57506002919050565b60158261ffff1610156128d357506003919050565b60178261ffff1610156128e857506004919050565b60188261ffff1610156128fd57506005919050565b60198261ffff16101561291257506006919050565b601b8261ffff16101561292757506007919050565b601c8261ffff16101561293c57506008919050565b601d8261ffff16101561295157506009919050565b601e8261ffff1610156129665750600a919050565b601f8261ffff16101561297b5750600b919050565b60208261ffff1610156129905750600d919050565b60218261ffff1610156129a55750600e919050565b60228261ffff1610156129ba5750600f919050565b60238261ffff1610156129cf57506011919050565b60248261ffff1610156129e457506012919050565b60258261ffff1610156129f957506014919050565b60268261ffff161015612a0e57506015919050565b60278261ffff161015612a2357506017919050565b60288261ffff161015612a3857506019919050565b60298261ffff161015612a4d5750601b919050565b602a8261ffff161015612a625750601d919050565b602b8261ffff161015612a775750601f919050565b602c8261ffff161015612a8c57506022919050565b602d8261ffff161015612aa157506024919050565b602e8261ffff161015612ab657506026919050565b602f8261ffff161015612acb57506029919050565b60308261ffff161015612ae05750602c919050565b60318261ffff161015612af55750602f919050565b60328261ffff161015612b0a57506032919050565b60338261ffff161015612b1f57506034919050565b60348261ffff161015612b3457506037919050565b60358261ffff161015612b495750603a919050565b60368261ffff161015612b5e5750603d919050565b60378261ffff161015612b735750603f919050565b60388261ffff161015612b8857506041919050565b60398261ffff161015612b9d57506044919050565b603a8261ffff161015612bb257506046919050565b603b8261ffff161015612bc757506048919050565b603c8261ffff161015612bdc5750604a919050565b603d8261ffff161015612bf15750604c919050565b603e8261ffff161015612c065750604e919050565b603f8261ffff161015612c1b5750604f919050565b60408261ffff161015612c3057506051919050565b60418261ffff161015612c4557506052919050565b60428261ffff161015612c5a57506054919050565b60438261ffff161015612c6f57506055919050565b60448261ffff161015612c8457506056919050565b60458261ffff161015612c9957506058919050565b60468261ffff161015612cae57506059919050565b60478261ffff161015612cc35750605a919050565b60488261ffff161015612cd85750605b919050565b604a8261ffff161015612ced5750605c919050565b604b8261ffff161015612d025750605d919050565b604c8261ffff161015612d175750605e919050565b604e8261ffff161015612d2c5750605f919050565b60508261ffff161015612d4157506060919050565b60528261ffff161015612d5657506061919050565b60568261ffff161015612d6b57506062919050565b506063919050565b60006027821015612d8657506000919050565b602d821015612d9757506001919050565b6031821015612da857506002919050565b6034821015612db957506003919050565b6035821015612dca57506004919050565b6036821015612ddb57506004919050565b6037821015612dec57506005919050565b6038821015612dfd57506005919050565b6039821015612e0e57506006919050565b603a821015612e1f57506006919050565b603b821015612e3057506007919050565b603c821015612e4157506007919050565b603d821015612e5257506008919050565b603e821015612e6357506009919050565b603f821015612e7457506009919050565b6040821015612e855750600a919050565b6041821015612e965750600b919050565b6042821015612ea75750600c919050565b6043821015612eb85750600d919050565b6044821015612ec95750600e919050565b6045821015612eda5750600f919050565b6046821015612eeb57506010919050565b6047821015612efc57506012919050565b6048821015612f0d57506013919050565b6049821015612f1e57506014919050565b604a821015612f2f57506016919050565b604b821015612f4057506017919050565b604c821015612f5157506019919050565b604d821015612f625750601b919050565b604e821015612f735750601c919050565b604f821015612f845750601e919050565b6050821015612f9557506020919050565b6051821015612fa657506022919050565b6052821015612fb757506025919050565b6053821015612fc857506027919050565b6054821015612fd957506029919050565b6055821015612fea5750602c919050565b6056821015612ffb5750602f919050565b605782101561300c57506031919050565b605882101561301d57506034919050565b605982101561302e57506037919050565b605a82101561303f5750603b919050565b605b8210156130505750603e919050565b605c82101561306157506041919050565b605d82101561307257506045919050565b605e82101561308357506049919050565b605f8210156130945750604d919050565b60608210156130a557506051919050565b60618210156130b657506055919050565b60628210156130c75750605a919050565b50605f919050565b600060168210156130e257506000919050565b601c8210156130f357506001919050565b602082101561310457506002919050565b602082101561311557506003919050565b602282101561312657506003919050565b602482101561313757506004919050565b602782101561314857506005919050565b602982101561315957506006919050565b602b82101561316a57506007919050565b602e82101561317b57506009919050565b602f82101561318c5750600a919050565b603182101561319d5750600b919050565b60328210156131ae5750600c919050565b60338210156131bf5750600d919050565b60358210156131d05750600e919050565b60368210156131e15750600f919050565b60378210156131f257506010919050565b603882101561320357506011919050565b603982101561321457506012919050565b603a82101561322557506013919050565b603b82101561323657506014919050565b603c82101561324757506015919050565b603d82101561325857506016919050565b603e82101561326957506017919050565b603f82101561327a57506019919050565b604082101561328b5750601a919050565b604182101561329c5750601b919050565b60428210156132ad5750601c919050565b60438210156132be5750601e919050565b60448210156132cf5750601f919050565b60458210156132e057506020919050565b60468210156132f157506022919050565b604782101561330257506023919050565b604882101561331357506025919050565b604982101561332457506026919050565b604a82101561333557506028919050565b604b8210156133465750602a919050565b604c8210156133575750602b919050565b604d8210156133685750602d919050565b604e8210156133795750602f919050565b604f82101561338a57506031919050565b605082101561339b57506033919050565b60518210156133ac57506035919050565b60528210156133bd57506037919050565b60538210156133ce57506039919050565b60548210156133df5750603b919050565b60558210156133f05750603d919050565b60568210156134015750603f919050565b605782101561341257506041919050565b605882101561342357506044919050565b605982101561343457506046919050565b605a82101561344557506048919050565b605b8210156134565750604b919050565b605c8210156134675750604d919050565b605d82101561347857506050919050565b605e82101561348957506053919050565b605f82101561349a57506055919050565b60608210156134ab57506058919050565b60618210156134bc5750605b919050565b60628210156134cd5750605e919050565b506061919050565b82805482825590600052602060002090810192821561352a579160200282015b8281111561352a57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906134f5565b50613536929150613561565b5090565b60405180608001604052806004905b60608152602001906001900390816135495790505090565b5b808211156135365760008155600101613562565b6001600160e01b031981168114610e9157600080fd5b60006020828403121561359e57600080fd5b813561175181613576565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff811182821017156135e2576135e26135a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613611576136116135a9565b604052919050565b6000602080838503121561362c57600080fd5b823567ffffffffffffffff8082111561364457600080fd5b818501915085601f83011261365857600080fd5b81358181111561366a5761366a6135a9565b8060051b915061367b8483016135e8565b818152918301840191848101908884111561369557600080fd5b938501935b838510156136b35784358252938501939085019061369a565b98975050505050505050565b60005b838110156136da5781810151838201526020016136c2565b50506000910152565b600081518084526136fb8160208601602086016136bf565b601f01601f19169290920160200192915050565b60208152600061175160208301846136e3565b60006020828403121561373457600080fd5b5035919050565b80356001600160a01b038116811461287857600080fd5b6000806040838503121561376557600080fd5b61376e8361373b565b946020939093013593505050565b60008060006060848603121561379157600080fd5b61379a8461373b565b92506137a86020850161373b565b9150604084013590509250925092565b6000602082840312156137ca57600080fd5b6117518261373b565b600067ffffffffffffffff8211156137ed576137ed6135a9565b50601f01601f191660200190565b600061380e613809846137d3565b6135e8565b905082815283838301111561382257600080fd5b828260208301376000602084830101529392505050565b600082601f83011261384a57600080fd5b611751838335602085016137fb565b60006020828403121561386b57600080fd5b813567ffffffffffffffff8082111561388357600080fd5b9083019060e0828603121561389757600080fd5b61389f6135bf565b8235828111156138ae57600080fd5b6138ba87828601613839565b8252506020830135828111156138cf57600080fd5b6138db87828601613839565b6020830152506040830135828111156138f357600080fd5b6138ff87828601613839565b60408301525060608301358281111561391757600080fd5b61392387828601613839565b60608301525060808301358281111561393b57600080fd5b61394787828601613839565b60808301525060a08301358281111561395f57600080fd5b61396b87828601613839565b60a08301525060c08301358281111561398357600080fd5b61398f87828601613839565b60c08301525095945050505050565b600080604083850312156139b157600080fd5b6139ba8361373b565b9150602083013580151581146139cf57600080fd5b809150509250929050565b600080600080608085870312156139f057600080fd5b6139f98561373b565b9350613a076020860161373b565b925060408501359150606085013567ffffffffffffffff811115613a2a57600080fd5b8501601f81018713613a3b57600080fd5b613a4a878235602084016137fb565b91505092959194509250565b6020808252825182820181905260009190848201906040850190845b81811015613a975783516001600160a01b031683529284019291840191600101613a72565b50909695505050505050565b60008060408385031215613ab657600080fd5b613abf8361373b565b9150613acd6020840161373b565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201613b1457613b14613aec565b5060010190565b600181811c90821680613b2f57607f821691505b602082108103613b4f57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561046057610460613aec565b606081526000613b7b60608301866136e3565b90508360208301526001600160a01b0383166040830152949350505050565b601f8211156107be57600081815260208120601f850160051c81016020861015613bc15750805b601f850160051c820191505b81811015613be057828155600101613bcd565b505050505050565b815167ffffffffffffffff811115613c0257613c026135a9565b613c1681613c108454613b1b565b84613b9a565b602080601f831160018114613c4b5760008415613c335750858301515b600019600386901b1c1916600185901b178555613be0565b600085815260208120601f198616915b82811015613c7a57888601518255948401946001909101908401613c5b565b5085821015613c985787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613cba57600080fd5b815167ffffffffffffffff811115613cd157600080fd5b8201601f81018413613ce257600080fd5b8051613cf0613809826137d3565b818152856020838501011115613d0557600080fd5b61239a8260208301602086016136bf565b60008154613d2381613b1b565b60018281168015613d3b5760018114613d5057613d7f565b60ff1984168752821515830287019450613d7f565b8560005260208060002060005b85811015613d765781548a820152908401908201613d5d565b50505082870194505b5050505092915050565b60006117518284613d16565b60008151613da78185602086016136bf565b9290920192915050565b693d913730b6b2911d101160b11b81528551600090613dd781600a850160208b016136bf565b600160fd1b600a918401918201528651613df881600b840160208b016136bf565b7f222c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b600b92909101918201526618985cd94d8d0b60ca1b602b8201528551613e46816032840160208a016136bf565b72111610113232b9b1b934b83a34b7b7111d101160691b603292909101918201528451613e7a8160458401602089016136bf565b7f222c202261747472696275746573223a205b0000000000000000000000000000910160458101919091527f7b2274726169745f74797065223a20225472616e7366657273222c202276616c6057820152653ab2911d101160d11b60778201526136b3613eea607d830186613d95565b63227d5d7d60e01b815260040190565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251613f3281601d8501602087016136bf565b91909101601d0192915050565b693d913730b6b2911d101160b11b81526000613f5e600a830189613d16565b72111610113232b9b1b934b83a34b7b7111d101160691b8152613f846013820189613d16565b6c1116101134b6b0b3b2911d101160991b81529050613fa6600d820188613d16565b90507f222c202273656c6c65725f6665655f62617369735f706f696e7473223a2022008152613fd8601f820187613d16565b90507f222c202273656c6c65725f6665655f726563697069656e74223a202200000000815261400a601c820186613d16565b90507f222c2022616e696d6174696f6e5f75726c223a20220000000000000000000000815261403c6015820185613d16565b61227d60f01b81526002019998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b671e39bb33903c1e9160c11b8152835160009061408e8160088501602089016136bf565b6411103c9e9160d91b60089184019182015284516140b381600d8401602089016136bf565b7f222077696474683d22323922206865696768743d223239222076696577426f78600d92909101918201526c1e9118101810191c90191c911f60991b602d820152835161410781603a8401602088016136bf565b651e17b9bb339f60d11b603a929091019182015260400195945050505050565b600083516141398184602088016136bf565b83519083019061414d8183602088016136bf565b01949350505050565b600082516141688184602087016136bf565b651e17b9bb339f60d11b920191825250600601919050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152611f6260808301846136e3565b6000602082840312156141c457600080fd5b815161175181613576565b828152600082516141e78160208501602087016136bf565b919091016020019392505050565b60008261420457614204614054565b500690565b808202811582820484141761046057610460613aec565b8181038181111561046057610460613aec565b600082516142458184602087016136bf565b9190910192915050565b681e33903334b6361e9160b91b815283516000906142748160098501602089016136bf565b61111f60f11b600991840191820152845161429681600b8401602089016136bf565b84519101906142ac81600b8401602088016136bf565b631e17b39f60e11b600b9290910191820152600f0195945050505050565b634e487b7160e01b600052603160045260246000fd5b600083516142f28184602088016136bf565b8351908301906143068183602088016136bf565b603b60f81b9101908152600101949350505050565b6000855161432d818460208a016136bf565b855190830190614341818360208a016136bf565b661110323ab91e9160c91b910190815284516143648160078401602089016136bf565b7f6d73222020626567696e3d22302e0000000000000000000000000000000000006007929091019182015283516143a28160158401602088016136bf565b6539911010179f60d11b60159290910191820152601b019695505050505050565b630d0e6d8560e31b8152600084516143e28160048501602089016136bf565b61016160f51b60049184019182015284516144048160068401602089016136bf565b6201296160ed1b6006929091019182015283516144288160098401602088016136bf565b61252960f01b60099290910191820152600b0195945050505050565b600060ff83168061445757614457614054565b8060ff84160691505092915050565b60ff8181168382160290811690818114610c8b57610c8b613aec565b60ff818116838216019081111561046057610460613aec565b60ff828116828216039081111561046057610460613aec565b80820182811260008312801582168215821617156144d4576144d4613aec565b505092915050565b8181036000831280158383131683831282161715610c8b57610c8b613aec565b80820260008212600160ff1b8414161561451857614518613aec565b818105831482151761046057610460613aec565b60008261453b5761453b614054565b50049056fe3c616e696d617465206174747269627574654e616d653d2266696c6c2220726570656174436f756e743d22696e646566696e697465222076616c7565733d22a26469706673582212207b6c61e35291a6d05244eeefbdbb30c0ba25a4418a6e25acc44a4794b5ffd0b664736f6c63430008140033000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cb43078c32423f5348cab5885911c3b5fae217f900000000000000000000000000000000000000000000000000000000000000065a6f72626974000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045a52425400000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x608060405234801561001057600080fd5b50600436106101da5760003560e01c806370a0823111610104578063bf8a7908116100a2578063e8a3d48511610071578063e8a3d485146103eb578063e985e9c5146103f3578063eefd82ae1461042f578063f2fde38b1461044257600080fd5b8063bf8a790814610392578063c87b56dd146103b2578063de5405a3146103c5578063e3356fa9146103d857600080fd5b80638da5cb5b116100de5780638da5cb5b1461035357806395d89b4114610364578063a22cb4651461036c578063b88d4fde1461037f57600080fd5b806370a0823114610325578063715018a614610338578063894b4c2e1461034057600080fd5b806323b872dd1161017c5780634c1e28821161014b5780634c1e2882146102d95780634f6ccce7146102ec5780636352211e146102ff5780636db6b2dd1461031257600080fd5b806323b872dd1461028d5780632f745c59146102a057806342842e0e146102b357806342d48093146102c657600080fd5b8063081812fc116101b8578063081812fc14610231578063095ea7b31461025c5780631249c58b1461026f57806318160ddd1461028557600080fd5b806301ffc9a7146101df57806303893edf1461020757806306fdde031461021c575b600080fd5b6101f26101ed36600461358c565b610455565b60405190151581526020015b60405180910390f35b61021a610215366004613619565b610466565b005b6102246104aa565b6040516101fe919061370f565b61024461023f366004613722565b61053c565b6040516001600160a01b0390911681526020016101fe565b61021a61026a366004613752565b610565565b610277610570565b6040519081526020016101fe565b600854610277565b61021a61029b36600461377c565b6106ae565b6102776102ae366004613752565b61073e565b61021a6102c136600461377c565b6107a3565b61021a6102d43660046137b8565b6107c3565b61021a6102e7366004613859565b6107ed565b6102776102fa366004613722565b610876565b61024461030d366004613722565b6108cf565b610224610320366004613722565b6108da565b6102776103333660046137b8565b6109e0565b61021a610a28565b61022461034e366004613722565b610a3c565b600a546001600160a01b0316610244565b610224610b1b565b61021a61037a36600461399e565b610b2a565b61021a61038d3660046139da565b610b35565b6103a56103a0366004613619565b610b4c565b6040516101fe9190613a56565b6102246103c0366004613722565b610c92565b61021a6103d3366004613722565b610ccb565b6103a56103e6366004613722565b610d90565b610224610e0a565b6101f2610401366004613aa3565b6001600160a01b03918216600090815260056020908152604080832093909416825291909152205460ff1690565b600b54610244906001600160a01b031681565b61021a6104503660046137b8565b610e56565b600061046082610e94565b92915050565b60005b81518110156104a65761049482828151811061048757610487613ad6565b6020026020010151610ccb565b8061049e81613b02565b915050610469565b5050565b6060600080546104b990613b1b565b80601f01602080910402602001604051908101604052809291908181526020018280546104e590613b1b565b80156105325780601f1061050757610100808354040283529160200191610532565b820191906000526020600020905b81548152906001019060200180831161051557829003601f168201915b5050505050905090565b600061054782610eb9565b506000828152600460205260409020546001600160a01b0316610460565b6104a6828233610ef2565b60008061057c60085490565b610587906001613b55565b905060006105bf61059783610eff565b44336040516020016105ab93929190613b68565b604051602081830303815290604052610fa0565b90506105cb818361100c565b604080516002808252606082018352600092602083019080368337019050509050338160008151811061060057610600613ad6565b60200260200101906001600160a01b031690816001600160a01b031681525050818160018151811061063457610634613ad6565b6001600160a01b03909216602092830291909101820152604080518083019091528281526013805460018101825560009190915281518051929384937f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090909301926106a292849201906134d5565b50949695505050505050565b6001600160a01b0382166106dd57604051633250574960e11b8152600060048201526024015b60405180910390fd5b60006106ea838333611026565b9050836001600160a01b0316816001600160a01b031614610738576040516364283d7b60e01b81526001600160a01b03808616600483015260248201849052821660448201526064016106d4565b50505050565b6000610749836109e0565b821061077a5760405163295f44f760e21b81526001600160a01b0384166004820152602481018390526044016106d4565b506001600160a01b03919091166000908152600660209081526040808320938352929052205490565b6107be83838360405180602001604052806000815250610b35565b505050565b6107cb611033565b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b6107f5611033565b8051600c906108049082613be8565b506020810151600d906108179082613be8565b506040810151600e9061082a9082613be8565b506060810151600f9061083d9082613be8565b5060808101516010906108509082613be8565b5060a08101516011906108639082613be8565b5060c08101516012906104a69082613be8565b600061088160085490565b82106108aa5760405163295f44f760e21b815260006004820152602481018390526044016106d4565b600882815481106108bd576108bd613ad6565b90600052602060002001549050919050565b600061046082610eb9565b60606000600b60009054906101000a90046001600160a01b03166001600160a01b0316632d15c0296040518163ffffffff1660e01b8152600401600060405180830381865afa158015610931573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526109599190810190613ca8565b905060006109d882856013878154811061097557610975613ad6565b60009182526020918290200180546040805182850281018501909152818152928301828280156109ce57602002820191906000526020600020905b81546001600160a01b031681526001909101906020018083116109b0575b5050505050611060565b949350505050565b60006001600160a01b038216610a0c576040516322718ad960e21b8152600060048201526024016106d4565b506001600160a01b031660009081526003602052604090205490565b610a30611033565b610a3a600061128b565b565b60606000610a49836108da565b9050610af4600c600001604051602001610a639190613d89565b604051602081830303815290604052610a7b85610eff565b610a84846112dd565b604051610a9690600d90602001613d89565b604051602081830303815290604052610acc60138981548110610abb57610abb613ad6565b600091825260209091200154610eff565b604051602001610ae0959493929190613db1565b6040516020818303038152906040526112dd565b604051602001610b049190613efa565b604051602081830303815290604052915050919050565b6060600180546104b990613b1b565b6104a63383836112eb565b610b408484846106ae565b6107388484848461138a565b60606000825167ffffffffffffffff811115610b6a57610b6a6135a9565b604051908082528060200260200182016040528015610b93578160200160208202803683370190505b50905060005b8351811015610c8b576000848281518110610bb657610bb6613ad6565b6020026020010151118015610be65750600854848281518110610bdb57610bdb613ad6565b602002602001015111155b15610c4457610c0d848281518110610c0057610c00613ad6565b60200260200101516108cf565b828281518110610c1f57610c1f613ad6565b60200260200101906001600160a01b031690816001600160a01b031681525050610c79565b6000828281518110610c5857610c58613ad6565b60200260200101906001600160a01b031690816001600160a01b0316815250505b80610c8381613b02565b915050610b99565b5092915050565b60606001821080610ca4575060085482115b15610cc257604051630cbdb7b360e41b815260040160405180910390fd5b61046082610a3c565b6001811080610cdb575060085481115b15610cf957604051630cbdb7b360e41b815260040160405180910390fd5b6000610d04826108cf565b90506000610d22610d1d610d184486613b55565b610eff565b610fa0565b9050610d3f828285604051806020016040528060008152506114b3565b60138381548110610d5257610d52613ad6565b60009182526020808320909101805460018101825590835291200180546001600160a01b039092166001600160a01b03199092169190911790555050565b606060138281548110610da557610da5613ad6565b6000918252602091829020018054604080518285028101850190915281815292830182828015610dfe57602002820191906000526020600020905b81546001600160a01b03168152600190910190602001808311610de0575b50505050509050919050565b604051606090610e3290610ae090600c90600d90600e90600f90601090601290602001613f3f565b604051602001610e429190613efa565b604051602081830303815290604052905090565b610e5e611033565b6001600160a01b038116610e8857604051631e4fbdf760e01b8152600060048201526024016106d4565b610e918161128b565b50565b60006001600160e01b0319821663780e9d6360e01b14806104605750610460826114bf565b6000818152600260205260408120546001600160a01b03168061046057604051637e27328960e01b8152600481018490526024016106d4565b6107be838383600161150f565b60606000610f0c83611634565b600101905060008167ffffffffffffffff811115610f2c57610f2c6135a9565b6040519080825280601f01601f191660200182016040528015610f56576020820181803683370190505b5090508181016020015b600019017f3031323334353637383961626364656600000000000000000000000000000000600a86061a8153600a8504945084610f60575b509392505050565b6000610fdc610fd783604051602001610fb9919061370f565b6040516020818303038152906040528051906020012060001c610eff565b611716565b604051602001610fee91815260200190565b60408051601f19818403018152919052805160209091012092915050565b6104a6828260405180602001604052806000815250611758565b60006109d884848461176f565b600a546001600160a01b03163314610a3a5760405163118cdaa760e01b81523360048201526024016106d4565b6060600060405160200161117b907f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222077696474683d223130302522206865696768743d2231303060208201527f25222066696c6c3d226e6f6e65222076696577426f783d22302030203131362060408201527f313430222073686170652d72656e646572696e673d226372697370456467657360608201527f223e3c706174682066696c6c3d22233030302220643d224d302030683131367660808201527f313430483056305a222f3e3c706174682066696c6c3d2223303530353035222060a08201527f643d224d3133203134683930763131324831335631345a222f3e00000000000060c082015260da0190565b60408051601f1981840301815260808301825260208084526030908401528282019190915260506060830152915060006111b5858261183c565b905060005b600481101561125e5760006111d1838a8a856119fc565b905060006111df602b610eff565b6112018685600481106111f4576111f4613ad6565b602002015160ff16610eff565b836040516020016112149392919061406a565b60405160208183030381529060405290508581604051602001611238929190614127565b60405160208183030381529060405295505050808061125690613b02565b9150506111ba565b50826040516020016112709190614156565b60405160208183030381529060405293505050509392505050565b600a80546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b606061046082600080611b25565b6001600160a01b03821661131d57604051630b61174360e31b81526001600160a01b03831660048201526024016106d4565b6001600160a01b03838116600081815260056020908152604080832094871680845294825291829020805460ff191686151590811790915591519182527f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a3505050565b6001600160a01b0383163b1561073857604051630a85bd0160e11b81526001600160a01b0384169063150b7a02906113cc903390889087908790600401614180565b6020604051808303816000875af1925050508015611407575060408051601f3d908101601f19168201909252611404918101906141b2565b60015b611470573d808015611435576040519150601f19603f3d011682016040523d82523d6000602084013e61143a565b606091505b50805160000361146857604051633250574960e11b81526001600160a01b03851660048201526024016106d4565b805181602001fd5b6001600160e01b03198116630a85bd0160e11b146114ac57604051633250574960e11b81526001600160a01b03851660048201526024016106d4565b5050505050565b6114ac83836000611026565b60006001600160e01b031982166380ac58cd60e01b14806114f057506001600160e01b03198216635b5e139f60e01b145b8061046057506301ffc9a760e01b6001600160e01b0319831614610460565b808061152357506001600160a01b03821615155b1561160457600061153384610eb9565b90506001600160a01b0383161580159061155f5750826001600160a01b0316816001600160a01b031614155b801561159157506001600160a01b0380821660009081526005602090815260408083209387168352929052205460ff16155b156115ba5760405163a9fbf51f60e01b81526001600160a01b03841660048201526024016106d4565b81156116025783856001600160a01b0316826001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92560405160405180910390a45b505b5050600090815260046020526040902080546001600160a01b0319166001600160a01b0392909216919091179055565b6000807a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000831061167d577a184f03e93ff9f4daa797ed6e38ed64bf6a1f010000000000000000830492506040015b6d04ee2d6d415b85acef810000000083106116a9576d04ee2d6d415b85acef8100000000830492506020015b662386f26fc1000083106116c757662386f26fc10000830492506010015b6305f5e10083106116df576305f5e100830492506008015b61271083106116f357612710830492506004015b60648310611705576064830492506002015b600a83106104605760010192915050565b600080448360405160200161172c9291906141cf565b60408051601f19818403018152919052805160209091012090506117516064826141f5565b9392505050565b6117628383611c0c565b6107be600084848461138a565b60008061177d858585611c71565b90506001600160a01b0381166117da576117d584600880546000838152600960205260408120829055600182018355919091527ff3f7a9fe364faab93b216da50a3214154f22a0a2b415b23a84c8169e8b636ee30155565b6117fd565b846001600160a01b0316816001600160a01b0316146117fd576117fd8185611d6a565b6001600160a01b0385166118195761181484611dfb565b6109d8565b846001600160a01b0316816001600160a01b0316146109d8576109d88585611eaa565b6060600080604590508085511015611852575083515b600061185f826004614209565b67ffffffffffffffff811115611877576118776135a9565b6040519080825280602002602001820160405280156118aa57816020015b60608152602001906001900390816118955790505b50905060005b828110156119f2576000816118c6600186614220565b6118d09190614220565b905086156119645760006118fc8983815181106118ef576118ef613ad6565b6020026020010151611efa565b905060005b600481101561195d5781816004811061191c5761191c613ad6565b602002015185888151811061193357611933613ad6565b6020908102919091010152611949600188613b55565b96508061195581613b02565b915050611901565b50506119df565b600061197b8983815181106118ef576118ef613ad6565b905060005b60048110156119dc5781816004811061199b5761199b613ad6565b60200201518588815181106119b2576119b2613ad6565b60209081029190910101526119c8600188613b55565b9650806119d481613b02565b915050611980565b50505b50806119ea81613b02565b9150506118b0565b5095945050505050565b604080516101a0810182526096815261012c6020808301829052828401829052606080840183905260808401929092526101f460a0840181905260c0840181905260e08401526102ee610100840181905261012084018190526101408401526103846101608401526104b0610180840152835190810186905290926000918391611a9191611a8a9101610fb9565b600d611f6c565b600d8110611aa157611aa1613ad6565b602002015161ffff1690506000611ab9888684611f82565b90506000888681518110611acf57611acf613ad6565b6020026020010151604051602001611ae79190614233565b60408051601f1981840301815290829052611b089184908b9060200161424f565b60408051808303601f190181529190529998505050505050505050565b606083518015610f98576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526106708515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f18603f52602083018181015b6003880197508751603f8160121c1651600053603f81600c1c1651600153603f8160061c1651600253603f811651600353506000518252600482019150808210611b9557602001604052613d3d60f01b60038406600204808303919091526000861515909102918290035290038252509392505050565b6001600160a01b038216611c3657604051633250574960e11b8152600060048201526024016106d4565b6000611c4483836000611026565b90506001600160a01b038116156107be576040516339e3563760e11b8152600060048201526024016106d4565b6000828152600260205260408120546001600160a01b0390811690831615611c9e57611c9e81848661211e565b6001600160a01b03811615611cdc57611cbb60008560008061150f565b6001600160a01b038116600090815260036020526040902080546000190190555b6001600160a01b03851615611d0b576001600160a01b0385166000908152600360205260409020805460010190555b60008481526002602052604080822080546001600160a01b0319166001600160a01b0389811691821790925591518793918516917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4949350505050565b6000611d75836109e0565b600083815260076020526040902054909150808214611dc8576001600160a01b03841660009081526006602090815260408083208584528252808320548484528184208190558352600790915290208190555b5060009182526007602090815260408084208490556001600160a01b039094168352600681528383209183525290812055565b600854600090611e0d90600190614220565b60008381526009602052604081205460088054939450909284908110611e3557611e35613ad6565b906000526020600020015490508060088381548110611e5657611e56613ad6565b6000918252602080832090910192909255828152600990915260408082208490558582528120556008805480611e8e57611e8e6142ca565b6001900381819060005260206000200160009055905550505050565b60006001611eb7846109e0565b611ec19190614220565b6001600160a01b039093166000908152600660209081526040808320868452825280832085905593825260079052919091209190915550565b611f0261353a565b6001600160a01b038216611f1857610460612182565b60ff828116066001600160a01b0383166000611f446001610167611f3f601386901a610eff565b6121df565b90506000601960ff85160660010160ff169050611f62848383612233565b9695505050505050565b600081611f7884612293565b61175191906141f5565b606060006040518060600160405280603f8152602001614541603f91399050606080868681518110611fb657611fb6613ad6565b6020026020010151604051602001611fce9190614233565b60408051601f1981840301815290829052611fec92916020016142e0565b604051602081830303815290604052905060005b8651811015612076578187828151811061201c5761201c613ad6565b60200260200101516040516020016120349190614233565b60408051601f198184030181529082905261205292916020016142e0565b6040516020818303038152906040529150808061206e90613b02565b915050612000565b508086868151811061208a5761208a613ad6565b60200260200101516040516020016120a29190614233565b60408051601f19818403018152908290526120c092916020016142e0565b604051602081830303815290604052905081816120e3885187610d189190614209565b6120f1610d18896004614220565b604051602001612104949392919061431b565b60408051808303601f190181529190529695505050505050565b6121298383836122a6565b6107be576001600160a01b03831661215757604051637e27328960e01b8152600481018290526024016106d4565b60405163177e802f60e01b81526001600160a01b0383166004820152602481018290526044016106d4565b61218a61353a565b60405180608001604052806121a2600080600f612329565b81526020016121b46000806019612329565b81526020016121c6600080603c612329565b81526020016121d8600080605a612329565b9052919050565b6000836121ec8185614220565b6121f7906001613b55565b61221f8460405160200161220b9190614233565b604051602081830303815290604052612293565b61222991906141f5565b6109d89190613b55565b61223b61353a565b60405180608001604052806122536001878787612370565b81526020016122656002878787612370565b81526020016122776003878787612370565b81526020016122896004878787612370565b9052949350505050565b600081604051602001610fee9190614233565b60006001600160a01b038316158015906109d85750826001600160a01b0316846001600160a01b0316148061230057506001600160a01b0380851660009081526005602090815260408083209387168352929052205460ff165b806109d85750506000908152600460205260409020546001600160a01b03908116911614919050565b606061233484610eff565b61233d84610eff565b61234684610eff565b604051602001612358939291906143c3565b60405160208183030381529060405290509392505050565b606061239a612381858786866123a3565b61238b8688612450565b6123958789612594565b612329565b95945050505050565b600061239a8560026123bb60ff808916908416613b55565b6123c591906141f5565b8660ff166001146123fa57846123e160ff808a16908b16613b55565b6123eb91906141f5565b6123f59087613b55565b6123fc565b855b6040516001600160f81b031960f88b811b821660208401528a901b1660218201526268756560e81b602282015261244b90600f906032906025015b6040516020818303038152906040526121df565b612638565b6000806124946008601486604051602001612437919060f89190911b6001600160f81b03191681526c39b0ba3ab930ba34b7b726b4b760991b6001820152600e0190565b905060006124d9604b606487604051602001612437919060f89190911b6001600160f81b03191681526c0e6c2e8eae4c2e8d2dedc9ac2f609b1b6001820152600e0190565b90508360ff166001036124ea575060165b8360ff166002036124f9575060285b61239a612507600287614444565b61251286600a614466565b61251c9085614482565b60ff168360ff1661258f600189612533919061449b565b61253e906019614466565b60ff1661254c8a6019614466565b6040516001600160f81b031960f88e811b821660208401528d901b1660218201526939b0ba3ab930ba34b7b760b11b602282015260ff9190911690602c01612437565b61278e565b60006008600f60ff84166002036125ad575060159050601f5b8360ff166003036125c0575060239050602f5b8360ff166004036125ef57603491506125da600686614444565b60ff16156125e95760446125ec565b604b5b90505b61239a6125fd600287614444565b8360ff168360ff1661263360016063611f3f8c604051602001610fb9919060f89190911b6001600160f81b031916815260010190565b6127d9565b600080612646600487614444565b60ff1690508360008290036126b7576126ae861561266e5761266982600a6144b4565b612679565b6126796000836144dc565b6126869060ff87166144fc565b8261269560ff881660646144dc565b61269f91906144fc565b6126a991906144b4565b61284a565b925050506109d8565b816001036126de576126ae86156126d35761266982601e6144b4565b612679601e836144dc565b81600203612738576126ae86156126ff576126fa8260326144b4565b61270a565b61270a6032836144dc565b6127168660ff1661287d565b61272091906144fc565b8261272d8760ff1661287d565b6126959060646144dc565b61278360808860ff161161274d576000612750565b60015b60ff16871561276057603c612764565b603b195b61276e91906144fc565b61277890836144b4565b61270a90601e6144b4565b979650505050505050565b6000808560ff166000036127c1576127a583612d73565b60ff1690506064818103860285830201046001019150506109d8565b50816064818103860285830201049695505050505050565b6000808560ff166000036127fa576127f083612d73565b60ff169050612809565b612803836130cf565b60ff1690505b60646128158583614209565b86612821846064614220565b61282b9190614209565b6128359190613b55565b61283f919061452c565b611f62906001613b55565b60649005600080821261286357610168825b0692915050565b61016882600019028161285c5761285c614054565b919050565b6000600d8261ffff16101561289457506000919050565b60118261ffff1610156128a957506001919050565b60138261ffff1610156128be57506002919050565b60158261ffff1610156128d357506003919050565b60178261ffff1610156128e857506004919050565b60188261ffff1610156128fd57506005919050565b60198261ffff16101561291257506006919050565b601b8261ffff16101561292757506007919050565b601c8261ffff16101561293c57506008919050565b601d8261ffff16101561295157506009919050565b601e8261ffff1610156129665750600a919050565b601f8261ffff16101561297b5750600b919050565b60208261ffff1610156129905750600d919050565b60218261ffff1610156129a55750600e919050565b60228261ffff1610156129ba5750600f919050565b60238261ffff1610156129cf57506011919050565b60248261ffff1610156129e457506012919050565b60258261ffff1610156129f957506014919050565b60268261ffff161015612a0e57506015919050565b60278261ffff161015612a2357506017919050565b60288261ffff161015612a3857506019919050565b60298261ffff161015612a4d5750601b919050565b602a8261ffff161015612a625750601d919050565b602b8261ffff161015612a775750601f919050565b602c8261ffff161015612a8c57506022919050565b602d8261ffff161015612aa157506024919050565b602e8261ffff161015612ab657506026919050565b602f8261ffff161015612acb57506029919050565b60308261ffff161015612ae05750602c919050565b60318261ffff161015612af55750602f919050565b60328261ffff161015612b0a57506032919050565b60338261ffff161015612b1f57506034919050565b60348261ffff161015612b3457506037919050565b60358261ffff161015612b495750603a919050565b60368261ffff161015612b5e5750603d919050565b60378261ffff161015612b735750603f919050565b60388261ffff161015612b8857506041919050565b60398261ffff161015612b9d57506044919050565b603a8261ffff161015612bb257506046919050565b603b8261ffff161015612bc757506048919050565b603c8261ffff161015612bdc5750604a919050565b603d8261ffff161015612bf15750604c919050565b603e8261ffff161015612c065750604e919050565b603f8261ffff161015612c1b5750604f919050565b60408261ffff161015612c3057506051919050565b60418261ffff161015612c4557506052919050565b60428261ffff161015612c5a57506054919050565b60438261ffff161015612c6f57506055919050565b60448261ffff161015612c8457506056919050565b60458261ffff161015612c9957506058919050565b60468261ffff161015612cae57506059919050565b60478261ffff161015612cc35750605a919050565b60488261ffff161015612cd85750605b919050565b604a8261ffff161015612ced5750605c919050565b604b8261ffff161015612d025750605d919050565b604c8261ffff161015612d175750605e919050565b604e8261ffff161015612d2c5750605f919050565b60508261ffff161015612d4157506060919050565b60528261ffff161015612d5657506061919050565b60568261ffff161015612d6b57506062919050565b506063919050565b60006027821015612d8657506000919050565b602d821015612d9757506001919050565b6031821015612da857506002919050565b6034821015612db957506003919050565b6035821015612dca57506004919050565b6036821015612ddb57506004919050565b6037821015612dec57506005919050565b6038821015612dfd57506005919050565b6039821015612e0e57506006919050565b603a821015612e1f57506006919050565b603b821015612e3057506007919050565b603c821015612e4157506007919050565b603d821015612e5257506008919050565b603e821015612e6357506009919050565b603f821015612e7457506009919050565b6040821015612e855750600a919050565b6041821015612e965750600b919050565b6042821015612ea75750600c919050565b6043821015612eb85750600d919050565b6044821015612ec95750600e919050565b6045821015612eda5750600f919050565b6046821015612eeb57506010919050565b6047821015612efc57506012919050565b6048821015612f0d57506013919050565b6049821015612f1e57506014919050565b604a821015612f2f57506016919050565b604b821015612f4057506017919050565b604c821015612f5157506019919050565b604d821015612f625750601b919050565b604e821015612f735750601c919050565b604f821015612f845750601e919050565b6050821015612f9557506020919050565b6051821015612fa657506022919050565b6052821015612fb757506025919050565b6053821015612fc857506027919050565b6054821015612fd957506029919050565b6055821015612fea5750602c919050565b6056821015612ffb5750602f919050565b605782101561300c57506031919050565b605882101561301d57506034919050565b605982101561302e57506037919050565b605a82101561303f5750603b919050565b605b8210156130505750603e919050565b605c82101561306157506041919050565b605d82101561307257506045919050565b605e82101561308357506049919050565b605f8210156130945750604d919050565b60608210156130a557506051919050565b60618210156130b657506055919050565b60628210156130c75750605a919050565b50605f919050565b600060168210156130e257506000919050565b601c8210156130f357506001919050565b602082101561310457506002919050565b602082101561311557506003919050565b602282101561312657506003919050565b602482101561313757506004919050565b602782101561314857506005919050565b602982101561315957506006919050565b602b82101561316a57506007919050565b602e82101561317b57506009919050565b602f82101561318c5750600a919050565b603182101561319d5750600b919050565b60328210156131ae5750600c919050565b60338210156131bf5750600d919050565b60358210156131d05750600e919050565b60368210156131e15750600f919050565b60378210156131f257506010919050565b603882101561320357506011919050565b603982101561321457506012919050565b603a82101561322557506013919050565b603b82101561323657506014919050565b603c82101561324757506015919050565b603d82101561325857506016919050565b603e82101561326957506017919050565b603f82101561327a57506019919050565b604082101561328b5750601a919050565b604182101561329c5750601b919050565b60428210156132ad5750601c919050565b60438210156132be5750601e919050565b60448210156132cf5750601f919050565b60458210156132e057506020919050565b60468210156132f157506022919050565b604782101561330257506023919050565b604882101561331357506025919050565b604982101561332457506026919050565b604a82101561333557506028919050565b604b8210156133465750602a919050565b604c8210156133575750602b919050565b604d8210156133685750602d919050565b604e8210156133795750602f919050565b604f82101561338a57506031919050565b605082101561339b57506033919050565b60518210156133ac57506035919050565b60528210156133bd57506037919050565b60538210156133ce57506039919050565b60548210156133df5750603b919050565b60558210156133f05750603d919050565b60568210156134015750603f919050565b605782101561341257506041919050565b605882101561342357506044919050565b605982101561343457506046919050565b605a82101561344557506048919050565b605b8210156134565750604b919050565b605c8210156134675750604d919050565b605d82101561347857506050919050565b605e82101561348957506053919050565b605f82101561349a57506055919050565b60608210156134ab57506058919050565b60618210156134bc5750605b919050565b60628210156134cd5750605e919050565b506061919050565b82805482825590600052602060002090810192821561352a579160200282015b8281111561352a57825182546001600160a01b0319166001600160a01b039091161782556020909201916001909101906134f5565b50613536929150613561565b5090565b60405180608001604052806004905b60608152602001906001900390816135495790505090565b5b808211156135365760008155600101613562565b6001600160e01b031981168114610e9157600080fd5b60006020828403121561359e57600080fd5b813561175181613576565b634e487b7160e01b600052604160045260246000fd5b60405160e0810167ffffffffffffffff811182821017156135e2576135e26135a9565b60405290565b604051601f8201601f1916810167ffffffffffffffff81118282101715613611576136116135a9565b604052919050565b6000602080838503121561362c57600080fd5b823567ffffffffffffffff8082111561364457600080fd5b818501915085601f83011261365857600080fd5b81358181111561366a5761366a6135a9565b8060051b915061367b8483016135e8565b818152918301840191848101908884111561369557600080fd5b938501935b838510156136b35784358252938501939085019061369a565b98975050505050505050565b60005b838110156136da5781810151838201526020016136c2565b50506000910152565b600081518084526136fb8160208601602086016136bf565b601f01601f19169290920160200192915050565b60208152600061175160208301846136e3565b60006020828403121561373457600080fd5b5035919050565b80356001600160a01b038116811461287857600080fd5b6000806040838503121561376557600080fd5b61376e8361373b565b946020939093013593505050565b60008060006060848603121561379157600080fd5b61379a8461373b565b92506137a86020850161373b565b9150604084013590509250925092565b6000602082840312156137ca57600080fd5b6117518261373b565b600067ffffffffffffffff8211156137ed576137ed6135a9565b50601f01601f191660200190565b600061380e613809846137d3565b6135e8565b905082815283838301111561382257600080fd5b828260208301376000602084830101529392505050565b600082601f83011261384a57600080fd5b611751838335602085016137fb565b60006020828403121561386b57600080fd5b813567ffffffffffffffff8082111561388357600080fd5b9083019060e0828603121561389757600080fd5b61389f6135bf565b8235828111156138ae57600080fd5b6138ba87828601613839565b8252506020830135828111156138cf57600080fd5b6138db87828601613839565b6020830152506040830135828111156138f357600080fd5b6138ff87828601613839565b60408301525060608301358281111561391757600080fd5b61392387828601613839565b60608301525060808301358281111561393b57600080fd5b61394787828601613839565b60808301525060a08301358281111561395f57600080fd5b61396b87828601613839565b60a08301525060c08301358281111561398357600080fd5b61398f87828601613839565b60c08301525095945050505050565b600080604083850312156139b157600080fd5b6139ba8361373b565b9150602083013580151581146139cf57600080fd5b809150509250929050565b600080600080608085870312156139f057600080fd5b6139f98561373b565b9350613a076020860161373b565b925060408501359150606085013567ffffffffffffffff811115613a2a57600080fd5b8501601f81018713613a3b57600080fd5b613a4a878235602084016137fb565b91505092959194509250565b6020808252825182820181905260009190848201906040850190845b81811015613a975783516001600160a01b031683529284019291840191600101613a72565b50909695505050505050565b60008060408385031215613ab657600080fd5b613abf8361373b565b9150613acd6020840161373b565b90509250929050565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052601160045260246000fd5b600060018201613b1457613b14613aec565b5060010190565b600181811c90821680613b2f57607f821691505b602082108103613b4f57634e487b7160e01b600052602260045260246000fd5b50919050565b8082018082111561046057610460613aec565b606081526000613b7b60608301866136e3565b90508360208301526001600160a01b0383166040830152949350505050565b601f8211156107be57600081815260208120601f850160051c81016020861015613bc15750805b601f850160051c820191505b81811015613be057828155600101613bcd565b505050505050565b815167ffffffffffffffff811115613c0257613c026135a9565b613c1681613c108454613b1b565b84613b9a565b602080601f831160018114613c4b5760008415613c335750858301515b600019600386901b1c1916600185901b178555613be0565b600085815260208120601f198616915b82811015613c7a57888601518255948401946001909101908401613c5b565b5085821015613c985787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060208284031215613cba57600080fd5b815167ffffffffffffffff811115613cd157600080fd5b8201601f81018413613ce257600080fd5b8051613cf0613809826137d3565b818152856020838501011115613d0557600080fd5b61239a8260208301602086016136bf565b60008154613d2381613b1b565b60018281168015613d3b5760018114613d5057613d7f565b60ff1984168752821515830287019450613d7f565b8560005260208060002060005b85811015613d765781548a820152908401908201613d5d565b50505082870194505b5050505092915050565b60006117518284613d16565b60008151613da78185602086016136bf565b9290920192915050565b693d913730b6b2911d101160b11b81528551600090613dd781600a850160208b016136bf565b600160fd1b600a918401918201528651613df881600b840160208b016136bf565b7f222c2022696d616765223a2022646174613a696d6167652f7376672b786d6c3b600b92909101918201526618985cd94d8d0b60ca1b602b8201528551613e46816032840160208a016136bf565b72111610113232b9b1b934b83a34b7b7111d101160691b603292909101918201528451613e7a8160458401602089016136bf565b7f222c202261747472696275746573223a205b0000000000000000000000000000910160458101919091527f7b2274726169745f74797065223a20225472616e7366657273222c202276616c6057820152653ab2911d101160d11b60778201526136b3613eea607d830186613d95565b63227d5d7d60e01b815260040190565b7f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815260008251613f3281601d8501602087016136bf565b91909101601d0192915050565b693d913730b6b2911d101160b11b81526000613f5e600a830189613d16565b72111610113232b9b1b934b83a34b7b7111d101160691b8152613f846013820189613d16565b6c1116101134b6b0b3b2911d101160991b81529050613fa6600d820188613d16565b90507f222c202273656c6c65725f6665655f62617369735f706f696e7473223a2022008152613fd8601f820187613d16565b90507f222c202273656c6c65725f6665655f726563697069656e74223a202200000000815261400a601c820186613d16565b90507f222c2022616e696d6174696f6e5f75726c223a20220000000000000000000000815261403c6015820185613d16565b61227d60f01b81526002019998505050505050505050565b634e487b7160e01b600052601260045260246000fd5b671e39bb33903c1e9160c11b8152835160009061408e8160088501602089016136bf565b6411103c9e9160d91b60089184019182015284516140b381600d8401602089016136bf565b7f222077696474683d22323922206865696768743d223239222076696577426f78600d92909101918201526c1e9118101810191c90191c911f60991b602d820152835161410781603a8401602088016136bf565b651e17b9bb339f60d11b603a929091019182015260400195945050505050565b600083516141398184602088016136bf565b83519083019061414d8183602088016136bf565b01949350505050565b600082516141688184602087016136bf565b651e17b9bb339f60d11b920191825250600601919050565b60006001600160a01b03808716835280861660208401525083604083015260806060830152611f6260808301846136e3565b6000602082840312156141c457600080fd5b815161175181613576565b828152600082516141e78160208501602087016136bf565b919091016020019392505050565b60008261420457614204614054565b500690565b808202811582820484141761046057610460613aec565b8181038181111561046057610460613aec565b600082516142458184602087016136bf565b9190910192915050565b681e33903334b6361e9160b91b815283516000906142748160098501602089016136bf565b61111f60f11b600991840191820152845161429681600b8401602089016136bf565b84519101906142ac81600b8401602088016136bf565b631e17b39f60e11b600b9290910191820152600f0195945050505050565b634e487b7160e01b600052603160045260246000fd5b600083516142f28184602088016136bf565b8351908301906143068183602088016136bf565b603b60f81b9101908152600101949350505050565b6000855161432d818460208a016136bf565b855190830190614341818360208a016136bf565b661110323ab91e9160c91b910190815284516143648160078401602089016136bf565b7f6d73222020626567696e3d22302e0000000000000000000000000000000000006007929091019182015283516143a28160158401602088016136bf565b6539911010179f60d11b60159290910191820152601b019695505050505050565b630d0e6d8560e31b8152600084516143e28160048501602089016136bf565b61016160f51b60049184019182015284516144048160068401602089016136bf565b6201296160ed1b6006929091019182015283516144288160098401602088016136bf565b61252960f01b60099290910191820152600b0195945050505050565b600060ff83168061445757614457614054565b8060ff84160691505092915050565b60ff8181168382160290811690818114610c8b57610c8b613aec565b60ff818116838216019081111561046057610460613aec565b60ff828116828216039081111561046057610460613aec565b80820182811260008312801582168215821617156144d4576144d4613aec565b505092915050565b8181036000831280158383131683831282161715610c8b57610c8b613aec565b80820260008212600160ff1b8414161561451857614518613aec565b818105831482151761046057610460613aec565b60008261453b5761453b614054565b50049056fe3c616e696d617465206174747269627574654e616d653d2266696c6c2220726570656174436f756e743d22696e646566696e697465222076616c7565733d22a26469706673582212207b6c61e35291a6d05244eeefbdbb30c0ba25a4418a6e25acc44a4794b5ffd0b664736f6c63430008140033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a0000000000000000000000000cb43078c32423f5348cab5885911c3b5fae217f900000000000000000000000000000000000000000000000000000000000000065a6f72626974000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000045a52425400000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : tokenName (string): Zorbit
Arg [1] : tokenSymbol (string): ZRBT
Arg [2] : initialOwner (address): 0xCB43078C32423F5348Cab5885911C3B5faE217F9
-----Encoded View---------------
7 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000060
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000a0
Arg [2] : 000000000000000000000000cb43078c32423f5348cab5885911c3b5fae217f9
Arg [3] : 0000000000000000000000000000000000000000000000000000000000000006
Arg [4] : 5a6f726269740000000000000000000000000000000000000000000000000000
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [6] : 5a52425400000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.