Source Code
Overview
ETH Balance
0.360019766006301955 ETH
Eth Value
$705.63 (@ $1,959.98/ETH)More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 3,268 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Lock Frame | 24566136 | 37 mins ago | IN | 0 ETH | 0.00063947 | ||||
| Lock Frame | 24565914 | 1 hr ago | IN | 0 ETH | 0.00060686 | ||||
| Lock Frame | 24565909 | 1 hr ago | IN | 0 ETH | 0.00060821 | ||||
| Lock Frame | 24565799 | 1 hr ago | IN | 0 ETH | 0.00003122 | ||||
| Mint | 24565798 | 1 hr ago | IN | 0.02532945 ETH | 0.00008572 | ||||
| Lock Frame | 24565796 | 1 hr ago | IN | 0 ETH | 0.00060975 | ||||
| Set Approval For... | 24565710 | 2 hrs ago | IN | 0 ETH | 0.00009748 | ||||
| Lock Frame | 24565696 | 2 hrs ago | IN | 0 ETH | 0.00002255 | ||||
| Lock Frame | 24565625 | 2 hrs ago | IN | 0 ETH | 0.00060566 | ||||
| Mint | 24565620 | 2 hrs ago | IN | 0.0045817 ETH | 0.00042129 | ||||
| Lock Frame | 24565521 | 2 hrs ago | IN | 0 ETH | 0.00062352 | ||||
| Lock Frame | 24565423 | 3 hrs ago | IN | 0 ETH | 0.00030997 | ||||
| Lock Frame | 24565365 | 3 hrs ago | IN | 0 ETH | 0.0003374 | ||||
| Lock Frame | 24565336 | 3 hrs ago | IN | 0 ETH | 0.00062181 | ||||
| Lock Frame | 24565306 | 3 hrs ago | IN | 0 ETH | 0.0000513 | ||||
| Mint | 24565305 | 3 hrs ago | IN | 0.00457918 ETH | 0.00001523 | ||||
| Mint | 24565298 | 3 hrs ago | IN | 0.00938732 ETH | 0.00004201 | ||||
| Lock Frame | 24565263 | 3 hrs ago | IN | 0 ETH | 0.00002313 | ||||
| Mint | 24565238 | 3 hrs ago | IN | 0.00938732 ETH | 0.00061281 | ||||
| Lock Frame | 24565204 | 3 hrs ago | IN | 0 ETH | 0.00061666 | ||||
| Lock Frame | 24565185 | 3 hrs ago | IN | 0 ETH | 0.00062948 | ||||
| Mint | 24565169 | 3 hrs ago | IN | 0.00457918 ETH | 0.00047282 | ||||
| Lock Frame | 24565157 | 3 hrs ago | IN | 0 ETH | 0.00066123 | ||||
| Set Approval For... | 24564948 | 4 hrs ago | IN | 0 ETH | 0.00000956 | ||||
| Mint | 24564931 | 4 hrs ago | IN | 0.00457641 ETH | 0.00002791 |
Latest 10 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| Mint | 24565626 | 2 hrs ago | 0.01516603 ETH | ||||
| Mint | 24565559 | 2 hrs ago | 0.0045817 ETH | ||||
| Transfer | 24555285 | 36 hrs ago | 16.00182425 ETH | ||||
| Mint | 24542991 | 3 days ago | 0.02413538 ETH | ||||
| Mint | 24532536 | 4 days ago | 0.0042901 ETH | ||||
| Mint | 24529859 | 5 days ago | 0.02355885 ETH | ||||
| Mint | 24528045 | 5 days ago | 0.00861 ETH | ||||
| Mint | 24523509 | 5 days ago | 0.02320765 ETH | ||||
| Mint | 24522464 | 6 days ago | 0.00904545 ETH | ||||
| Mint | 24522460 | 6 days ago | 0.0042023 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
Contract Name:
ToBeAMachine
Compiler Version
v0.8.23+commit.f704f362
Optimization Enabled:
Yes with 1 runs
Other Settings:
paris EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity =0.8.23;
import "erc721a/contracts/ERC721A.sol";
import "erc721a/contracts/extensions/ERC721ABurnable.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/utils/ReentrancyGuard.sol";
import "@openzeppelin/contracts/token/common/ERC2981.sol";
import "../interfaces/IToBeAMachineRenderer.sol";
import "../interfaces/IToBeAMachineEditions.sol";
import "../interfaces/IToBeAMachineCalibrationRenderer.sol";
import "../interfaces/ITBAMAuctionHouse.sol";
import "../interfaces/IMintWindowManager.sol";
/**
* @title ToBeAMachine
* @notice ERC-721A collection of generative screen tests that evolve with each block
* until the collector locks a specific frame, creating a permanent print
*
* Core mechanics:
* - Each token shows a different image every block based on mint hash, token ID, and current block hash
* - Collectors can call lockFrame() to permanently capture a specific frame ("commit")
* - When locked, a 24-hour open edition is created for that frame
*
* Mint window system:
* - Delegated to MintWindowManager for upgradeability
* - First Run: 24-hour initial mint period, settlements ARE allowed
* - After First Run: Machine goes idle until someone commits (locks a frame)
* - Commits: Each commit opens or queues a new window (69 minutes)
*/
contract ToBeAMachine is ERC721A, ERC721ABurnable, Ownable, ReentrancyGuard, ERC2981 {
// ============ Errors ============
error MintPriceNotMet();
error NonexistentToken();
error TokenAlreadyLocked();
error InvalidLockBlockNumber();
error BlockHashNotAvailable();
error NotTokenOwnerOrApproved();
error EditionsNotSet();
error Token0AlreadyMinted();
error Token0CannotBeLocked();
error MachineNotOpen();
error Unauthorized();
error MintWindowManagerNotSet();
error CalibrationRendererNotSet();
error MintingIsPaused();
error InvalidPayoutRecipient();
error PayoutRecipientNotSet();
// ============ State Variables ============
/// @notice Address of the renderer contract
address public renderer;
/// @notice Address of the calibration plate renderer contract (for token 0)
address public calibrationRenderer;
/// @notice Address of the editions contract
address public editions;
/// @notice Collection-level metadata URI (OpenSea contractURI standard)
string public contractURI;
/// @notice Address of the mint window manager contract
address public mintWindowManager;
// Per-token storage
/// @notice Unix timestamp when each token was minted
mapping(uint256 => uint64) public mintedAt;
/// @notice Unix timestamp when each token was locked (0 if still live)
mapping(uint256 => uint64) public lockedAt;
/// @notice Block number when each token was minted
mapping(uint256 => uint64) public mintBlockNumber;
/// @notice Block hash from mint (part of seed)
mapping(uint256 => bytes32) public mintBlockHash;
/// @notice Block number used for locked frame
mapping(uint256 => uint64) public lockBlockNumber;
/// @notice Block hash used for locked frame (permanent after lock)
mapping(uint256 => bytes32) public lockBlockHash;
/// @notice Whether each token's frame is locked
mapping(uint256 => bool) public isLocked;
/// @notice Which print run (window) each token was minted during
/// @dev 0 = First Run, 1+ = Print Run number
mapping(uint256 => uint256) public tokenPrintRun;
/// @notice Address authorized to start first run (e.g., auction contract)
address public auctionContract;
/// @notice Whether minting is paused (prevents new mints and new mint windows)
bool public mintingPaused;
/// @notice Addresses authorized to perform admin functions
mapping(address => bool) public isAdmin;
/// @notice Address that receives funds when withdraw() is called
address public payoutRecipient;
// ============ Events ============
event FrameLocked(
uint256 indexed tokenId,
address indexed owner,
uint64 lockedAt,
uint64 lockBlockNumber,
bytes32 lockBlockHash,
uint256 currentWindowId,
uint256 cumulativePriceIncrease
);
event MintWindowManagerUpdated(address indexed oldManager, address indexed newManager);
event MintingPausedUpdated(bool paused);
/// @dev EIP-4906: Emitted when the metadata of a token is changed
event MetadataUpdate(uint256 _tokenId);
/// @dev EIP-4906: Emitted when the metadata of a range of tokens is changed
event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId);
event RendererUpdated(
address indexed oldRenderer,
address indexed newRenderer
);
event EditionsUpdated(
address indexed oldEditions,
address indexed newEditions
);
event CalibrationRendererUpdated(
address indexed oldCalibrationRenderer,
address indexed newCalibrationRenderer
);
event AdminUpdated(address indexed admin, bool status);
event PayoutRecipientUpdated(address indexed oldRecipient, address indexed newRecipient);
// ============ Modifiers ============
modifier onlyAdmin() {
if (!isAdmin[msg.sender] && msg.sender != owner())
revert Unauthorized();
_;
}
// ============ Constructor ============
constructor(
address _renderer,
address _editions,
address _mintWindowManager
) ERC721A("To Be a Machine", "MACHINE") Ownable(msg.sender) {
renderer = _renderer;
editions = _editions;
mintWindowManager = _mintWindowManager;
}
// ============ Minting ============
/**
* @notice Mint token 0 to a specified address (admin only)
* @dev Token 0 has special on-chain metadata, separate from the renderer
* @param to Address to mint token 0 to
*/
function mintToken0(address to) external onlyAdmin {
if (_nextTokenId() != 0) revert Token0AlreadyMinted();
_safeMint(to, 1);
// Store mint data
mintedAt[0] = uint64(block.timestamp);
mintBlockNumber[0] = uint64(block.number);
mintBlockHash[0] = blockhash(block.number - 1);
}
/**
* @notice Mint new screen test tokens
* @dev Price calculated by MintWindowManager, includes per-wallet escalation
* Machine must be open (during First Run or during an active mint window)
* @param amount Number of tokens to mint
*/
function mint(uint256 amount) external payable nonReentrant {
if (mintingPaused) revert MintingIsPaused();
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
require(amount > 0 && amount <= 50, "Invalid mint amount");
IMintWindowManager manager = IMintWindowManager(mintWindowManager);
if (!manager.isMachineOpen()) revert MachineNotOpen();
// Calculate total price with per-wallet escalation
uint256 mintPriceWei = manager.mintPriceFor(msg.sender, amount);
if (msg.value < mintPriceWei) revert MintPriceNotMet();
// Notify manager of mint (updates throttle state)
manager.processMint(msg.sender, amount);
// Get the starting token ID for this mint batch
uint256 startTokenId = _nextTokenId();
// We use blockhash(block.number - 1) because:
// - blockhash(block.number) is always 0 (current block hash not yet available)
// - blockhash(block.number - 1) gives us the most recent known block hash
// - This hash is part of the seed and ensures each token has a consistent starting point
bytes32 mintHash = blockhash(block.number - 1);
uint64 mintTime = uint64(block.timestamp);
uint64 mintBlock = uint64(block.number);
// Get current print run from manager
uint256 currentPrintRun = manager.currentWindowId();
// Store mint data for each newly minted token BEFORE _safeMint
// This prevents external contracts from reading zeroed-out data during onERC721Received callback
for (uint256 i = 0; i < amount; i++) {
uint256 tokenId = startTokenId + i;
mintedAt[tokenId] = mintTime;
mintBlockNumber[tokenId] = mintBlock;
mintBlockHash[tokenId] = mintHash;
tokenPrintRun[tokenId] = currentPrintRun;
}
// Mint tokens using ERC721A's efficient batch minting
_safeMint(msg.sender, amount);
}
// ============ Locking (Commits) ============
/**
* @notice Lock a specific frame for a token, permanently capturing its current visual state
* @dev Creates a 24-hour open edition. Allowed during First Run (settlements don't affect windows).
* Each commit after First Run opens or queues a new window.
* @param tokenId The token ID to lock
* @param requestedLockBlockNumber The block number to use for locking (0 for most recent)
*/
function lockFrame(
uint256 tokenId,
uint256 requestedLockBlockNumber
) external nonReentrant {
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
// Token 0 (calibration plate) cannot be locked
if (tokenId == 0) revert Token0CannotBeLocked();
// Access control: only token owner or approved operator
if (!_isApprovedOrOwner(msg.sender, tokenId)) {
revert NotTokenOwnerOrApproved();
}
// Check if already locked
if (isLocked[tokenId]) {
revert TokenAlreadyLocked();
}
// Determine which block number to use for locking
uint256 lockBlock;
if (requestedLockBlockNumber == 0) {
// Use most recent block (same as mint logic)
lockBlock = block.number - 1;
} else {
lockBlock = requestedLockBlockNumber;
}
// Validate lock block number
if (lockBlock < mintBlockNumber[tokenId]) {
revert InvalidLockBlockNumber();
}
// Block must be within the last 256 blocks for blockhash to be available
// (EVM only stores the most recent 256 block hashes)
// Handle underflow: if block.number < 256, all blocks are valid
if (block.number > 256 && lockBlock < block.number - 256) {
revert InvalidLockBlockNumber();
}
if (lockBlock >= block.number) {
revert InvalidLockBlockNumber();
}
// Get the block hash and ensure it's available
bytes32 lockHash = blockhash(lockBlock);
if (lockHash == bytes32(0)) {
revert BlockHashNotAvailable();
}
// Mark token as locked and store lock data
isLocked[tokenId] = true;
uint64 lockTime = uint64(block.timestamp);
lockedAt[tokenId] = lockTime;
lockBlockNumber[tokenId] = uint64(lockBlock);
lockBlockHash[tokenId] = lockHash;
// Notify manager of settlement (handles window logic)
// Skip if minting is paused to prevent new windows from opening
IMintWindowManager manager = IMintWindowManager(mintWindowManager);
if (!mintingPaused) {
manager.processSettlement();
}
// Emit EIP-4906 metadata update for marketplaces
emit MetadataUpdate(tokenId);
emit FrameLocked(
tokenId,
msg.sender,
lockTime,
uint64(lockBlock),
lockHash,
manager.currentWindowId(),
manager.cumulativePriceIncrease()
);
// Notify editions contract to open a 24-hour edition window
// The printer (msg.sender) receives 1 free edition
if (editions == address(0)) revert EditionsNotSet();
IToBeAMachineEditions(editions).startEditionForLockedFrame(
tokenId,
msg.sender
);
}
// ============ View Functions ============
/**
* @notice Get seed inputs for rendering a token
* @dev Used by the renderer to generate consistent visuals
* @param tokenId The token ID
* @return mintHash The block hash from mint
* @return activeBlockHash The current active block hash (locked hash if locked, current if live)
* @return locked Whether the token is locked
*/
function getSeedInputs(
uint256 tokenId
)
external
view
returns (bytes32 mintHash, bytes32 activeBlockHash, bool locked)
{
if (!_exists(tokenId)) revert NonexistentToken();
mintHash = mintBlockHash[tokenId];
locked = isLocked[tokenId];
if (locked) {
// For locked tokens, use the stored lock hash
activeBlockHash = lockBlockHash[tokenId];
} else {
// For live tokens, use the most recent block hash
// This means the visual changes every block
activeBlockHash = blockhash(block.number - 1);
}
}
/**
* @notice Get the total number of tokens in existence
* @dev Returns minted minus burned for accurate count
* @return Total supply of tokens
*/
function totalSupply() public view override(ERC721A, IERC721A) returns (uint256) {
return _totalMinted() - _totalBurned();
}
/**
* @notice Check if the machine is currently open for minting
* @return True if minting is allowed (during First Run or an active mint window)
*/
function isMachineOpen() public view returns (bool) {
if (mintWindowManager == address(0)) return false;
return IMintWindowManager(mintWindowManager).isMachineOpen();
}
/**
* @notice Check if we're currently in the First Run period
* @return True if the First Run is active
*/
function isFirstRun() public view returns (bool) {
if (mintWindowManager == address(0)) return false;
return IMintWindowManager(mintWindowManager).isFirstRun();
}
/**
* @notice Get the current mint price for one token
* @return The price in wei to mint one token
*/
function currentMintPrice() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).currentMintPrice();
}
/**
* @notice Get the total mint cost for a specific user to mint `quantity` tokens in the current window
* @dev Accounts for per-wallet escalating pricing (1.2x per previous mint)
* @param user The address to check
* @param quantity Number of tokens to mint
* @return Total cost in wei
*/
function mintPriceFor(
address user,
uint256 quantity
) public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).mintPriceFor(user, quantity);
}
/**
* @notice Get how many tokens a user has minted in the current window
* @param user The address to check
* @return Number of mints in current window
*/
function mintCountInCurrentWindow(
address user
) public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).mintCountInCurrentWindow(user);
}
/**
* @notice Get remaining time in the current mint window
* @return Seconds remaining, or 0 if machine is idle
*/
function windowTimeRemaining() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).windowTimeRemaining();
}
/**
* @notice Get the current window ID (same as print run)
* @return Current window ID
*/
function currentWindowId() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).currentWindowId();
}
/**
* @notice Get the cumulative price increase from all settlements
* @return Cumulative price increase in wei
*/
function cumulativePriceIncrease() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).cumulativePriceIncrease();
}
// ============ Passthrough Getters (Manager Config) ============
/**
* @notice Get the timestamp when First Run started
* @return Unix timestamp, or 0 if not started
*/
function firstRunStartedAt() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).firstRunStartedAt();
}
/**
* @notice Get the base mint price before any escalation
* @return Base price in wei
*/
function baseMintPrice() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).baseMintPrice();
}
/**
* @notice Get the First Run duration
* @return Duration in seconds
*/
function firstRunDuration() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).firstRunDuration();
}
/**
* @notice Get the duration of each mint window
* @return Duration in seconds
*/
function windowDuration() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).windowDuration();
}
/**
* @notice Get the price increase for the current window
* @return Price increase in wei
*/
function currentWindowPriceIncrease() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).currentWindowPriceIncrease();
}
/**
* @notice Get the timestamp when the current window started
* @return Unix timestamp, or 0 if no window active
*/
function currentWindowStartedAt() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).currentWindowStartedAt();
}
/**
* @notice Get the number of queued commits waiting to open windows
* @return Number of queued commits
*/
function queueLength() public view returns (uint256) {
if (mintWindowManager == address(0)) return 0;
return IMintWindowManager(mintWindowManager).queueLength();
}
/**
* @notice Get the token URI for a specific token
* @dev Token 0 uses the calibration plate renderer; all others delegate to the main renderer
* @param tokenId The token ID
* @return The complete data URI with JSON metadata
*/
function tokenURI(
uint256 tokenId
) public view override(ERC721A, IERC721A) returns (string memory) {
if (!_exists(tokenId)) revert NonexistentToken();
if (tokenId == 0) {
return _buildToken0URI();
}
return IToBeAMachineRenderer(renderer).tokenURI(tokenId);
}
/**
* @notice Build token 0 URI using the calibration plate renderer
* @dev Reads auction state and stored block hash to generate calibration plate
* The calibration seed and block hash are stored in the renderer (updated by auction bids)
* Once settled, uses stored winner, settlement block, and locked block hash for permanent display
*/
function _buildToken0URI() internal view returns (string memory) {
// Calibration renderer must be set for token 0
if (calibrationRenderer == address(0)) revert CalibrationRendererNotSet();
IToBeAMachineCalibrationRenderer calibRenderer = IToBeAMachineCalibrationRenderer(calibrationRenderer);
// Check if calibration is locked (auction settled)
bool calibLocked = calibRenderer.calibrationLocked();
uint256 auctionBid = 0;
address leaderAddress = address(0);
uint256 blockNumber = block.number;
// Get block hash from renderer (stored on bid, locked at settlement)
// Falls back to current block if no bids yet
bytes32 blockHash = calibRenderer.activeBlockHash();
if (blockHash == bytes32(0)) {
// No bids yet - use current block hash (teaser mode)
blockHash = blockhash(block.number - 1);
}
if (calibLocked) {
// Use stored settlement data for permanent display
leaderAddress = calibRenderer.auctionWinner();
blockNumber = calibRenderer.settlementBlock();
// Block hash is already locked in activeBlockHash
} else if (auctionContract != address(0)) {
// Auction still active - get current bid data
try ITBAMAuctionHouse(auctionContract).auctions(0) returns (
uint256, // tokenId
address, // tokenContract
bool, // approved
uint256 amount,
uint256, // duration
uint256, // firstBidTime
uint256, // reservePrice
uint8, // curatorFeePercentage
address, // tokenOwner
address payable bidder,
address payable, // curator
address // auctionCurrency
) {
auctionBid = amount;
leaderAddress = bidder;
} catch {
// Auction not available, use defaults
}
}
// Get token 0's mint hash for TOKEN_SEED display
bytes32 tokenMintHash = mintBlockHash[0];
return calibRenderer.tokenURI(
blockHash,
auctionBid,
leaderAddress,
blockNumber,
tokenMintHash
);
}
/**
* @notice Check if the contract supports an interface
* @dev Returns true for ERC721A, ERC2981 (royalties), and ERC-4906 (metadata update)
*/
function supportsInterface(
bytes4 interfaceId
) public view override(ERC721A, IERC721A, ERC2981) returns (bool) {
// EIP-4906 interface ID is 0x49064906
return interfaceId == bytes4(0x49064906) ||
ERC721A.supportsInterface(interfaceId) ||
ERC2981.supportsInterface(interfaceId);
}
// ============ Admin Functions ============
/**
* @notice Set admin status for an address
* @dev Only owner can call this
* @param admin Address to update
* @param status Whether the address should be an admin
*/
function setAdmin(address admin, bool status) external onlyOwner {
isAdmin[admin] = status;
emit AdminUpdated(admin, status);
}
/**
* @notice Pause or unpause minting
* @dev When paused: mint() reverts, lockFrame() skips processSettlement (no new windows)
* Existing tokens can still be locked/burned, but no new mints or windows will occur
* @param paused True to pause, false to unpause
*/
function setMintingPaused(bool paused) external onlyAdmin {
mintingPaused = paused;
emit MintingPausedUpdated(paused);
}
/**
* @notice Update the renderer contract address
* @param newRenderer New renderer contract address
*/
function setRenderer(address newRenderer) external onlyAdmin {
address oldRenderer = renderer;
renderer = newRenderer;
emit RendererUpdated(oldRenderer, newRenderer);
}
/**
* @notice Update the calibration plate renderer contract address
* @param newCalibrationRenderer New calibration renderer contract address
*/
function setCalibrationRenderer(address newCalibrationRenderer) external onlyAdmin {
address oldCalibrationRenderer = calibrationRenderer;
calibrationRenderer = newCalibrationRenderer;
emit CalibrationRendererUpdated(oldCalibrationRenderer, newCalibrationRenderer);
}
/**
* @notice Update the editions contract address
* @param newEditions New editions contract address
*/
function setEditions(address newEditions) external onlyAdmin {
address oldEditions = editions;
editions = newEditions;
emit EditionsUpdated(oldEditions, newEditions);
}
/**
* @notice Update the mint window manager contract address
* @param newManager New mint window manager contract address
*/
function setMintWindowManager(address newManager) external onlyOwner {
address oldManager = mintWindowManager;
mintWindowManager = newManager;
emit MintWindowManagerUpdated(oldManager, newManager);
}
/**
* @notice Start the First Run period (initial mint window, default 24 hours)
* @dev Delegates to MintWindowManager. Can be called by owner, admin, or authorized auction contract.
*/
function startFirstRun() external {
if (
msg.sender != owner() &&
!isAdmin[msg.sender] &&
msg.sender != auctionContract
) {
revert Unauthorized();
}
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
IMintWindowManager(mintWindowManager).startFirstRun();
}
/**
* @notice Set the auction contract address (authorized to start first run)
* @param auction Address of the auction contract
*/
function setAuctionContract(address auction) external onlyAdmin {
auctionContract = auction;
// Also set on manager if available
if (mintWindowManager != address(0)) {
IMintWindowManager(mintWindowManager).setAuthorizedFirstRunStarter(auction);
}
}
/**
* @notice Set the base mint price (delegates to manager)
* @param _price New base mint price in wei
*/
function setBaseMintPrice(uint256 _price) external onlyOwner {
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
IMintWindowManager(mintWindowManager).setBaseMintPrice(_price);
}
/**
* @notice Set the first run duration (delegates to manager)
* @param _duration Duration in seconds
*/
function setFirstRunDuration(uint256 _duration) external onlyOwner {
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
IMintWindowManager(mintWindowManager).setFirstRunDuration(_duration);
}
/**
* @notice Set the window duration for commit windows (delegates to manager)
* @param _duration Duration in seconds
*/
function setWindowDuration(uint256 _duration) external onlyOwner {
if (mintWindowManager == address(0)) revert MintWindowManagerNotSet();
IMintWindowManager(mintWindowManager).setWindowDuration(_duration);
}
/**
* @notice Withdraw all contract balance to the payout recipient
* @dev Only callable by admin. Used to retrieve auction proceeds and mint fees.
*/
function withdraw() external onlyAdmin {
if (payoutRecipient == address(0)) revert PayoutRecipientNotSet();
uint256 balance = address(this).balance;
require(balance > 0, "No balance to withdraw");
(bool success, ) = payoutRecipient.call{value: balance}("");
require(success, "Withdraw failed");
}
/**
* @notice Set the payout recipient address for withdrawals
* @dev Only callable by owner
* @param _payoutRecipient Address to receive withdrawn funds
*/
function setPayoutRecipient(address _payoutRecipient) external onlyOwner {
if (_payoutRecipient == address(0)) revert InvalidPayoutRecipient();
address oldRecipient = payoutRecipient;
payoutRecipient = _payoutRecipient;
emit PayoutRecipientUpdated(oldRecipient, _payoutRecipient);
}
/**
* @notice Set the collection-level metadata URI
* @dev Used by OpenSea and other marketplaces for collection info
* @param _contractURI The metadata URI (typically IPFS or HTTPS)
*/
function setContractURI(string memory _contractURI) external onlyAdmin {
contractURI = _contractURI;
}
/**
* @notice Set the default royalty for all tokens
* @dev EIP-2981 royalty standard. Fee denominator is 10000 (e.g., 500 = 5%)
* @param receiver Address to receive royalty payments
* @param feeNumerator Royalty fee in basis points (e.g., 500 = 5%)
*/
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
/**
* @notice Delete the default royalty
* @dev Removes royalty info for all tokens
*/
function deleteDefaultRoyalty() external onlyOwner {
_deleteDefaultRoyalty();
}
// ============ Internal Functions ============
/**
* @notice Check if a spender is approved or owner of a token
* @param spender Address to check
* @param tokenId Token ID to check
* @return True if spender is owner or approved
*/
function _isApprovedOrOwner(
address spender,
uint256 tokenId
) internal view returns (bool) {
address owner = ownerOf(tokenId);
return (spender == owner ||
getApproved(tokenId) == spender ||
isApprovedForAll(owner, spender));
}
}// 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.4.0) (interfaces/IERC2981.sol)
pragma solidity >=0.6.2;
import {IERC165} from "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*
* NOTE: ERC-2981 allows setting the royalty to 100% of the price. In that case all the price would be sent to the
* royalty receiver and 0 tokens to the seller. Contracts dealing with royalty should consider empty transfers.
*/
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) external view returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.20;
import {IERC2981} from "../../interfaces/IERC2981.sol";
import {IERC165, ERC165} from "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the ERC. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 tokenId => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev The default royalty set is invalid (eg. (numerator / denominator) >= 1).
*/
error ERC2981InvalidDefaultRoyalty(uint256 numerator, uint256 denominator);
/**
* @dev The default royalty receiver is invalid.
*/
error ERC2981InvalidDefaultRoyaltyReceiver(address receiver);
/**
* @dev The royalty set for a specific `tokenId` is invalid (eg. (numerator / denominator) >= 1).
*/
error ERC2981InvalidTokenRoyalty(uint256 tokenId, uint256 numerator, uint256 denominator);
/**
* @dev The royalty receiver for `tokenId` is invalid.
*/
error ERC2981InvalidTokenRoyaltyReceiver(uint256 tokenId, address receiver);
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/// @inheritdoc IERC2981
function royaltyInfo(
uint256 tokenId,
uint256 salePrice
) public view virtual returns (address receiver, uint256 amount) {
RoyaltyInfo storage _royaltyInfo = _tokenRoyaltyInfo[tokenId];
address royaltyReceiver = _royaltyInfo.receiver;
uint96 royaltyFraction = _royaltyInfo.royaltyFraction;
if (royaltyReceiver == address(0)) {
royaltyReceiver = _defaultRoyaltyInfo.receiver;
royaltyFraction = _defaultRoyaltyInfo.royaltyFraction;
}
uint256 royaltyAmount = (salePrice * royaltyFraction) / _feeDenominator();
return (royaltyReceiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
// Royalty fee will exceed the sale price
revert ERC2981InvalidDefaultRoyalty(feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidDefaultRoyaltyReceiver(address(0));
}
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual {
uint256 denominator = _feeDenominator();
if (feeNumerator > denominator) {
// Royalty fee will exceed the sale price
revert ERC2981InvalidTokenRoyalty(tokenId, feeNumerator, denominator);
}
if (receiver == address(0)) {
revert ERC2981InvalidTokenRoyaltyReceiver(tokenId, address(0));
}
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}// 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.4.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 ERC-165 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 {
/// @inheritdoc IERC165
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v5.4.0) (utils/introspection/IERC165.sol)
pragma solidity >=0.4.16;
/**
* @dev Interface of the ERC-165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[ERC].
*
* 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[ERC 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.1.0) (utils/ReentrancyGuard.sol)
pragma solidity ^0.8.20;
/**
* @dev Contract module that helps prevent reentrant calls to a function.
*
* Inheriting from `ReentrancyGuard` will make the {nonReentrant} modifier
* available, which can be applied to functions to make sure there are no nested
* (reentrant) calls to them.
*
* Note that because there is a single `nonReentrant` guard, functions marked as
* `nonReentrant` may not call one another. This can be worked around by making
* those functions `private`, and then adding `external` `nonReentrant` entry
* points to them.
*
* TIP: If EIP-1153 (transient storage) is available on the chain you're deploying at,
* consider using {ReentrancyGuardTransient} instead.
*
* TIP: If you would like to learn more about reentrancy and alternative ways
* to protect against it, check out our blog post
* https://blog.openzeppelin.com/reentrancy-after-istanbul/[Reentrancy After Istanbul].
*/
abstract contract ReentrancyGuard {
// Booleans are more expensive than uint256 or any type that takes up a full
// word because each write operation emits an extra SLOAD to first read the
// slot's contents, replace the bits taken up by the boolean, and then write
// back. This is the compiler's defense against contract upgrades and
// pointer aliasing, and it cannot be disabled.
// The values being non-zero value makes deployment a bit more expensive,
// but in exchange the refund on every call to nonReentrant will be lower in
// amount. Since refunds are capped to a percentage of the total
// transaction's gas, it is best to keep them low in cases like this one, to
// increase the likelihood of the full refund coming into effect.
uint256 private constant NOT_ENTERED = 1;
uint256 private constant ENTERED = 2;
uint256 private _status;
/**
* @dev Unauthorized reentrant call.
*/
error ReentrancyGuardReentrantCall();
constructor() {
_status = NOT_ENTERED;
}
/**
* @dev Prevents a contract from calling itself, directly or indirectly.
* Calling a `nonReentrant` function from another `nonReentrant`
* function is not supported. It is possible to prevent this from happening
* by making the `nonReentrant` function external, and making it call a
* `private` function that does the actual work.
*/
modifier nonReentrant() {
_nonReentrantBefore();
_;
_nonReentrantAfter();
}
function _nonReentrantBefore() private {
// On the first call to nonReentrant, _status will be NOT_ENTERED
if (_status == ENTERED) {
revert ReentrancyGuardReentrantCall();
}
// Any calls to nonReentrant after this point will fail
_status = ENTERED;
}
function _nonReentrantAfter() private {
// By storing the original value once again, a refund is triggered (see
// https://eips.ethereum.org/EIPS/eip-2200)
_status = NOT_ENTERED;
}
/**
* @dev Returns true if the reentrancy guard is currently set to "entered", which indicates there is a
* `nonReentrant` function in the call stack.
*/
function _reentrancyGuardEntered() internal view returns (bool) {
return _status == ENTERED;
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721A.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* The `_sequentialUpTo()` function can be overriden to enable spot mints
* (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is IERC721A {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 private _currentIndex;
// The number of tokens burned.
uint256 private _burnCounter;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) private _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) private _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// The amount of tokens minted above `_sequentialUpTo()`.
// We call these spot mints (i.e. non-sequential mints).
uint256 private _spotMinted;
// =============================================================
// CONSTRUCTOR
// =============================================================
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector);
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID for sequential mints.
*
* Override this function to change the starting token ID for sequential mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the maximum token ID (inclusive) for sequential mints.
*
* Override this function to return a value less than 2**256 - 1,
* but greater than `_startTokenId()`, to enable spot (non-sequential) mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _sequentialUpTo() internal view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
/**
* @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() public view virtual override returns (uint256 result) {
// Counter underflow is impossible as `_burnCounter` cannot be incremented
// more than `_currentIndex + _spotMinted - _startTokenId()` times.
unchecked {
// With spot minting, the intermediate `result` can be temporarily negative,
// and the computation must be unchecked.
result = _currentIndex - _burnCounter - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256 result) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
result = _currentIndex - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
/**
* @dev Returns the total number of tokens that are spot-minted.
*/
function _totalSpotMinted() internal view virtual returns (uint256) {
return _spotMinted;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
// =============================================================
// 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) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @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, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
/**
* @dev Returns whether the ownership slot at `index` is initialized.
* An uninitialized slot does not necessarily mean that the slot has no owner.
*/
function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {
return _packedOwnerships[index] != 0;
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* @dev Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
if (_startTokenId() <= tokenId) {
packed = _packedOwnerships[tokenId];
if (tokenId > _sequentialUpTo()) {
if (_packedOwnershipExists(packed)) return packed;
_revert(OwnerQueryForNonexistentToken.selector);
}
// If the data at the starting slot does not exist, start the scan.
if (packed == 0) {
if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector);
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `tokenId` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
for (;;) {
unchecked {
packed = _packedOwnerships[--tokenId];
}
if (packed == 0) continue;
if (packed & _BITMASK_BURNED == 0) return packed;
// Otherwise, the token is burned, and we must revert.
// This handles the case of batch burned tokens, where only the burned bit
// of the starting slot is set, and remaining slots are left uninitialized.
_revert(OwnerQueryForNonexistentToken.selector);
}
}
// Otherwise, the data exists and we can skip the scan.
// This is possible because we have already achieved the target condition.
// This saves 2143 gas on transfers of initialized tokens.
// If the token is not burned, return `packed`. Otherwise, revert.
if (packed & _BITMASK_BURNED == 0) return packed;
}
_revert(OwnerQueryForNonexistentToken.selector);
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
*/
function approve(address to, uint256 tokenId) public payable virtual override {
_approve(to, tokenId, true);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);
return _tokenApprovals[tokenId].value;
}
/**
* @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) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool result) {
if (_startTokenId() <= tokenId) {
if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]);
if (tokenId < _currentIndex) {
uint256 packed;
while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId;
result = packed & _BITMASK_BURNED == 0;
}
}
}
/**
* @dev Returns whether `packed` represents a token that exists.
*/
function _packedOwnershipExists(uint256 packed) private pure returns (bool result) {
assembly {
// The following is equivalent to `owner != address(0) && burned == false`.
// Symbolically tested.
result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED))
}
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* 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
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
// Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.
from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));
if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--_packedAddressData[from]; // Updates: `balance -= 1`.
++_packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
from, // `from`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
if (toMasked == 0) _revert(TransferToZeroAddress.selector);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @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 memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
assembly {
revert(add(32, reason), mload(reason))
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) _revert(MintZeroQuantity.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
uint256 end = startTokenId + quantity;
uint256 tokenId = startTokenId;
if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
do {
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
// The `!=` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
} while (++tokenId != end);
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) _revert(MintToZeroAddress.selector);
if (quantity == 0) _revert(MintZeroQuantity.selector);
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
} while (index < end);
// This prevents reentrancy to `_safeMint`.
// It does not prevent reentrancy to `_safeMintSpot`.
if (_currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
/**
* @dev Mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* Emits a {Transfer} event for each mint.
*/
function _mintSpot(address to, uint256 tokenId) internal virtual {
if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector);
uint256 prevOwnershipPacked = _packedOwnerships[tokenId];
if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector);
_beforeTokenTransfers(address(0), to, tokenId, 1);
// Overflows are incredibly unrealistic.
// The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1.
// `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `true` (as `quantity == 1`).
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked)
);
// Updates:
// - `balance += 1`.
// - `numberMinted += 1`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1;
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
++_spotMinted;
}
_afterTokenTransfers(address(0), to, tokenId, 1);
}
/**
* @dev Safely mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* See {_mintSpot}.
*
* Emits a {Transfer} event.
*/
function _safeMintSpot(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mintSpot(to, tokenId);
unchecked {
if (to.code.length != 0) {
uint256 currentSpotMinted = _spotMinted;
if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
// This prevents reentrancy to `_safeMintSpot`.
// It does not prevent reentrancy to `_safeMint`.
if (_spotMinted != currentSpotMinted) revert();
}
}
}
/**
* @dev Equivalent to `_safeMintSpot(to, tokenId, '')`.
*/
function _safeMintSpot(address to, uint256 tokenId) internal virtual {
_safeMintSpot(to, tokenId, '');
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_approve(to, tokenId, false)`.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_approve(to, tokenId, false);
}
/**
* @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:
*
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
bool approvalCheck
) internal virtual {
address owner = ownerOf(tokenId);
if (approvalCheck && _msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
_revert(ApprovalCallerNotOwnerNorApproved.selector);
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times.
unchecked {
_burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/**
* @dev For more efficient reverts.
*/
function _revert(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721ABurnable.sol';
import '../ERC721A.sol';
/**
* @title ERC721ABurnable.
*
* @dev ERC721A token that can be irreversibly burned (destroyed).
*/
abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) public virtual override {
_burn(tokenId, true);
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721A.sol';
/**
* @dev Interface of ERC721ABurnable.
*/
interface IERC721ABurnable is IERC721A {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721A {
/**
* 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();
/**
* `_sequentialUpTo()` must be greater than `_startTokenId()`.
*/
error SequentialUpToTooSmall();
/**
* The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`.
*/
error SequentialMintExceedsLimit();
/**
* Spot minting requires a `tokenId` greater than `_sequentialUpTo()`.
*/
error SpotMintTokenIdTooSmall();
/**
* Cannot mint over a token that already exists.
*/
error TokenAlreadyExists();
/**
* The feature is not compatible with spot mints.
*/
error NotCompatibleWithSpotMints();
// =============================================================
// 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
pragma solidity =0.8.23;
/**
* @title IMintWindowManager
* @notice Interface for mint window and pricing logic delegation
*
* Window Mechanics:
* - First Run: 24-hour initial mint period at base price, settlements ARE allowed
* - Settlements during first run don't affect windows/pricing
* - Post-Run: First settlement opens a 69-minute window with price = base + gas cost
* - Settlements during active window queue future windows (don't extend current)
* - Each queued window has price = cumulative price at time of queueing
* - Windows chain immediately when queue > 0
* - Per-address throttle resets at window boundaries
* - currentWindowStartedAt == 0 is authoritative for "idle" state
*/
interface IMintWindowManager {
// ============ Events ============
event FirstRunStarted(uint256 endsAt);
event WindowOpened(uint256 windowId, uint256 closesAt, uint256 priceIncrease);
event WindowQueued(uint256 queuePosition, uint256 priceIncrease);
event WindowAdvanced(uint256 newWindowId, uint256 closesAt, uint256 priceIncrease);
// ============ View Functions ============
/**
* @notice Check if the machine is currently open for minting
* @return True if minting is allowed (during First Run or an active mint window)
*/
function isMachineOpen() external view returns (bool);
/**
* @notice Check if we're currently in the First Run period
* @return True if the First Run is active
*/
function isFirstRun() external view returns (bool);
/**
* @notice Get the current mint price for one token (base + any window increase)
* @return The price in wei to mint one token
*/
function currentMintPrice() external view returns (uint256);
/**
* @notice Get the total mint cost for a user to mint `quantity` tokens
* @dev Accounts for per-wallet escalating pricing (1.2x per previous mint)
* @param user The address to check
* @param quantity Number of tokens to mint
* @return Total cost in wei
*/
function mintPriceFor(address user, uint256 quantity) external view returns (uint256);
/**
* @notice Get how many tokens a user has minted in the current window
* @param user The address to check
* @return Number of mints in current window
*/
function mintCountInCurrentWindow(address user) external view returns (uint256);
/**
* @notice Get remaining time in the current mint window
* @return Seconds remaining, or 0 if machine is idle
*/
function windowTimeRemaining() external view returns (uint256);
/**
* @notice Get the current window ID (print run number)
* @return Current window ID (0 = First Run, 1+ = Print Run number)
*/
function currentWindowId() external view returns (uint256);
/**
* @notice Get the number of windows queued after the current one
* @return Number of queued windows
*/
function queueLength() external view returns (uint256);
/**
* @notice Get the running total of price increases from all post-first-run settlements
* @return Cumulative price increase in wei
*/
function cumulativePriceIncrease() external view returns (uint256);
// ============ Config Getters ============
/**
* @notice Get the base mint price
* @return Base mint price in wei
*/
function baseMintPrice() external view returns (uint256);
/**
* @notice Get the first run duration
* @return Duration in seconds
*/
function firstRunDuration() external view returns (uint256);
/**
* @notice Get the window duration for commit windows
* @return Duration in seconds
*/
function windowDuration() external view returns (uint256);
/**
* @notice Get the timestamp when the first run was started (0 if not started)
* @return Unix timestamp
*/
function firstRunStartedAt() external view returns (uint256);
/**
* @notice Get the timestamp when the current window started (0 if idle)
* @return Unix timestamp
*/
function currentWindowStartedAt() external view returns (uint256);
/**
* @notice Get the price increase locked for the current window
* @return Price increase in wei
*/
function currentWindowPriceIncrease() external view returns (uint256);
// ============ State-Modifying Functions (called by ToBeAMachine) ============
/**
* @notice Process a mint operation - updates per-address throttle
* @dev Only callable by authorized caller (ToBeAMachine)
* @param user The address that is minting
* @param quantity Number of tokens being minted
*/
function processMint(address user, uint256 quantity) external;
/**
* @notice Process a settlement (frame lock) - opens/queues windows
* @dev Only callable by authorized caller (ToBeAMachine)
* During first run: no-op (settlements allowed but don't affect windows)
* After first run idle: opens new window
* During active window: queues future window
*/
function processSettlement() external;
/**
* @notice Start the First Run period
* @dev Only callable by owner, admin, or authorized first run starter
*/
function startFirstRun() external;
// ============ Admin Functions ============
/**
* @notice Set the base mint price
* @param price New base mint price in wei
*/
function setBaseMintPrice(uint256 price) external;
/**
* @notice Set the first run duration
* @param duration Duration in seconds
*/
function setFirstRunDuration(uint256 duration) external;
/**
* @notice Set the window duration for commit windows
* @param duration Duration in seconds
*/
function setWindowDuration(uint256 duration) external;
/**
* @notice Set the authorized caller (ToBeAMachine contract)
* @param caller Address of the ToBeAMachine contract
*/
function setAuthorizedCaller(address caller) external;
/**
* @notice Set the authorized first run starter (auction contract)
* @param starter Address that can start the first run
*/
function setAuthorizedFirstRunStarter(address starter) external;
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.23;
interface ITBAMAuctionHouse {
struct Auction {
uint256 tokenId;
address tokenContract;
bool approved;
uint256 amount;
uint256 duration;
uint256 firstBidTime;
uint256 reservePrice;
uint8 curatorFeePercentage;
address tokenOwner;
address payable bidder;
address payable curator;
address auctionCurrency;
}
function auctions(uint256 auctionId) external view returns (
uint256 tokenId,
address tokenContract,
bool approved,
uint256 amount,
uint256 duration,
uint256 firstBidTime,
uint256 reservePrice,
uint8 curatorFeePercentage,
address tokenOwner,
address payable bidder,
address payable curator,
address auctionCurrency
);
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.23;
interface IToBeAMachineCalibrationRenderer {
/**
* @notice Generate complete tokenURI for the calibration plate
* @param blockHash Current block hash (changes per block)
* @param auctionBid Current auction bid in wei
* @param leaderAddress Current auction leader
* @param blockNumber Current block number
* @param mintHash Token 0's mint hash (for TOKEN_SEED display)
* @return Complete data URI with JSON metadata
*/
function tokenURI(
bytes32 blockHash,
uint256 auctionBid,
address leaderAddress,
uint256 blockNumber,
bytes32 mintHash
) external view returns (string memory);
/**
* @notice Set the calibration seed and block hash (auction house only)
* @param newSeed The new calibration seed
* @param newBlockHash The block hash at the time of the bid
*/
function setCalibrationSeed(bytes32 newSeed, bytes32 newBlockHash) external;
/**
* @notice Lock the calibration seed and block hash permanently (auction house only)
* @param winner The auction winner address
* @param blockNum The settlement block number
* @param blockHash The block hash to lock
*/
function lockCalibrationSeed(address winner, uint256 blockNum, bytes32 blockHash) external;
/**
* @notice Get the active block hash (updated per bid, locked at settlement)
* @return The active block hash
*/
function activeBlockHash() external view returns (bytes32);
/**
* @notice Get the current calibration seed
* @return The calibration seed
*/
function calibrationSeed() external view returns (bytes32);
/**
* @notice Check if the calibration seed is locked
* @return True if locked
*/
function calibrationLocked() external view returns (bool);
/**
* @notice Get the auction winner address (set at settlement)
* @return The winner address
*/
function auctionWinner() external view returns (address);
/**
* @notice Get the settlement block number (set at settlement)
* @return The block number
*/
function settlementBlock() external view returns (uint256);
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.23;
/**
* @title IToBeAMachineEditions
* @notice Interface for the ERC-1155 open editions contract
*/
interface IToBeAMachineEditions {
/**
* @notice Start a new edition for a locked frame
* @dev Called by the ToBeAMachine contract when a frame is locked
* Edition ID equals the screenTokenId
* @param screenTokenId The ERC-721 token ID that was locked (becomes the edition ID)
* @param printer The address that locked the frame
*/
function startEditionForLockedFrame(uint256 screenTokenId, address printer) external;
/**
* @notice Get edition information
* @param editionId The edition ID (== 721 token ID)
* @return printer The address that locked the frame
* @return openUntil Unix timestamp when the edition window closes
* @return initialized Whether the edition exists
* @return totalMinted Total supply minted for this edition
* @return gasUnitsForPrice Gas units used for pricing calculation
*/
function editions(uint256 editionId)
external
view
returns (
address printer,
uint64 openUntil,
bool initialized,
uint256 totalMinted,
uint256 gasUnitsForPrice
);
}// SPDX-License-Identifier: MIT
pragma solidity =0.8.23;
/**
* @title IToBeAMachineRenderer
* @notice Interface for the renderer contract that generates metadata and visuals
* for ERC-721 screen tests
*/
interface IToBeAMachineRenderer {
// ============ Trait Enums ============
enum Substrate { Pure, Tinted }
enum PixelBias { Uniform, Small, Large, Extremes }
enum FlowMode { Full, Mixed, None }
enum DitherMethod { FLOYD_STEINBERG, ORDERED, MIXED }
enum PaletteType { Monochrome, Duotone, Triadic, Tetrad, Rich, Spectrum }
// ============ Trait Struct ============
/// @notice Struct containing all calculated visual traits for a token (derived from renderSeed)
struct Traits {
bool border;
Substrate substrate;
PixelBias pixelBias;
FlowMode flowMode;
DitherMethod ditherMethod;
}
/**
* @notice Generate complete tokenURI for a token
* @param tokenId The token ID
* @return Complete data URI with JSON metadata
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
/**
* @notice Generate a screen visualization for a specific token at a specific block
* @param tokenId The ERC-721 token ID
* @param blockNumber The block number (used for range validation)
* @param blockHash The block hash to use for the visualization
* @return HTML data URI for the screen visualization
*/
function screenAtBlock(uint256 tokenId, uint256 blockNumber, bytes32 blockHash) external view returns (string memory);
}{
"optimizer": {
"enabled": true,
"runs": 1
},
"viaIR": true,
"outputSelection": {
"*": {
"*": [
"evm.bytecode",
"evm.deployedBytecode",
"devdoc",
"userdoc",
"metadata",
"abi"
]
}
},
"evmVersion": "paris"
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_renderer","type":"address"},{"internalType":"address","name":"_editions","type":"address"},{"internalType":"address","name":"_mintWindowManager","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BlockHashNotAvailable","type":"error"},{"inputs":[],"name":"CalibrationRendererNotSet","type":"error"},{"inputs":[{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidDefaultRoyalty","type":"error"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidDefaultRoyaltyReceiver","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"numerator","type":"uint256"},{"internalType":"uint256","name":"denominator","type":"uint256"}],"name":"ERC2981InvalidTokenRoyalty","type":"error"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"}],"name":"ERC2981InvalidTokenRoyaltyReceiver","type":"error"},{"inputs":[],"name":"EditionsNotSet","type":"error"},{"inputs":[],"name":"InvalidLockBlockNumber","type":"error"},{"inputs":[],"name":"InvalidPayoutRecipient","type":"error"},{"inputs":[],"name":"MachineNotOpen","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintPriceNotMet","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintWindowManagerNotSet","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"MintingIsPaused","type":"error"},{"inputs":[],"name":"NonexistentToken","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[],"name":"NotTokenOwnerOrApproved","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":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"PayoutRecipientNotSet","type":"error"},{"inputs":[],"name":"ReentrancyGuardReentrantCall","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"Token0AlreadyMinted","type":"error"},{"inputs":[],"name":"Token0CannotBeLocked","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenAlreadyLocked","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"admin","type":"address"},{"indexed":false,"internalType":"bool","name":"status","type":"bool"}],"name":"AdminUpdated","type":"event"},{"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":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldCalibrationRenderer","type":"address"},{"indexed":true,"internalType":"address","name":"newCalibrationRenderer","type":"address"}],"name":"CalibrationRendererUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldEditions","type":"address"},{"indexed":true,"internalType":"address","name":"newEditions","type":"address"}],"name":"EditionsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"uint64","name":"lockedAt","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"lockBlockNumber","type":"uint64"},{"indexed":false,"internalType":"bytes32","name":"lockBlockHash","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"currentWindowId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"cumulativePriceIncrease","type":"uint256"}],"name":"FrameLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_tokenId","type":"uint256"}],"name":"MetadataUpdate","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldManager","type":"address"},{"indexed":true,"internalType":"address","name":"newManager","type":"address"}],"name":"MintWindowManagerUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"paused","type":"bool"}],"name":"MintingPausedUpdated","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":"oldRecipient","type":"address"},{"indexed":true,"internalType":"address","name":"newRecipient","type":"address"}],"name":"PayoutRecipientUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldRenderer","type":"address"},{"indexed":true,"internalType":"address","name":"newRenderer","type":"address"}],"name":"RendererUpdated","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":"payable","type":"function"},{"inputs":[],"name":"auctionContract","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"calibrationRenderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cumulativePriceIncrease","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentWindowId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentWindowPriceIncrease","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentWindowStartedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"deleteDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"editions","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstRunDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"firstRunStartedAt","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"uint256","name":"tokenId","type":"uint256"}],"name":"getSeedInputs","outputs":[{"internalType":"bytes32","name":"mintHash","type":"bytes32"},{"internalType":"bytes32","name":"activeBlockHash","type":"bytes32"},{"internalType":"bool","name":"locked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isAdmin","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isFirstRun","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"isLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"isMachineOpen","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockBlockHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockBlockNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"requestedLockBlockNumber","type":"uint256"}],"name":"lockFrame","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"lockedAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintBlockHash","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintBlockNumber","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"mintCountInCurrentWindow","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintPriceFor","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mintToken0","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mintWindowManager","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"mintedAt","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"mintingPaused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","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":[],"name":"payoutRecipient","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"queueLength","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renderer","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"amount","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":"safeTransferFrom","outputs":[],"stateMutability":"payable","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"admin","type":"address"},{"internalType":"bool","name":"status","type":"bool"}],"name":"setAdmin","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":[{"internalType":"address","name":"auction","type":"address"}],"name":"setAuctionContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_price","type":"uint256"}],"name":"setBaseMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newCalibrationRenderer","type":"address"}],"name":"setCalibrationRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_contractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newEditions","type":"address"}],"name":"setEditions","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setFirstRunDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newManager","type":"address"}],"name":"setMintWindowManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"paused","type":"bool"}],"name":"setMintingPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_payoutRecipient","type":"address"}],"name":"setPayoutRecipient","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newRenderer","type":"address"}],"name":"setRenderer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_duration","type":"uint256"}],"name":"setWindowDuration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"startFirstRun","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenPrintRun","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":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"windowDuration","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"windowTimeRemaining","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
608060405234620002635762003c0e6060813803918262000020816200029e565b93849283398101031262000263576200003981620002c4565b6020906200005760406200004f848601620002c4565b9401620002c4565b9162000062620002d9565b6e546f2042652061204d616368696e6560881b8282015262000083620002ea565b664d414348494e4560c81b838201528151909290916001600160401b0383116200025d57620000bf83620000b9600254620002fb565b62000338565b81601f8411600114620001cb57509180620000f892620001019594600092620001bf575b50508160011b916000199060031b1c19161790565b600255620003ee565b600080553315620001a65762000196926200015262000174926200012533620004dc565b620001306001600a55565b600d80546001600160a01b0319166001600160a01b0392909216919091179055565b600f80546001600160a01b0319166001600160a01b0392909216919091179055565b601180546001600160a01b0319166001600160a01b0392909216919091179055565b6040516136e89081620005268239f35b604051631e4fbdf760e01b815260006004820152602490fd5b015190503880620000e3565b60026000529190601f1984167f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace936000905b8282106200024457505091600193918562000101979694106200022a575b505050811b01600255620003ee565b015160001960f88460031b161c191690553880806200021b565b80600186978294978701518155019601940190620001fd565b62000268565b600080fd5b634e487b7160e01b600052604160045260246000fd5b60408051919082016001600160401b038111838210176200025d57604052565b6040519190601f01601f191682016001600160401b038111838210176200025d57604052565b51906001600160a01b03821682036200026357565b620002e36200027e565b90600f8252565b620002f46200027e565b9060078252565b90600182811c921680156200032d575b60208310146200031757565b634e487b7160e01b600052602260045260246000fd5b91607f16916200030b565b601f811162000345575050565b60009060026000526020600020906020601f850160051c8301941062000388575b601f0160051c01915b8281106200037c57505050565b8181556001016200036f565b909250829062000366565b601f8111620003a0575050565b60009060036000526020600020906020601f850160051c83019410620003e3575b601f0160051c01915b828110620003d757505050565b818155600101620003ca565b9092508290620003c1565b80519091906001600160401b0381116200025d576200041a8162000414600354620002fb565b62000393565b602080601f831160011462000454575081906200044f9394600092620001bf5750508160011b916000199060031b1c19161790565b600355565b6003600052601f198316949091907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b926000905b878210620004c3575050836001959610620004a9575b505050811b01600355565b015160001960f88460031b161c191690553880806200049e565b8060018596829496860151815501950193019062000488565b600980546001600160a01b039283166001600160a01b0319821681179092559091167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a356fe6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610487578063023924c71461048257806304634d8d1461047d5780630543842b146104785780630561942a1461047357806306fdde031461046e578063081812fc14610469578063095ea7b3146104645780630ab8afac1461045f5780630e9949e01461045a57806315c80cf81461045557806318160ddd1461045057806323b872dd1461044b57806324d7806c146104465780632a55205a146104415780633a1526d01461043c5780633ccfd60b146104375780633f6e01a1146104325780633fb80b151461042d57806340311a6114610428578063420401e91461042357806342842e0e1461041e57806342966c681461041957806346bb5954146104145780634b0bddd21461040f5780634f08dc921461040a5780634ff4573f1461040557806356d3163d146104005780635c11ff7a146103fb5780635c288744146103f65780636352211e146103f157806370a08231146103ec578063715018a6146103e7578063749fa284146103e2578063755e2fc3146103dd5780637aa1a123146103d85780638559dff3146103d35780638957e5af146103ce5780638a82837c146103c95780638ada6b0f146103c45780638da5cb5b146103bf578063938e3d7b146103ba57806395d89b41146103b557806398249f8c146103b0578063a0712d68146103ab578063a22cb465146103a6578063aa1b103f146103a1578063ab91c7b01461039c578063ad13419d14610397578063b33bd5a714610392578063b40639501461038d578063b4f738cf14610388578063b88d4fde14610383578063b8ddbcb31461037e578063c1bf865814610379578063c87b56dd14610374578063c95439791461036f578063d218c6371461036a578063d256063a14610365578063dcae675414610360578063e011bf8e1461035b578063e1a283d614610356578063e48e7ecf14610351578063e8a3d4851461034c578063e96079fd14610347578063e985e9c514610342578063f02adefc1461033d578063f1b0aa1514610338578063f2fde38b14610333578063f6aacfb11461032e5763f8f8ffca1461032957600080fd5b6125b1565b612580565b612506565b6124d2565b61249e565b612446565b61242b565b61239f565b6122cc565b6122a6565b61220d565b6121d9565b6121be565b612195565b61217a565b612147565b61208e565b612065565b612003565b611fa0565b611f85565b611f59565b611ec2565b611ea7565b611e86565b611e0f565b611b97565b611b63565b611ad7565b61197d565b611877565b61184e565b611823565b611758565b61173d565b611696565b61166a565b61163f565b6115f3565b611596565b611567565b61153e565b611523565b61148a565b6110a7565b611039565b610fcd565b610f19565b610df2565b610dcf565b610d6c565b610d47565b610d1e565b610d03565b610c3f565b610c24565b610ba4565b610b47565b610aea565b610a8e565b610a00565b6109d9565b6109b0565b6108f8565b6108c8565b61080a565b610793565b610770565b61067f565b610584565b6104a3565b6001600160e01b031981160361049e57565b600080fd5b3461049e57602036600319011261049e576104f86004356104c38161048c565b63ffffffff60e01b16632483248360e11b8114908115610527575b81156104fc575b5060405190151581529081906020820190565b0390f35b63152a902d60e11b811491508115610516575b50386104e5565b6301ffc9a760e01b1490503861050f565b90506301ffc9a760e01b81148015610557575b8015610547575b906104de565b50635b5e139f60e01b8114610541565b506380ac58cd60e01b811461053a565b6001600160a01b031690565b6001600160a01b0381160361049e57565b3461049e57602036600319011261049e576004356105a181610573565b600090338252601b60205260ff604083205416158061066a575b61065957601a80546001600160a01b0319166001600160a01b0380841691909117909155601154839291906105ef90610567565b1690816105fa575050f35b813b15610655576040516340e1684f60e01b81526001600160a01b0391909116600482015291908290602490829084905af180156106505761063a575080f35b8061064761064d926118b6565b80610765565b80f35b6125dd565b5050fd5b6040516282b42960e81b8152600490fd5b506009546001600160a01b03163314156105bb565b3461049e57604036600319011261049e5760043561069c81610573565b602435906001600160601b03821680830361049e576106b961304f565b6127108082116107475750506001600160a01b0381161561072e5761070561072c926106f56106e661190c565b6001600160a01b039094168452565b6001600160601b03166020830152565b805160209091015160a01b6001600160a01b0319166001600160a01b039190911617600b55565b005b604051635b6cc80560e11b815260006004820152602490fd5b6044925060405191636f483d0960e01b835260048301526024820152fd5b600091031261049e57565b3461049e57600036600319011261049e57602061078b6125f8565b604051908152f35b3461049e57600036600319011261049e57602061078b612653565b60005b8381106107c15750506000910152565b81810151838201526020016107b1565b906020916107ea815180928185528580860191016107ae565b601f01601f1916010190565b9060206108079281815201906107d1565b90565b3461049e576000806003193601126108c5576040518160025461082c81612365565b908184526020926001916001811690816000146108a35750600114610868575b6104f88561085c818903826118e9565b604051918291826107f6565b929450600283528483205b82841061089057505050816104f89361085c92820101933861084c565b8054858501870152928501928101610873565b60ff191686860152505050151560051b820101915061085c816104f83861084c565b80fd5b3461049e57602036600319011261049e5760206108e660043561268f565b6040516001600160a01b039091168152f35b604036600319011261049e5760043561091081610573565b6024356001600160a01b038061092583613122565b1690813303610980575b600083815260066020526040812080546001600160a01b0319166001600160a01b0387161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b81600052600760205260ff610999336040600020610b30565b541661092f576367d9dca160e11b60005260046000fd5b3461049e57600036600319011261049e57601a546040516001600160a01b039091168152602090f35b3461049e57602036600319011261049e57602061078b6004356109fb81610573565b6126c9565b3461049e57602036600319011261049e57610a1961304f565b6011546001600160a01b0390610a2e90610567565b168015610a7c57803b1561049e576040516302b9019f60e31b81526004803590820152906000908290818381602481015b03925af1801561065057610a6f57005b8061064761072c926118b6565b60405163265641c560e11b8152600490fd5b3461049e57600036600319011261049e576000546001548103908111610ab957602090604051908152f35b612717565b606090600319011261049e57600435610ad681610573565b90602435610ae381610573565b9060443590565b61072c610af636610abe565b9161274b565b6001600160a01b0316600090815260076020526040902090565b6001600160a01b0316600090815260056020526040902090565b9060018060a01b0316600052602052604060002090565b3461049e57602036600319011261049e57600435610b6481610573565b60018060a01b0316600052601b602052602060ff604060002054166040519015158152f35b6001600160a01b039091168152602081019190915260400190565b3461049e57604036600319011261049e57602435600435600052600c6020526040600020549060018060a01b038083169260a01c908315610c11575b506001600160601b03168181029180159083049091141715610ab9576104f861271092604051938493049083610b89565b925050600b549182169160a01c38610be0565b3461049e57600036600319011261049e57602061078b61285b565b3461049e576000806003193601126108c557338152601b60205260ff6040822054161580610cee575b61065957601c546001600160a01b03168015610cdc57478015610c9e57828080809361064d955af1610c98612897565b506128c7565b60405162461bcd60e51b81526020600482015260166024820152754e6f2062616c616e636520746f20776974686472617760501b6044820152606490fd5b604051631c6c69d760e11b8152600490fd5b506009546001600160a01b0316331415610c68565b3461049e57600036600319011261049e57602061078b612905565b3461049e57600036600319011261049e57601c546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e576020610d62612956565b6040519015158152f35b3461049e57602036600319011261049e57610d8561304f565b6011546001600160a01b0390610d9a90610567565b168015610a7c57803b1561049e5760405163420401e960e01b8152600480359082015290600090829081838160248101610a5f565b61072c610ddb36610abe565b9060405192610de9846118ce565b60008452612be8565b3461049e57602036600319011261049e57600435610e0f81613122565b60008281526006602052604090208054916001600160a01b03811691610e3d610e3933858761318f565b1590565b610ef0575b600093610ee7575b50610e5482610b16565b80546001600160801b030190556001600160a01b0382164260a01b17600360e01b17610e7f8561165a565b55600160e11b811615610eb4575b506000805160206136938339815191528280a461072c610eaf60015460010190565b600155565b60018401610ec18161165a565b5415610ece575b50610e8d565b83548114610ec857610edf9061165a565b553880610ec8565b83905538610e4a565b610f0f610e39610f0833610f0387610afc565b610b30565b5460ff1690565b15610e42576130be565b3461049e57602036600319011261049e57600435610f3681610573565b610f3e61304f565b6001600160a01b03908116908115610f8c57601c80546001600160a01b031981168417909155167ff4d517cbe6d8f91c2d0818ac9a797925923e87e3f276fef4537a73dd2cd19167600080a3005b6040516321c17ee560e11b8152600490fd5b8015150361049e57565b604090600319011261049e57600435610fc081610573565b9060243561080781610f9e565b3461049e5760207f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133610ffe36610fa8565b929061100861304f565b6001600160a01b03166000818152601b835260409020805460ff191660ff86151516179055926040519015158152a2005b3461049e57602036600319011261049e5760043561105681610573565b61105e61304f565b601180546001600160a01b039283166001600160a01b0319821681179092559091167f6f27b91599f4078d27a70be3466af653ea3fd93615886de17a3c304cd9a6241e600080a3005b3461049e5760408060031936011261049e576004908135916024356110ca6131be565b6011546001600160a01b03919082906110e290610567565b161561147a57841561146a576110fb610e3986336131e1565b61145a57611116610f08866000526018602052604060002090565b61144a578061144557506111294361272d565b61115c611150611143876000526014602052604060002090565b546001600160401b031690565b6001600160401b031690565b811061142457610100431180611434575b61142457438110156114245780408015611414576111a5611198876000526018602052604060002090565b805460ff19166001179055565b60018060401b03804216926111cd846111c88a6000526013602052604060002090565b6129ab565b166111e6816111c8896000526016602052604060002090565b816111fb886000526017602052604060002090565b558361121061120b601154610567565b610567565b601a546112219060a01c60ff161590565b6113cb575b87518981527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790602090a116918651916303a1526d60e41b8352602080848981885afa9485156106505788946000966113aa575b5081908a519586809263692b031d60e11b82525afa8015610650578a957f416cb75bc03562caf614ec69bf85b2a924e05c74d59c8d3ddb709645c539b5a7956112fd9360009361137b575b50508a5194859433998691959493909260809360a084019760018060401b038092168552166020840152604083015260608201520152565b0390a361130b600f54610567565b16801561136c57803b1561049e579151637187036d60e11b815290810192835233602084015291600091839182908490829060400103925af1801561065057611359575b61072c6001600a55565b80610647611366926118b6565b3861134f565b509051635946bb1d60e01b8152fd5b61139b929350803d106113a3575b61139381836118e9565b8101906125e9565b9038806112c5565b503d611389565b829196506113c490823d84116113a35761139381836118e9565b959061127a565b90811690813b1561049e5760008092888a5180958193635a262d4360e11b83525af1918215610650578692611401575b50611226565b8061064761140e926118b6565b386113fb565b8451631ce084cd60e01b81528490fd5b835163ccc8ba5360e01b81528390fd5b5061143e4361273c565b811061116d565b611129565b8351637cca156760e11b81528390fd5b8351634cd9539b60e11b81528390fd5b8351635a50eb3360e11b81528390fd5b835163265641c560e11b81528390fd5b3461049e57602036600319011261049e576004356114a781610573565b600090338252601b60205260ff604083205416158061150e575b61065957600d80546001600160a01b039283166001600160a01b0319821681179092559091167f10e9b6d73105db46c6a41a698f35efb8e1688178fe274b7b21f0bdc792de3ea58380a380f35b506009546001600160a01b03163314156114c1565b3461049e57600036600319011261049e57602061078b6129ca565b3461049e57600036600319011261049e57600e546040516001600160a01b039091168152602090f35b3461049e57602036600319011261049e5760206001600160a01b0361158d600435613122565b16604051908152f35b3461049e57602036600319011261049e576004356115b381610573565b6001600160a01b031680156115e2576000526005602052602060018060401b0360406000205416604051908152f35b6323d3ad8160e21b60005260046000fd5b3461049e576000806003193601126108c55761160d61304f565b600980546001600160a01b0319811690915581906001600160a01b03166000805160206136738339815191528280a380f35b3461049e57600036600319011261049e57602061078b612a06565b6000526004602052604060002090565b3461049e57602036600319011261049e5760043560005260156020526020604060002054604051908152f35b3461049e57602036600319011261049e5760043560006116b58261307b565b1561172b57818152601560205260ff6040808320549260186020522054169182600014611717576116f36104f8916000526017602052604060002090565b54925b60405193849384919260409194936060840195845260208401521515910152565b506104f86117244361272d565b40926116f6565b60405163163a09e160e31b8152600490fd5b3461049e57600036600319011261049e57602061078b612a42565b3461049e57602036600319011261049e5760043561177581610573565b600090338252601b60205260ff604083205416158061180e575b6106595781546117fc576117a29061324a565b6117d360018060401b0382805260126020526117c3814216604085206129ab565b60146020524316604083206129ab565b6000194301438111610ab957600080526015602052406000805160206136538339815191525580f35b604051639546f5ab60e01b8152600490fd5b506009546001600160a01b031633141561178f565b3461049e57604036600319011261049e57602061078b60043561184581610573565b60243590612a7e565b3461049e57600036600319011261049e57600d546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e576009546040516001600160a01b039091168152602090f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116118c957604052565b6118a0565b602081019081106001600160401b038211176118c957604052565b601f909101601f19168101906001600160401b038211908210176118c957604052565b60408051919082016001600160401b038111838210176118c957604052565b6001600160401b0381116118c957601f01601f191660200190565b9291926119528261192b565b9161196060405193846118e9565b82948184528183011161049e578281602093846000960137010152565b3461049e5760208060031936011261049e576001600160401b039060043582811161049e573660238201121561049e576119c1903690602481600401359101611946565b91600091338352601b60205260ff6040842054161580611ac2575b6106595783519182116118c9576119fd826119f8601054612365565b612acb565b602090601f8311600114611a40575081908394611a2f9492611a35575b50508160011b916000199060031b1c19161790565b60105580f35b015190503880611a1a565b6010600052601f198316947f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae672929185905b878210611aaa575050836001959610611a91575b505050811b0160105580f35b015160001960f88460031b161c19169055388080611a85565b80600185968294968601518155019501930190611a71565b506009546001600160a01b03163314156119dc565b3461049e576000806003193601126108c55760405181600354611af981612365565b908184526020926001916001811690816000146108a35750600114611b28576104f88561085c818903826118e9565b929450600383528483205b828410611b5057505050816104f89361085c92820101933861084c565b8054858501870152928501928101611b33565b3461049e57602036600319011261049e576004356000526014602052602060018060401b0360406000205416604051908152f35b60208060031936011261049e576004803591611bb16131be565b601a5460a01c60ff16611e00576011546001600160a01b0390611bd390610567565b168015611def5783151580611de4575b611bec90612b21565b60409283516340311a6160e01b815283818381865afa90811561065057600091611db7575b5015611da95783516322a0a0df60e21b8152838180611c338933878401610b89565b0381865afa90811561065057600091611d8c575b503410611d7e57813b1561049e578351637dd6e76560e11b815260008180611c728933878401610b89565b038183875af1801561065057611d6b575b5060005493611c914361272d565b90516303a1526d60e41b81526001600160401b034281169492409343909116928691839182905afa94851561065057600095611d4c575b505060005b868110611cde5761134f8733613356565b8085611d45611cef6001948a612b63565b611d07886111c8836000526012602052604060002090565b611d1f866111c8836000526014602052604060002090565b86611d34826000526015602052604060002090565b556000526019602052604060002090565b5501611ccd565b611d63929550803d106113a35761139381836118e9565b923880611cc8565b80610647611d78926118b6565b38611c83565b8351633cc6859560e21b8152fd5b611da39150843d86116113a35761139381836118e9565b38611c47565b8351635dcef89b60e01b8152fd5b611dd79150843d8611611ddd575b611dcf81836118e9565b810190612941565b38611c11565b503d611dc5565b506032841115611be3565b60405163265641c560e11b81528390fd5b50604051620de45360ea1b8152fd5b3461049e57611e1d36610fa8565b90336000526007602052611e4a82611e39836040600020610b30565b9060ff801983541691151516179055565b60405191151582526001600160a01b03169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190602090a3005b3461049e576000806003193601126108c557611ea061304f565b80600b5580f35b3461049e57600036600319011261049e57602061078b612b70565b3461049e57602036600319011261049e57600435611edf81610f9e565b33600052601b60205260ff604060002054161580611f44575b6106595760207f6a904c879e06836c65d53725658c103f44f031e87a49cd56cdfa24ca60ffaecf911515601a5460ff60a01b8260a01b169060ff60a01b191617601a55604051908152a1005b506009546001600160a01b0316331415611ef8565b3461049e57602036600319011261049e5760043560005260176020526020604060002054604051908152f35b3461049e57600036600319011261049e57602061078b612bac565b3461049e57602036600319011261049e57611fb961304f565b6011546001600160a01b0390611fce90610567565b168015610a7c57803b1561049e5760405163b4f738cf60e01b8152600480359082015290600090829081838160248101610a5f565b608036600319011261049e5760043561201b81610573565b60243561202781610573565b606435916001600160401b03831161049e573660238401121561049e5761205b61072c933690602481600401359101611946565b9160443591612be8565b3461049e57600036600319011261049e57600f546040516001600160a01b039091168152602090f35b3461049e576000806003193601126108c5576120ae61120b600954610567565b33141580612125575b8061210e575b610659576011546001600160a01b03906120d690610567565b168015610a7c578082913b1561210b578190600460405180948193631837f0cb60e31b83525af180156106505761063a575080f35b50fd5b5061211d61120b601a54610567565b3314156120bd565b50336000908152601b6020526040902061214290610e3990610f08565b6120b7565b3461049e57602036600319011261049e576104f8612166600435612c89565b6040519182916020835260208301906107d1565b3461049e57600036600319011261049e57602061078b612f9b565b3461049e57600036600319011261049e576011546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e57602061078b612fd7565b3461049e57602036600319011261049e576004356000526013602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e5760043561222a81610573565b600090338252601b60205260ff6040832054161580612291575b61065957600f80546001600160a01b039283166001600160a01b0319821681179092559091167fa388bfe30ea1cc13f506d2a7b1667cfe5a24612ab41e459ff01bde952cd197e28380a380f35b506009546001600160a01b0316331415612244565b3461049e57600036600319011261049e57602060ff601a5460a01c166040519015158152f35b3461049e57602036600319011261049e576004356122e981610573565b600090338252601b60205260ff6040832054161580612350575b61065957600e80546001600160a01b039283166001600160a01b0319821681179092559091167f19a2dab6142d87b6d696bc64c6b7f457dcccae35ffd93262875e8ad029bb5a8f8380a380f35b506009546001600160a01b0316331415612303565b90600182811c92168015612395575b602083101461237f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612374565b3461049e576000806003193601126108c557604051816010546123c181612365565b908184526020926001916001811690816000146108a357506001146123f0576104f88561085c818903826118e9565b929450601083528483205b82841061241857505050816104f89361085c92820101933861084c565b80548585018701529285019281016123fb565b3461049e57600036600319011261049e576020610d62613013565b3461049e57604036600319011261049e57602060ff61249260043561246a81610573565b6024359061247782610573565b6001600160a01b031660009081526007855260409020610b30565b54166040519015158152f35b3461049e57602036600319011261049e576004356000526016602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e576004356000526012602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e5760043561252381610573565b61252b61304f565b6001600160a01b0390811690811561256757600980546001600160a01b03198116841790915516600080516020613673833981519152600080a3005b604051631e4fbdf760e01b815260006004820152602490fd5b3461049e57602036600319011261049e576004356000526018602052602060ff604060002054166040519015158152f35b3461049e57602036600319011261049e5760043560005260196020526020604060002054604051908152f35b6040513d6000823e3d90fd5b9081602091031261049e575190565b6011546001600160a01b0316801561264d57602060049160405192838092630543842b60e01b82525afa90811561065057600091612634575090565b610807915060203d6020116113a35761139381836118e9565b50600090565b6011546001600160a01b0316801561264d576020600491604051928380926302b0ca1560e11b82525afa90811561065057600091612634575090565b6126988161307b565b156126b8576000908152600660205260409020546001600160a01b031690565b6333d1c03960e21b60005260046000fd5b6011546001600160a01b039081169190821561270f57602460209260405194859384926274ca4f60e51b84521660048301525afa90811561065057600091612634575090565b505050600090565b634e487b7160e01b600052601160045260246000fd5b600019810191908211610ab957565b60ff19810191908211610ab957565b91909161275782613122565b6001600160a01b039182169390828116859003612856576000848152600660205260409020805461278c610e3933898461318f565b612839575b61282f575b506127a085610b16565b80546000190190556127b182610b16565b805460010190556127c1826131a7565b6127ca8561165a565b55600160e11b8116156127fb575b50168092600080516020613693833981519152600080a4156127f657565b6130df565b600184016128088161165a565b5415612815575b506127d8565b600054811461280f576128279061165a565b55388061280f565b6000905538612796565b61284c610e39610f0833610f038b610afc565b15612791576130be565b6130cf565b6011546001600160a01b0316801561264d576020600491604051928380926303a1526d60e41b82525afa90811561065057600091612634575090565b3d156128c2573d906128a88261192b565b916128b660405193846118e9565b82523d6000602084013e565b606090565b156128ce57565b60405162461bcd60e51b815260206004820152600f60248201526e15da5d1a191c985dc819985a5b1959608a1b6044820152606490fd5b6011546001600160a01b0316801561264d57602060049160405192838092633f6e01a160e01b82525afa90811561065057600091612634575090565b9081602091031261049e575161080781610f9e565b6011546001600160a01b0316801561264d576020600491604051928380926340311a6160e01b82525afa90811561065057600091612992575090565b610807915060203d602011611ddd57611dcf81836118e9565b80546001600160401b0319166001600160401b03909216919091179055565b6011546001600160a01b0316801561264d57602060049160405192838092632e08ffbd60e11b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092631d27e8a160e21b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092638559dff360e01b82525afa90811561065057600091612634575090565b6011546001600160a01b031691821561270f576040516322a0a0df60e21b815292602092849283918291612ab59160048401610b89565b03915afa90811561065057600091612634575090565b601f8111612ad7575050565b60009060106000526020600020906020601f850160051c83019410612b17575b601f0160051c01915b828110612b0c57505050565b818155600101612b00565b9092508290612af7565b15612b2857565b60405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081b5a5b9d08185b5bdd5b9d606a1b6044820152606490fd5b91908201809211610ab957565b6011546001600160a01b0316801561264d57602060049160405192838092630ab91c7b60e41b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092630b40639560e41b82525afa90811561065057600091612634575090565b929190612bf682828661274b565b803b612c03575b50505050565b612c0c9361357b565b15612c1a5738808080612bfd565b6368d2bf6b60e11b60005260046000fd5b60208183031261049e578051906001600160401b03821161049e570181601f8201121561049e578051612c5d8161192b565b92612c6b60405194856118e9565b8184526020828401011161049e5761080791602080850191016107ae565b612c928161307b565b1561172b578015612d07576000612cd491612cb461120b61120b600d54610567565b604051808095819463c87b56dd60e01b8352600483019190602083019252565b03915afa90811561065057600091612cea575090565b61080791503d806000833e612cff81836118e9565b810190612c2b565b50600e546001600160a01b03908190612d1f90610567565b16908115612f895760409081519263b37a769160e01b8452602093600485828281865afa91821561065057600092612f6a575b50600093844391875194635f6f7ca560e11b8652898686818a5afa958615610650578396612f4b575b508515612f39575b15612e7e575050855163b37a8be360e01b8152905086818381875afa90811561065057600091612e51575b50958551956220903160ea1b875281878481885afa801561065057600097612cd4938992612e34575b50505b60008052601560205260008051602061365383398151915254915198899788968796633c3515db60e21b885287019192608093969594919660a08401978452602084015260018060a01b0316604083015260608201520152565b612e4a9250803d106113a35761139381836118e9565b3880612dd7565b612e719150873d8911612e77575b612e6981836118e9565b81019061363d565b38612dae565b503d612e5f565b809197929850612e8f601a54610567565b169081612ea6575b5050612cd49060009697612dda565b825180926302b8d13560e51b82526101809182918180612ecd8a8201906000602083019252565b03915afa8993849282612ef9575b5050612ee8575b50612e97565b911696509450806000612cd4612ee2565b8091929550612f1d9350903d10612f32575b612f1581836118e9565b8101906135b1565b50509850505050505091505090923880612edb565b503d612f0b565b9450612f444361272d565b4094612d83565b612f639196508a3d8c116113a35761139381836118e9565b9438612d7b565b612f82919250863d8811611ddd57611dcf81836118e9565b9038612d52565b604051630115914f60e01b8152600490fd5b6011546001600160a01b0316801561264d5760206004916040519283809263c954397960e01b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d5760206004916040519283809263692b031d60e11b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d5760206004916040519283809263e96079fd60e01b82525afa90811561065057600091612992575090565b6009546001600160a01b0316330361306357565b60405163118cdaa760e01b8152336004820152602490fd5b9060009160008054821061308d575050565b92505b80835260046020526040832054806130b257508015610ab95760001901613090565b600160e01b1615925050565b632ce44b5f60e11b60005260046000fd5b62a1148160e81b60005260046000fd5b633a954ecd60e21b60005260046000fd5b636f96cda160e11b60005260046000fd5b63b562e8dd60e01b60005260046000fd5b622e076360e81b60005260046000fd5b61312b8161165a565b549081156131425750600160e01b81166130f05790565b90506000906000548110156130f0575b6000190161315f8161165a565b549081156131885750600160e01b81161561318357636f96cda160e11b8252600482fd5b905090565b9050613152565b6001600160a01b039182169190921690811491141790565b6001600160a01b03164260a01b17600160e11b1790565b6002600a54146131cf576002600a55565b604051633ee5aeb560e01b8152600490fd5b6001600160a01b03806131f384613122565b169080831690828214948515613232575b505050821561321257505090565b60ff92509061322d9160005260076020526040600020610b30565b541690565b61323f919293955061268f565b161491388080613204565b60405190613257826118ce565b6000918281528254613268836131a7565b6132718261165a565b5561327b83610b16565b80546001600160401b010190556001600160a01b038316928315613351576001918281019481908480805b613314575b50505050848655813b6132c1575b505050505050565b9180805b6132e0575b50505050508154036108c55780808080806132b9565b15613307575b856132f8610e398684870196866134e1565b61330257816132c5565b612c1a565b8483106132e657806132ca565b15613339575b50878583838b6000805160206136938339815191528180a490816132a6565b9091019086821461334a578461331a565b84816132ab565b613112565b604051613362816118ce565b600092838252835492811561346b576001916001600160a01b0382164260a01b82851460e11b17176133938661165a565b5561339d82610b16565b80546001600160401b0183020190556001600160a01b03821680156133515781860195908480805b61342e575b50505050848655813b6133df57505050505050565b84039180805b6133ff5750505050508154036108c55780808080806132b9565b15613421575b85613417610e398684870196866134e1565b61330257816133e5565b84831061340557806132ca565b15613453575b50878583838b6000805160206136938339815191528180a490816133c5565b909101908682146134645784613434565b84816133ca565b613101565b9081602091031261049e57516108078161048c565b610807939260809260018060a01b0316825260006020830152604082015281606082015201906107d1565b6001600160a01b039182168152911660208201526040810191909152608060608201819052610807929101906107d1565b61350a60209160009394604051948580948193630a85bd0160e11b998a84523360048501613485565b03926001600160a01b03165af16000918161354a575b5061353c5761352d612897565b805115612c1a57805190602001fd5b6001600160e01b0319161490565b61356d91925060203d602011613574575b61356581836118e9565b810190613470565b9038613520565b503d61355b565b9260209161350a936000604051809681958294630a85bd0160e11b9a8b855233600486016134b0565b51906135af82610573565b565b91908261018091031261049e5781519160208101516135cf81610573565b9160408201516135de81610f9e565b9160608101519160808201519160a08101519160c08201519160e081015160ff8116810361049e579161361461010083016135a4565b9161362261012082016135a4565b9161080761016061363661014085016135a4565b93016135a4565b9081602091031261049e57516108078161057356fea31547ce6245cdb9ecea19cf8c7eb9f5974025bb4075011409251ae855b30aed8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122044b5b1b38f41c8e6c87eccf37d6f083d29c19f4a3b891b89eac039d11ba069e564736f6c63430008170033000000000000000000000000fe4c33f74fac6e23aac32667b10a1052a128c83e000000000000000000000000324c68bb517b43ca96bcabfb57ff90e1d5101152000000000000000000000000616d32e6e4d0fd86489cbd91ac35a8fd01f09d9e
Deployed Bytecode
0x6080604052600436101561001257600080fd5b60003560e01c806301ffc9a714610487578063023924c71461048257806304634d8d1461047d5780630543842b146104785780630561942a1461047357806306fdde031461046e578063081812fc14610469578063095ea7b3146104645780630ab8afac1461045f5780630e9949e01461045a57806315c80cf81461045557806318160ddd1461045057806323b872dd1461044b57806324d7806c146104465780632a55205a146104415780633a1526d01461043c5780633ccfd60b146104375780633f6e01a1146104325780633fb80b151461042d57806340311a6114610428578063420401e91461042357806342842e0e1461041e57806342966c681461041957806346bb5954146104145780634b0bddd21461040f5780634f08dc921461040a5780634ff4573f1461040557806356d3163d146104005780635c11ff7a146103fb5780635c288744146103f65780636352211e146103f157806370a08231146103ec578063715018a6146103e7578063749fa284146103e2578063755e2fc3146103dd5780637aa1a123146103d85780638559dff3146103d35780638957e5af146103ce5780638a82837c146103c95780638ada6b0f146103c45780638da5cb5b146103bf578063938e3d7b146103ba57806395d89b41146103b557806398249f8c146103b0578063a0712d68146103ab578063a22cb465146103a6578063aa1b103f146103a1578063ab91c7b01461039c578063ad13419d14610397578063b33bd5a714610392578063b40639501461038d578063b4f738cf14610388578063b88d4fde14610383578063b8ddbcb31461037e578063c1bf865814610379578063c87b56dd14610374578063c95439791461036f578063d218c6371461036a578063d256063a14610365578063dcae675414610360578063e011bf8e1461035b578063e1a283d614610356578063e48e7ecf14610351578063e8a3d4851461034c578063e96079fd14610347578063e985e9c514610342578063f02adefc1461033d578063f1b0aa1514610338578063f2fde38b14610333578063f6aacfb11461032e5763f8f8ffca1461032957600080fd5b6125b1565b612580565b612506565b6124d2565b61249e565b612446565b61242b565b61239f565b6122cc565b6122a6565b61220d565b6121d9565b6121be565b612195565b61217a565b612147565b61208e565b612065565b612003565b611fa0565b611f85565b611f59565b611ec2565b611ea7565b611e86565b611e0f565b611b97565b611b63565b611ad7565b61197d565b611877565b61184e565b611823565b611758565b61173d565b611696565b61166a565b61163f565b6115f3565b611596565b611567565b61153e565b611523565b61148a565b6110a7565b611039565b610fcd565b610f19565b610df2565b610dcf565b610d6c565b610d47565b610d1e565b610d03565b610c3f565b610c24565b610ba4565b610b47565b610aea565b610a8e565b610a00565b6109d9565b6109b0565b6108f8565b6108c8565b61080a565b610793565b610770565b61067f565b610584565b6104a3565b6001600160e01b031981160361049e57565b600080fd5b3461049e57602036600319011261049e576104f86004356104c38161048c565b63ffffffff60e01b16632483248360e11b8114908115610527575b81156104fc575b5060405190151581529081906020820190565b0390f35b63152a902d60e11b811491508115610516575b50386104e5565b6301ffc9a760e01b1490503861050f565b90506301ffc9a760e01b81148015610557575b8015610547575b906104de565b50635b5e139f60e01b8114610541565b506380ac58cd60e01b811461053a565b6001600160a01b031690565b6001600160a01b0381160361049e57565b3461049e57602036600319011261049e576004356105a181610573565b600090338252601b60205260ff604083205416158061066a575b61065957601a80546001600160a01b0319166001600160a01b0380841691909117909155601154839291906105ef90610567565b1690816105fa575050f35b813b15610655576040516340e1684f60e01b81526001600160a01b0391909116600482015291908290602490829084905af180156106505761063a575080f35b8061064761064d926118b6565b80610765565b80f35b6125dd565b5050fd5b6040516282b42960e81b8152600490fd5b506009546001600160a01b03163314156105bb565b3461049e57604036600319011261049e5760043561069c81610573565b602435906001600160601b03821680830361049e576106b961304f565b6127108082116107475750506001600160a01b0381161561072e5761070561072c926106f56106e661190c565b6001600160a01b039094168452565b6001600160601b03166020830152565b805160209091015160a01b6001600160a01b0319166001600160a01b039190911617600b55565b005b604051635b6cc80560e11b815260006004820152602490fd5b6044925060405191636f483d0960e01b835260048301526024820152fd5b600091031261049e57565b3461049e57600036600319011261049e57602061078b6125f8565b604051908152f35b3461049e57600036600319011261049e57602061078b612653565b60005b8381106107c15750506000910152565b81810151838201526020016107b1565b906020916107ea815180928185528580860191016107ae565b601f01601f1916010190565b9060206108079281815201906107d1565b90565b3461049e576000806003193601126108c5576040518160025461082c81612365565b908184526020926001916001811690816000146108a35750600114610868575b6104f88561085c818903826118e9565b604051918291826107f6565b929450600283528483205b82841061089057505050816104f89361085c92820101933861084c565b8054858501870152928501928101610873565b60ff191686860152505050151560051b820101915061085c816104f83861084c565b80fd5b3461049e57602036600319011261049e5760206108e660043561268f565b6040516001600160a01b039091168152f35b604036600319011261049e5760043561091081610573565b6024356001600160a01b038061092583613122565b1690813303610980575b600083815260066020526040812080546001600160a01b0319166001600160a01b0387161790559316907f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9258480a480f35b81600052600760205260ff610999336040600020610b30565b541661092f576367d9dca160e11b60005260046000fd5b3461049e57600036600319011261049e57601a546040516001600160a01b039091168152602090f35b3461049e57602036600319011261049e57602061078b6004356109fb81610573565b6126c9565b3461049e57602036600319011261049e57610a1961304f565b6011546001600160a01b0390610a2e90610567565b168015610a7c57803b1561049e576040516302b9019f60e31b81526004803590820152906000908290818381602481015b03925af1801561065057610a6f57005b8061064761072c926118b6565b60405163265641c560e11b8152600490fd5b3461049e57600036600319011261049e576000546001548103908111610ab957602090604051908152f35b612717565b606090600319011261049e57600435610ad681610573565b90602435610ae381610573565b9060443590565b61072c610af636610abe565b9161274b565b6001600160a01b0316600090815260076020526040902090565b6001600160a01b0316600090815260056020526040902090565b9060018060a01b0316600052602052604060002090565b3461049e57602036600319011261049e57600435610b6481610573565b60018060a01b0316600052601b602052602060ff604060002054166040519015158152f35b6001600160a01b039091168152602081019190915260400190565b3461049e57604036600319011261049e57602435600435600052600c6020526040600020549060018060a01b038083169260a01c908315610c11575b506001600160601b03168181029180159083049091141715610ab9576104f861271092604051938493049083610b89565b925050600b549182169160a01c38610be0565b3461049e57600036600319011261049e57602061078b61285b565b3461049e576000806003193601126108c557338152601b60205260ff6040822054161580610cee575b61065957601c546001600160a01b03168015610cdc57478015610c9e57828080809361064d955af1610c98612897565b506128c7565b60405162461bcd60e51b81526020600482015260166024820152754e6f2062616c616e636520746f20776974686472617760501b6044820152606490fd5b604051631c6c69d760e11b8152600490fd5b506009546001600160a01b0316331415610c68565b3461049e57600036600319011261049e57602061078b612905565b3461049e57600036600319011261049e57601c546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e576020610d62612956565b6040519015158152f35b3461049e57602036600319011261049e57610d8561304f565b6011546001600160a01b0390610d9a90610567565b168015610a7c57803b1561049e5760405163420401e960e01b8152600480359082015290600090829081838160248101610a5f565b61072c610ddb36610abe565b9060405192610de9846118ce565b60008452612be8565b3461049e57602036600319011261049e57600435610e0f81613122565b60008281526006602052604090208054916001600160a01b03811691610e3d610e3933858761318f565b1590565b610ef0575b600093610ee7575b50610e5482610b16565b80546001600160801b030190556001600160a01b0382164260a01b17600360e01b17610e7f8561165a565b55600160e11b811615610eb4575b506000805160206136938339815191528280a461072c610eaf60015460010190565b600155565b60018401610ec18161165a565b5415610ece575b50610e8d565b83548114610ec857610edf9061165a565b553880610ec8565b83905538610e4a565b610f0f610e39610f0833610f0387610afc565b610b30565b5460ff1690565b15610e42576130be565b3461049e57602036600319011261049e57600435610f3681610573565b610f3e61304f565b6001600160a01b03908116908115610f8c57601c80546001600160a01b031981168417909155167ff4d517cbe6d8f91c2d0818ac9a797925923e87e3f276fef4537a73dd2cd19167600080a3005b6040516321c17ee560e11b8152600490fd5b8015150361049e57565b604090600319011261049e57600435610fc081610573565b9060243561080781610f9e565b3461049e5760207f235bc17e7930760029e9f4d860a2a8089976de5b381cf8380fc11c1d88a11133610ffe36610fa8565b929061100861304f565b6001600160a01b03166000818152601b835260409020805460ff191660ff86151516179055926040519015158152a2005b3461049e57602036600319011261049e5760043561105681610573565b61105e61304f565b601180546001600160a01b039283166001600160a01b0319821681179092559091167f6f27b91599f4078d27a70be3466af653ea3fd93615886de17a3c304cd9a6241e600080a3005b3461049e5760408060031936011261049e576004908135916024356110ca6131be565b6011546001600160a01b03919082906110e290610567565b161561147a57841561146a576110fb610e3986336131e1565b61145a57611116610f08866000526018602052604060002090565b61144a578061144557506111294361272d565b61115c611150611143876000526014602052604060002090565b546001600160401b031690565b6001600160401b031690565b811061142457610100431180611434575b61142457438110156114245780408015611414576111a5611198876000526018602052604060002090565b805460ff19166001179055565b60018060401b03804216926111cd846111c88a6000526013602052604060002090565b6129ab565b166111e6816111c8896000526016602052604060002090565b816111fb886000526017602052604060002090565b558361121061120b601154610567565b610567565b601a546112219060a01c60ff161590565b6113cb575b87518981527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce790602090a116918651916303a1526d60e41b8352602080848981885afa9485156106505788946000966113aa575b5081908a519586809263692b031d60e11b82525afa8015610650578a957f416cb75bc03562caf614ec69bf85b2a924e05c74d59c8d3ddb709645c539b5a7956112fd9360009361137b575b50508a5194859433998691959493909260809360a084019760018060401b038092168552166020840152604083015260608201520152565b0390a361130b600f54610567565b16801561136c57803b1561049e579151637187036d60e11b815290810192835233602084015291600091839182908490829060400103925af1801561065057611359575b61072c6001600a55565b80610647611366926118b6565b3861134f565b509051635946bb1d60e01b8152fd5b61139b929350803d106113a3575b61139381836118e9565b8101906125e9565b9038806112c5565b503d611389565b829196506113c490823d84116113a35761139381836118e9565b959061127a565b90811690813b1561049e5760008092888a5180958193635a262d4360e11b83525af1918215610650578692611401575b50611226565b8061064761140e926118b6565b386113fb565b8451631ce084cd60e01b81528490fd5b835163ccc8ba5360e01b81528390fd5b5061143e4361273c565b811061116d565b611129565b8351637cca156760e11b81528390fd5b8351634cd9539b60e11b81528390fd5b8351635a50eb3360e11b81528390fd5b835163265641c560e11b81528390fd5b3461049e57602036600319011261049e576004356114a781610573565b600090338252601b60205260ff604083205416158061150e575b61065957600d80546001600160a01b039283166001600160a01b0319821681179092559091167f10e9b6d73105db46c6a41a698f35efb8e1688178fe274b7b21f0bdc792de3ea58380a380f35b506009546001600160a01b03163314156114c1565b3461049e57600036600319011261049e57602061078b6129ca565b3461049e57600036600319011261049e57600e546040516001600160a01b039091168152602090f35b3461049e57602036600319011261049e5760206001600160a01b0361158d600435613122565b16604051908152f35b3461049e57602036600319011261049e576004356115b381610573565b6001600160a01b031680156115e2576000526005602052602060018060401b0360406000205416604051908152f35b6323d3ad8160e21b60005260046000fd5b3461049e576000806003193601126108c55761160d61304f565b600980546001600160a01b0319811690915581906001600160a01b03166000805160206136738339815191528280a380f35b3461049e57600036600319011261049e57602061078b612a06565b6000526004602052604060002090565b3461049e57602036600319011261049e5760043560005260156020526020604060002054604051908152f35b3461049e57602036600319011261049e5760043560006116b58261307b565b1561172b57818152601560205260ff6040808320549260186020522054169182600014611717576116f36104f8916000526017602052604060002090565b54925b60405193849384919260409194936060840195845260208401521515910152565b506104f86117244361272d565b40926116f6565b60405163163a09e160e31b8152600490fd5b3461049e57600036600319011261049e57602061078b612a42565b3461049e57602036600319011261049e5760043561177581610573565b600090338252601b60205260ff604083205416158061180e575b6106595781546117fc576117a29061324a565b6117d360018060401b0382805260126020526117c3814216604085206129ab565b60146020524316604083206129ab565b6000194301438111610ab957600080526015602052406000805160206136538339815191525580f35b604051639546f5ab60e01b8152600490fd5b506009546001600160a01b031633141561178f565b3461049e57604036600319011261049e57602061078b60043561184581610573565b60243590612a7e565b3461049e57600036600319011261049e57600d546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e576009546040516001600160a01b039091168152602090f35b634e487b7160e01b600052604160045260246000fd5b6001600160401b0381116118c957604052565b6118a0565b602081019081106001600160401b038211176118c957604052565b601f909101601f19168101906001600160401b038211908210176118c957604052565b60408051919082016001600160401b038111838210176118c957604052565b6001600160401b0381116118c957601f01601f191660200190565b9291926119528261192b565b9161196060405193846118e9565b82948184528183011161049e578281602093846000960137010152565b3461049e5760208060031936011261049e576001600160401b039060043582811161049e573660238201121561049e576119c1903690602481600401359101611946565b91600091338352601b60205260ff6040842054161580611ac2575b6106595783519182116118c9576119fd826119f8601054612365565b612acb565b602090601f8311600114611a40575081908394611a2f9492611a35575b50508160011b916000199060031b1c19161790565b60105580f35b015190503880611a1a565b6010600052601f198316947f1b6847dc741a1b0cd08d278845f9d819d87b734759afb55fe2de5cb82a9ae672929185905b878210611aaa575050836001959610611a91575b505050811b0160105580f35b015160001960f88460031b161c19169055388080611a85565b80600185968294968601518155019501930190611a71565b506009546001600160a01b03163314156119dc565b3461049e576000806003193601126108c55760405181600354611af981612365565b908184526020926001916001811690816000146108a35750600114611b28576104f88561085c818903826118e9565b929450600383528483205b828410611b5057505050816104f89361085c92820101933861084c565b8054858501870152928501928101611b33565b3461049e57602036600319011261049e576004356000526014602052602060018060401b0360406000205416604051908152f35b60208060031936011261049e576004803591611bb16131be565b601a5460a01c60ff16611e00576011546001600160a01b0390611bd390610567565b168015611def5783151580611de4575b611bec90612b21565b60409283516340311a6160e01b815283818381865afa90811561065057600091611db7575b5015611da95783516322a0a0df60e21b8152838180611c338933878401610b89565b0381865afa90811561065057600091611d8c575b503410611d7e57813b1561049e578351637dd6e76560e11b815260008180611c728933878401610b89565b038183875af1801561065057611d6b575b5060005493611c914361272d565b90516303a1526d60e41b81526001600160401b034281169492409343909116928691839182905afa94851561065057600095611d4c575b505060005b868110611cde5761134f8733613356565b8085611d45611cef6001948a612b63565b611d07886111c8836000526012602052604060002090565b611d1f866111c8836000526014602052604060002090565b86611d34826000526015602052604060002090565b556000526019602052604060002090565b5501611ccd565b611d63929550803d106113a35761139381836118e9565b923880611cc8565b80610647611d78926118b6565b38611c83565b8351633cc6859560e21b8152fd5b611da39150843d86116113a35761139381836118e9565b38611c47565b8351635dcef89b60e01b8152fd5b611dd79150843d8611611ddd575b611dcf81836118e9565b810190612941565b38611c11565b503d611dc5565b506032841115611be3565b60405163265641c560e11b81528390fd5b50604051620de45360ea1b8152fd5b3461049e57611e1d36610fa8565b90336000526007602052611e4a82611e39836040600020610b30565b9060ff801983541691151516179055565b60405191151582526001600160a01b03169033907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3190602090a3005b3461049e576000806003193601126108c557611ea061304f565b80600b5580f35b3461049e57600036600319011261049e57602061078b612b70565b3461049e57602036600319011261049e57600435611edf81610f9e565b33600052601b60205260ff604060002054161580611f44575b6106595760207f6a904c879e06836c65d53725658c103f44f031e87a49cd56cdfa24ca60ffaecf911515601a5460ff60a01b8260a01b169060ff60a01b191617601a55604051908152a1005b506009546001600160a01b0316331415611ef8565b3461049e57602036600319011261049e5760043560005260176020526020604060002054604051908152f35b3461049e57600036600319011261049e57602061078b612bac565b3461049e57602036600319011261049e57611fb961304f565b6011546001600160a01b0390611fce90610567565b168015610a7c57803b1561049e5760405163b4f738cf60e01b8152600480359082015290600090829081838160248101610a5f565b608036600319011261049e5760043561201b81610573565b60243561202781610573565b606435916001600160401b03831161049e573660238401121561049e5761205b61072c933690602481600401359101611946565b9160443591612be8565b3461049e57600036600319011261049e57600f546040516001600160a01b039091168152602090f35b3461049e576000806003193601126108c5576120ae61120b600954610567565b33141580612125575b8061210e575b610659576011546001600160a01b03906120d690610567565b168015610a7c578082913b1561210b578190600460405180948193631837f0cb60e31b83525af180156106505761063a575080f35b50fd5b5061211d61120b601a54610567565b3314156120bd565b50336000908152601b6020526040902061214290610e3990610f08565b6120b7565b3461049e57602036600319011261049e576104f8612166600435612c89565b6040519182916020835260208301906107d1565b3461049e57600036600319011261049e57602061078b612f9b565b3461049e57600036600319011261049e576011546040516001600160a01b039091168152602090f35b3461049e57600036600319011261049e57602061078b612fd7565b3461049e57602036600319011261049e576004356000526013602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e5760043561222a81610573565b600090338252601b60205260ff6040832054161580612291575b61065957600f80546001600160a01b039283166001600160a01b0319821681179092559091167fa388bfe30ea1cc13f506d2a7b1667cfe5a24612ab41e459ff01bde952cd197e28380a380f35b506009546001600160a01b0316331415612244565b3461049e57600036600319011261049e57602060ff601a5460a01c166040519015158152f35b3461049e57602036600319011261049e576004356122e981610573565b600090338252601b60205260ff6040832054161580612350575b61065957600e80546001600160a01b039283166001600160a01b0319821681179092559091167f19a2dab6142d87b6d696bc64c6b7f457dcccae35ffd93262875e8ad029bb5a8f8380a380f35b506009546001600160a01b0316331415612303565b90600182811c92168015612395575b602083101461237f57565b634e487b7160e01b600052602260045260246000fd5b91607f1691612374565b3461049e576000806003193601126108c557604051816010546123c181612365565b908184526020926001916001811690816000146108a357506001146123f0576104f88561085c818903826118e9565b929450601083528483205b82841061241857505050816104f89361085c92820101933861084c565b80548585018701529285019281016123fb565b3461049e57600036600319011261049e576020610d62613013565b3461049e57604036600319011261049e57602060ff61249260043561246a81610573565b6024359061247782610573565b6001600160a01b031660009081526007855260409020610b30565b54166040519015158152f35b3461049e57602036600319011261049e576004356000526016602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e576004356000526012602052602060018060401b0360406000205416604051908152f35b3461049e57602036600319011261049e5760043561252381610573565b61252b61304f565b6001600160a01b0390811690811561256757600980546001600160a01b03198116841790915516600080516020613673833981519152600080a3005b604051631e4fbdf760e01b815260006004820152602490fd5b3461049e57602036600319011261049e576004356000526018602052602060ff604060002054166040519015158152f35b3461049e57602036600319011261049e5760043560005260196020526020604060002054604051908152f35b6040513d6000823e3d90fd5b9081602091031261049e575190565b6011546001600160a01b0316801561264d57602060049160405192838092630543842b60e01b82525afa90811561065057600091612634575090565b610807915060203d6020116113a35761139381836118e9565b50600090565b6011546001600160a01b0316801561264d576020600491604051928380926302b0ca1560e11b82525afa90811561065057600091612634575090565b6126988161307b565b156126b8576000908152600660205260409020546001600160a01b031690565b6333d1c03960e21b60005260046000fd5b6011546001600160a01b039081169190821561270f57602460209260405194859384926274ca4f60e51b84521660048301525afa90811561065057600091612634575090565b505050600090565b634e487b7160e01b600052601160045260246000fd5b600019810191908211610ab957565b60ff19810191908211610ab957565b91909161275782613122565b6001600160a01b039182169390828116859003612856576000848152600660205260409020805461278c610e3933898461318f565b612839575b61282f575b506127a085610b16565b80546000190190556127b182610b16565b805460010190556127c1826131a7565b6127ca8561165a565b55600160e11b8116156127fb575b50168092600080516020613693833981519152600080a4156127f657565b6130df565b600184016128088161165a565b5415612815575b506127d8565b600054811461280f576128279061165a565b55388061280f565b6000905538612796565b61284c610e39610f0833610f038b610afc565b15612791576130be565b6130cf565b6011546001600160a01b0316801561264d576020600491604051928380926303a1526d60e41b82525afa90811561065057600091612634575090565b3d156128c2573d906128a88261192b565b916128b660405193846118e9565b82523d6000602084013e565b606090565b156128ce57565b60405162461bcd60e51b815260206004820152600f60248201526e15da5d1a191c985dc819985a5b1959608a1b6044820152606490fd5b6011546001600160a01b0316801561264d57602060049160405192838092633f6e01a160e01b82525afa90811561065057600091612634575090565b9081602091031261049e575161080781610f9e565b6011546001600160a01b0316801561264d576020600491604051928380926340311a6160e01b82525afa90811561065057600091612992575090565b610807915060203d602011611ddd57611dcf81836118e9565b80546001600160401b0319166001600160401b03909216919091179055565b6011546001600160a01b0316801561264d57602060049160405192838092632e08ffbd60e11b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092631d27e8a160e21b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092638559dff360e01b82525afa90811561065057600091612634575090565b6011546001600160a01b031691821561270f576040516322a0a0df60e21b815292602092849283918291612ab59160048401610b89565b03915afa90811561065057600091612634575090565b601f8111612ad7575050565b60009060106000526020600020906020601f850160051c83019410612b17575b601f0160051c01915b828110612b0c57505050565b818155600101612b00565b9092508290612af7565b15612b2857565b60405162461bcd60e51b8152602060048201526013602482015272125b9d985b1a59081b5a5b9d08185b5bdd5b9d606a1b6044820152606490fd5b91908201809211610ab957565b6011546001600160a01b0316801561264d57602060049160405192838092630ab91c7b60e41b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d57602060049160405192838092630b40639560e41b82525afa90811561065057600091612634575090565b929190612bf682828661274b565b803b612c03575b50505050565b612c0c9361357b565b15612c1a5738808080612bfd565b6368d2bf6b60e11b60005260046000fd5b60208183031261049e578051906001600160401b03821161049e570181601f8201121561049e578051612c5d8161192b565b92612c6b60405194856118e9565b8184526020828401011161049e5761080791602080850191016107ae565b612c928161307b565b1561172b578015612d07576000612cd491612cb461120b61120b600d54610567565b604051808095819463c87b56dd60e01b8352600483019190602083019252565b03915afa90811561065057600091612cea575090565b61080791503d806000833e612cff81836118e9565b810190612c2b565b50600e546001600160a01b03908190612d1f90610567565b16908115612f895760409081519263b37a769160e01b8452602093600485828281865afa91821561065057600092612f6a575b50600093844391875194635f6f7ca560e11b8652898686818a5afa958615610650578396612f4b575b508515612f39575b15612e7e575050855163b37a8be360e01b8152905086818381875afa90811561065057600091612e51575b50958551956220903160ea1b875281878481885afa801561065057600097612cd4938992612e34575b50505b60008052601560205260008051602061365383398151915254915198899788968796633c3515db60e21b885287019192608093969594919660a08401978452602084015260018060a01b0316604083015260608201520152565b612e4a9250803d106113a35761139381836118e9565b3880612dd7565b612e719150873d8911612e77575b612e6981836118e9565b81019061363d565b38612dae565b503d612e5f565b809197929850612e8f601a54610567565b169081612ea6575b5050612cd49060009697612dda565b825180926302b8d13560e51b82526101809182918180612ecd8a8201906000602083019252565b03915afa8993849282612ef9575b5050612ee8575b50612e97565b911696509450806000612cd4612ee2565b8091929550612f1d9350903d10612f32575b612f1581836118e9565b8101906135b1565b50509850505050505091505090923880612edb565b503d612f0b565b9450612f444361272d565b4094612d83565b612f639196508a3d8c116113a35761139381836118e9565b9438612d7b565b612f82919250863d8811611ddd57611dcf81836118e9565b9038612d52565b604051630115914f60e01b8152600490fd5b6011546001600160a01b0316801561264d5760206004916040519283809263c954397960e01b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d5760206004916040519283809263692b031d60e11b82525afa90811561065057600091612634575090565b6011546001600160a01b0316801561264d5760206004916040519283809263e96079fd60e01b82525afa90811561065057600091612992575090565b6009546001600160a01b0316330361306357565b60405163118cdaa760e01b8152336004820152602490fd5b9060009160008054821061308d575050565b92505b80835260046020526040832054806130b257508015610ab95760001901613090565b600160e01b1615925050565b632ce44b5f60e11b60005260046000fd5b62a1148160e81b60005260046000fd5b633a954ecd60e21b60005260046000fd5b636f96cda160e11b60005260046000fd5b63b562e8dd60e01b60005260046000fd5b622e076360e81b60005260046000fd5b61312b8161165a565b549081156131425750600160e01b81166130f05790565b90506000906000548110156130f0575b6000190161315f8161165a565b549081156131885750600160e01b81161561318357636f96cda160e11b8252600482fd5b905090565b9050613152565b6001600160a01b039182169190921690811491141790565b6001600160a01b03164260a01b17600160e11b1790565b6002600a54146131cf576002600a55565b604051633ee5aeb560e01b8152600490fd5b6001600160a01b03806131f384613122565b169080831690828214948515613232575b505050821561321257505090565b60ff92509061322d9160005260076020526040600020610b30565b541690565b61323f919293955061268f565b161491388080613204565b60405190613257826118ce565b6000918281528254613268836131a7565b6132718261165a565b5561327b83610b16565b80546001600160401b010190556001600160a01b038316928315613351576001918281019481908480805b613314575b50505050848655813b6132c1575b505050505050565b9180805b6132e0575b50505050508154036108c55780808080806132b9565b15613307575b856132f8610e398684870196866134e1565b61330257816132c5565b612c1a565b8483106132e657806132ca565b15613339575b50878583838b6000805160206136938339815191528180a490816132a6565b9091019086821461334a578461331a565b84816132ab565b613112565b604051613362816118ce565b600092838252835492811561346b576001916001600160a01b0382164260a01b82851460e11b17176133938661165a565b5561339d82610b16565b80546001600160401b0183020190556001600160a01b03821680156133515781860195908480805b61342e575b50505050848655813b6133df57505050505050565b84039180805b6133ff5750505050508154036108c55780808080806132b9565b15613421575b85613417610e398684870196866134e1565b61330257816133e5565b84831061340557806132ca565b15613453575b50878583838b6000805160206136938339815191528180a490816133c5565b909101908682146134645784613434565b84816133ca565b613101565b9081602091031261049e57516108078161048c565b610807939260809260018060a01b0316825260006020830152604082015281606082015201906107d1565b6001600160a01b039182168152911660208201526040810191909152608060608201819052610807929101906107d1565b61350a60209160009394604051948580948193630a85bd0160e11b998a84523360048501613485565b03926001600160a01b03165af16000918161354a575b5061353c5761352d612897565b805115612c1a57805190602001fd5b6001600160e01b0319161490565b61356d91925060203d602011613574575b61356581836118e9565b810190613470565b9038613520565b503d61355b565b9260209161350a936000604051809681958294630a85bd0160e11b9a8b855233600486016134b0565b51906135af82610573565b565b91908261018091031261049e5781519160208101516135cf81610573565b9160408201516135de81610f9e565b9160608101519160808201519160a08101519160c08201519160e081015160ff8116810361049e579161361461010083016135a4565b9161362261012082016135a4565b9161080761016061363661014085016135a4565b93016135a4565b9081602091031261049e57516108078161057356fea31547ce6245cdb9ecea19cf8c7eb9f5974025bb4075011409251ae855b30aed8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa264697066735822122044b5b1b38f41c8e6c87eccf37d6f083d29c19f4a3b891b89eac039d11ba069e564736f6c63430008170033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000fe4c33f74fac6e23aac32667b10a1052a128c83e000000000000000000000000324c68bb517b43ca96bcabfb57ff90e1d5101152000000000000000000000000616d32e6e4d0fd86489cbd91ac35a8fd01f09d9e
-----Decoded View---------------
Arg [0] : _renderer (address): 0xFE4C33f74faC6E23aaC32667B10a1052a128c83E
Arg [1] : _editions (address): 0x324c68bb517B43Ca96BcABFb57FF90e1d5101152
Arg [2] : _mintWindowManager (address): 0x616d32e6e4d0FD86489CBd91Ac35A8FD01F09D9e
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000fe4c33f74fac6e23aac32667b10a1052a128c83e
Arg [1] : 000000000000000000000000324c68bb517b43ca96bcabfb57ff90e1d5101152
Arg [2] : 000000000000000000000000616d32e6e4d0fd86489cbd91ac35a8fd01f09d9e
Loading...
Loading
Loading...
Loading
Net Worth in USD
$705.63
Net Worth in ETH
0.36002
Token Allocations
ETH
100.00%
Multichain Portfolio | 33 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $1,959.98 | 0.36 | $705.63 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ 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.