Feature Tip: Add private address tag to any address under My Name Tag !
Source Code
Overview
ETH Balance
0 ETH
Eth Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 314 transactions
| Transaction Hash |
Method
|
Block
|
From
|
|
To
|
||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 23947055 | 63 days ago | IN | 0 ETH | 0.00009356 | ||||
| Set Message | 23848529 | 77 days ago | IN | 0 ETH | 0.00024901 | ||||
| Set Message | 23730891 | 93 days ago | IN | 0 ETH | 0.00004402 | ||||
| Set Message | 23730890 | 93 days ago | IN | 0 ETH | 0.00006886 | ||||
| Set Approval For... | 23676752 | 101 days ago | IN | 0 ETH | 0.00002098 | ||||
| Set Message | 23308888 | 152 days ago | IN | 0 ETH | 0.00010931 | ||||
| Set Approval For... | 23258015 | 159 days ago | IN | 0 ETH | 0.00005623 | ||||
| Set Approval For... | 23257188 | 159 days ago | IN | 0 ETH | 0.00005311 | ||||
| Set Approval For... | 23248805 | 160 days ago | IN | 0 ETH | 0.00006598 | ||||
| Set Approval For... | 22976651 | 198 days ago | IN | 0 ETH | 0.00015974 | ||||
| Set Message | 22923147 | 206 days ago | IN | 0 ETH | 0.00003727 | ||||
| Set Message | 22910565 | 208 days ago | IN | 0 ETH | 0.00003547 | ||||
| Set Message | 22910551 | 208 days ago | IN | 0 ETH | 0.0001072 | ||||
| Set Message | 22910019 | 208 days ago | IN | 0 ETH | 0.00002461 | ||||
| Set Approval For... | 22888913 | 211 days ago | IN | 0 ETH | 0.00019674 | ||||
| Set Approval For... | 22840748 | 217 days ago | IN | 0 ETH | 0.00010147 | ||||
| Set Approval For... | 22812473 | 221 days ago | IN | 0 ETH | 0.00010512 | ||||
| Set Approval For... | 22586018 | 253 days ago | IN | 0 ETH | 0.00011181 | ||||
| Set Approval For... | 22479222 | 268 days ago | IN | 0 ETH | 0.00006379 | ||||
| Set Approval For... | 22478914 | 268 days ago | IN | 0 ETH | 0.00007269 | ||||
| Set Approval For... | 22421113 | 276 days ago | IN | 0 ETH | 0.0000394 | ||||
| Set Approval For... | 22398151 | 279 days ago | IN | 0 ETH | 0.00001853 | ||||
| Set Approval For... | 22389688 | 281 days ago | IN | 0 ETH | 0.0000803 | ||||
| Set Approval For... | 22389688 | 281 days ago | IN | 0 ETH | 0.0000803 | ||||
| Set Approval For... | 22389688 | 281 days ago | IN | 0 ETH | 0.0000803 |
Latest 3 internal transactions
Advanced mode:
| Parent Transaction Hash | Method | Block |
From
|
|
To
|
||
|---|---|---|---|---|---|---|---|
| 0x6115ee80 | 19067042 | 745 days ago | Contract Creation | 0 ETH | |||
| 0x61376080 | 19067041 | 745 days ago | Contract Creation | 0 ETH | |||
| 0x6134fa80 | 19066863 | 745 days ago | Contract Creation | 0 ETH |
Loading...
Loading
Loading...
Loading
Cross-Chain Transactions
Loading...
Loading
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
Contract ABI
API[{"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
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 34 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.