ERC-721
Overview
Max Total Supply
1,018 NONON_FRIEND
Holders
1,018
Market
Volume (24H)
N/A
Min Price (24H)
N/A
Max Price (24H)
N/A
Other Info
Token Contract
Balance
1 NONON_FRIENDLoading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
NononFriendCard
Compiler Version
v0.8.4+commit.c7e474f2
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT /// @title NONON FRIEND CARD - YOUR SPECIAL GIFT pragma solidity 0.8.4; import "../ERC721A.sol"; import "../IERC721A.sol"; import "solady/src/auth/OwnableRoles.sol"; import "solady/src/utils/Base64.sol"; import "solady/src/utils/SSTORE2.sol"; import "solady/src/utils/LibBitmap.sol"; import "./INononFriendCard.sol"; contract NononFriendCard is INononFriendCard, ERC721A, OwnableRoles { using LibBitmap for LibBitmap.Bitmap; // track tokens that have been collected by a given address mapping(address => LibBitmap.Bitmap) private receivedBitmap; mapping(address => LibBitmap.Bitmap) private sentBitmap; string public constant TOKEN_NAME = "NONON FRIEND CARD: "; string public constant DEFAULT_DESC = "share your message at nonon.house"; uint256 public constant NONON_MAX_SUPPLY = 5000; address public immutable collectionAddress; // address where bytes for base SVG are stored address private baseSvgPointer; bool private baseSvgPointerLocked; // address where bytes for svg defs are stored address private defsSvgPointer; bool private defsSvgPointerLocked; // address where level sprites are stored address private spritesSvgPointer; bool private spritesSvgPointerLocked; struct Level { uint256 minimum; string name; string colorGradient; uint16 spriteIndex; uint16 spriteLength; } struct LevelImageData { string name; string colorGradient; uint16 spriteIndex; uint16 spriteLength; uint256 cap; } // the evolution levels of the token Level[] public levels; struct TokenPoints { uint256 id; address owner; uint256 points; } // for easy lookup mapping(address => uint256) public tokenOf; // user messages (tokenId => message) mapping(uint256 => string) public messages; constructor(address tokenCollectionAddress) ERC721A("NONON FRIEND CARD", "NONON_FRIEND") { _setOwner(msg.sender); collectionAddress = tokenCollectionAddress; levels.push(Level(0, "ANGELS", "grad-1", 0, 288)); levels.push(Level(10, "ARCHANGELS", "grad-2", 288, 652)); levels.push(Level(50, "PRINCIPALITIES", "grad-3", 940, 758)); levels.push(Level(150, "VIRTUES", "grad-4", 1698, 646)); levels.push(Level(500, "DOMINIONS", "grad-5", 2344, 984)); levels.push(Level(1500, "THRONES", "grad-6", 3328, 817)); levels.push(Level(3500, "CHERUBIM", "grad-7", 4145, 758)); levels.push(Level(7500, "SERAPHIM", "grad-8", 4903, 709)); } function setBaseSvgPointer(bytes memory baseImage) public onlyOwner { if (baseSvgPointerLocked) revert SvgAlreadySet(); baseSvgPointer = SSTORE2.write(baseImage); baseSvgPointerLocked = true; } function setDefsSvgPointer(bytes memory defs) public onlyOwner { if (defsSvgPointerLocked) revert SvgAlreadySet(); defsSvgPointer = SSTORE2.write(defs); defsSvgPointerLocked = true; } function setSpritesSvgPointer(bytes memory spriteImages) public onlyOwner { if (spritesSvgPointerLocked) revert SvgAlreadySet(); spritesSvgPointer = SSTORE2.write(spriteImages); spritesSvgPointerLocked = true; } function mintTo(address to) external override onlyCollection { uint256 id = _nextTokenId(); tokenOf[to] = id; _mint(to, 1); emit Locked(id); } function burnToken(uint256 tokenId) public { delete tokenOf[ownerOf(tokenId)]; _burn(tokenId, true); } // set custom message for a token function setMessage(uint256 _tokenId, string calldata _message) public { if (ownerOf(_tokenId) != msg.sender) revert Unauthorized(); if (bytes(_message).length > 256) revert MessageTooLong(); messages[_tokenId] = _message; emit MetadataUpdate(_tokenId); } function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) revert URIQueryForNonexistentToken(); uint256 tokenPoints = points(tokenId); LevelImageData memory level = levelData(tokenPoints); string memory message = tokenMessage(tokenId); string memory baseUrl = "data:application/json;base64,"; return string( abi.encodePacked( baseUrl, Base64.encode( bytes( abi.encodePacked( '{"name":"', bytes.concat(bytes(TOKEN_NAME), bytes(level.name)), '",', '"description":"', message, '",', '"attributes":[{"trait_type":"Points","max_value":', _toString(level.cap), ',"value":', _toString(tokenPoints), '}, {"trait_type":"Level","value":"', level.name, '"}],', '"image":"', buildSvg(level.colorGradient, level.spriteIndex, level.spriteLength, message), '"}' ) ) ) ) ); } function tokenMessage(uint256 tokenId) public view returns (string memory) { string memory message = messages[tokenId]; if (bytes(message).length > 0) { return message; } else { return DEFAULT_DESC; } } // construct image svg function buildSvg(string memory colorGradient, uint16 spriteIndex, uint16 spriteLength, string memory message) internal view returns (string memory) { string memory baseUrl = "data:image/svg+xml;base64,"; bytes memory baseSvg = SSTORE2.read(baseSvgPointer); bytes memory spritesSvg = SSTORE2.read(spritesSvgPointer); bytes memory defs = SSTORE2.read(defsSvgPointer); return string( abi.encodePacked( baseUrl, Base64.encode( bytes( abi.encodePacked( '<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 1080 1080"><path fill="rgba(255,255,255,0)" d="M0 0h1080v1080H0z" />', '<path fill="url(#', colorGradient, ')" d="M24 40a16 16 0 0 1 16-16h1000a16 16 0 0 1 16 16v914a16 16 0 0 1-16 16H114.5a24 24 0 0 0-17.6 7.7l-59 63.4a8 8 0 0 1-13.9-5.4V40Z" />', baseSvg, getSpriteSubstring(spritesSvg, spriteIndex, spriteLength), '<text xml:space="preserve" fill="#009DF5" font-family="Courier" font-size="24" letter-spacing="0em" style="white-space:pre"><tspan x="144" y="1044.9">', message, "</tspan></text>", defs, "</svg>" ) ) ) ) ); } function getSpriteSubstring(bytes memory spritesSvg, uint16 spriteIndex, uint16 spriteLength) internal pure returns (bytes memory) { bytes memory sprite = new bytes(spriteLength); for (uint256 i = 0; i < sprite.length; i++) { sprite[i] = spritesSvg[i + spriteIndex]; } return sprite; } // get metadata for token display based on a given points value function levelData(uint256 tokenPoints) internal view returns (LevelImageData memory levelImageData) { for (uint256 i = levels.length; i > 0;) { Level memory level = levels[i - 1]; if (tokenPoints >= level.minimum) { if (i < levels.length) { // there is at least one level above current, so get its minimum Level memory nextLevel = levels[i]; return LevelImageData( level.name, level.colorGradient, level.spriteIndex, level.spriteLength, nextLevel.minimum ); } else { // highest level uint256 maxPoints = IERC721A(collectionAddress).totalSupply() * 2; return LevelImageData(level.name, level.colorGradient, level.spriteIndex, level.spriteLength, maxPoints); } } unchecked { --i; } } } // prevent transfer (except mint and burn) function _beforeTokenTransfers(address from, address to, uint256, uint256) internal pure override { if (from != address(0) && to != address(0)) { revert OnlyForYou(); } } // add ID for associated sequential tokens to appropriate lists function registerTokenMovement(address from, address to, uint256 collectionTokenStartId, uint256 quantity) external override onlyCollection { if (from != address(0)) { if (to != from) { sentBitmap[from].setBatch(collectionTokenStartId, quantity); } } if (to != address(0)) { receivedBitmap[to].setBatch(collectionTokenStartId, quantity); } emit BatchMetadataUpdate(1, type(uint256).max); } // total points accumulated by a holder function points(uint256 tokenId) public view returns (uint256) { address owner = ownerOf(tokenId); uint256 max = IERC721A(collectionAddress).totalSupply() + 1; return receivedBitmap[owner].popCount(1, max) + sentBitmap[owner].popCount(1, max); } // convenience function to get point information in a token range // note that this is expensive and most likely will require multiple calls to cover large ranges. function tokenPointsInRange(uint256 startId, uint256 endId) external view returns (TokenPoints[] memory) { if (endId < startId) revert InvalidParams(); TokenPoints[] memory tokenPoints = new TokenPoints[]((endId - startId) + 1); uint256 max = IERC721A(collectionAddress).totalSupply() + 1; uint256 pointsIndex; for (uint256 i = startId; i <= endId;) { if (_exists(i)) { address owner = ownerOf(i); uint256 totalPoints = receivedBitmap[owner].popCount(1, max) + sentBitmap[owner].popCount(1, max); tokenPoints[pointsIndex] = TokenPoints({id: i, owner: owner, points: totalPoints}); ++pointsIndex; } ++i; } return tokenPoints; } // check if given address is a holder of the token function hasToken(address receiver) public view override returns (bool) { return balanceOf(receiver) > 0; } // check if given address has ever received tokenId function hasReceivedToken(address owner, uint256 tokenId) external view returns (bool) { return receivedBitmap[owner].get(tokenId); } // check if given address has ever sent tokenId function hasSentToken(address owner, uint256 tokenId) external view returns (bool) { return sentBitmap[owner].get(tokenId); } function tokenStatusMap(address owner, bool sent) external view returns (uint256[] memory received) { uint256 maxWordIndex = NONON_MAX_SUPPLY >> 8; uint256[] memory words = new uint256[](maxWordIndex + 1); for (uint256 i = 0; i <= maxWordIndex; i++) { words[i] = (sent ? sentBitmap[owner].map[i] : receivedBitmap[owner].map[i]); } return words; } function _startTokenId() internal view virtual override returns (uint256) { return 1; } modifier onlyCollection() { if (msg.sender != collectionAddress) { revert Unauthorized(); } _; } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // 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()`. * * 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 { // Reference type for token approval. 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; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _currentIndex = _startTokenId(); } // ============================================================= // TOKEN COUNTING OPERATIONS // ============================================================= /** * @dev Returns the starting token ID. * To change the starting token ID, please override this function. */ function _startTokenId() internal view virtual returns (uint256) { return 0; } /** * @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) { // Counter underflow is impossible as _burnCounter cannot be incremented // more than `_currentIndex - _startTokenId()` times. unchecked { return _currentIndex - _burnCounter - _startTokenId(); } } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view virtual returns (uint256) { // Counter underflow is impossible as `_currentIndex` does not decrement, // and it is initialized to `_startTokenId()`. unchecked { return _currentIndex - _startTokenId(); } } /** * @dev Returns the total number of tokens burned. */ function _totalBurned() internal view virtual returns (uint256) { return _burnCounter; } // ============================================================= // 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(); 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(); 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 Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal virtual { if (_packedOwnerships[index] == 0) { _packedOwnerships[index] = _packedOwnershipOf(index); } } /** * Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) private view returns (uint256) { uint256 curr = tokenId; unchecked { if (_startTokenId() <= curr) if (curr < _currentIndex) { uint256 packed = _packedOwnerships[curr]; // If not burned. if (packed & _BITMASK_BURNED == 0) { // 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, `curr` will not underflow. // // We can directly compare the packed value. // If the address is zero, packed will be zero. while (packed == 0) { packed = _packedOwnerships[--curr]; } return packed; } } } revert OwnerQueryForNonexistentToken(); } /** * @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. * 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) public virtual override { address owner = ownerOf(tokenId); if (_msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) { revert ApprovalCallerNotOwnerNorApproved(); } _tokenApprovals[tokenId].value = to; emit Approval(owner, to, tokenId); } /** * @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(); 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 { if (operator == _msgSenderERC721A()) revert ApproveToCaller(); _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) { return _startTokenId() <= tokenId && tokenId < _currentIndex && // If within bounds, _packedOwnerships[tokenId] & _BITMASK_BURNED == 0; // and not 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 virtual override { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); if (address(uint160(prevOwnershipPacked)) != from) revert TransferFromIncorrectOwner(); (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(); if (to == address(0)) revert TransferToZeroAddress(); _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; } } } } emit Transfer(from, to, tokenId); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public 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 virtual override { transferFrom(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { revert TransferToNonERC721ReceiverImplementer(); } } /** * @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(); } else { 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(); _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: // - `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) ); uint256 toMasked; uint256 end = startTokenId + quantity; // Use assembly to loop and emit the `Transfer` event for gas savings. // The duplicated `log4` removes an extra check and reduces stack juggling. // The assembly, together with the surrounding Solidity code, have been // delicately arranged to nudge the compiler into producing optimized opcodes. assembly { // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. toMasked := and(to, _BITMASK_ADDRESS) // 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`. startTokenId // `tokenId`. ) for { let tokenId := add(startTokenId, 1) } iszero(eq(tokenId, end)) { tokenId := add(tokenId, 1) } { // Emit the `Transfer` event. Similar to above. log4(0, 0, _TRANSFER_EVENT_SIGNATURE, 0, toMasked, tokenId) } } if (toMasked == 0) revert MintToZeroAddress(); _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(); if (quantity == 0) revert MintZeroQuantity(); if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) revert MintERC2309QuantityExceedsLimit(); _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) ); 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(); } } while (index < end); // Reentrancy protection. if (_currentIndex != end) revert(); } } } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal virtual { _safeMint(to, quantity, ''); } // ============================================================= // 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(); } _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 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(); 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 0x80 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 32-byte word to store the length, // and 3 32-byte words to store a maximum of 78 digits. Total: 0x20 + 3 * 0x20 = 0x80. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, str) // 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) } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.2.2 // 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(); /** * The caller cannot approve to their own address. */ error ApproveToCaller(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables * (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, * checking first that contract recipients are aware of the ERC721 protocol * to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move * this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external; /** * @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; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the 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.4; interface INononFriendCard { /** * cannot transfer the soulbound token */ error OnlyForYou(); /** * cannot set collection address to zero address */ error CollectionZeroAddress(); /** * cannot add new level with a lower minimum */ error LevelMinimumLowerThanExisting(); /** * incorrect params given */ error InvalidParams(); /** * message exceeds size limit */ error MessageTooLong(); /** * svg data already set */ error SvgAlreadySet(); event MetadataUpdate(uint256 _tokenId); event BatchMetadataUpdate(uint256 _fromTokenId, uint256 _toTokenId); event Locked(uint256 tokenId); function registerTokenMovement(address from, address to, uint256 collectionTokenStartId, uint256 quantity) external; function mintTo(address to) external; function hasToken(address receiver) external returns (bool); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple single owner and multiroles authorization mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol) /// @dev While the ownable portion follows [EIP-173](https://eips.ethereum.org/EIPS/eip-173) /// for compatibility, the nomenclature for the 2-step ownership handover and roles /// may be unique to this codebase. abstract contract OwnableRoles { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The caller is not authorized to call the function. error Unauthorized(); /// @dev The `newOwner` cannot be the zero address. error NewOwnerIsZeroAddress(); /// @dev The `pendingOwner` does not have a valid handover request. error NoHandoverRequest(); /// @dev `bytes4(keccak256(bytes("Unauthorized()")))`. uint256 private constant _UNAUTHORIZED_ERROR_SELECTOR = 0x82b42900; /// @dev `bytes4(keccak256(bytes("NewOwnerIsZeroAddress()")))`. uint256 private constant _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR = 0x7448fbae; /// @dev `bytes4(keccak256(bytes("NoHandoverRequest()")))`. uint256 private constant _NO_HANDOVER_REQUEST_ERROR_SELECTOR = 0x6f5e8818; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 The `user`'s roles is updated to `roles`. /// Each bit of `roles` represents whether the role is set. event RolesUpdated(address indexed user, uint256 indexed roles); /// @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; /// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`. uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE = 0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The owner slot is given by: `not(_OWNER_SLOT_NOT)`. /// It is intentionally choosen 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. /// /// The role slot of `user` is given by: /// ``` /// mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) /// let roleSlot := keccak256(0x00, 0x20) /// ``` /// This automatically ignores the upper bits of the `user` in case /// they are not clean, as well as keep the `keccak256` under 32-bytes. 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 Grants the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn on. function _grantRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) let roleSlot := keccak256(0x00, 0x20) // Load the current value and `or` it with `roles`. let newRoles := or(sload(roleSlot), roles) // Store the new value. sstore(roleSlot, newRoles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles) } } /// @dev Removes the roles directly without authorization guard. /// Each bit of `roles` represents the role to turn off. function _removeRoles(address user, uint256 roles) internal virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) let roleSlot := keccak256(0x00, 0x20) // Load the current value. let currentRoles := sload(roleSlot) // Use `and` to compute the intersection of `currentRoles` and `roles`, // `xor` it with `currentRoles` to flip the bits in the intersection. let newRoles := xor(currentRoles, and(currentRoles, roles)) // Then, store the new value. sstore(roleSlot, newRoles) // Emit the {RolesUpdated} event. log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, shl(96, user)), newRoles) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 { // Clean the upper 96 bits. newOwner := shr(96, shl(96, newOwner)) // Reverts if the `newOwner` is the zero address. if iszero(newOwner) { mstore(0x00, _NEW_OWNER_IS_ZERO_ADDRESS_ERROR_SELECTOR) revert(0x1c, 0x04) } // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), newOwner) // Store the new value. sstore(not(_OWNER_SLOT_NOT), newOwner) } } /// @dev Allows the owner to renounce their ownership. function renounceOwnership() public payable virtual onlyOwner { /// @solidity memory-safe-assembly assembly { // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), 0) // Store the new value. sstore(not(_OWNER_SLOT_NOT), 0) } } /// @dev Request a two-step ownership handover to the caller. /// The request will be 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 1. mstore(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED)) sstore(keccak256(0x00, 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(0x00, or(shl(96, caller()), _HANDOVER_SLOT_SEED)) sstore(keccak256(0x00, 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 { // Clean the upper 96 bits. pendingOwner := shr(96, shl(96, pendingOwner)) // Compute and set the handover slot to 0. mstore(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED)) let handoverSlot := keccak256(0x00, 0x20) // If the handover does not exist, or has expired. if gt(timestamp(), sload(handoverSlot)) { mstore(0x00, _NO_HANDOVER_REQUEST_ERROR_SELECTOR) revert(0x1c, 0x04) } // Set the handover slot to 0. sstore(handoverSlot, 0) // Emit the {OwnershipTransferred} event. log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, caller(), pendingOwner) // Store the new value. sstore(not(_OWNER_SLOT_NOT), pendingOwner) } } /// @dev Allows the owner to grant `user` `roles`. /// If the `user` already has a role, then it will be an no-op for the role. function grantRoles(address user, uint256 roles) public payable virtual onlyOwner { _grantRoles(user, roles); } /// @dev Allows the owner to remove `user` `roles`. /// If the `user` does not have a role, then it will be an no-op for the role. function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner { _removeRoles(user, roles); } /// @dev Allow the caller to remove their own roles. /// If the caller does not have a role, then it will be an no-op for the role. function renounceRoles(uint256 roles) public payable virtual { _removeRoles(msg.sender, roles); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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(0x00, or(shl(96, pendingOwner), _HANDOVER_SLOT_SEED)) // Load the handover slot. result := sload(keccak256(0x00, 0x20)) } } /// @dev Returns how long a two-step ownership handover is valid for in seconds. function ownershipHandoverValidFor() public view virtual returns (uint64) { return 48 * 3600; } /// @dev Returns whether `user` has any of `roles`. function hasAnyRole(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // Load the stored value, and set the result to whether the // `and` intersection of the value and `roles` is not zero. result := iszero(iszero(and(sload(keccak256(0x00, 0x20)), roles))) } } /// @dev Returns whether `user` has all of `roles`. function hasAllRoles(address user, uint256 roles) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // Whether the stored value is contains all the set bits in `roles`. result := eq(and(sload(keccak256(0x00, 0x20)), roles), roles) } } /// @dev Returns the roles of `user`. function rolesOf(address user) public view virtual returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, user), _OWNER_SLOT_NOT)) // Load the stored value. roles := sload(keccak256(0x00, 0x20)) } } /// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. function rolesFromOrdinals(uint8[] memory ordinals) public pure returns (uint256 roles) { /// @solidity memory-safe-assembly assembly { // Skip the length slot. let o := add(ordinals, 0x20) // `shl` 5 is equivalent to multiplying by 0x20. let end := add(o, shl(5, mload(ordinals))) // prettier-ignore for {} iszero(eq(o, end)) { o := add(o, 0x20) } { roles := or(roles, shl(and(mload(o), 0xff), 1)) } } } /// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap. /// This is meant for frontends like Etherscan, and is therefore not fully optimized. /// Not recommended to be called on-chain. function ordinalsFromRoles(uint256 roles) public pure returns (uint8[] memory ordinals) { /// @solidity memory-safe-assembly assembly { // Grab the pointer to the free memory. let ptr := add(mload(0x40), 0x20) // The absence of lookup tables, De Bruijn, etc., here is intentional for // smaller bytecode, as this function is not meant to be called on-chain. // prettier-ignore for { let i := 0 } 1 { i := add(i, 1) } { mstore(ptr, i) // `shr` 5 is equivalent to multiplying by 0x20. // Push back into the ordinals array if the bit is set. ptr := add(ptr, shl(5, and(roles, 1))) roles := shr(1, roles) // prettier-ignore if iszero(roles) { break } } // Set `ordinals` to the start of the free memory. ordinals := mload(0x40) // Allocate the memory. mstore(0x40, ptr) // Store the length of `ordinals`. mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20)))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MODIFIERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Marks a function as only callable by the owner. modifier onlyOwner() 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, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } _; } /// @dev Marks a function as only callable by an account with `roles`. modifier onlyRoles(uint256 roles) virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } _; } /// @dev Marks a function as only callable by the owner or by an account /// with `roles`. Checks for ownership first, then lazily checks for roles. modifier onlyOwnerOrRoles(uint256 roles) virtual { /// @solidity memory-safe-assembly assembly { // If the caller is not the stored owner. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } _; } /// @dev Marks a function as only callable by an account with `roles` /// or the owner. Checks for roles first, then lazily checks for ownership. modifier onlyRolesOrOwner(uint256 roles) virtual { /// @solidity memory-safe-assembly assembly { // Compute the role slot. mstore(0x00, or(shl(96, caller()), _OWNER_SLOT_NOT)) // Load the stored value, and if the `and` intersection // of the value and `roles` is zero, revert. if iszero(and(sload(keccak256(0x00, 0x20)), roles)) { // If the caller is not the stored owner. if iszero(eq(caller(), sload(not(_OWNER_SLOT_NOT)))) { mstore(0x00, _UNAUTHORIZED_ERROR_SELECTOR) revert(0x1c, 0x04) } } } _; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ROLE CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // IYKYK uint256 internal constant _ROLE_0 = 1 << 0; uint256 internal constant _ROLE_1 = 1 << 1; uint256 internal constant _ROLE_2 = 1 << 2; uint256 internal constant _ROLE_3 = 1 << 3; uint256 internal constant _ROLE_4 = 1 << 4; uint256 internal constant _ROLE_5 = 1 << 5; uint256 internal constant _ROLE_6 = 1 << 6; uint256 internal constant _ROLE_7 = 1 << 7; uint256 internal constant _ROLE_8 = 1 << 8; uint256 internal constant _ROLE_9 = 1 << 9; uint256 internal constant _ROLE_10 = 1 << 10; uint256 internal constant _ROLE_11 = 1 << 11; uint256 internal constant _ROLE_12 = 1 << 12; uint256 internal constant _ROLE_13 = 1 << 13; uint256 internal constant _ROLE_14 = 1 << 14; uint256 internal constant _ROLE_15 = 1 << 15; uint256 internal constant _ROLE_16 = 1 << 16; uint256 internal constant _ROLE_17 = 1 << 17; uint256 internal constant _ROLE_18 = 1 << 18; uint256 internal constant _ROLE_19 = 1 << 19; uint256 internal constant _ROLE_20 = 1 << 20; uint256 internal constant _ROLE_21 = 1 << 21; uint256 internal constant _ROLE_22 = 1 << 22; uint256 internal constant _ROLE_23 = 1 << 23; uint256 internal constant _ROLE_24 = 1 << 24; uint256 internal constant _ROLE_25 = 1 << 25; uint256 internal constant _ROLE_26 = 1 << 26; uint256 internal constant _ROLE_27 = 1 << 27; uint256 internal constant _ROLE_28 = 1 << 28; uint256 internal constant _ROLE_29 = 1 << 29; uint256 internal constant _ROLE_30 = 1 << 30; uint256 internal constant _ROLE_31 = 1 << 31; uint256 internal constant _ROLE_32 = 1 << 32; uint256 internal constant _ROLE_33 = 1 << 33; uint256 internal constant _ROLE_34 = 1 << 34; uint256 internal constant _ROLE_35 = 1 << 35; uint256 internal constant _ROLE_36 = 1 << 36; uint256 internal constant _ROLE_37 = 1 << 37; uint256 internal constant _ROLE_38 = 1 << 38; uint256 internal constant _ROLE_39 = 1 << 39; uint256 internal constant _ROLE_40 = 1 << 40; uint256 internal constant _ROLE_41 = 1 << 41; uint256 internal constant _ROLE_42 = 1 << 42; uint256 internal constant _ROLE_43 = 1 << 43; uint256 internal constant _ROLE_44 = 1 << 44; uint256 internal constant _ROLE_45 = 1 << 45; uint256 internal constant _ROLE_46 = 1 << 46; uint256 internal constant _ROLE_47 = 1 << 47; uint256 internal constant _ROLE_48 = 1 << 48; uint256 internal constant _ROLE_49 = 1 << 49; uint256 internal constant _ROLE_50 = 1 << 50; uint256 internal constant _ROLE_51 = 1 << 51; uint256 internal constant _ROLE_52 = 1 << 52; uint256 internal constant _ROLE_53 = 1 << 53; uint256 internal constant _ROLE_54 = 1 << 54; uint256 internal constant _ROLE_55 = 1 << 55; uint256 internal constant _ROLE_56 = 1 << 56; uint256 internal constant _ROLE_57 = 1 << 57; uint256 internal constant _ROLE_58 = 1 << 58; uint256 internal constant _ROLE_59 = 1 << 59; uint256 internal constant _ROLE_60 = 1 << 60; uint256 internal constant _ROLE_61 = 1 << 61; uint256 internal constant _ROLE_62 = 1 << 62; uint256 internal constant _ROLE_63 = 1 << 63; uint256 internal constant _ROLE_64 = 1 << 64; uint256 internal constant _ROLE_65 = 1 << 65; uint256 internal constant _ROLE_66 = 1 << 66; uint256 internal constant _ROLE_67 = 1 << 67; uint256 internal constant _ROLE_68 = 1 << 68; uint256 internal constant _ROLE_69 = 1 << 69; uint256 internal constant _ROLE_70 = 1 << 70; uint256 internal constant _ROLE_71 = 1 << 71; uint256 internal constant _ROLE_72 = 1 << 72; uint256 internal constant _ROLE_73 = 1 << 73; uint256 internal constant _ROLE_74 = 1 << 74; uint256 internal constant _ROLE_75 = 1 << 75; uint256 internal constant _ROLE_76 = 1 << 76; uint256 internal constant _ROLE_77 = 1 << 77; uint256 internal constant _ROLE_78 = 1 << 78; uint256 internal constant _ROLE_79 = 1 << 79; uint256 internal constant _ROLE_80 = 1 << 80; uint256 internal constant _ROLE_81 = 1 << 81; uint256 internal constant _ROLE_82 = 1 << 82; uint256 internal constant _ROLE_83 = 1 << 83; uint256 internal constant _ROLE_84 = 1 << 84; uint256 internal constant _ROLE_85 = 1 << 85; uint256 internal constant _ROLE_86 = 1 << 86; uint256 internal constant _ROLE_87 = 1 << 87; uint256 internal constant _ROLE_88 = 1 << 88; uint256 internal constant _ROLE_89 = 1 << 89; uint256 internal constant _ROLE_90 = 1 << 90; uint256 internal constant _ROLE_91 = 1 << 91; uint256 internal constant _ROLE_92 = 1 << 92; uint256 internal constant _ROLE_93 = 1 << 93; uint256 internal constant _ROLE_94 = 1 << 94; uint256 internal constant _ROLE_95 = 1 << 95; uint256 internal constant _ROLE_96 = 1 << 96; uint256 internal constant _ROLE_97 = 1 << 97; uint256 internal constant _ROLE_98 = 1 << 98; uint256 internal constant _ROLE_99 = 1 << 99; uint256 internal constant _ROLE_100 = 1 << 100; uint256 internal constant _ROLE_101 = 1 << 101; uint256 internal constant _ROLE_102 = 1 << 102; uint256 internal constant _ROLE_103 = 1 << 103; uint256 internal constant _ROLE_104 = 1 << 104; uint256 internal constant _ROLE_105 = 1 << 105; uint256 internal constant _ROLE_106 = 1 << 106; uint256 internal constant _ROLE_107 = 1 << 107; uint256 internal constant _ROLE_108 = 1 << 108; uint256 internal constant _ROLE_109 = 1 << 109; uint256 internal constant _ROLE_110 = 1 << 110; uint256 internal constant _ROLE_111 = 1 << 111; uint256 internal constant _ROLE_112 = 1 << 112; uint256 internal constant _ROLE_113 = 1 << 113; uint256 internal constant _ROLE_114 = 1 << 114; uint256 internal constant _ROLE_115 = 1 << 115; uint256 internal constant _ROLE_116 = 1 << 116; uint256 internal constant _ROLE_117 = 1 << 117; uint256 internal constant _ROLE_118 = 1 << 118; uint256 internal constant _ROLE_119 = 1 << 119; uint256 internal constant _ROLE_120 = 1 << 120; uint256 internal constant _ROLE_121 = 1 << 121; uint256 internal constant _ROLE_122 = 1 << 122; uint256 internal constant _ROLE_123 = 1 << 123; uint256 internal constant _ROLE_124 = 1 << 124; uint256 internal constant _ROLE_125 = 1 << 125; uint256 internal constant _ROLE_126 = 1 << 126; uint256 internal constant _ROLE_127 = 1 << 127; uint256 internal constant _ROLE_128 = 1 << 128; uint256 internal constant _ROLE_129 = 1 << 129; uint256 internal constant _ROLE_130 = 1 << 130; uint256 internal constant _ROLE_131 = 1 << 131; uint256 internal constant _ROLE_132 = 1 << 132; uint256 internal constant _ROLE_133 = 1 << 133; uint256 internal constant _ROLE_134 = 1 << 134; uint256 internal constant _ROLE_135 = 1 << 135; uint256 internal constant _ROLE_136 = 1 << 136; uint256 internal constant _ROLE_137 = 1 << 137; uint256 internal constant _ROLE_138 = 1 << 138; uint256 internal constant _ROLE_139 = 1 << 139; uint256 internal constant _ROLE_140 = 1 << 140; uint256 internal constant _ROLE_141 = 1 << 141; uint256 internal constant _ROLE_142 = 1 << 142; uint256 internal constant _ROLE_143 = 1 << 143; uint256 internal constant _ROLE_144 = 1 << 144; uint256 internal constant _ROLE_145 = 1 << 145; uint256 internal constant _ROLE_146 = 1 << 146; uint256 internal constant _ROLE_147 = 1 << 147; uint256 internal constant _ROLE_148 = 1 << 148; uint256 internal constant _ROLE_149 = 1 << 149; uint256 internal constant _ROLE_150 = 1 << 150; uint256 internal constant _ROLE_151 = 1 << 151; uint256 internal constant _ROLE_152 = 1 << 152; uint256 internal constant _ROLE_153 = 1 << 153; uint256 internal constant _ROLE_154 = 1 << 154; uint256 internal constant _ROLE_155 = 1 << 155; uint256 internal constant _ROLE_156 = 1 << 156; uint256 internal constant _ROLE_157 = 1 << 157; uint256 internal constant _ROLE_158 = 1 << 158; uint256 internal constant _ROLE_159 = 1 << 159; uint256 internal constant _ROLE_160 = 1 << 160; uint256 internal constant _ROLE_161 = 1 << 161; uint256 internal constant _ROLE_162 = 1 << 162; uint256 internal constant _ROLE_163 = 1 << 163; uint256 internal constant _ROLE_164 = 1 << 164; uint256 internal constant _ROLE_165 = 1 << 165; uint256 internal constant _ROLE_166 = 1 << 166; uint256 internal constant _ROLE_167 = 1 << 167; uint256 internal constant _ROLE_168 = 1 << 168; uint256 internal constant _ROLE_169 = 1 << 169; uint256 internal constant _ROLE_170 = 1 << 170; uint256 internal constant _ROLE_171 = 1 << 171; uint256 internal constant _ROLE_172 = 1 << 172; uint256 internal constant _ROLE_173 = 1 << 173; uint256 internal constant _ROLE_174 = 1 << 174; uint256 internal constant _ROLE_175 = 1 << 175; uint256 internal constant _ROLE_176 = 1 << 176; uint256 internal constant _ROLE_177 = 1 << 177; uint256 internal constant _ROLE_178 = 1 << 178; uint256 internal constant _ROLE_179 = 1 << 179; uint256 internal constant _ROLE_180 = 1 << 180; uint256 internal constant _ROLE_181 = 1 << 181; uint256 internal constant _ROLE_182 = 1 << 182; uint256 internal constant _ROLE_183 = 1 << 183; uint256 internal constant _ROLE_184 = 1 << 184; uint256 internal constant _ROLE_185 = 1 << 185; uint256 internal constant _ROLE_186 = 1 << 186; uint256 internal constant _ROLE_187 = 1 << 187; uint256 internal constant _ROLE_188 = 1 << 188; uint256 internal constant _ROLE_189 = 1 << 189; uint256 internal constant _ROLE_190 = 1 << 190; uint256 internal constant _ROLE_191 = 1 << 191; uint256 internal constant _ROLE_192 = 1 << 192; uint256 internal constant _ROLE_193 = 1 << 193; uint256 internal constant _ROLE_194 = 1 << 194; uint256 internal constant _ROLE_195 = 1 << 195; uint256 internal constant _ROLE_196 = 1 << 196; uint256 internal constant _ROLE_197 = 1 << 197; uint256 internal constant _ROLE_198 = 1 << 198; uint256 internal constant _ROLE_199 = 1 << 199; uint256 internal constant _ROLE_200 = 1 << 200; uint256 internal constant _ROLE_201 = 1 << 201; uint256 internal constant _ROLE_202 = 1 << 202; uint256 internal constant _ROLE_203 = 1 << 203; uint256 internal constant _ROLE_204 = 1 << 204; uint256 internal constant _ROLE_205 = 1 << 205; uint256 internal constant _ROLE_206 = 1 << 206; uint256 internal constant _ROLE_207 = 1 << 207; uint256 internal constant _ROLE_208 = 1 << 208; uint256 internal constant _ROLE_209 = 1 << 209; uint256 internal constant _ROLE_210 = 1 << 210; uint256 internal constant _ROLE_211 = 1 << 211; uint256 internal constant _ROLE_212 = 1 << 212; uint256 internal constant _ROLE_213 = 1 << 213; uint256 internal constant _ROLE_214 = 1 << 214; uint256 internal constant _ROLE_215 = 1 << 215; uint256 internal constant _ROLE_216 = 1 << 216; uint256 internal constant _ROLE_217 = 1 << 217; uint256 internal constant _ROLE_218 = 1 << 218; uint256 internal constant _ROLE_219 = 1 << 219; uint256 internal constant _ROLE_220 = 1 << 220; uint256 internal constant _ROLE_221 = 1 << 221; uint256 internal constant _ROLE_222 = 1 << 222; uint256 internal constant _ROLE_223 = 1 << 223; uint256 internal constant _ROLE_224 = 1 << 224; uint256 internal constant _ROLE_225 = 1 << 225; uint256 internal constant _ROLE_226 = 1 << 226; uint256 internal constant _ROLE_227 = 1 << 227; uint256 internal constant _ROLE_228 = 1 << 228; uint256 internal constant _ROLE_229 = 1 << 229; uint256 internal constant _ROLE_230 = 1 << 230; uint256 internal constant _ROLE_231 = 1 << 231; uint256 internal constant _ROLE_232 = 1 << 232; uint256 internal constant _ROLE_233 = 1 << 233; uint256 internal constant _ROLE_234 = 1 << 234; uint256 internal constant _ROLE_235 = 1 << 235; uint256 internal constant _ROLE_236 = 1 << 236; uint256 internal constant _ROLE_237 = 1 << 237; uint256 internal constant _ROLE_238 = 1 << 238; uint256 internal constant _ROLE_239 = 1 << 239; uint256 internal constant _ROLE_240 = 1 << 240; uint256 internal constant _ROLE_241 = 1 << 241; uint256 internal constant _ROLE_242 = 1 << 242; uint256 internal constant _ROLE_243 = 1 << 243; uint256 internal constant _ROLE_244 = 1 << 244; uint256 internal constant _ROLE_245 = 1 << 245; uint256 internal constant _ROLE_246 = 1 << 246; uint256 internal constant _ROLE_247 = 1 << 247; uint256 internal constant _ROLE_248 = 1 << 248; uint256 internal constant _ROLE_249 = 1 << 249; uint256 internal constant _ROLE_250 = 1 << 250; uint256 internal constant _ROLE_251 = 1 << 251; uint256 internal constant _ROLE_252 = 1 << 252; uint256 internal constant _ROLE_253 = 1 << 253; uint256 internal constant _ROLE_254 = 1 << 254; uint256 internal constant _ROLE_255 = 1 << 255; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library to encode strings in Base64. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/Base64.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/Base64.sol) /// @author Modified from (https://github.com/Brechtpd/base64/blob/main/base64.sol) by Brecht Devos - <[email protected]>. library Base64 { /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// See: https://datatracker.ietf.org/doc/html/rfc4648 /// @param fileSafe Whether to replace '+' with '-' and '/' with '_'. /// @param noPadding Whether to strip away the padding. function encode( bytes memory data, bool fileSafe, bool noPadding ) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { // Multiply by 4/3 rounded up. // The `shl(2, ...)` is equivalent to multiplying by 4. let encodedLength := shl(2, div(add(dataLength, 2), 3)) // Set `result` to point to the start of the free memory. result := mload(0x40) // Store the table into the scratch space. // Offsetted by -1 byte so that the `mload` will load the character. // We will rewrite the free memory pointer at `0x40` later with // the allocated size. // The magic constant 0x0230 will translate "-_" + "+/". mstore(0x1f, "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdef") mstore(0x3f, sub("ghijklmnopqrstuvwxyz0123456789-_", mul(iszero(fileSafe), 0x0230))) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) let end := add(ptr, encodedLength) // Run over the input, 3 bytes at a time. // prettier-ignore for {} 1 {} { data := add(data, 3) // Advance 3 bytes. let input := mload(data) // Write 4 bytes. Optimized for fewer stack operations. mstore8( ptr , mload(and(shr(18, input), 0x3F))) mstore8(add(ptr, 1), mload(and(shr(12, input), 0x3F))) mstore8(add(ptr, 2), mload(and(shr( 6, input), 0x3F))) mstore8(add(ptr, 3), mload(and( input , 0x3F))) ptr := add(ptr, 4) // Advance 4 bytes. // prettier-ignore if iszero(lt(ptr, end)) { break } } let r := mod(dataLength, 3) switch noPadding case 0 { // Offset `ptr` and pad with '='. We can simply write over the end. mstore8(sub(ptr, iszero(iszero(r))), 0x3d) // Pad at `ptr - 1` if `r > 0`. mstore8(sub(ptr, shl(1, eq(r, 1))), 0x3d) // Pad at `ptr - 2` if `r == 1`. // Write the length of the string. mstore(result, encodedLength) } default { // Write the length of the string. mstore(result, sub(encodedLength, add(iszero(iszero(r)), eq(r, 1)))) } // Allocate the memory for the string. // Add 31 and mask with `not(31)` to round the // free memory pointer up the next multiple of 32. mstore(0x40, and(add(end, 31), not(31))) } } } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, false, false)`. function encode(bytes memory data) internal pure returns (string memory result) { result = encode(data, false, false); } /// @dev Encodes `data` using the base64 encoding described in RFC 4648. /// Equivalent to `encode(data, fileSafe, false)`. function encode(bytes memory data, bool fileSafe) internal pure returns (string memory result) { result = encode(data, fileSafe, false); } /// @dev Encodes base64 encoded `data`. /// /// Supports: /// - RFC 4648 (both standard and file-safe mode). /// - RFC 3501 (63: ','). /// /// Does not support: /// - Line breaks. /// /// Note: For performance reasons, /// this function will NOT revert on invalid `data` inputs. /// Outputs for invalid inputs will simply be undefined behaviour. /// It is the user's responsibility to ensure that the `data` /// is a valid base64 encoded string. function decode(string memory data) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let dataLength := mload(data) if dataLength { let end := add(data, dataLength) let decodedLength := mul(shr(2, dataLength), 3) switch and(dataLength, 3) case 0 { // If padded. decodedLength := sub( decodedLength, add(eq(and(mload(end), 0xFF), 0x3d), eq(and(mload(end), 0xFFFF), 0x3d3d)) ) } default { // If non-padded. decodedLength := add(decodedLength, sub(and(dataLength, 3), 1)) } result := mload(0x40) // Write the length of the string. mstore(result, decodedLength) // Skip the first slot, which stores the length. let ptr := add(result, 0x20) // Load the table into the scratch space. // Constants are optimized for smaller bytecode with zero gas overhead. // `m` also doubles as the mask of the upper 6 bits. let m := 0xfc000000fc00686c7074787c8084888c9094989ca0a4a8acb0b4b8bcc0c4c8cc mstore(0x5b, m) mstore(0x3b, 0x04080c1014181c2024282c3034383c4044484c5054585c6064) mstore(0x1a, 0xf8fcf800fcd0d4d8dce0e4e8ecf0f4) // prettier-ignore for {} 1 {} { // Read 4 bytes. data := add(data, 4) let input := mload(data) // Write 3 bytes. mstore(ptr, or( and(m, mload(byte(28, input))), shr(6, or( and(m, mload(byte(29, input))), shr(6, or( and(m, mload(byte(30, input))), shr(6, mload(byte(31, input))) )) )) )) ptr := add(ptr, 3) // prettier-ignore if iszero(lt(data, end)) { break } } // Allocate the memory for the string. // Add 32 + 31 and mask with `not(31)` to round the // free memory pointer up the next multiple of 32. mstore(0x40, and(add(add(result, decodedLength), 63), not(31))) // Restore the zero slot. mstore(0x60, 0) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for bit twiddling operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBit.sol) /// @author Inspired by (https://graphics.stanford.edu/~seander/bithacks.html) library LibBit { /// @dev Find last set. /// Returns the index of the most significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. /// Equivalent to `log2(x)`, but without reverting for the zero case. function fls(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(8, iszero(x)) r := or(r, shl(7, lt(0xffffffffffffffffffffffffffffffff, x))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) // For the remaining 32 bits, use a De Bruijn lookup. x := shr(r, x) x := or(x, shr(1, x)) x := or(x, shr(2, x)) x := or(x, shr(4, x)) x := or(x, shr(8, x)) x := or(x, shr(16, x)) // prettier-ignore r := or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f)) } } /// @dev Count leading zeros. /// Returns the number of zeros preceding the most significant one bit. /// If `x` is zero, returns 256. function clz(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { let t := add(iszero(x), 255) r := shl(7, lt(0xffffffffffffffffffffffffffffffff, x)) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) // For the remaining 32 bits, use a De Bruijn lookup. x := shr(r, x) x := or(x, shr(1, x)) x := or(x, shr(2, x)) x := or(x, shr(4, x)) x := or(x, shr(8, x)) x := or(x, shr(16, x)) // prettier-ignore r := sub(t, or(r, byte(shr(251, mul(x, shl(224, 0x07c4acdd))), 0x0009010a0d15021d0b0e10121619031e080c141c0f111807131b17061a05041f))) } } /// @dev Find first set. /// Returns the index of the least significant bit of `x`, /// counting from the least significant bit position. /// If `x` is zero, returns 256. /// Equivalent to `ctz` (count trailing zeros), which gives /// the number of zeros following the least significant one bit. function ffs(uint256 x) internal pure returns (uint256 r) { /// @solidity memory-safe-assembly assembly { r := shl(8, iszero(x)) // Isolate the least significant bit. x := and(x, add(not(x), 1)) r := or(r, shl(7, lt(0xffffffffffffffffffffffffffffffff, x))) r := or(r, shl(6, lt(0xffffffffffffffff, shr(r, x)))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) // For the remaining 32 bits, use a De Bruijn lookup. // prettier-ignore r := or(r, byte(shr(251, mul(shr(r, x), shl(224, 0x077cb531))), 0x00011c021d0e18031e16140f191104081f1b0d17151310071a0c12060b050a09)) } } /// @dev Returns the number of set bits in `x`. function popCount(uint256 x) internal pure returns (uint256 c) { /// @solidity memory-safe-assembly assembly { let max := not(0) let isMax := eq(x, max) x := sub(x, and(shr(1, x), div(max, 3))) x := add(and(x, div(max, 5)), and(shr(2, x), div(max, 5))) x := and(add(x, shr(4, x)), div(max, 17)) c := or(shl(8, isMax), shr(248, mul(x, div(max, 255)))) } } /// @dev Returns whether `x` is a power of 2. function isPo2(uint256 x) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // Equivalent to `x && !(x & (x - 1))`. result := iszero(add(and(x, sub(x, 1)), iszero(x))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "./LibBit.sol"; /// @notice Efficient bitmap library for mapping integers to single bit booleans. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBitmap.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibBitmap.sol) /// @author Modified from Solidity-Bits (https://github.com/estarriolvetch/solidity-bits/blob/main/contracts/BitMaps.sol) library LibBitmap { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when a bitmap scan does not find a result. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A bitmap in storage. struct Bitmap { mapping(uint256 => uint256) map; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the boolean value of the bit at `index` in `bitmap`. function get(Bitmap storage bitmap, uint256 index) internal view returns (bool isSet) { // It is better to set `isSet` to either 0 or 1, than zero vs non-zero. // Both cost the same amount of gas, but the former allows the returned value // to be reused without cleaning the upper bits. uint256 b = (bitmap.map[index >> 8] >> (index & 0xff)) & 1; /// @solidity memory-safe-assembly assembly { isSet := b } } /// @dev Updates the bit at `index` in `bitmap` to true. function set(Bitmap storage bitmap, uint256 index) internal { bitmap.map[index >> 8] |= (1 << (index & 0xff)); } /// @dev Updates the bit at `index` in `bitmap` to false. function unset(Bitmap storage bitmap, uint256 index) internal { bitmap.map[index >> 8] &= ~(1 << (index & 0xff)); } /// @dev Flips the bit at `index` in `bitmap`. /// Returns the boolean result of the flipped bit. function toggle(Bitmap storage bitmap, uint256 index) internal returns (bool newIsSet) { /// @solidity memory-safe-assembly assembly { mstore(0x00, shr(8, index)) mstore(0x20, bitmap.slot) let storageSlot := keccak256(0x00, 0x40) let shift := and(index, 0xff) let storageValue := sload(storageSlot) let mask := shl(shift, 1) storageValue := xor(storageValue, mask) // It makes sense to return the `newIsSet`, // as it allow us to skip an additional warm `sload`, // and it costs minimal gas (about 15), // which may be optimized away if the returned value is unused. newIsSet := iszero(iszero(and(storageValue, mask))) sstore(storageSlot, storageValue) } } /// @dev Updates the bit at `index` in `bitmap` to `shouldSet`. function setTo( Bitmap storage bitmap, uint256 index, bool shouldSet ) internal { /// @solidity memory-safe-assembly assembly { mstore(0x20, bitmap.slot) mstore(0x00, shr(8, index)) let storageSlot := keccak256(0x00, 0x40) let storageValue := sload(storageSlot) let shift := and(index, 0xff) sstore( storageSlot, // Unsets the bit at `shift` via `and`, then sets its new value via `or`. or(and(storageValue, not(shl(shift, 1))), shl(shift, iszero(iszero(shouldSet)))) ) } } /// @dev Consecutively sets `amount` of bits starting from the bit at `start`. function setBatch( Bitmap storage bitmap, uint256 start, uint256 amount ) internal { /// @solidity memory-safe-assembly assembly { let max := not(0) let shift := and(start, 0xff) mstore(0x20, bitmap.slot) mstore(0x00, shr(8, start)) if iszero(lt(add(shift, amount), 257)) { let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, or(sload(storageSlot), shl(shift, max))) let bucket := add(mload(0x00), 1) let bucketEnd := add(mload(0x00), shr(8, add(amount, shift))) amount := and(add(amount, shift), 0xff) shift := 0 // prettier-ignore for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } { mstore(0x00, bucket) sstore(keccak256(0x00, 0x40), max) } mstore(0x00, bucket) } let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, or(sload(storageSlot), shl(shift, shr(sub(256, amount), max)))) } } /// @dev Consecutively unsets `amount` of bits starting from the bit at `start`. function unsetBatch( Bitmap storage bitmap, uint256 start, uint256 amount ) internal { /// @solidity memory-safe-assembly assembly { let shift := and(start, 0xff) mstore(0x20, bitmap.slot) mstore(0x00, shr(8, start)) if iszero(lt(add(shift, amount), 257)) { let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, and(sload(storageSlot), not(shl(shift, not(0))))) let bucket := add(mload(0x00), 1) let bucketEnd := add(mload(0x00), shr(8, add(amount, shift))) amount := and(add(amount, shift), 0xff) shift := 0 // prettier-ignore for {} iszero(eq(bucket, bucketEnd)) { bucket := add(bucket, 1) } { mstore(0x00, bucket) sstore(keccak256(0x00, 0x40), 0) } mstore(0x00, bucket) } let storageSlot := keccak256(0x00, 0x40) sstore(storageSlot, and(sload(storageSlot), not(shl(shift, shr(sub(256, amount), not(0)))))) } } /// @dev Returns number of set bits within a range by /// scanning `amount` of bits starting from the bit at `start`. function popCount( Bitmap storage bitmap, uint256 start, uint256 amount ) internal view returns (uint256 count) { unchecked { uint256 bucket = start >> 8; uint256 shift = start & 0xff; if (!(amount + shift < 257)) { count = LibBit.popCount(bitmap.map[bucket] >> shift); uint256 bucketEnd = bucket + ((amount + shift) >> 8); amount = (amount + shift) & 0xff; shift = 0; for (++bucket; bucket != bucketEnd; ++bucket) { count += LibBit.popCount(bitmap.map[bucket]); } } count += LibBit.popCount((bitmap.map[bucket] >> shift) << (256 - amount)); } } /// @dev Returns the index of the most significant set bit before the bit at `before`. /// If no set bit is found, returns `NOT_FOUND`. function findLastSet(Bitmap storage bitmap, uint256 before) internal view returns (uint256 setBitIndex) { uint256 bucket; uint256 bucketBits; /// @solidity memory-safe-assembly assembly { setBitIndex := not(0) bucket := shr(8, before) mstore(0x00, bucket) mstore(0x20, bitmap.slot) let offset := xor(0xff, and(0xff, before)) // `256 - (255 & before) - 1`. bucketBits := shr(offset, shl(offset, sload(keccak256(0x00, 0x40)))) if iszero(bucketBits) { // prettier-ignore for {} bucket {} { bucket := sub(bucket, 1) mstore(0x00, bucket) bucketBits := sload(keccak256(0x00, 0x40)) // prettier-ignore if bucketBits { break } } } } if (bucketBits != 0) { setBitIndex = (bucket << 8) | LibBit.fls(bucketBits); /// @solidity memory-safe-assembly assembly { setBitIndex := or(setBitIndex, sub(0, gt(setBitIndex, before))) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Read and write to persistent storage at a fraction of the cost. /// @author Solady (https://github.com/vectorized/solmady/blob/main/src/utils/SSTORE2.sol) /// @author Saw-mon-and-Natalie (https://github.com/Saw-mon-and-Natalie) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/SSTORE2.sol) /// @author Modified from 0xSequence (https://github.com/0xSequence/sstore2/blob/master/contracts/SSTORE2.sol) library SSTORE2 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to deploy the storage contract. error DeploymentFailed(); /// @dev The storage contract address is invalid. error InvalidPointer(); /// @dev Attempt to read outside of the storage contract's bytecode bounds. error ReadOutOfBounds(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WRITE LOGIC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Writes `data` into the bytecode of a storage contract and returns its address. function write(bytes memory data) internal returns (address pointer) { // Note: The assembly block below does not expand the memory. /// @solidity memory-safe-assembly assembly { let originalDataLength := mload(data) // Add 1 to data size since we are prefixing it with a STOP opcode. let dataSize := add(originalDataLength, 1) /** * ------------------------------------------------------------------------------+ * Opcode | Mnemonic | Stack | Memory | * ------------------------------------------------------------------------------| * 61 codeSize | PUSH2 codeSize | codeSize | | * 80 | DUP1 | codeSize codeSize | | * 60 0xa | PUSH1 0xa | 0xa codeSize codeSize | | * 3D | RETURNDATASIZE | 0 0xa codeSize codeSize | | * 39 | CODECOPY | codeSize | [0..codeSize): code | * 3D | RETURNDATASZIE | 0 codeSize | [0..codeSize): code | * F3 | RETURN | | [0..codeSize): code | * 00 | STOP | | | * ------------------------------------------------------------------------------+ * @dev Prefix the bytecode with a STOP opcode to ensure it cannot be called. * Also PUSH2 is used since max contract size cap is 24,576 bytes which is less than 2 ** 16. */ mstore( data, or( 0x61000080600a3d393df300, // Left shift `dataSize` by 64 so that it lines up with the 0000 after PUSH2. shl(0x40, dataSize) ) ) // Deploy a new contract with the generated creation code. pointer := create(0, add(data, 0x15), add(dataSize, 0xa)) // If `pointer` is zero, revert. if iszero(pointer) { // Store the function selector of `DeploymentFailed()`. mstore(0x00, 0x30116425) // Revert with (offset, size). revert(0x1c, 0x04) } // Restore original length of the variable size `data`. mstore(data, originalDataLength) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* READ LOGIC */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns all the `data` from the bytecode of the storage contract at `pointer`. function read(address pointer) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { let pointerCodesize := extcodesize(pointer) if iszero(pointerCodesize) { // Store the function selector of `InvalidPointer()`. mstore(0x00, 0x11052bb4) // Revert with (offset, size). revert(0x1c, 0x04) } // Offset all indices by 1 to skip the STOP opcode. let size := sub(pointerCodesize, 1) // Get the pointer to the free memory and allocate // enough 32-byte words for the data and the length of the data, // then copy the code to the allocated memory. // Masking with 0xffe0 will suffice, since contract size is less than 16 bits. data := mload(0x40) mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0))) mstore(data, size) mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot. extcodecopy(pointer, add(data, 0x20), 1, size) } } /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`, /// from the byte at `start`, to the end of the data stored. function read(address pointer, uint256 start) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { let pointerCodesize := extcodesize(pointer) if iszero(pointerCodesize) { // Store the function selector of `InvalidPointer()`. mstore(0x00, 0x11052bb4) // Revert with (offset, size). revert(0x1c, 0x04) } // If `!(pointer.code.size > start)`, reverts. // This also handles the case where `start + 1` overflows. if iszero(gt(pointerCodesize, start)) { // Store the function selector of `ReadOutOfBounds()`. mstore(0x00, 0x84eb0dd1) // Revert with (offset, size). revert(0x1c, 0x04) } let size := sub(pointerCodesize, add(start, 1)) // Get the pointer to the free memory and allocate // enough 32-byte words for the data and the length of the data, // then copy the code to the allocated memory. // Masking with 0xffe0 will suffice, since contract size is less than 16 bits. data := mload(0x40) mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0))) mstore(data, size) mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot. extcodecopy(pointer, add(data, 0x20), add(start, 1), size) } } /// @dev Returns the `data` from the bytecode of the storage contract at `pointer`, /// from the byte at `start`, to the byte at `end` (exclusive) of the data stored. function read( address pointer, uint256 start, uint256 end ) internal view returns (bytes memory data) { /// @solidity memory-safe-assembly assembly { let pointerCodesize := extcodesize(pointer) if iszero(pointerCodesize) { // Store the function selector of `InvalidPointer()`. mstore(0x00, 0x11052bb4) // Revert with (offset, size). revert(0x1c, 0x04) } // If `!(pointer.code.size > end) || (start > end)`, revert. // This also handles the cases where `end + 1` or `start + 1` overflow. if iszero( and( gt(pointerCodesize, end), // Within bounds. iszero(gt(start, end)) // Valid range. ) ) { // Store the function selector of `ReadOutOfBounds()`. mstore(0x00, 0x84eb0dd1) // Revert with (offset, size). revert(0x1c, 0x04) } let size := sub(end, start) // Get the pointer to the free memory and allocate // enough 32-byte words for the data and the length of the data, // then copy the code to the allocated memory. // Masking with 0xffe0 will suffice, since contract size is less than 16 bits. data := mload(0x40) mstore(0x40, add(data, and(add(size, 0x3f), 0xffe0))) mstore(data, size) mstore(add(add(data, 0x20), size), 0) // Zeroize the last slot. extcodecopy(pointer, add(data, 0x20), add(start, 1), size) } } }
{ "optimizer": { "enabled": true, "runs": 200 }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"tokenCollectionAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ApproveToCaller","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CollectionZeroAddress","type":"error"},{"inputs":[],"name":"InvalidParams","type":"error"},{"inputs":[],"name":"LevelMinimumLowerThanExisting","type":"error"},{"inputs":[],"name":"MessageTooLong","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"OnlyForYou","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"SvgAlreadySet","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":"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":"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":false,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Locked","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":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","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":[],"name":"DEFAULT_DESC","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"NONON_MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TOKEN_NAME","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burnToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"collectionAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hasReceivedToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"hasSentToken","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"}],"name":"hasToken","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"levels","outputs":[{"internalType":"uint256","name":"minimum","type":"uint256"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"colorGradient","type":"string"},{"internalType":"uint16","name":"spriteIndex","type":"uint16"},{"internalType":"uint16","name":"spriteLength","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"messages","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"}],"name":"mintTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"ordinalsFromRoles","outputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ownershipHandoverValidFor","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"points","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":"collectionTokenStartId","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"registerTokenMovement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint8[]","name":"ordinals","type":"uint8[]"}],"name":"rolesFromOrdinals","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","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":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"baseImage","type":"bytes"}],"name":"setBaseSvgPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"defs","type":"bytes"}],"name":"setDefsSvgPointer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_tokenId","type":"uint256"},{"internalType":"string","name":"_message","type":"string"}],"name":"setMessage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes","name":"spriteImages","type":"bytes"}],"name":"setSpritesSvgPointer","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":"tokenId","type":"uint256"}],"name":"tokenMessage","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"tokenOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"startId","type":"uint256"},{"internalType":"uint256","name":"endId","type":"uint256"}],"name":"tokenPointsInRange","outputs":[{"components":[{"internalType":"uint256","name":"id","type":"uint256"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"points","type":"uint256"}],"internalType":"struct NononFriendCard.TokenPoints[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"bool","name":"sent","type":"bool"}],"name":"tokenStatusMap","outputs":[{"internalType":"uint256[]","name":"received","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"payable","type":"function"}]
Contract Creation Code
60a06040523480156200001157600080fd5b506040516200448d3803806200448d833981016040819052620000349162000a30565b60408051808201825260118152701393d393d3881194925153910810d05491607a1b60208083019182528351808501909452600c84526b1393d393d397d1949251539160a21b90840152815191929162000091916002916200098a565b508051620000a79060039060208401906200098a565b5050600160005550620000ba336200094c565b606081811b6001600160601b03191660809081526040805160a081018252600080825282518084018452600680825265414e47454c5360d01b6020808401919091528085019283528551808701875291825265677261642d3160d01b828201529484015294820181905261012093820193909352600d8054600181018255935280516000805160206200444d83398151915260049094029384019081559351805191949362000180936000805160206200446d833981519152909101929101906200098a565b50604082015180516200019e9160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252600a808252825180840184529081526941524348414e47454c5360b01b60208281019190915280830191825283518085018552600681526533b930b2169960d11b81830152938301939093526101209382019390935261028c93810193909352600d8054600181018255600091909152835160049091026000805160206200444d833981519152810191825592518051919362000291936000805160206200446d833981519152909101929101906200098a565b5060408201518051620002af9160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526032815281518083018352600e81526d5052494e434950414c495449455360901b602082810191909152808301918252835180850185526006815265677261642d3360d01b81830152938301939093526103ac938201939093526102f693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620003a6936000805160206200446d833981519152909101929101906200098a565b5060408201518051620003c49160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252609681528151808301835260078152665649525455455360c81b60208281019190915280830191825283518085018552600681526519dc98590b4d60d21b81830152938301939093526106a29382019390935261028693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620004b4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620004d29160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526101f48152815180830183526009815268444f4d494e494f4e5360b81b602082810191909152808301918252835180850185526006815265677261642d3560d01b8183015293830193909352610928938201939093526103d893810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620005c5936000805160206200446d833981519152909101929101906200098a565b5060408201518051620005e39160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a0810182526105dc81528151808301835260078152665448524f4e455360c81b60208281019190915280830191825283518085018552600681526533b930b2169b60d11b8183015293830193909352610d009382019390935261033193810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620006d4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620006f29160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252610dac8152815180830183526008815267434845525542494d60c01b602082810191909152808301918252835180850185526006815265677261642d3760d01b8183015293830193909352611031938201939093526102f693810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620007e4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620008029160028401916020909101906200098a565b506060828101516003909201805460809485015161ffff908116620100000263ffffffff19909216941693909317929092179091556040805160a081018252611d4c8152815180830183526008815267534552415048494d60c01b6020828101919091528083019182528351808501855260068152650cee4c2c85a760d31b8183015293830193909352611327938201939093526102c593810193909352600d8054600181018255600091909152835160049091026000805160206200444d8339815191528101918255925180519193620008f4936000805160206200446d833981519152909101929101906200098a565b5060408201518051620009129160028401916020909101906200098a565b5060608201516003909101805460809093015161ffff908116620100000263ffffffff199094169216919091179190911790555062000a9d565b638b78c6d81980546001600160a01b039092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b828054620009989062000a60565b90600052602060002090601f016020900481019282620009bc576000855562000a07565b82601f10620009d757805160ff191683800117855562000a07565b8280016001018555821562000a07579182015b8281111562000a07578251825591602001919060010190620009ea565b5062000a1592915062000a19565b5090565b5b8082111562000a15576000815560010162000a1a565b60006020828403121562000a42578081fd5b81516001600160a01b038116811462000a59578182fd5b9392505050565b600181811c9082168062000a7557607f821691505b6020821081141562000a9757634e487b7160e01b600052602260045260246000fd5b50919050565b60805160601c61396e62000adf6000396000818161068e01528181610d1e0152818161141901528181611512015281816118170152612804015261396e6000f3fe6080604052600436106102e45760003560e01c8063648345c811610190578063b6ee607a116100dc578063e4b7baeb11610095578063eacd39221161006f578063eacd39221461094d578063f04e283e1461096d578063f2fde38b14610980578063fee81cf41461099357600080fd5b8063e4b7baeb146108b7578063e6771966146108d7578063e985e9c51461090457600080fd5b8063b6ee607a14610804578063b88d4fde14610824578063b8ea8c6f14610844578063c0a4b93914610859578063c87b56dd14610879578063d7533f021461089957600080fd5b80637b47ec1a116101495780639799b4e7116101235780639799b4e7146107735780639bb0f59914610793578063a22cb465146107b3578063b2596a67146107d357600080fd5b80637b47ec1a146107255780638da5cb5b1461074557806395d89b411461075e57600080fd5b8063648345c81461065c5780636aa003711461067c57806370a08231146106b0578063715018a6146106d05780637359e41f146106d8578063755edd171461070557600080fd5b806323b872dd1161024f57806342ec38e2116102085780634a4ee7b1116101e25780634a4ee7b1146105ea578063514e62fc146105fd57806354d1f13d146106345780636352211e1461063c57600080fd5b806342ec38e2146105875780634812e9a6146105b4578063498a3596146105d457600080fd5b806323b872dd146104ce57806325692962146104ee5780632de94807146104f6578063372b67de14610527578063417011dc1461054757806342842e0e1461056757600080fd5b806316ab3342116102a157806316ab3342146103e857806318160ddd14610415578063183a4f6e1461043257806318821400146104455780631c10893f146104845780631cd64df41461049757600080fd5b806301ffc9a7146102e957806306fdde031461031e578063081812fc14610340578063095ea7b3146103785780630d80fefd1461039a57806313a661ed146103ba575b600080fd5b3480156102f557600080fd5b50610309610304366004613076565b6109c4565b60405190151581526020015b60405180910390f35b34801561032a57600080fd5b50610333610a16565b604051610315919061375b565b34801561034c57600080fd5b5061036061035b3660046130e1565b610aa8565b6040516001600160a01b039091168152602001610315565b34801561038457600080fd5b50610398610393366004612f94565b610aec565b005b3480156103a657600080fd5b506103336103b53660046130e1565b610b8c565b3480156103c657600080fd5b506103da6103d5366004612fbd565b610c26565b604051908152602001610315565b3480156103f457600080fd5b50610408610403366004613188565b610c59565b604051610315919061367a565b34801561042157600080fd5b5060015460005403600019016103da565b6103986104403660046130e1565b610eaf565b34801561045157600080fd5b506103336040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b81525081565b610398610492366004612f94565b610ebc565b3480156104a357600080fd5b506103096104b2366004612f94565b60609190911b638b78c6d8176000908152602090205481161490565b3480156104da57600080fd5b506103986104e9366004612e78565b610ee5565b61039861107b565b34801561050257600080fd5b506103da610511366004612e2c565b60601b638b78c6d8176000908152602090205490565b34801561053357600080fd5b506103986105423660046130ae565b6110cc565b34801561055357600080fd5b506103986105623660046130ae565b611144565b34801561057357600080fd5b50610398610582366004612e78565b6111bc565b34801561059357600080fd5b506103da6105a2366004612e2c565b600e6020526000908152604090205481565b3480156105c057600080fd5b506103096105cf366004612f94565b6111dc565b3480156105e057600080fd5b506103da61138881565b6103986105f8366004612f94565b611213565b34801561060957600080fd5b50610309610618366004612f94565b60609190911b638b78c6d8176000908152602090205416151590565b610398611238565b34801561064857600080fd5b506103606106573660046130e1565b611275565b34801561066857600080fd5b50610398610677366004613111565b611280565b34801561068857600080fd5b506103607f000000000000000000000000000000000000000000000000000000000000000081565b3480156106bc57600080fd5b506103da6106cb366004612e2c565b611325565b610398611374565b3480156106e457600080fd5b506106f86106f33660046130e1565b6113c2565b6040516103159190613720565b34801561071157600080fd5b50610398610720366004612e2c565b61140e565b34801561073157600080fd5b506103986107403660046130e1565b6114b5565b34801561075157600080fd5b50638b78c6d81954610360565b34801561076a57600080fd5b506103336114f1565b34801561077f57600080fd5b506103da61078e3660046130e1565b611500565b34801561079f57600080fd5b506103096107ae366004612e2c565b611609565b3480156107bf57600080fd5b506103986107ce366004612f5a565b61161c565b3480156107df57600080fd5b506107f36107ee3660046130e1565b6116b2565b60405161031595949392919061376e565b34801561081057600080fd5b5061039861081f366004612f19565b61180c565b34801561083057600080fd5b5061039861083f366004612eb3565b611912565b34801561085057600080fd5b5061033361195c565b34801561086557600080fd5b506103986108743660046130ae565b611978565b34801561088557600080fd5b506103336108943660046130e1565b6119f0565b3480156108a557600080fd5b506040516202a3008152602001610315565b3480156108c357600080fd5b506103336108d23660046130e1565b611b56565b3480156108e357600080fd5b506108f76108f2366004612f5a565b611c2a565b60405161031591906136dc565b34801561091057600080fd5b5061030961091f366004612e46565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b34801561095957600080fd5b50610309610968366004612f94565b611d30565b61039861097b366004612e2c565b611d65565b61039861098e366004612e2c565b611de7565b34801561099f57600080fd5b506103da6109ae366004612e2c565b60601b63389a75e1176000908152602090205490565b60006301ffc9a760e01b6001600160e01b0319831614806109f557506380ac58cd60e01b6001600160e01b03198316145b80610a105750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060028054610a2590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5190613865565b8015610a9e5780601f10610a7357610100808354040283529160200191610a9e565b820191906000526020600020905b815481529060010190602001808311610a8157829003601f168201915b5050505050905090565b6000610ab382611e4e565b610ad0576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610af782611275565b9050336001600160a01b03821614610b3057610b13813361091f565b610b30576040516367d9dca160e11b815260040160405180910390fd5b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600f6020526000908152604090208054610ba590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd190613865565b8015610c1e5780601f10610bf357610100808354040283529160200191610c1e565b820191906000526020600020905b815481529060010190602001808311610c0157829003601f168201915b505050505081565b600060208201825160051b81015b808214610c5257600160ff8351161b83179250602082019150610c34565b5050919050565b606082821015610c7c57604051635435b28960e11b815260040160405180910390fd5b6000610c888484613822565b610c939060016137eb565b67ffffffffffffffff811115610cb957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610d1757816020015b610d0460405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b815260200190600190039081610cd75790505b50905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7557600080fd5b505afa158015610d89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dad91906130f9565b610db89060016137eb565b90506000855b858111610ea457610dce81611e4e565b15610e94576000610dde82611275565b6001600160a01b038116600090815260096020526040812091925090610e0690600187611e83565b6001600160a01b0383166000908152600860205260409020610e2a90600188611e83565b610e3491906137eb565b90506040518060600160405280848152602001836001600160a01b0316815260200182815250868581518110610e7a57634e487b7160e01b600052603260045260246000fd5b602002602001018190525083610e8f9061389a565b935050505b610e9d8161389a565b9050610dbe565b509195945050505050565b610eb93382611f26565b50565b638b78c6d819543314610ed7576382b429006000526004601cfd5b610ee18282611f77565b5050565b6000610ef082611fc3565b9050836001600160a01b0316816001600160a01b031614610f235760405162a1148160e81b815260040160405180910390fd5b60008281526006602052604090208054610f4f8187335b6001600160a01b039081169116811491141790565b610f7a57610f5d863361091f565b610f7a57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610fa157604051633a954ecd60e21b815260040160405180910390fd5b610fae868686600161202c565b8015610fb957600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040902055600160e11b831661104457600184016000818152600460205260409020546110425760005481146110425760008181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03166000805160206138f883398151915260405160405180910390a4505050505050565b60006202a30067ffffffffffffffff164201905063389a75e13360601b1760005280602060002055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b638b78c6d8195433146110e7576382b429006000526004601cfd5b600c54600160a01b900460ff1615611112576040516327ec863960e01b815260040160405180910390fd5b61111b8161206a565b600c80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b638b78c6d81954331461115f576382b429006000526004601cfd5b600a54600160a01b900460ff161561118a576040516327ec863960e01b815260040160405180910390fd5b6111938161206a565b600a80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b6111d783838360405180602001604052806000815250611912565b505050565b6001600160a01b03821660009081526008602081815260408084209285901c845291905281205460ff83161c6001165b9392505050565b638b78c6d81954331461122e576382b429006000526004601cfd5b610ee18282611f26565b63389a75e13360601b176000526000602060002055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610a1082611fc3565b3361128a84611275565b6001600160a01b0316146112b0576040516282b42960e81b815260040160405180910390fd5b6101008111156112d3576040516347e8b47560e11b815260040160405180910390fd5b6000838152600f602052604090206112ec908383612d0c565b506040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b60006001600160a01b03821661134e576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b638b78c6d81954331461138f576382b429006000526004601cfd5b6000337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36000638b78c6d81955565b606060206040510160005b8082526001841660051b820191508360011c9350836113eb576113f3565b6001016113cd565b5060405191508060405260208201810360051c825250919050565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611456576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b0383168252600e602052604090912081905561147e8260016120ac565b6040518181527f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a16119060200160405180910390a15050565b600e60006114c283611275565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009055610eb981600161218c565b606060038054610a2590613865565b60008061150c83611275565b905060007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156957600080fd5b505afa15801561157d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a191906130f9565b6115ac9060016137eb565b6001600160a01b03831660009081526009602052604090209091506115d390600183611e83565b6001600160a01b03831660009081526008602052604090206115f790600184611e83565b61160191906137eb565b949350505050565b60008061161583611325565b1192915050565b6001600160a01b0382163314156116465760405163b06307db60e01b815260040160405180910390fd5b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600d81815481106116c257600080fd5b600091825260209091206004909102018054600182018054919350906116e790613865565b80601f016020809104026020016040519081016040528092919081815260200182805461171390613865565b80156117605780601f1061173557610100808354040283529160200191611760565b820191906000526020600020905b81548152906001019060200180831161174357829003601f168201915b50505050509080600201805461177590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546117a190613865565b80156117ee5780601f106117c3576101008083540402835291602001916117ee565b820191906000526020600020905b8154815290600101906020018083116117d157829003601f168201915b5050506003909301549192505061ffff808216916201000090041685565b336001600160a01b037f00000000000000000000000000000000000000000000000000000000000000001614611854576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0384161561189f57836001600160a01b0316836001600160a01b03161461189f576001600160a01b038416600090815260096020526040902061189f9083836122cb565b6001600160a01b038316156118d1576001600160a01b03831660009081526008602052604090206118d19083836122cb565b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a150505050565b61191d848484610ee5565b6001600160a01b0383163b156119565761193984848484612348565b611956576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6040518060600160405280602181526020016139186021913981565b638b78c6d819543314611993576382b429006000526004601cfd5b600b54600160a01b900460ff16156119be576040516327ec863960e01b815260040160405180910390fd5b6119c78161206a565b600b80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b60606119fb82611e4e565b611a1857604051630a14c4b560e41b815260040160405180910390fd5b6000611a2383611500565b90506000611a308261243f565b90506000611a3d85611b56565b905060006040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815250905080611b2b6040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b8152508560000151604051602001611abf9291906131f1565b60405160208183030381529060405284611adc87608001516128f3565b611ae5896128f3565b8860000151611b028a602001518b604001518c606001518c612935565b604051602001611b1796959493929190613220565b604051602081830303815290604052612a12565b604051602001611b3c9291906131f1565b604051602081830303815290604052945050505050919050565b6000818152600f6020526040812080546060929190611b7490613865565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba090613865565b8015611bed5780601f10611bc257610100808354040283529160200191611bed565b820191906000526020600020905b815481529060010190602001808311611bd057829003601f168201915b50505050509050600081511115611c045792915050565b604051806060016040528060218152602001613918602191399392505050565b50919050565b606060136000611c3b8260016137eb565b67ffffffffffffffff811115611c6157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c8a578160200160208202803683370190505b50905060005b828111611d275784611cc5576001600160a01b0386166000908152600860209081526040808320848452909152902054611cea565b6001600160a01b03861660009081526009602090815260408083208484529091529020545b828281518110611d0a57634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611d1f8161389a565b915050611c90565b50949350505050565b6001600160a01b0382166000908152600960209081526040808320600885901c845290915281205460ff83161c60011661120c565b638b78c6d819543314611d80576382b429006000526004601cfd5b8060601b60601c905063389a75e18160601b1760005260206000208054421115611db257636f5e88186000526004601cfd5b600081555080337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d819543314611e02576382b429006000526004601cfd5b6001600160a01b031680611e1e57637448fbae6000526004601cfd5b80337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b600081600111158015611e62575060005482105b8015610a10575050600090815260046020526040902054600160e01b161590565b6000600883901c60ff841661010184820110611ef957600082815260208790526040902054611eb390821c612a20565b930160ff8116939250600182019160009160081c015b808314611ef757600083815260208890526040902054611ee890612a20565b84019350826001019250611ec9565b505b600082815260208790526040902054611f1a90821c6101008690031b612a20565b90920195945050505050565b638b78c6d88260601b176000526020600020805482811681189050808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b638b78c6d88260601b17600052602060002081815417808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b600081806001116120135760005481101561201357600081815260046020526040902054600160e01b8116612011575b8061120c575060001901600081815260046020526040902054611ff3565b505b604051636f96cda160e11b815260040160405180910390fd5b6001600160a01b0384161580159061204c57506001600160a01b03831615155b1561195657604051632f65177960e21b815260040160405180910390fd5b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925050816120a65763301164256000526004601cfd5b90915290565b600054816120cd5760405163b562e8dd60e01b815260040160405180910390fd5b6120da600084838561202c565b6001600160a01b03831660008181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083906000805160206138f88339815191528180a4600183015b81811461216557808360006000805160206138f8833981519152600080a460010161213f565b508161218357604051622e076360e81b815260040160405180910390fd5b60005550505050565b600061219783611fc3565b9050806000806121b586600090815260066020526040902080549091565b9150915084156121f5576121ca818433610f3a565b6121f5576121d8833361091f565b6121f557604051632ce44b5f60e11b815260040160405180910390fd5b61220383600088600161202c565b801561220e57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040902055600160e11b841661229557600186016000818152600460205260409020546122935760005481146122935760008181526004602052604090208590555b505b60405186906000906001600160a01b038616906000805160206138f8833981519152908390a45050600180548101905550505050565b60001960ff8316846020528360081c6000526101018382011061232d576000805160408220805485851b1790559390910160ff811693600181019160081c015b80821461232857816000528360406000205560018201915061230b565b506000525b60406000208284610100031c821b8154178155505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061237d90339089908890889060040161363d565b602060405180830381600087803b15801561239757600080fd5b505af19250505080156123c7575060408051601f3d908101601f191682019092526123c491810190613092565b60015b612422573d8080156123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50805161241a576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6124796040518060a001604052806060815260200160608152602001600061ffff168152602001600061ffff168152602001600081525090565b600d545b8015611c24576000600d612492600184613822565b815481106124b057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a0016040529081600082015481526020016001820180546124e390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461250f90613865565b801561255c5780601f106125315761010080835404028352916020019161255c565b820191906000526020600020905b81548152906001019060200180831161253f57829003601f168201915b5050505050815260200160028201805461257590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546125a190613865565b80156125ee5780601f106125c3576101008083540402835291602001916125ee565b820191906000526020600020905b8154815290600101906020018083116125d157829003601f168201915b50505091835250506003919091015461ffff80821660208401526201000090910416604090910152805190915084106128e957600d54821015612800576000600d838154811061264e57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a00160405290816000820154815260200160018201805461268190613865565b80601f01602080910402602001604051908101604052809291908181526020018280546126ad90613865565b80156126fa5780601f106126cf576101008083540402835291602001916126fa565b820191906000526020600020905b8154815290600101906020018083116126dd57829003601f168201915b5050505050815260200160028201805461271390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461273f90613865565b801561278c5780601f106127615761010080835404028352916020019161278c565b820191906000526020600020905b81548152906001019060200180831161276f57829003601f168201915b50505091835250506003919091015461ffff808216602080850191909152620100009092048116604093840152825160a08101845286830151815286840151928101929092526060808701518216938301939093526080958601511691810191909152905192810192909252509392505050565b60007f00000000000000000000000000000000000000000000000000000000000000006001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561285b57600080fd5b505afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289391906130f9565b61289e906002613803565b90506040518060a001604052808360200151815260200183604001518152602001836060015161ffff168152602001836080015161ffff168152602001828152509350505050919050565b506000190161247d565b604080516080019081905280825b600183039250600a81066030018353600a90048061291e57612923565b612901565b50819003601f19909101908152919050565b60408051808201909152601a81527f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000006020820152600a5460609190600090612985906001600160a01b0316612ad0565b600c549091506000906129a0906001600160a01b0316612ad0565b600b549091506000906129bb906001600160a01b0316612ad0565b9050836129e48a856129ce868d8d612b1a565b8a86604051602001611b17959493929190613396565b6040516020016129f59291906131f1565b604051602081830303815290604052945050505050949350505050565b6060610a1082600080612c03565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c6000199190911460081b1790565b6060813b80612ae7576311052bb46000526004601cfd5b600181039050604051915061ffe0603f820116820160405280825260008160208401015280600160208401853c50919050565b606060008261ffff1667ffffffffffffffff811115612b4957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015612b73576020820181803683370190505b50905060005b8151811015611d275785612b9161ffff8716836137eb565b81518110612baf57634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b828281518110612bda57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535080612bfb8161389a565b915050612b79565b606083518015612d04576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015350600482019150808210612cbc57612cc1565b612c73565b60038406868015612cdd57600182148215150185038752612cf5565b603d821515850353603d6001831460011b8503538487525b5050601f01601f191660405250505b509392505050565b828054612d1890613865565b90600052602060002090601f016020900481019282612d3a5760008555612d80565b82601f10612d535782800160ff19823516178555612d80565b82800160010185558215612d80579182015b82811115612d80578235825591602001919060010190612d65565b50612d8c929150612d90565b5090565b5b80821115612d8c5760008155600101612d91565b80356001600160a01b0381168114612dbc57600080fd5b919050565b600082601f830112612dd1578081fd5b813567ffffffffffffffff811115612deb57612deb6138cb565b612dfe601f8201601f19166020016137ba565b818152846020838601011115612e12578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612e3d578081fd5b61120c82612da5565b60008060408385031215612e58578081fd5b612e6183612da5565b9150612e6f60208401612da5565b90509250929050565b600080600060608486031215612e8c578081fd5b612e9584612da5565b9250612ea360208501612da5565b9150604084013590509250925092565b60008060008060808587031215612ec8578081fd5b612ed185612da5565b9350612edf60208601612da5565b925060408501359150606085013567ffffffffffffffff811115612f01578182fd5b612f0d87828801612dc1565b91505092959194509250565b60008060008060808587031215612f2e578384fd5b612f3785612da5565b9350612f4560208601612da5565b93969395505050506040820135916060013590565b60008060408385031215612f6c578182fd5b612f7583612da5565b915060208301358015158114612f89578182fd5b809150509250929050565b60008060408385031215612fa6578182fd5b612faf83612da5565b946020939093013593505050565b60006020808385031215612fcf578182fd5b823567ffffffffffffffff80821115612fe6578384fd5b818501915085601f830112612ff9578384fd5b81358181111561300b5761300b6138cb565b8060051b915061301c8483016137ba565b8181528481019084860184860187018a1015613036578788fd5b8795505b83861015613069578035945060ff85168514613054578788fd5b8483526001959095019491860191860161303a565b5098975050505050505050565b600060208284031215613087578081fd5b813561120c816138e1565b6000602082840312156130a3578081fd5b815161120c816138e1565b6000602082840312156130bf578081fd5b813567ffffffffffffffff8111156130d5578182fd5b61160184828501612dc1565b6000602082840312156130f2578081fd5b5035919050565b60006020828403121561310a578081fd5b5051919050565b600080600060408486031215613125578081fd5b83359250602084013567ffffffffffffffff80821115613143578283fd5b818601915086601f830112613156578283fd5b813581811115613164578384fd5b876020828501011115613175578384fd5b6020830194508093505050509250925092565b6000806040838503121561319a578182fd5b50508035926020909101359150565b600081518084526131c1816020860160208601613839565b601f01601f19169290920160200192915050565b600081516131e7818560208601613839565b9290920192915050565b60008351613203818460208801613839565b835190830190613217818360208801613839565b01949350505050565b683d913730b6b2911d1160b91b81528651600090613245816009850160208c01613839565b61088b60f21b60099184019182018190526e113232b9b1b934b83a34b7b7111d1160891b600b830152885161328181601a850160208d01613839565b601a9201918201527f2261747472696275746573223a5b7b2274726169745f74797065223a22506f69601c82015270373a3991161136b0bc2fbb30b63ab2911d60791b603c82015286516132dc81604d840160208b01613839565b61338861337a61337461335f61334f61334961331561330f604d898b01016816113b30b63ab2911d60b91b815260090190565b8e6131d5565b7f7d2c207b2274726169745f74797065223a224c6576656c222c2276616c7565228152611d1160f11b602082015260220190565b8b6131d5565b63089f574b60e21b815260040190565b681134b6b0b3b2911d1160b91b815260090190565b876131d5565b61227d60f01b815260020190565b9a9950505050505050505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222066696c6c3d226e6f6e65222076696577426f783d2230203060208201527f20313038302031303830223e3c706174682066696c6c3d22726762612832353560408201527f2c3235352c3235352c30292220643d224d3020306831303830763130383048306060820152643d1110179f60d91b6080820152703c706174682066696c6c3d2275726c282360781b608582015260008651613468816096850160208b01613839565b7f292220643d224d32342034306131362031362030203020312031362d313668316096918401918201527f303030613136203136203020302031203136203136763931346131362031362060b68201527f30203020312d3136203136483131342e356132342032342030203020302d313760d68201527f2e3620372e376c2d35392036332e34613820382030203020312d31332e392d3560f682015269171a2b1a182d1110179f60b11b61011682015261363161361f6136196135fe6135f861353e61353861012088018e6131d5565b8c6131d5565b7f3c7465787420786d6c3a73706163653d227072657365727665222066696c6c3d81527f22233030394446352220666f6e742d66616d696c793d22436f7572696572222060208201527f666f6e742d73697a653d22323422206c65747465722d73706163696e673d223060408201527f656d22207374796c653d2277686974652d73706163653a707265223e3c74737060608201527530b7103c1e91189a1a11103c9e9118981a1a171c911f60511b608082015260960190565b896131d5565b6e1e17ba39b830b71f1e17ba32bc3a1f60891b8152600f0190565b866131d5565b651e17b9bb339f60d11b815260060190565b98975050505050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613670908301846131a9565b9695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156136cf57815180518552868101516001600160a01b0316878601528501518585015260609093019290850190600101613697565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015613714578351835292840192918401916001016136f8565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561371457835160ff168352928401929184019160010161373c565b60208152600061120c60208301846131a9565b85815260a06020820152600061378760a08301876131a9565b828103604084015261379981876131a9565b91505061ffff80851660608401528084166080840152509695505050505050565b604051601f8201601f1916810167ffffffffffffffff811182821017156137e3576137e36138cb565b604052919050565b600082198211156137fe576137fe6138b5565b500190565b600081600019048311821515161561381d5761381d6138b5565b500290565b600082821015613834576138346138b5565b500390565b60005b8381101561385457818101518382015260200161383c565b838111156119565750506000910152565b600181811c9082168061387957607f821691505b60208210811415611c2457634e487b7160e01b600052602260045260246000fd5b60006000198214156138ae576138ae6138b5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610eb957600080fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef736861726520796f7572206d657373616765206174206e6f6e6f6e2e686f757365a26469706673582212206d095de219df15e46294140727498581aae7d369cc3a076e0839aca95b3c4fca64736f6c63430008040033d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb5d7b6990105719101dabeb77144f2a3385c8033acd3af97e9423a695e81ad1eb6000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6
Deployed Bytecode
0x6080604052600436106102e45760003560e01c8063648345c811610190578063b6ee607a116100dc578063e4b7baeb11610095578063eacd39221161006f578063eacd39221461094d578063f04e283e1461096d578063f2fde38b14610980578063fee81cf41461099357600080fd5b8063e4b7baeb146108b7578063e6771966146108d7578063e985e9c51461090457600080fd5b8063b6ee607a14610804578063b88d4fde14610824578063b8ea8c6f14610844578063c0a4b93914610859578063c87b56dd14610879578063d7533f021461089957600080fd5b80637b47ec1a116101495780639799b4e7116101235780639799b4e7146107735780639bb0f59914610793578063a22cb465146107b3578063b2596a67146107d357600080fd5b80637b47ec1a146107255780638da5cb5b1461074557806395d89b411461075e57600080fd5b8063648345c81461065c5780636aa003711461067c57806370a08231146106b0578063715018a6146106d05780637359e41f146106d8578063755edd171461070557600080fd5b806323b872dd1161024f57806342ec38e2116102085780634a4ee7b1116101e25780634a4ee7b1146105ea578063514e62fc146105fd57806354d1f13d146106345780636352211e1461063c57600080fd5b806342ec38e2146105875780634812e9a6146105b4578063498a3596146105d457600080fd5b806323b872dd146104ce57806325692962146104ee5780632de94807146104f6578063372b67de14610527578063417011dc1461054757806342842e0e1461056757600080fd5b806316ab3342116102a157806316ab3342146103e857806318160ddd14610415578063183a4f6e1461043257806318821400146104455780631c10893f146104845780631cd64df41461049757600080fd5b806301ffc9a7146102e957806306fdde031461031e578063081812fc14610340578063095ea7b3146103785780630d80fefd1461039a57806313a661ed146103ba575b600080fd5b3480156102f557600080fd5b50610309610304366004613076565b6109c4565b60405190151581526020015b60405180910390f35b34801561032a57600080fd5b50610333610a16565b604051610315919061375b565b34801561034c57600080fd5b5061036061035b3660046130e1565b610aa8565b6040516001600160a01b039091168152602001610315565b34801561038457600080fd5b50610398610393366004612f94565b610aec565b005b3480156103a657600080fd5b506103336103b53660046130e1565b610b8c565b3480156103c657600080fd5b506103da6103d5366004612fbd565b610c26565b604051908152602001610315565b3480156103f457600080fd5b50610408610403366004613188565b610c59565b604051610315919061367a565b34801561042157600080fd5b5060015460005403600019016103da565b6103986104403660046130e1565b610eaf565b34801561045157600080fd5b506103336040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b81525081565b610398610492366004612f94565b610ebc565b3480156104a357600080fd5b506103096104b2366004612f94565b60609190911b638b78c6d8176000908152602090205481161490565b3480156104da57600080fd5b506103986104e9366004612e78565b610ee5565b61039861107b565b34801561050257600080fd5b506103da610511366004612e2c565b60601b638b78c6d8176000908152602090205490565b34801561053357600080fd5b506103986105423660046130ae565b6110cc565b34801561055357600080fd5b506103986105623660046130ae565b611144565b34801561057357600080fd5b50610398610582366004612e78565b6111bc565b34801561059357600080fd5b506103da6105a2366004612e2c565b600e6020526000908152604090205481565b3480156105c057600080fd5b506103096105cf366004612f94565b6111dc565b3480156105e057600080fd5b506103da61138881565b6103986105f8366004612f94565b611213565b34801561060957600080fd5b50610309610618366004612f94565b60609190911b638b78c6d8176000908152602090205416151590565b610398611238565b34801561064857600080fd5b506103606106573660046130e1565b611275565b34801561066857600080fd5b50610398610677366004613111565b611280565b34801561068857600080fd5b506103607f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca681565b3480156106bc57600080fd5b506103da6106cb366004612e2c565b611325565b610398611374565b3480156106e457600080fd5b506106f86106f33660046130e1565b6113c2565b6040516103159190613720565b34801561071157600080fd5b50610398610720366004612e2c565b61140e565b34801561073157600080fd5b506103986107403660046130e1565b6114b5565b34801561075157600080fd5b50638b78c6d81954610360565b34801561076a57600080fd5b506103336114f1565b34801561077f57600080fd5b506103da61078e3660046130e1565b611500565b34801561079f57600080fd5b506103096107ae366004612e2c565b611609565b3480156107bf57600080fd5b506103986107ce366004612f5a565b61161c565b3480156107df57600080fd5b506107f36107ee3660046130e1565b6116b2565b60405161031595949392919061376e565b34801561081057600080fd5b5061039861081f366004612f19565b61180c565b34801561083057600080fd5b5061039861083f366004612eb3565b611912565b34801561085057600080fd5b5061033361195c565b34801561086557600080fd5b506103986108743660046130ae565b611978565b34801561088557600080fd5b506103336108943660046130e1565b6119f0565b3480156108a557600080fd5b506040516202a3008152602001610315565b3480156108c357600080fd5b506103336108d23660046130e1565b611b56565b3480156108e357600080fd5b506108f76108f2366004612f5a565b611c2a565b60405161031591906136dc565b34801561091057600080fd5b5061030961091f366004612e46565b6001600160a01b03918216600090815260076020908152604080832093909416825291909152205460ff1690565b34801561095957600080fd5b50610309610968366004612f94565b611d30565b61039861097b366004612e2c565b611d65565b61039861098e366004612e2c565b611de7565b34801561099f57600080fd5b506103da6109ae366004612e2c565b60601b63389a75e1176000908152602090205490565b60006301ffc9a760e01b6001600160e01b0319831614806109f557506380ac58cd60e01b6001600160e01b03198316145b80610a105750635b5e139f60e01b6001600160e01b03198316145b92915050565b606060028054610a2590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610a5190613865565b8015610a9e5780601f10610a7357610100808354040283529160200191610a9e565b820191906000526020600020905b815481529060010190602001808311610a8157829003601f168201915b5050505050905090565b6000610ab382611e4e565b610ad0576040516333d1c03960e21b815260040160405180910390fd5b506000908152600660205260409020546001600160a01b031690565b6000610af782611275565b9050336001600160a01b03821614610b3057610b13813361091f565b610b30576040516367d9dca160e11b815260040160405180910390fd5b60008281526006602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b600f6020526000908152604090208054610ba590613865565b80601f0160208091040260200160405190810160405280929190818152602001828054610bd190613865565b8015610c1e5780601f10610bf357610100808354040283529160200191610c1e565b820191906000526020600020905b815481529060010190602001808311610c0157829003601f168201915b505050505081565b600060208201825160051b81015b808214610c5257600160ff8351161b83179250602082019150610c34565b5050919050565b606082821015610c7c57604051635435b28960e11b815260040160405180910390fd5b6000610c888484613822565b610c939060016137eb565b67ffffffffffffffff811115610cb957634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015610d1757816020015b610d0460405180606001604052806000815260200160006001600160a01b03168152602001600081525090565b815260200190600190039081610cd75790505b50905060007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b158015610d7557600080fd5b505afa158015610d89573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610dad91906130f9565b610db89060016137eb565b90506000855b858111610ea457610dce81611e4e565b15610e94576000610dde82611275565b6001600160a01b038116600090815260096020526040812091925090610e0690600187611e83565b6001600160a01b0383166000908152600860205260409020610e2a90600188611e83565b610e3491906137eb565b90506040518060600160405280848152602001836001600160a01b0316815260200182815250868581518110610e7a57634e487b7160e01b600052603260045260246000fd5b602002602001018190525083610e8f9061389a565b935050505b610e9d8161389a565b9050610dbe565b509195945050505050565b610eb93382611f26565b50565b638b78c6d819543314610ed7576382b429006000526004601cfd5b610ee18282611f77565b5050565b6000610ef082611fc3565b9050836001600160a01b0316816001600160a01b031614610f235760405162a1148160e81b815260040160405180910390fd5b60008281526006602052604090208054610f4f8187335b6001600160a01b039081169116811491141790565b610f7a57610f5d863361091f565b610f7a57604051632ce44b5f60e11b815260040160405180910390fd5b6001600160a01b038516610fa157604051633a954ecd60e21b815260040160405180910390fd5b610fae868686600161202c565b8015610fb957600082555b6001600160a01b038681166000908152600560205260408082208054600019019055918716808252919020805460010190554260a01b17600160e11b17600085815260046020526040902055600160e11b831661104457600184016000818152600460205260409020546110425760005481146110425760008181526004602052604090208490555b505b83856001600160a01b0316876001600160a01b03166000805160206138f883398151915260405160405180910390a4505050505050565b60006202a30067ffffffffffffffff164201905063389a75e13360601b1760005280602060002055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b638b78c6d8195433146110e7576382b429006000526004601cfd5b600c54600160a01b900460ff1615611112576040516327ec863960e01b815260040160405180910390fd5b61111b8161206a565b600c80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b638b78c6d81954331461115f576382b429006000526004601cfd5b600a54600160a01b900460ff161561118a576040516327ec863960e01b815260040160405180910390fd5b6111938161206a565b600a80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b6111d783838360405180602001604052806000815250611912565b505050565b6001600160a01b03821660009081526008602081815260408084209285901c845291905281205460ff83161c6001165b9392505050565b638b78c6d81954331461122e576382b429006000526004601cfd5b610ee18282611f26565b63389a75e13360601b176000526000602060002055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b6000610a1082611fc3565b3361128a84611275565b6001600160a01b0316146112b0576040516282b42960e81b815260040160405180910390fd5b6101008111156112d3576040516347e8b47560e11b815260040160405180910390fd5b6000838152600f602052604090206112ec908383612d0c565b506040518381527ff8e1a15aba9398e019f0b49df1a4fde98ee17ae345cb5f6b5e2c27f5033e8ce79060200160405180910390a1505050565b60006001600160a01b03821661134e576040516323d3ad8160e21b815260040160405180910390fd5b506001600160a01b031660009081526005602052604090205467ffffffffffffffff1690565b638b78c6d81954331461138f576382b429006000526004601cfd5b6000337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a36000638b78c6d81955565b606060206040510160005b8082526001841660051b820191508360011c9350836113eb576113f3565b6001016113cd565b5060405191508060405260208201810360051c825250919050565b336001600160a01b037f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca61614611456576040516282b42960e81b815260040160405180910390fd5b600080546001600160a01b0383168252600e602052604090912081905561147e8260016120ac565b6040518181527f032bc66be43dbccb7487781d168eb7bda224628a3b2c3388bdf69b532a3a16119060200160405180910390a15050565b600e60006114c283611275565b6001600160a01b03166001600160a01b0316815260200190815260200160002060009055610eb981600161218c565b606060038054610a2590613865565b60008061150c83611275565b905060007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561156957600080fd5b505afa15801561157d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115a191906130f9565b6115ac9060016137eb565b6001600160a01b03831660009081526009602052604090209091506115d390600183611e83565b6001600160a01b03831660009081526008602052604090206115f790600184611e83565b61160191906137eb565b949350505050565b60008061161583611325565b1192915050565b6001600160a01b0382163314156116465760405163b06307db60e01b815260040160405180910390fd5b3360008181526007602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b600d81815481106116c257600080fd5b600091825260209091206004909102018054600182018054919350906116e790613865565b80601f016020809104026020016040519081016040528092919081815260200182805461171390613865565b80156117605780601f1061173557610100808354040283529160200191611760565b820191906000526020600020905b81548152906001019060200180831161174357829003601f168201915b50505050509080600201805461177590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546117a190613865565b80156117ee5780601f106117c3576101008083540402835291602001916117ee565b820191906000526020600020905b8154815290600101906020018083116117d157829003601f168201915b5050506003909301549192505061ffff808216916201000090041685565b336001600160a01b037f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca61614611854576040516282b42960e81b815260040160405180910390fd5b6001600160a01b0384161561189f57836001600160a01b0316836001600160a01b03161461189f576001600160a01b038416600090815260096020526040902061189f9083836122cb565b6001600160a01b038316156118d1576001600160a01b03831660009081526008602052604090206118d19083836122cb565b604080516001815260001960208201527f6bd5c950a8d8df17f772f5af37cb3655737899cbf903264b9795592da439661c910160405180910390a150505050565b61191d848484610ee5565b6001600160a01b0383163b156119565761193984848484612348565b611956576040516368d2bf6b60e11b815260040160405180910390fd5b50505050565b6040518060600160405280602181526020016139186021913981565b638b78c6d819543314611993576382b429006000526004601cfd5b600b54600160a01b900460ff16156119be576040516327ec863960e01b815260040160405180910390fd5b6119c78161206a565b600b80546001600160a81b0319166001600160a01b039290921691909117600160a01b17905550565b60606119fb82611e4e565b611a1857604051630a14c4b560e41b815260040160405180910390fd5b6000611a2383611500565b90506000611a308261243f565b90506000611a3d85611b56565b905060006040518060400160405280601d81526020017f646174613a6170706c69636174696f6e2f6a736f6e3b6261736536342c000000815250905080611b2b6040518060400160405280601381526020017202727a727a710232924a2a7221021a0a9221d1606d1b8152508560000151604051602001611abf9291906131f1565b60405160208183030381529060405284611adc87608001516128f3565b611ae5896128f3565b8860000151611b028a602001518b604001518c606001518c612935565b604051602001611b1796959493929190613220565b604051602081830303815290604052612a12565b604051602001611b3c9291906131f1565b604051602081830303815290604052945050505050919050565b6000818152600f6020526040812080546060929190611b7490613865565b80601f0160208091040260200160405190810160405280929190818152602001828054611ba090613865565b8015611bed5780601f10611bc257610100808354040283529160200191611bed565b820191906000526020600020905b815481529060010190602001808311611bd057829003601f168201915b50505050509050600081511115611c045792915050565b604051806060016040528060218152602001613918602191399392505050565b50919050565b606060136000611c3b8260016137eb565b67ffffffffffffffff811115611c6157634e487b7160e01b600052604160045260246000fd5b604051908082528060200260200182016040528015611c8a578160200160208202803683370190505b50905060005b828111611d275784611cc5576001600160a01b0386166000908152600860209081526040808320848452909152902054611cea565b6001600160a01b03861660009081526009602090815260408083208484529091529020545b828281518110611d0a57634e487b7160e01b600052603260045260246000fd5b602090810291909101015280611d1f8161389a565b915050611c90565b50949350505050565b6001600160a01b0382166000908152600960209081526040808320600885901c845290915281205460ff83161c60011661120c565b638b78c6d819543314611d80576382b429006000526004601cfd5b8060601b60601c905063389a75e18160601b1760005260206000208054421115611db257636f5e88186000526004601cfd5b600081555080337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b638b78c6d819543314611e02576382b429006000526004601cfd5b6001600160a01b031680611e1e57637448fbae6000526004601cfd5b80337f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a3638b78c6d81955565b600081600111158015611e62575060005482105b8015610a10575050600090815260046020526040902054600160e01b161590565b6000600883901c60ff841661010184820110611ef957600082815260208790526040902054611eb390821c612a20565b930160ff8116939250600182019160009160081c015b808314611ef757600083815260208890526040902054611ee890612a20565b84019350826001019250611ec9565b505b600082815260208790526040902054611f1a90821c6101008690031b612a20565b90920195945050505050565b638b78c6d88260601b176000526020600020805482811681189050808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b638b78c6d88260601b17600052602060002081815417808255808460601b60601c7f715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26600080a350505050565b600081806001116120135760005481101561201357600081815260046020526040902054600160e01b8116612011575b8061120c575060001901600081815260046020526040902054611ff3565b505b604051636f96cda160e11b815260040160405180910390fd5b6001600160a01b0384161580159061204c57506001600160a01b03831615155b1561195657604051632f65177960e21b815260040160405180910390fd5b60008151600181018060401b6a61000080600a3d393df300178452600a8101601585016000f0925050816120a65763301164256000526004601cfd5b90915290565b600054816120cd5760405163b562e8dd60e01b815260040160405180910390fd5b6120da600084838561202c565b6001600160a01b03831660008181526005602090815260408083208054680100000000000000018802019055848352600490915281206001851460e11b4260a01b178317905582840190839083906000805160206138f88339815191528180a4600183015b81811461216557808360006000805160206138f8833981519152600080a460010161213f565b508161218357604051622e076360e81b815260040160405180910390fd5b60005550505050565b600061219783611fc3565b9050806000806121b586600090815260066020526040902080549091565b9150915084156121f5576121ca818433610f3a565b6121f5576121d8833361091f565b6121f557604051632ce44b5f60e11b815260040160405180910390fd5b61220383600088600161202c565b801561220e57600082555b6001600160a01b038316600081815260056020526040902080546fffffffffffffffffffffffffffffffff0190554260a01b17600360e01b17600087815260046020526040902055600160e11b841661229557600186016000818152600460205260409020546122935760005481146122935760008181526004602052604090208590555b505b60405186906000906001600160a01b038616906000805160206138f8833981519152908390a45050600180548101905550505050565b60001960ff8316846020528360081c6000526101018382011061232d576000805160408220805485851b1790559390910160ff811693600181019160081c015b80821461232857816000528360406000205560018201915061230b565b506000525b60406000208284610100031c821b8154178155505050505050565b604051630a85bd0160e11b81526000906001600160a01b0385169063150b7a029061237d90339089908890889060040161363d565b602060405180830381600087803b15801561239757600080fd5b505af19250505080156123c7575060408051601f3d908101601f191682019092526123c491810190613092565b60015b612422573d8080156123f5576040519150601f19603f3d011682016040523d82523d6000602084013e6123fa565b606091505b50805161241a576040516368d2bf6b60e11b815260040160405180910390fd5b805181602001fd5b6001600160e01b031916630a85bd0160e11b149050949350505050565b6124796040518060a001604052806060815260200160608152602001600061ffff168152602001600061ffff168152602001600081525090565b600d545b8015611c24576000600d612492600184613822565b815481106124b057634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a0016040529081600082015481526020016001820180546124e390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461250f90613865565b801561255c5780601f106125315761010080835404028352916020019161255c565b820191906000526020600020905b81548152906001019060200180831161253f57829003601f168201915b5050505050815260200160028201805461257590613865565b80601f01602080910402602001604051908101604052809291908181526020018280546125a190613865565b80156125ee5780601f106125c3576101008083540402835291602001916125ee565b820191906000526020600020905b8154815290600101906020018083116125d157829003601f168201915b50505091835250506003919091015461ffff80821660208401526201000090910416604090910152805190915084106128e957600d54821015612800576000600d838154811061264e57634e487b7160e01b600052603260045260246000fd5b90600052602060002090600402016040518060a00160405290816000820154815260200160018201805461268190613865565b80601f01602080910402602001604051908101604052809291908181526020018280546126ad90613865565b80156126fa5780601f106126cf576101008083540402835291602001916126fa565b820191906000526020600020905b8154815290600101906020018083116126dd57829003601f168201915b5050505050815260200160028201805461271390613865565b80601f016020809104026020016040519081016040528092919081815260200182805461273f90613865565b801561278c5780601f106127615761010080835404028352916020019161278c565b820191906000526020600020905b81548152906001019060200180831161276f57829003601f168201915b50505091835250506003919091015461ffff808216602080850191909152620100009092048116604093840152825160a08101845286830151815286840151928101929092526060808701518216938301939093526080958601511691810191909152905192810192909252509392505050565b60007f000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca66001600160a01b03166318160ddd6040518163ffffffff1660e01b815260040160206040518083038186803b15801561285b57600080fd5b505afa15801561286f573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061289391906130f9565b61289e906002613803565b90506040518060a001604052808360200151815260200183604001518152602001836060015161ffff168152602001836080015161ffff168152602001828152509350505050919050565b506000190161247d565b604080516080019081905280825b600183039250600a81066030018353600a90048061291e57612923565b612901565b50819003601f19909101908152919050565b60408051808201909152601a81527f646174613a696d6167652f7376672b786d6c3b6261736536342c0000000000006020820152600a5460609190600090612985906001600160a01b0316612ad0565b600c549091506000906129a0906001600160a01b0316612ad0565b600b549091506000906129bb906001600160a01b0316612ad0565b9050836129e48a856129ce868d8d612b1a565b8a86604051602001611b17959493929190613396565b6040516020016129f59291906131f1565b604051602081830303815290604052945050505050949350505050565b6060610a1082600080612c03565b7f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f0f7f5555555555555555555555555555555555555555555555555555555555555555600183901c168203600281901c7f3333333333333333333333333333333333333333333333333333333333333333908116911601600481901c01167f01010101010101010101010101010101010101010101010101010101010101010260f81c6000199190911460081b1790565b6060813b80612ae7576311052bb46000526004601cfd5b600181039050604051915061ffe0603f820116820160405280825260008160208401015280600160208401853c50919050565b606060008261ffff1667ffffffffffffffff811115612b4957634e487b7160e01b600052604160045260246000fd5b6040519080825280601f01601f191660200182016040528015612b73576020820181803683370190505b50905060005b8151811015611d275785612b9161ffff8716836137eb565b81518110612baf57634e487b7160e01b600052603260045260246000fd5b602001015160f81c60f81b828281518110612bda57634e487b7160e01b600052603260045260246000fd5b60200101906001600160f81b031916908160001a90535080612bfb8161389a565b915050612b79565b606083518015612d04576003600282010460021b60405192507f4142434445464748494a4b4c4d4e4f505152535455565758595a616263646566601f526102308515027f6768696a6b6c6d6e6f707172737475767778797a303132333435363738392d5f03603f52602083018181015b6003880197508751603f8160121c16518353603f81600c1c16516001840153603f8160061c16516002840153603f811651600384015350600482019150808210612cbc57612cc1565b612c73565b60038406868015612cdd57600182148215150185038752612cf5565b603d821515850353603d6001831460011b8503538487525b5050601f01601f191660405250505b509392505050565b828054612d1890613865565b90600052602060002090601f016020900481019282612d3a5760008555612d80565b82601f10612d535782800160ff19823516178555612d80565b82800160010185558215612d80579182015b82811115612d80578235825591602001919060010190612d65565b50612d8c929150612d90565b5090565b5b80821115612d8c5760008155600101612d91565b80356001600160a01b0381168114612dbc57600080fd5b919050565b600082601f830112612dd1578081fd5b813567ffffffffffffffff811115612deb57612deb6138cb565b612dfe601f8201601f19166020016137ba565b818152846020838601011115612e12578283fd5b816020850160208301379081016020019190915292915050565b600060208284031215612e3d578081fd5b61120c82612da5565b60008060408385031215612e58578081fd5b612e6183612da5565b9150612e6f60208401612da5565b90509250929050565b600080600060608486031215612e8c578081fd5b612e9584612da5565b9250612ea360208501612da5565b9150604084013590509250925092565b60008060008060808587031215612ec8578081fd5b612ed185612da5565b9350612edf60208601612da5565b925060408501359150606085013567ffffffffffffffff811115612f01578182fd5b612f0d87828801612dc1565b91505092959194509250565b60008060008060808587031215612f2e578384fd5b612f3785612da5565b9350612f4560208601612da5565b93969395505050506040820135916060013590565b60008060408385031215612f6c578182fd5b612f7583612da5565b915060208301358015158114612f89578182fd5b809150509250929050565b60008060408385031215612fa6578182fd5b612faf83612da5565b946020939093013593505050565b60006020808385031215612fcf578182fd5b823567ffffffffffffffff80821115612fe6578384fd5b818501915085601f830112612ff9578384fd5b81358181111561300b5761300b6138cb565b8060051b915061301c8483016137ba565b8181528481019084860184860187018a1015613036578788fd5b8795505b83861015613069578035945060ff85168514613054578788fd5b8483526001959095019491860191860161303a565b5098975050505050505050565b600060208284031215613087578081fd5b813561120c816138e1565b6000602082840312156130a3578081fd5b815161120c816138e1565b6000602082840312156130bf578081fd5b813567ffffffffffffffff8111156130d5578182fd5b61160184828501612dc1565b6000602082840312156130f2578081fd5b5035919050565b60006020828403121561310a578081fd5b5051919050565b600080600060408486031215613125578081fd5b83359250602084013567ffffffffffffffff80821115613143578283fd5b818601915086601f830112613156578283fd5b813581811115613164578384fd5b876020828501011115613175578384fd5b6020830194508093505050509250925092565b6000806040838503121561319a578182fd5b50508035926020909101359150565b600081518084526131c1816020860160208601613839565b601f01601f19169290920160200192915050565b600081516131e7818560208601613839565b9290920192915050565b60008351613203818460208801613839565b835190830190613217818360208801613839565b01949350505050565b683d913730b6b2911d1160b91b81528651600090613245816009850160208c01613839565b61088b60f21b60099184019182018190526e113232b9b1b934b83a34b7b7111d1160891b600b830152885161328181601a850160208d01613839565b601a9201918201527f2261747472696275746573223a5b7b2274726169745f74797065223a22506f69601c82015270373a3991161136b0bc2fbb30b63ab2911d60791b603c82015286516132dc81604d840160208b01613839565b61338861337a61337461335f61334f61334961331561330f604d898b01016816113b30b63ab2911d60b91b815260090190565b8e6131d5565b7f7d2c207b2274726169745f74797065223a224c6576656c222c2276616c7565228152611d1160f11b602082015260220190565b8b6131d5565b63089f574b60e21b815260040190565b681134b6b0b3b2911d1160b91b815260090190565b876131d5565b61227d60f01b815260020190565b9a9950505050505050505050565b7f3c73766720786d6c6e733d22687474703a2f2f7777772e77332e6f72672f323081527f30302f737667222066696c6c3d226e6f6e65222076696577426f783d2230203060208201527f20313038302031303830223e3c706174682066696c6c3d22726762612832353560408201527f2c3235352c3235352c30292220643d224d3020306831303830763130383048306060820152643d1110179f60d91b6080820152703c706174682066696c6c3d2275726c282360781b608582015260008651613468816096850160208b01613839565b7f292220643d224d32342034306131362031362030203020312031362d313668316096918401918201527f303030613136203136203020302031203136203136763931346131362031362060b68201527f30203020312d3136203136483131342e356132342032342030203020302d313760d68201527f2e3620372e376c2d35392036332e34613820382030203020312d31332e392d3560f682015269171a2b1a182d1110179f60b11b61011682015261363161361f6136196135fe6135f861353e61353861012088018e6131d5565b8c6131d5565b7f3c7465787420786d6c3a73706163653d227072657365727665222066696c6c3d81527f22233030394446352220666f6e742d66616d696c793d22436f7572696572222060208201527f666f6e742d73697a653d22323422206c65747465722d73706163696e673d223060408201527f656d22207374796c653d2277686974652d73706163653a707265223e3c74737060608201527530b7103c1e91189a1a11103c9e9118981a1a171c911f60511b608082015260960190565b896131d5565b6e1e17ba39b830b71f1e17ba32bc3a1f60891b8152600f0190565b866131d5565b651e17b9bb339f60d11b815260060190565b98975050505050505050565b6001600160a01b0385811682528416602082015260408101839052608060608201819052600090613670908301846131a9565b9695505050505050565b602080825282518282018190526000919060409081850190868401855b828110156136cf57815180518552868101516001600160a01b0316878601528501518585015260609093019290850190600101613697565b5091979650505050505050565b6020808252825182820181905260009190848201906040850190845b81811015613714578351835292840192918401916001016136f8565b50909695505050505050565b6020808252825182820181905260009190848201906040850190845b8181101561371457835160ff168352928401929184019160010161373c565b60208152600061120c60208301846131a9565b85815260a06020820152600061378760a08301876131a9565b828103604084015261379981876131a9565b91505061ffff80851660608401528084166080840152509695505050505050565b604051601f8201601f1916810167ffffffffffffffff811182821017156137e3576137e36138cb565b604052919050565b600082198211156137fe576137fe6138b5565b500190565b600081600019048311821515161561381d5761381d6138b5565b500290565b600082821015613834576138346138b5565b500390565b60005b8381101561385457818101518382015260200161383c565b838111156119565750506000910152565b600181811c9082168061387957607f821691505b60208210811415611c2457634e487b7160e01b600052602260045260246000fd5b60006000198214156138ae576138ae6138b5565b5060010190565b634e487b7160e01b600052601160045260246000fd5b634e487b7160e01b600052604160045260246000fd5b6001600160e01b031981168114610eb957600080fdfeddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef736861726520796f7572206d657373616765206174206e6f6e6f6e2e686f757365a26469706673582212206d095de219df15e46294140727498581aae7d369cc3a076e0839aca95b3c4fca64736f6c63430008040033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6
-----Decoded View---------------
Arg [0] : tokenCollectionAddress (address): 0xD3607bc8c7927B348bac50dc224C28E3ce933ca6
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 000000000000000000000000d3607bc8c7927b348bac50dc224c28e3ce933ca6
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.