ERC-721
Overview
Max Total Supply
0 FTTKN
Holders
94
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 FTTKNLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
TreasuryToken
Compiler Version
v0.8.20+commit.a1b79de6
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; import {ERC721} from "solady/src/tokens/ERC721.sol"; import {Ownable} from "solady/src/auth/Ownable.sol"; import {ITokenMetadata} from "./interfaces/ITokenMetadata.sol"; interface IERC721 { function transferFrom(address, address, uint256) external; function ownerOf(uint256) external view returns (address); } contract TreasuryToken is ERC721, Ownable { error NotStaked(); error NotOwner(); error Soulbound(); event MetadataUpdate(uint256 _tokenId); event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); IERC721 public immutable FOUNDERS_PASS; ITokenMetadata public metadataContract; uint256 private tokenIdIndex = 0; mapping(uint256 => uint256) private stakedTokenMap; constructor() { FOUNDERS_PASS = IERC721(0xdf9669A65c5845E472ad3Ca83d07605a9d7701b7); _initializeOwner(0x6544fa99fa7b6301cE366bc56C39397B7016Ca1C); } /// @dev Returns the token collection name. function name() public pure override returns (string memory) { return "Frensville Treasury Token"; } /// @dev Returns the token collection symbol. function symbol() public pure override returns (string memory) { return "FTTKN"; } /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view override returns (string memory) { return metadataContract.tokenURI(id); } function stake(uint256[5] calldata tokenIds) public { uint256 tokenIdToMint = ++tokenIdIndex; uint96 packedTokenIds; for (uint256 i; i < 5;) { uint256 tokenId = tokenIds[i]; stakedTokenMap[tokenId] = tokenIdToMint; FOUNDERS_PASS.transferFrom(msg.sender, address(this), tokenId); unchecked { // founders pass has supply of 800 and we are going to assume that the supply is never // going to exceed 65535, so it it safe to pack these token ids in 16 bits packedTokenIds += uint96(tokenId << (16 * i)); ++i; } } _mint(msg.sender, tokenIdToMint); _setExtraData(tokenIdToMint, packedTokenIds); } function unstake(uint256 stakedTokenId) public { if (ownerOf(stakedTokenId) != msg.sender) { revert NotOwner(); } uint96 tokenData = _getExtraData(stakedTokenId); uint256[] memory tokenIds = unpackTokenIds(tokenData); for (uint256 i; i < tokenIds.length;) { uint256 tokenId = tokenIds[i]; delete stakedTokenMap[tokenId]; FOUNDERS_PASS.transferFrom(address(this), msg.sender, tokenId); unchecked { ++i; } } _burn(stakedTokenId); _setExtraData(stakedTokenId, 0); emit MetadataUpdate(stakedTokenId); } function transferFrom(address, address, uint256) public payable override { revert Soulbound(); } function approve(address, uint256) public payable override { revert Soulbound(); } function setApprovalForAll(address, bool) public pure override { revert Soulbound(); } /// @notice gets the staking token id associated with a founders pass /// @param tokenId the founders pass to check /// @return staked token id or reverts if not staked function getStakedTokenId(uint256 tokenId) public view returns (uint256) { uint256 token = stakedTokenMap[tokenId]; if (token == 0) { revert NotStaked(); } return token; } /// @notice gets the owner of the specified founders pass, regardless of staking status /// @dev this method will not revert if the token is not staked and instead passes through /// to the underlying founders pass contract ownership /// @param tokenId token to check ownership of /// @return owner of the specified token function foundersPassOwnerOf(uint256 tokenId) public view returns (address) { uint256 token = stakedTokenMap[tokenId]; if (token == 0) { return FOUNDERS_PASS.ownerOf(tokenId); } return ownerOf(token); } /// @notice Gets the founders pass IDs staked with a specific treasury token /// @param tokenId treasury token to get staked founders passes /// @return tokenIds staked with the specified treasury token id function stakedIdsForToken(uint256 tokenId) public view returns (uint256[] memory) { uint96 tokenData = _getExtraData(tokenId); return unpackTokenIds(tokenData); } function unpackTokenIds(uint96 data) private pure returns (uint256[] memory) { uint256[] memory tokenIds = new uint256[](5); tokenIds[0] = data & type(uint16).max; tokenIds[1] = data >> 16 & type(uint16).max; tokenIds[2] = data >> 32 & type(uint16).max; tokenIds[3] = data >> 48 & type(uint16).max; tokenIds[4] = data >> 64 & type(uint16).max; return tokenIds; } function setMetadataContract(address metadata) external onlyOwner { metadataContract = ITokenMetadata(metadata); } function exists(uint256 id) external view returns (bool) { return _exists(id); } function metadataChanged() external { if (msg.sender != address(metadataContract)) { revert Unauthorized(); } emit BatchMetadataUpdate(1, type(uint256).max); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// /// For performance, methods are made payable where permitted by the ERC721 standard. /// /// For performance, most of the code is manually duplicated and inlined. /// Overriding internal functions may not alter the functionality of external functions. /// Please check and override accordingly. /// /// Please take care when overriding to never violate the ERC721 invariant: /// the balance of an owner must be always be equal to their number of ownership slots. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shr(96, shl(96, sload(ownershipSlot)))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3( 0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator)) ) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function safeTransferFrom(address from, address to, uint256 id, bytes calldata data) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) if iszero(and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeMint(address to, uint256 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Transfer} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(0x00, 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if `from` is not the owner, or does not exist. if iszero(mul(owner, eq(owner, from))) { if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } mstore(0x00, 0xa1148100) // `TransferFromIncorrectOwner()`. revert(0x1c, 0x04) } // Revert if `to` is the zero address. if iszero(to) { mstore(0x00, 0xea553b34) // `TransferToZeroAddress()`. revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) if iszero(and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE)) { mstore(0x00, 0x01336cea) // `AccountBalanceOverflow()`. revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(0x00, 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(0x00, 0x00, returndatasize()) revert(0x00, returndatasize()) } mstore(m, 0) } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol) /// /// @dev Note: /// This implementation does NOT auto-initialize the owner to `msg.sender`. /// You MUST call the `_initializeOwner` in the constructor / initializer. /// /// While the ownable portion follows /// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility, /// the nomenclature for the 2-step ownership handover may be unique to this codebase. abstract contract Ownable { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership is transferred from `oldOwner` to `newOwner`. /// This event is intentionally kept the same as OpenZeppelin's Ownable to be /// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173), /// despite it not being as lightweight as a single argument event. event OwnershipTransferred(address indexed oldOwner, address indexed newOwner); /// @dev An ownership handover to `pendingOwner` has been requested. event OwnershipHandoverRequested(address indexed pendingOwner); /// @dev The ownership handover to `pendingOwner` has been canceled. event OwnershipHandoverCanceled(address indexed pendingOwner); /// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`. uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE = 0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0; /// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE = 0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d; /// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`. uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE = 0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally chosen to be a high value /// to avoid collision with lower slots. /// The choice of manual storage layout is to enable compatibility /// with both regular and upgradeable contracts. uint256 private constant _OWNER_SLOT_NOT = 0x8b78c6d8; /// The ownership handover slot of `newOwner` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED)) /// let handoverSlot := keccak256(0x00, 0x20) /// ``` /// It stores the expiry timestamp of the two-step ownership handover. uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Initializes the owner directly without authorization guard. /// This function must be called upon initialization, /// regardless of whether the contract is upgradeable or not. /// This is to enable generalization to both regular and upgradeable contracts, /// and to save gas in case the initial owner is not the caller. /// For performance reasons, this function will not check if there /// is an existing owner. function _initializeOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner) } } /// @dev Sets the owner directly without authorization guard. function _setOwner(address newOwner) internal virtual { /// @solidity memory-safe-assembly assembly { let ownerSlot := not(_OWNER_SLOT_NOT) // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner) // Store the new value. sstore(ownerSlot, newOwner) } } /// @dev Throws if the sender is not the owner. function _checkOwner() internal view virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner, revert. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. /// Override to return a different value if needed. /// Made internal to conserve bytecode. Wrap it in a public function if needed. function _ownershipHandoverValidFor() internal view virtual returns (uint64) { return 48 * 3600; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC UPDATE FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Allows the owner to transfer the ownership to `newOwner`. function transferOwnership(address newOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { if iszero(shl(96, newOwner)) { mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`. revert(0x1c, 0x04) } } _setOwner(newOwner); } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { _setOwner(address(0)); } /// @dev Request a two-step ownership handover to the caller. /// The request will automatically expire in 48 hours (172800 seconds) by default. function requestOwnershipHandover() public payable virtual { unchecked { uint256 expires = block.timestamp + _ownershipHandoverValidFor(); /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to `expires`. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), expires) // Emit the {OwnershipHandoverRequested} event. log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller()) } } } /// @dev Cancels the two-step ownership handover to the caller, if any. function cancelOwnershipHandover() public payable virtual { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x20), 0) // Emit the {OwnershipHandoverCanceled} event. log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller()) } } /// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`. /// Reverts if there is no existing ownership handover requested by `pendingOwner`. function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Compute and set the handover slot to 0. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) let handoverSlot := keccak256(0x0c, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`. revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) } _setOwner(pendingOwner); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PUBLIC READ FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of the contract. function owner() public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { result := sload(not(_OWNER_SLOT_NOT)) } } /// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`. function ownershipHandoverExpiresAt(address pendingOwner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Compute the handover slot. mstore(0x0c, _HANDOVER_SLOT_SEED) mstore(0x00, pendingOwner) // Load the handover slot. result := sload(keccak256(0x0c, 0x20)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() virtual { _checkOwner(); _; } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.19; interface ITokenMetadata { function tokenURI(uint256 id) external view returns (string memory); }
{ "remappings": [ "ERC1155P/=lib/ERC1155P/contracts/", "closedsea/=lib/closedsea/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "erc721a-upgradeable/=lib/closedsea/lib/erc721a-upgradeable/contracts/", "erc721a/=lib/closedsea/lib/erc721a/contracts/", "forge-std/=lib/forge-std/src/", "openzeppelin-contracts-upgradeable/=lib/closedsea/lib/openzeppelin-contracts-upgradeable/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "openzeppelin/=lib/openzeppelin-contracts/contracts/", "operator-filter-registry/=lib/closedsea/lib/operator-filter-registry/", "solady/=lib/solady/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "paris", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotOwner","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"NotStaked","type":"error"},{"inputs":[],"name":"Soulbound","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"_fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"_toTokenId","type":"uint256"}],"name":"BatchMetadataUpdate","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":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"FOUNDERS_PASS","outputs":[{"internalType":"contract IERC721","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"exists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"foundersPassOwnerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getStakedTokenId","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"metadataChanged","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"metadataContract","outputs":[{"internalType":"contract ITokenMetadata","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"bool","name":"","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"metadata","type":"address"}],"name":"setMetadataContract","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[5]","name":"tokenIds","type":"uint256[5]"}],"name":"stake","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"stakedIdsForToken","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"stakedTokenId","type":"uint256"}],"name":"unstake","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60a0604052600060015534801561001557600080fd5b5073df9669a65c5845e472ad3ca83d07605a9d7701b760805261004b736544fa99fa7b6301ce366bc56c39397b7016ca1c610050565b61008c565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b60805161149f6100bc600039600081816104db0152818161069f0152818161083f01526109ec015261149f6000f3fe6080604052600436106101cd5760003560e01c806370a08231116100f7578063e5187f4311610095578063f2fde38b11610064578063f2fde38b14610546578063f6f3846614610559578063fc4d549f1461056e578063fee81cf41461058e57600080fd5b8063e5187f43146104a9578063e581171a146104c9578063e985e9c5146104fd578063f04e283e1461053357600080fd5b806395d89b41116100d157806395d89b411461042d578063a22cb4651461045b578063b88d4fde14610476578063c87b56dd1461048957600080fd5b806370a08231146103de578063715018a61461040c5780638da5cb5b1461041457600080fd5b80632e17de781161016f57806354d1f13d1161013e57806354d1f13d146103695780635cdc7136146103715780636003af2e1461039e5780636352211e146103be57600080fd5b80632e17de78146102f6578063352098211461031657806342842e0e146103365780634f558e791461034957600080fd5b8063095ea7b3116101ab578063095ea7b3146102ab57806317c54c64146102c057806323b872dd146102e057806325692962146102ee57600080fd5b806301ffc9a7146101d257806306fdde0314610224578063081812fc14610273575b600080fd5b3480156101de57600080fd5b5061020f6101ed36600461109c565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561023057600080fd5b5060408051808201909152601981527f4672656e7376696c6c6520547265617375727920546f6b656e0000000000000060208201525b60405161021b91906110ea565b34801561027f57600080fd5b5061029361028e36600461111d565b6105c1565b6040516001600160a01b03909116815260200161021b565b6102be6102b936600461114b565b610604565b005b3480156102cc57600080fd5b506102be6102db366004611177565b61061d565b6102be6102b936600461119f565b6102be610727565b34801561030257600080fd5b506102be61031136600461111d565b610777565b34801561032257600080fd5b50600054610293906001600160a01b031681565b6102be61034436600461119f565b6108f4565b34801561035557600080fd5b5061020f61036436600461111d565b610921565b6102be610948565b34801561037d57600080fd5b5061039161038c36600461111d565b610984565b60405161021b91906111e0565b3480156103aa57600080fd5b506102936103b936600461111d565b6109c0565b3480156103ca57600080fd5b506102936103d936600461111d565b610a64565b3480156103ea57600080fd5b506103fe6103f9366004611224565b610aa2565b60405190815260200161021b565b6102be610add565b34801561042057600080fd5b50638b78c6d81954610293565b34801561043957600080fd5b50604080518082019091526005815264232a2a25a760d91b6020820152610266565b34801561046757600080fd5b506102be6102b9366004611241565b6102be61048436600461127f565b610af1565b34801561049557600080fd5b506102666104a436600461111d565b610b4c565b3480156104b557600080fd5b506102be6104c4366004611224565b610bbe565b3480156104d557600080fd5b506102937f000000000000000000000000000000000000000000000000000000000000000081565b34801561050957600080fd5b5061020f61051836600461131e565b601c52670a5a2e7a000000006008526000526030600c205490565b6102be610541366004611224565b610be8565b6102be610554366004611224565b610c28565b34801561056557600080fd5b506102be610c4f565b34801561057a57600080fd5b506103fe61058936600461111d565b610cb6565b34801561059a57600080fd5b506103fe6105a9366004611224565b63389a75e1600c908152600091909152602090205490565b6000818152673ec412a9852d173d60c11b601c52602081208201820180546001600160a01b03166105fa5763ceea21b66000526004601cfd5b6001015492915050565b60405163a4420a9560e01b815260040160405180910390fd5b600060016000815461062e9061134c565b918290555090506000805b600581101561070d57600084826005811061065657610656611373565b602090810291909101356000818152600290925260409182902086905590516323b872dd60e01b8152336004820152306024820152604481018290529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b1580156106e357600080fd5b505af11580156106f7573d6000803e3d6000fd5b50505050601082021b9190910190600101610639565b506107183383610ce4565b6107228282610d92565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b3361078182610a64565b6001600160a01b0316146107a8576040516330cd747160e01b815260040160405180910390fd5b6000818152673ec412a9852d173d60c11b601c5260208120820182015460a01c906107d282610dc3565b905060005b81518110156108a75760008282815181106107f4576107f4611373565b6020908102919091018101516000818152600290925260408083209290925590516323b872dd60e01b8152306004820152336024820152604481018290529091506001600160a01b037f000000000000000000000000000000000000000000000000000000000000000016906323b872dd90606401600060405180830381600087803b15801561088357600080fd5b505af1158015610897573d6000803e3d6000fd5b50505050816001019150506107d7565b506108b183610ed8565b6108bc836000610d92565b6040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b6108ff838383610604565b813b156107225761072283838360405180602001604052806000815250610ee3565b6000818152673ec412a9852d173d60c11b601c5260208120820182015460601b5b92915050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b606060006109ae836000818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b90506109b981610dc3565b9392505050565b600081815260026020526040812054808203610a5f576040516331a9108f60e11b8152600481018490527f00000000000000000000000000000000000000000000000000000000000000006001600160a01b031690636352211e90602401602060405180830381865afa158015610a3b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b99190611389565b6109b9815b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b031680610a9d5763ceea21b66000526004601cfd5b919050565b600081610ab757638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b610ae5610f75565b610aef6000610f90565b565b610afc858585610604565b833b15610b4557610b4585858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ee392505050565b5050505050565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610b96573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261094291908101906113bc565b610bc6610f75565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b610bf0610f75565b63389a75e1600c52806000526020600c208054421115610c1857636f5e88186000526004601cfd5b60009055610c2581610f90565b50565b610c30610f75565b8060601b610c4657637448fbae6000526004601cfd5b610c2581610f90565b6000546001600160a01b03163314610c79576040516282b42960e81b815260040160405180910390fd5b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a1565b600081815260026020526040812054808203610942576040516273e5c360e31b815260040160405180910390fd5b6001600160a01b039091169081610d035763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b15610d385763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116610d64576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b81600052673ec412a9852d173d60c11b601c5260206000208201820180548060a01c831860a01b8118825550505050565b60408051600580825260c08201909252606091600091906020820160a080368337505081519192505061ffff8416908290600090610e0357610e03611373565b60209081029190910101528051601084901c61ffff169082906001908110610e2d57610e2d611373565b60200260200101818152505061ffff80166020846bffffffffffffffffffffffff16901c166bffffffffffffffffffffffff1681600281518110610e7357610e73611373565b60209081029190910101528051603084901c61ffff169082906003908110610e9d57610e9d611373565b60209081029190910101528051604084901c61ffff169082906004908110610ec757610ec7611373565b602090810291909101015292915050565b610c25600082610fce565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f2a578060c08401826020870160045afa505b60208360a48301601c860160008a5af1610f53573d15610f4e573d6000803e3d6000fd5b600083525b508060e01b825114610f6d5763d1a57ed66000526004601cfd5b505050505050565b638b78c6d819543314610aef576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6000610fd982610a64565b90505060008181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826110205763ceea21b66000526004601cfd5b8260005281600101548086148487141786151761104f576030600c205461104f57634b6e7f186000526004601cfd5b801561105d57600083600101555b5082189055601c600c208054600019019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b6000602082840312156110ae57600080fd5b81356001600160e01b0319811681146109b957600080fd5b60005b838110156110e15781810151838201526020016110c9565b50506000910152565b60208152600082518060208401526111098160408501602087016110c6565b601f01601f19169190910160400192915050565b60006020828403121561112f57600080fd5b5035919050565b6001600160a01b0381168114610c2557600080fd5b6000806040838503121561115e57600080fd5b823561116981611136565b946020939093013593505050565b600060a0828403121561118957600080fd5b8260a08301111561119957600080fd5b50919050565b6000806000606084860312156111b457600080fd5b83356111bf81611136565b925060208401356111cf81611136565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b81811015611218578351835292840192918401916001016111fc565b50909695505050505050565b60006020828403121561123657600080fd5b81356109b981611136565b6000806040838503121561125457600080fd5b823561125f81611136565b91506020830135801515811461127457600080fd5b809150509250929050565b60008060008060006080868803121561129757600080fd5b85356112a281611136565b945060208601356112b281611136565b935060408601359250606086013567ffffffffffffffff808211156112d657600080fd5b818801915088601f8301126112ea57600080fd5b8135818111156112f957600080fd5b89602082850101111561130b57600080fd5b9699959850939650602001949392505050565b6000806040838503121561133157600080fd5b823561133c81611136565b9150602083013561127481611136565b60006001820161136c57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561139b57600080fd5b81516109b981611136565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156113ce57600080fd5b815167ffffffffffffffff808211156113e657600080fd5b818401915084601f8301126113fa57600080fd5b81518181111561140c5761140c6113a6565b604051601f8201601f19908116603f01168101908382118183101715611434576114346113a6565b8160405282815287602084870101111561144d57600080fd5b61145e8360208301602088016110c6565b97965050505050505056fea2646970667358221220e75059c2e0a34ebcd33c20c1d8b2c5619ba822dea2ab0099909c700922b6721b64736f6c63430008140033
Deployed Bytecode
0x6080604052600436106101cd5760003560e01c806370a08231116100f7578063e5187f4311610095578063f2fde38b11610064578063f2fde38b14610546578063f6f3846614610559578063fc4d549f1461056e578063fee81cf41461058e57600080fd5b8063e5187f43146104a9578063e581171a146104c9578063e985e9c5146104fd578063f04e283e1461053357600080fd5b806395d89b41116100d157806395d89b411461042d578063a22cb4651461045b578063b88d4fde14610476578063c87b56dd1461048957600080fd5b806370a08231146103de578063715018a61461040c5780638da5cb5b1461041457600080fd5b80632e17de781161016f57806354d1f13d1161013e57806354d1f13d146103695780635cdc7136146103715780636003af2e1461039e5780636352211e146103be57600080fd5b80632e17de78146102f6578063352098211461031657806342842e0e146103365780634f558e791461034957600080fd5b8063095ea7b3116101ab578063095ea7b3146102ab57806317c54c64146102c057806323b872dd146102e057806325692962146102ee57600080fd5b806301ffc9a7146101d257806306fdde0314610224578063081812fc14610273575b600080fd5b3480156101de57600080fd5b5061020f6101ed36600461109c565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561023057600080fd5b5060408051808201909152601981527f4672656e7376696c6c6520547265617375727920546f6b656e0000000000000060208201525b60405161021b91906110ea565b34801561027f57600080fd5b5061029361028e36600461111d565b6105c1565b6040516001600160a01b03909116815260200161021b565b6102be6102b936600461114b565b610604565b005b3480156102cc57600080fd5b506102be6102db366004611177565b61061d565b6102be6102b936600461119f565b6102be610727565b34801561030257600080fd5b506102be61031136600461111d565b610777565b34801561032257600080fd5b50600054610293906001600160a01b031681565b6102be61034436600461119f565b6108f4565b34801561035557600080fd5b5061020f61036436600461111d565b610921565b6102be610948565b34801561037d57600080fd5b5061039161038c36600461111d565b610984565b60405161021b91906111e0565b3480156103aa57600080fd5b506102936103b936600461111d565b6109c0565b3480156103ca57600080fd5b506102936103d936600461111d565b610a64565b3480156103ea57600080fd5b506103fe6103f9366004611224565b610aa2565b60405190815260200161021b565b6102be610add565b34801561042057600080fd5b50638b78c6d81954610293565b34801561043957600080fd5b50604080518082019091526005815264232a2a25a760d91b6020820152610266565b34801561046757600080fd5b506102be6102b9366004611241565b6102be61048436600461127f565b610af1565b34801561049557600080fd5b506102666104a436600461111d565b610b4c565b3480156104b557600080fd5b506102be6104c4366004611224565b610bbe565b3480156104d557600080fd5b506102937f000000000000000000000000df9669a65c5845e472ad3ca83d07605a9d7701b781565b34801561050957600080fd5b5061020f61051836600461131e565b601c52670a5a2e7a000000006008526000526030600c205490565b6102be610541366004611224565b610be8565b6102be610554366004611224565b610c28565b34801561056557600080fd5b506102be610c4f565b34801561057a57600080fd5b506103fe61058936600461111d565b610cb6565b34801561059a57600080fd5b506103fe6105a9366004611224565b63389a75e1600c908152600091909152602090205490565b6000818152673ec412a9852d173d60c11b601c52602081208201820180546001600160a01b03166105fa5763ceea21b66000526004601cfd5b6001015492915050565b60405163a4420a9560e01b815260040160405180910390fd5b600060016000815461062e9061134c565b918290555090506000805b600581101561070d57600084826005811061065657610656611373565b602090810291909101356000818152600290925260409182902086905590516323b872dd60e01b8152336004820152306024820152604481018290529091506001600160a01b037f000000000000000000000000df9669a65c5845e472ad3ca83d07605a9d7701b716906323b872dd90606401600060405180830381600087803b1580156106e357600080fd5b505af11580156106f7573d6000803e3d6000fd5b50505050601082021b9190910190600101610639565b506107183383610ce4565b6107228282610d92565b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b3361078182610a64565b6001600160a01b0316146107a8576040516330cd747160e01b815260040160405180910390fd5b6000818152673ec412a9852d173d60c11b601c5260208120820182015460a01c906107d282610dc3565b905060005b81518110156108a75760008282815181106107f4576107f4611373565b6020908102919091018101516000818152600290925260408083209290925590516323b872dd60e01b8152306004820152336024820152604481018290529091506001600160a01b037f000000000000000000000000df9669a65c5845e472ad3ca83d07605a9d7701b716906323b872dd90606401600060405180830381600087803b15801561088357600080fd5b505af1158015610897573d6000803e3d6000fd5b50505050816001019150506107d7565b506108b183610ed8565b6108bc836000610d92565b6040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b6108ff838383610604565b813b156107225761072283838360405180602001604052806000815250610ee3565b6000818152673ec412a9852d173d60c11b601c5260208120820182015460601b5b92915050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b606060006109ae836000818152673ec412a9852d173d60c11b601c52602090208101015460a01c90565b90506109b981610dc3565b9392505050565b600081815260026020526040812054808203610a5f576040516331a9108f60e11b8152600481018490527f000000000000000000000000df9669a65c5845e472ad3ca83d07605a9d7701b76001600160a01b031690636352211e90602401602060405180830381865afa158015610a3b573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906109b99190611389565b6109b9815b6000818152673ec412a9852d173d60c11b601c526020902081018101546001600160a01b031680610a9d5763ceea21b66000526004601cfd5b919050565b600081610ab757638f4eb6046000526004601cfd5b673ec412a9852d173d60c11b601c528160005263ffffffff601c600c2054169050919050565b610ae5610f75565b610aef6000610f90565b565b610afc858585610604565b833b15610b4557610b4585858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250610ee392505050565b5050505050565b60005460405163c87b56dd60e01b8152600481018390526060916001600160a01b03169063c87b56dd90602401600060405180830381865afa158015610b96573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f1916820160405261094291908101906113bc565b610bc6610f75565b600080546001600160a01b0319166001600160a01b0392909216919091179055565b610bf0610f75565b63389a75e1600c52806000526020600c208054421115610c1857636f5e88186000526004601cfd5b60009055610c2581610f90565b50565b610c30610f75565b8060601b610c4657637448fbae6000526004601cfd5b610c2581610f90565b6000546001600160a01b03163314610c79576040516282b42960e81b815260040160405180910390fd5b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a1565b600081815260026020526040812054808203610942576040516273e5c360e31b815260040160405180910390fd5b6001600160a01b039091169081610d035763ea553b346000526004601cfd5b80600052673ec412a9852d173d60c11b601c5260206000208101810180548060601b15610d385763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff8116610d64576301336cea6000526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a45050565b81600052673ec412a9852d173d60c11b601c5260206000208201820180548060a01c831860a01b8118825550505050565b60408051600580825260c08201909252606091600091906020820160a080368337505081519192505061ffff8416908290600090610e0357610e03611373565b60209081029190910101528051601084901c61ffff169082906001908110610e2d57610e2d611373565b60200260200101818152505061ffff80166020846bffffffffffffffffffffffff16901c166bffffffffffffffffffffffff1681600281518110610e7357610e73611373565b60209081029190910101528051603084901c61ffff169082906003908110610e9d57610e9d611373565b60209081029190910101528051604084901c61ffff169082906004908110610ec757610ec7611373565b602090810291909101015292915050565b610c25600082610fce565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015610f2a578060c08401826020870160045afa505b60208360a48301601c860160008a5af1610f53573d15610f4e573d6000803e3d6000fd5b600083525b508060e01b825114610f6d5763d1a57ed66000526004601cfd5b505050505050565b638b78c6d819543314610aef576382b429006000526004601cfd5b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b6000610fd982610a64565b90505060008181526001600160a01b03928316673ec412a9852d173d60c11b8117601c5260209091208201820180549193821691826110205763ceea21b66000526004601cfd5b8260005281600101548086148487141786151761104f576030600c205461104f57634b6e7f186000526004601cfd5b801561105d57600083600101555b5082189055601c600c208054600019019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8280a4505050565b6000602082840312156110ae57600080fd5b81356001600160e01b0319811681146109b957600080fd5b60005b838110156110e15781810151838201526020016110c9565b50506000910152565b60208152600082518060208401526111098160408501602087016110c6565b601f01601f19169190910160400192915050565b60006020828403121561112f57600080fd5b5035919050565b6001600160a01b0381168114610c2557600080fd5b6000806040838503121561115e57600080fd5b823561116981611136565b946020939093013593505050565b600060a0828403121561118957600080fd5b8260a08301111561119957600080fd5b50919050565b6000806000606084860312156111b457600080fd5b83356111bf81611136565b925060208401356111cf81611136565b929592945050506040919091013590565b6020808252825182820181905260009190848201906040850190845b81811015611218578351835292840192918401916001016111fc565b50909695505050505050565b60006020828403121561123657600080fd5b81356109b981611136565b6000806040838503121561125457600080fd5b823561125f81611136565b91506020830135801515811461127457600080fd5b809150509250929050565b60008060008060006080868803121561129757600080fd5b85356112a281611136565b945060208601356112b281611136565b935060408601359250606086013567ffffffffffffffff808211156112d657600080fd5b818801915088601f8301126112ea57600080fd5b8135818111156112f957600080fd5b89602082850101111561130b57600080fd5b9699959850939650602001949392505050565b6000806040838503121561133157600080fd5b823561133c81611136565b9150602083013561127481611136565b60006001820161136c57634e487b7160e01b600052601160045260246000fd5b5060010190565b634e487b7160e01b600052603260045260246000fd5b60006020828403121561139b57600080fd5b81516109b981611136565b634e487b7160e01b600052604160045260246000fd5b6000602082840312156113ce57600080fd5b815167ffffffffffffffff808211156113e657600080fd5b818401915084601f8301126113fa57600080fd5b81518181111561140c5761140c6113a6565b604051601f8201601f19908116603f01168101908382118183101715611434576114346113a6565b8160405282815287602084870101111561144d57600080fd5b61145e8360208301602088016110c6565b97965050505050505056fea2646970667358221220e75059c2e0a34ebcd33c20c1d8b2c5619ba822dea2ab0099909c700922b6721b64736f6c63430008140033
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.