More Info
Private Name Tags
ContractCreator
TokenTracker
Multichain Info
No addresses found
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
3285848 | 347 days ago | 0.0007 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
BlazeType
Compiler Version
v0.8.24+commit.e11b9ed9
Optimization Enabled:
Yes with 200 runs
Other Settings:
shanghai EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; // forgefmt: disable-start // // // // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓██████▓▒░░▒▓████████▓▒░▒▓████████▓▒░ ░▒▓██████▓▒░░▒▓███████▓▒░ ░▒▓██████▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░ ░▒▓██▓▒░░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓█▓▒░ ░▒▓████████▓▒░ ░▒▓██▓▒░ ░▒▓██████▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒▒▓███▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░░▒▓██▓▒░ ░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░ ░▒▓█▓▒░ ░▒▓██▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓█▓▒░░▒▓█▓▒░ // ░▒▓███████▓▒░░▒▓████████▓▒░▒▓█▓▒░░▒▓█▓▒░▒▓████████▓▒░▒▓████████▓▒░▒▓██▓▒░░▒▓██████▓▒░░▒▓█▓▒░░▒▓█▓▒░░▒▓██████▓▒░ // // // // forgefmt: disable-end import { ERC721A } from "ERC721A/ERC721A.sol"; import { ERC2981 } from "@solady/tokens/ERC2981.sol"; import { Ownable2Step, Ownable } from "@openzeppelin/access/Ownable2Step.sol"; import { LibString } from "@solady/utils/LibString.sol"; import { MerkleProofLib } from "@solady/utils/MerkleProofLib.sol"; import { IBlast } from "src/lib/IBlast.sol"; import { IBlastPoints } from "src/lib/IBlastPoints.sol"; import "src/lib/Errors.sol"; import "src/lib/Structs.sol"; /// @title BlazeType /// @author www.blaze.ong /// @notice Blaze0ng NFT Launchpad ERC721 contract. contract BlazeType is ERC721A, ERC2981, Ownable2Step { // ------------------------------------------------------------------------- // Storage // ------------------------------------------------------------------------- Params public params; Locks public locks; /// @notice The amount of funds recived from all mints. uint256 private _totalFundsReceived; /// @notice Mapping for tracking whitelist claims. mapping(uint8 phase => mapping(address listee => uint256)) whitelistClaims; bool private _mintingClosed; // ------------------------------------------------------------------------- // Events // ------------------------------------------------------------------------- /// @notice Emitted when the collection owner stops the public mint. event StopMint(); /// @notice Emitted when the `baseURI` is updated via `setBaseURI()`. event BaseURIUpdated(); /// @notice Emitted when the `contractURI` is updated via `setContractURI()`. event ContractURIUpdated(); /// @notice Emitted when the `maxSupply` is updated via `setMaxSupply()` or /// `stopMint()`. event MaxSupplyUpdated(uint256 newMaxSupply); /// @notice Emitted when the royalty parameters are updated via `setRoyaltyParams()`. event RoyaltyParamsUpdated(address _royaltyReceiver, uint16 _defaultRoyalty); /// @notice BlazeType constructor /// @param _params Initial parameters for the contract. /// @param _name The name of the NFT. /// @param _symbol The symbol of the NFT. /// @param _owner The owner of the collection. constructor( Params memory _params, string memory _name, string memory _symbol, address _owner ) ERC721A(_name, _symbol) Ownable(_owner) { IBlast(0x4300000000000000000000000000000000000002).configureAutomaticYield(); IBlastPoints(0x2536FE9ab3F511540F2f9e2eC2A805005C3Dd800).configurePointsOperator( POINTS_OPERATOR ); if ( keccak256(bytes(_params.baseURI)) == keccak256(bytes("")) || _params.defaultRoyalty > MAX_ROYALTY ) { revert InvalidParams(); } _setDefaultRoyalty(_params.royaltyReceiver, _params.defaultRoyalty); if (_params.mintsToOwner > 0) _mint(_owner, _params.mintsToOwner); params = _params; _validateWhitelistPhases(_params.whitelistPhases); } function supportsInterface(bytes4 interfaceId) public view override(ERC721A, ERC2981) returns (bool) { return ERC721A.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId); } function tokenURI(uint256 _tokenId) public view override returns (string memory) { if (!_exists(_tokenId)) revert TokenDoesNotExist(); return string(abi.encodePacked(params.baseURI, LibString.toString(_tokenId))); } function contractURI() external view returns (string memory) { return params.contractURI; } // ------------------------------------------------------------------------- // External // ------------------------------------------------------------------------- /// @notice Returns the whitelist phases for the NFT. /// @return The array of whitelist phases. function whitelistPhases() external view returns (WhitelistPhase[] memory) { return params.whitelistPhases; } /// @notice Mints an NFT to `_to`. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFT's to mint. function mint(address _to, uint256 _amount) external payable { if (params.start > block.timestamp || params.end < block.timestamp || _mintingClosed) { revert MintNotActive(); } if (_nextTokenId() + _amount > params.maxSupply) revert MaxSupplyReached(); if (msg.value < params.mintPrice * _amount) revert InsufficientFunds(); _totalFundsReceived += msg.value; _mint(_to, _amount); } /// @notice Mints an NFT for a whitelisted address /// @param _phase The whitelist phase. /// @param _merkleProof The merkle proof for the whitelist. /// @param _to Address that receives the NFT. /// @param _amount Amount of NFT's to mint. function whitelistMint( uint8 _phase, bytes32[] calldata _merkleProof, address _to, uint256 _amount ) external payable { WhitelistPhase memory thisPhase = params.whitelistPhases[_phase]; if (thisPhase.start > block.timestamp || thisPhase.end < block.timestamp) { revert WhitelistPhaseNotActive(); } if (_nextTokenId() + _amount > params.maxSupply) revert MaxSupplyReached(); if (msg.value < thisPhase.whitelistMintPrice * _amount) revert InsufficientFunds(); bytes32 leaf = keccak256(bytes.concat(keccak256(abi.encode(_to, _amount)))); if (!MerkleProofLib.verifyCalldata(_merkleProof, thisPhase.merkleRoot, leaf)) { revert InvalidMerkleProof(); } _totalFundsReceived += msg.value; _mint(_to, _amount); } // ------------------------------------------------------------------------- // OnlyOwner // ------------------------------------------------------------------------- /// @notice Updates collection params in a batch. function ownerBatch(bytes[] calldata _calls) external onlyOwner returns (bytes[] memory results) { results = new bytes[](_calls.length); for (uint256 i; i < _calls.length; i++) { (bool success, bytes memory result) = address(this).delegatecall(_calls[i]); if (!success) { if (result.length < 68) revert("Transaction reverted without a reason"); bytes memory returnData; assembly { returnData := add(returnData, 0x04) } revert(string(returnData)); } results[i] = result; } } /// @notice Withdraws the mint funds to the collection owner. function withdraw() external onlyOwner { (bool success,) = msg.sender.call{ value: address(this).balance }(""); if(!success) { revert WithdrawalFailed(); } _totalFundsReceived = 0; } /// @notice Withdraws a specified amount of mint funds to the collection owner. /// @param _amount The amount to withdraw. function withdraw(uint256 _amount) external onlyOwner { _amount > _totalFundsReceived ? _totalFundsReceived = 0 : _totalFundsReceived -= _amount; (bool success,) = msg.sender.call{ value: _amount }(""); if(!success) { revert WithdrawalFailed(); } } /// @notice Allows owner to arbitrarily end public mint capping supply at the current /// amount. function stopMint() external onlyOwner { _mintingClosed = true; uint256 newMaxSupply = _nextTokenId(); params.maxSupply = newMaxSupply; emit StopMint(); emit MaxSupplyUpdated(newMaxSupply); } /// @notice Allows the owner to claim the yield generated from the mints. function claimYield() external onlyOwner { (bool success,) = msg.sender.call{ value: address(this).balance - _totalFundsReceived }(""); if(!success) { revert WithdrawalFailed(); } } /// @notice Allows the owner to claim a specific amount of yield. /// @param _amount The amount of yield to claim. function claimYield(uint256 _amount) external onlyOwner { if (address(this).balance - _totalFundsReceived < _amount) { revert InsufficientFunds(); } (bool success,) = msg.sender.call{ value: _amount }(""); if(!success) { revert WithdrawalFailed(); } } /// @notice Setter for `baseURI`. /// @param _baseUri The `baseURI` for the NFTs. function setBaseURI(string calldata _baseUri) external onlyOwner { if (locks.baseURILocked) revert BaseURILocked(); params.baseURI = _baseUri; emit BaseURIUpdated(); } /// @notice Permanently locks `baseURI`. function lockBaseURI() external onlyOwner { locks.baseURILocked = true; } /// @notice Setter for `contractURI`. /// @param _contractURI The `contractURI` for the NFTs. function setContractURI(string calldata _contractURI) external onlyOwner { if (locks.contractURILocked) revert ContractURILocked(); params.contractURI = _contractURI; emit ContractURIUpdated(); } /// @notice Permanently locks `contractURI`. function lockContractURI() external onlyOwner { locks.contractURILocked = true; } /// @notice Setter for `maxSupply`. /// @param _newMaxSupply The new maximum supply for the NFTs. function setMaxSupply(uint256 _newMaxSupply) external onlyOwner { _validateParamUpdate(); if (_newMaxSupply < _nextTokenId()) revert InvalidMaxSupply(); params.maxSupply = _newMaxSupply; emit MaxSupplyUpdated(_newMaxSupply); } /// @notice Sets the mint price for the public mint. /// @param _mintPrice The mint price for the public mint. function setMintPrice(uint120 _mintPrice) external onlyOwner { _validateParamUpdate(); params.mintPrice = _mintPrice; } /// @notice Sets the mint price for the given whitelist phase. /// @param _phase The whitelist phase to set the mint price for. /// @param _whitelistMintPrice The mint price for the whitelist phase. function setWhitelistMintPrice(uint8 _phase, uint120 _whitelistMintPrice) external onlyOwner { _validateParamUpdate(); params.whitelistPhases[_phase].whitelistMintPrice = _whitelistMintPrice; } /// @notice Setter for the receiving address and bps for royalties. /// @param _royaltyReceiver The receiving address for any royalties. /// @param _defaultRoyalty The bps for royalties. function setRoyaltyParams(address _royaltyReceiver, uint16 _defaultRoyalty) external onlyOwner { if (locks.royaltyParamsLocked) revert RoyaltyParamsLocked(); if (_defaultRoyalty > MAX_ROYALTY) revert InvalidDefaultRoyalty(); params.royaltyReceiver = _royaltyReceiver; params.defaultRoyalty = _defaultRoyalty; _setDefaultRoyalty(_royaltyReceiver, _defaultRoyalty); emit RoyaltyParamsUpdated(_royaltyReceiver, _defaultRoyalty); } /// @notice Permanently locks `royaltyReceiver` and `defaultRoyalty`. function lockRoyaltyParams() external onlyOwner { locks.royaltyParamsLocked = true; } // ------------------------------------------------------------------------- // Internal // ------------------------------------------------------------------------- /// @notice Validates whitelist phases. /// @param _phases The whitelist phases to be validated. function _validateWhitelistPhases(WhitelistPhase[] memory _phases) internal view { // Check for length > 3 if (_phases.length > 3) revert InvalidWhitelistPhases(); // Check that phase start must be before phase end, phase ends must be before public // mint start, and that phases do not overlap. uint256 prevEnd; for (uint256 i; i < _phases.length;) { if ( _phases[i].start > _phases[i].end || _phases[i].end > params.start || (_phases[i].start != 0 && _phases[i].start < prevEnd) ) { revert InvalidWhitelistPhases(); } prevEnd = _phases[i].end; unchecked { ++i; } } } /// @notice Checks that minting is active and reverts if true. Ensures parameters cannot /// be changed during minting phases. function _validateParamUpdate() internal view { if (block.timestamp > params.start && block.timestamp < params.end) { revert MintingActive(); } for (uint256 i; i < params.whitelistPhases.length;) { if ( block.timestamp > params.whitelistPhases[i].start && block.timestamp < params.whitelistPhases[i].end ) revert MintingActive(); unchecked { ++i; } } } }
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.3.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import './IERC721A.sol'; /** * @dev Interface of ERC721 token receiver. */ interface ERC721A__IERC721Receiver { function onERC721Received( address operator, address from, uint256 tokenId, bytes calldata data ) external returns (bytes4); } /** * @title ERC721A * * @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721) * Non-Fungible Token Standard, including the Metadata extension. * Optimized for lower gas during batch mints. * * Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...) * starting from `_startTokenId()`. * * The `_sequentialUpTo()` function can be overriden to enable spot mints * (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`. * * Assumptions: * * - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply. * - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256). */ contract ERC721A is IERC721A { // Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364). struct TokenApprovalRef { address value; } // ============================================================= // CONSTANTS // ============================================================= // Mask of an entry in packed address data. uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1; // The bit position of `numberMinted` in packed address data. uint256 private constant _BITPOS_NUMBER_MINTED = 64; // The bit position of `numberBurned` in packed address data. uint256 private constant _BITPOS_NUMBER_BURNED = 128; // The bit position of `aux` in packed address data. uint256 private constant _BITPOS_AUX = 192; // Mask of all 256 bits in packed address data except the 64 bits for `aux`. uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1; // The bit position of `startTimestamp` in packed ownership. uint256 private constant _BITPOS_START_TIMESTAMP = 160; // The bit mask of the `burned` bit in packed ownership. uint256 private constant _BITMASK_BURNED = 1 << 224; // The bit position of the `nextInitialized` bit in packed ownership. uint256 private constant _BITPOS_NEXT_INITIALIZED = 225; // The bit mask of the `nextInitialized` bit in packed ownership. uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225; // The bit position of `extraData` in packed ownership. uint256 private constant _BITPOS_EXTRA_DATA = 232; // Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`. uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1; // The mask of the lower 160 bits for addresses. uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1; // The maximum `quantity` that can be minted with {_mintERC2309}. // This limit is to prevent overflows on the address data entries. // For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309} // is required to cause an overflow, which is unrealistic. uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000; // The `Transfer` event signature is given by: // `keccak256(bytes("Transfer(address,address,uint256)"))`. bytes32 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; // ============================================================= // STORAGE // ============================================================= // The next token ID to be minted. uint256 private _currentIndex; // The number of tokens burned. uint256 private _burnCounter; // Token name string private _name; // Token symbol string private _symbol; // Mapping from token ID to ownership details // An empty struct value does not necessarily mean the token is unowned. // See {_packedOwnershipOf} implementation for details. // // Bits Layout: // - [0..159] `addr` // - [160..223] `startTimestamp` // - [224] `burned` // - [225] `nextInitialized` // - [232..255] `extraData` mapping(uint256 => uint256) private _packedOwnerships; // Mapping owner address to address data. // // Bits Layout: // - [0..63] `balance` // - [64..127] `numberMinted` // - [128..191] `numberBurned` // - [192..255] `aux` mapping(address => uint256) private _packedAddressData; // Mapping from token ID to approved address. mapping(uint256 => TokenApprovalRef) private _tokenApprovals; // Mapping from owner to operator approvals mapping(address => mapping(address => bool)) private _operatorApprovals; // The amount of tokens minted above `_sequentialUpTo()`. // We call these spot mints (i.e. non-sequential mints). uint256 private _spotMinted; // ============================================================= // CONSTRUCTOR // ============================================================= constructor(string memory name_, string memory symbol_) { _name = name_; _symbol = symbol_; _currentIndex = _startTokenId(); if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector); } // ============================================================= // TOKEN COUNTING OPERATIONS // ============================================================= /** * @dev Returns the starting token ID for sequential mints. * * Override this function to change the starting token ID for sequential mints. * * Note: The value returned must never change after any tokens have been minted. */ function _startTokenId() internal view virtual returns (uint256) { return 0; } /** * @dev Returns the maximum token ID (inclusive) for sequential mints. * * Override this function to return a value less than 2**256 - 1, * but greater than `_startTokenId()`, to enable spot (non-sequential) mints. * * Note: The value returned must never change after any tokens have been minted. */ function _sequentialUpTo() internal view virtual returns (uint256) { return type(uint256).max; } /** * @dev Returns the next token ID to be minted. */ function _nextTokenId() internal view virtual returns (uint256) { return _currentIndex; } /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() public view virtual override returns (uint256 result) { // Counter underflow is impossible as `_burnCounter` cannot be incremented // more than `_currentIndex + _spotMinted - _startTokenId()` times. unchecked { // With spot minting, the intermediate `result` can be temporarily negative, // and the computation must be unchecked. result = _currentIndex - _burnCounter - _startTokenId(); if (_sequentialUpTo() != type(uint256).max) result += _spotMinted; } } /** * @dev Returns the total amount of tokens minted in the contract. */ function _totalMinted() internal view virtual returns (uint256 result) { // Counter underflow is impossible as `_currentIndex` does not decrement, // and it is initialized to `_startTokenId()`. unchecked { result = _currentIndex - _startTokenId(); if (_sequentialUpTo() != type(uint256).max) result += _spotMinted; } } /** * @dev Returns the total number of tokens burned. */ function _totalBurned() internal view virtual returns (uint256) { return _burnCounter; } /** * @dev Returns the total number of tokens that are spot-minted. */ function _totalSpotMinted() internal view virtual returns (uint256) { return _spotMinted; } // ============================================================= // ADDRESS DATA OPERATIONS // ============================================================= /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) public view virtual override returns (uint256) { if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector); return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens minted by `owner`. */ function _numberMinted(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the number of tokens burned by or on behalf of `owner`. */ function _numberBurned(address owner) internal view returns (uint256) { return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY; } /** * Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). */ function _getAux(address owner) internal view returns (uint64) { return uint64(_packedAddressData[owner] >> _BITPOS_AUX); } /** * Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used). * If there are multiple variables, please pack them into a uint64. */ function _setAux(address owner, uint64 aux) internal virtual { uint256 packed = _packedAddressData[owner]; uint256 auxCasted; // Cast `aux` with assembly to avoid redundant masking. assembly { auxCasted := aux } packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX); _packedAddressData[owner] = packed; } // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) { // The interface IDs are constants representing the first 4 bytes // of the XOR of all function selectors in the interface. // See: [ERC165](https://eips.ethereum.org/EIPS/eip-165) // (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`) return interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165. interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721. interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata. } // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() public view virtual override returns (string memory) { return _name; } /** * @dev Returns the token collection symbol. */ function symbol() public view virtual override returns (string memory) { return _symbol; } /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) public view virtual override returns (string memory) { if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector); string memory baseURI = _baseURI(); return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : ''; } /** * @dev Base URI for computing {tokenURI}. If set, the resulting URI for each * token will be the concatenation of the `baseURI` and the `tokenId`. Empty * by default, it can be overridden in child contracts. */ function _baseURI() internal view virtual returns (string memory) { return ''; } // ============================================================= // OWNERSHIPS OPERATIONS // ============================================================= /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) public view virtual override returns (address) { return address(uint160(_packedOwnershipOf(tokenId))); } /** * @dev Gas spent here starts off proportional to the maximum mint batch size. * It gradually moves to O(1) as tokens get transferred around over time. */ function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnershipOf(tokenId)); } /** * @dev Returns the unpacked `TokenOwnership` struct at `index`. */ function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) { return _unpackedOwnership(_packedOwnerships[index]); } /** * @dev Returns whether the ownership slot at `index` is initialized. * An uninitialized slot does not necessarily mean that the slot has no owner. */ function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) { return _packedOwnerships[index] != 0; } /** * @dev Initializes the ownership slot minted at `index` for efficiency purposes. */ function _initializeOwnershipAt(uint256 index) internal virtual { if (_packedOwnerships[index] == 0) { _packedOwnerships[index] = _packedOwnershipOf(index); } } /** * @dev Returns the packed ownership data of `tokenId`. */ function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) { if (_startTokenId() <= tokenId) { packed = _packedOwnerships[tokenId]; if (tokenId > _sequentialUpTo()) { if (_packedOwnershipExists(packed)) return packed; _revert(OwnerQueryForNonexistentToken.selector); } // If the data at the starting slot does not exist, start the scan. if (packed == 0) { if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector); // Invariant: // There will always be an initialized ownership slot // (i.e. `ownership.addr != address(0) && ownership.burned == false`) // before an unintialized ownership slot // (i.e. `ownership.addr == address(0) && ownership.burned == false`) // Hence, `tokenId` will not underflow. // // We can directly compare the packed value. // If the address is zero, packed will be zero. for (;;) { unchecked { packed = _packedOwnerships[--tokenId]; } if (packed == 0) continue; if (packed & _BITMASK_BURNED == 0) return packed; // Otherwise, the token is burned, and we must revert. // This handles the case of batch burned tokens, where only the burned bit // of the starting slot is set, and remaining slots are left uninitialized. _revert(OwnerQueryForNonexistentToken.selector); } } // Otherwise, the data exists and we can skip the scan. // This is possible because we have already achieved the target condition. // This saves 2143 gas on transfers of initialized tokens. // If the token is not burned, return `packed`. Otherwise, revert. if (packed & _BITMASK_BURNED == 0) return packed; } _revert(OwnerQueryForNonexistentToken.selector); } /** * @dev Returns the unpacked `TokenOwnership` struct from `packed`. */ function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) { ownership.addr = address(uint160(packed)); ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP); ownership.burned = packed & _BITMASK_BURNED != 0; ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA); } /** * @dev Packs ownership data into a single uint256. */ function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`. result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags)) } } /** * @dev Returns the `nextInitialized` flag set if `quantity` equals 1. */ function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) { // For branchless setting of the `nextInitialized` flag. assembly { // `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`. result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1)) } } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}. * * Requirements: * * - The caller must own the token or be an approved operator. */ function approve(address to, uint256 tokenId) public payable virtual override { _approve(to, tokenId, true); } /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) public view virtual override returns (address) { if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector); return _tokenApprovals[tokenId].value; } /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool approved) public virtual override { _operatorApprovals[_msgSenderERC721A()][operator] = approved; emit ApprovalForAll(_msgSenderERC721A(), operator, approved); } /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) { return _operatorApprovals[owner][operator]; } /** * @dev Returns whether `tokenId` exists. * * Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}. * * Tokens start existing when they are minted. See {_mint}. */ function _exists(uint256 tokenId) internal view virtual returns (bool result) { if (_startTokenId() <= tokenId) { if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]); if (tokenId < _currentIndex) { uint256 packed; while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId; result = packed & _BITMASK_BURNED == 0; } } } /** * @dev Returns whether `packed` represents a token that exists. */ function _packedOwnershipExists(uint256 packed) private pure returns (bool result) { assembly { // The following is equivalent to `owner != address(0) && burned == false`. // Symbolically tested. result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED)) } } /** * @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`. */ function _isSenderApprovedOrOwner( address approvedAddress, address owner, address msgSender ) private pure returns (bool result) { assembly { // Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean. owner := and(owner, _BITMASK_ADDRESS) // Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean. msgSender := and(msgSender, _BITMASK_ADDRESS) // `msgSender == owner || msgSender == approvedAddress`. result := or(eq(msgSender, owner), eq(msgSender, approvedAddress)) } } /** * @dev Returns the storage slot and value for the approved address of `tokenId`. */ function _getApprovedSlotAndAddress(uint256 tokenId) private view returns (uint256 approvedAddressSlot, address approvedAddress) { TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId]; // The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`. assembly { approvedAddressSlot := tokenApproval.slot approvedAddress := sload(approvedAddressSlot) } } // ============================================================= // TRANSFER OPERATIONS // ============================================================= /** * @dev Transfers `tokenId` from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) public payable virtual override { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); // Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean. from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS)); if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); _beforeTokenTransfers(from, to, tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // We can directly increment and decrement the balances. --_packedAddressData[from]; // Updates: `balance -= 1`. ++_packedAddressData[to]; // Updates: `balance += 1`. // Updates: // - `address` to the next owner. // - `startTimestamp` to the timestamp of transfering. // - `burned` to `false`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( to, _BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. from, // `from`. toMasked, // `to`. tokenId // `tokenId`. ) } if (toMasked == 0) _revert(TransferToZeroAddress.selector); _afterTokenTransfers(from, to, tokenId, 1); } /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) public payable virtual override { safeTransferFrom(from, to, tokenId, ''); } /** * @dev Safely transfers `tokenId` token from `from` to `to`. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes memory _data ) public payable virtual override { transferFrom(from, to, tokenId); if (to.code.length != 0) if (!_checkContractOnERC721Received(from, to, tokenId, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } /** * @dev Hook that is called before a set of serially-ordered token IDs * are about to be transferred. This includes minting. * And also called before burning one token. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Hook that is called after a set of serially-ordered token IDs * have been transferred. This includes minting. * And also called after one token has been burned. * * `startTokenId` - the first token ID to be transferred. * `quantity` - the amount to be transferred. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` has been * transferred to `to`. * - When `from` is zero, `tokenId` has been minted for `to`. * - When `to` is zero, `tokenId` has been burned by `from`. * - `from` and `to` are never both zero. */ function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual {} /** * @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract. * * `from` - Previous owner of the given token ID. * `to` - Target address that will receive the token. * `tokenId` - Token ID to be transferred. * `_data` - Optional data to send along with the call. * * Returns whether the call correctly returned the expected magic value. */ function _checkContractOnERC721Received( address from, address to, uint256 tokenId, bytes memory _data ) private returns (bool) { try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns ( bytes4 retval ) { return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector; } catch (bytes memory reason) { if (reason.length == 0) { _revert(TransferToNonERC721ReceiverImplementer.selector); } assembly { revert(add(32, reason), mload(reason)) } } } // ============================================================= // MINT OPERATIONS // ============================================================= /** * @dev Mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {Transfer} event for each mint. */ function _mint(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (quantity == 0) _revert(MintZeroQuantity.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are incredibly unrealistic. // `balance` and `numberMinted` have a maximum limit of 2**64. // `tokenId` has a maximum limit of 2**256. unchecked { // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; if (toMasked == 0) _revert(MintToZeroAddress.selector); uint256 end = startTokenId + quantity; uint256 tokenId = startTokenId; if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector); do { assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. tokenId // `tokenId`. ) } // The `!=` check ensures that large values of `quantity` // that overflows uint256 will make the loop run out of gas. } while (++tokenId != end); _currentIndex = end; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Mints `quantity` tokens and transfers them to `to`. * * This function is intended for efficient minting only during contract creation. * * It emits only one {ConsecutiveTransfer} as defined in * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309), * instead of a sequence of {Transfer} event(s). * * Calling this function outside of contract creation WILL make your contract * non-compliant with the ERC721 standard. * For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309 * {ConsecutiveTransfer} event is only permissible during contract creation. * * Requirements: * * - `to` cannot be the zero address. * - `quantity` must be greater than 0. * * Emits a {ConsecutiveTransfer} event. */ function _mintERC2309(address to, uint256 quantity) internal virtual { uint256 startTokenId = _currentIndex; if (to == address(0)) _revert(MintToZeroAddress.selector); if (quantity == 0) _revert(MintZeroQuantity.selector); if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector); _beforeTokenTransfers(address(0), to, startTokenId, quantity); // Overflows are unrealistic due to the above check for `quantity` to be below the limit. unchecked { // Updates: // - `balance += quantity`. // - `numberMinted += quantity`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1); // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `quantity == 1`. _packedOwnerships[startTokenId] = _packOwnershipData( to, _nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0) ); if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector); emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to); _currentIndex = startTokenId + quantity; } _afterTokenTransfers(address(0), to, startTokenId, quantity); } /** * @dev Safely mints `quantity` tokens and transfers them to `to`. * * Requirements: * * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called for each safe transfer. * - `quantity` must be greater than 0. * * See {_mint}. * * Emits a {Transfer} event for each mint. */ function _safeMint( address to, uint256 quantity, bytes memory _data ) internal virtual { _mint(to, quantity); unchecked { if (to.code.length != 0) { uint256 end = _currentIndex; uint256 index = end - quantity; do { if (!_checkContractOnERC721Received(address(0), to, index++, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } } while (index < end); // This prevents reentrancy to `_safeMint`. // It does not prevent reentrancy to `_safeMintSpot`. if (_currentIndex != end) revert(); } } } /** * @dev Equivalent to `_safeMint(to, quantity, '')`. */ function _safeMint(address to, uint256 quantity) internal virtual { _safeMint(to, quantity, ''); } /** * @dev Mints a single token at `tokenId`. * * Note: A spot-minted `tokenId` that has been burned can be re-minted again. * * Requirements: * * - `to` cannot be the zero address. * - `tokenId` must be greater than `_sequentialUpTo()`. * - `tokenId` must not exist. * * Emits a {Transfer} event for each mint. */ function _mintSpot(address to, uint256 tokenId) internal virtual { if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector); uint256 prevOwnershipPacked = _packedOwnerships[tokenId]; if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector); _beforeTokenTransfers(address(0), to, tokenId, 1); // Overflows are incredibly unrealistic. // The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1. // `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1. unchecked { // Updates: // - `address` to the owner. // - `startTimestamp` to the timestamp of minting. // - `burned` to `false`. // - `nextInitialized` to `true` (as `quantity == 1`). _packedOwnerships[tokenId] = _packOwnershipData( to, _nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked) ); // Updates: // - `balance += 1`. // - `numberMinted += 1`. // // We can directly add to the `balance` and `numberMinted`. _packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1; // Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean. uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS; if (toMasked == 0) _revert(MintToZeroAddress.selector); assembly { // Emit the `Transfer` event. log4( 0, // Start of data (0, since no data). 0, // End of data (0, since no data). _TRANSFER_EVENT_SIGNATURE, // Signature. 0, // `address(0)`. toMasked, // `to`. tokenId // `tokenId`. ) } ++_spotMinted; } _afterTokenTransfers(address(0), to, tokenId, 1); } /** * @dev Safely mints a single token at `tokenId`. * * Note: A spot-minted `tokenId` that has been burned can be re-minted again. * * Requirements: * * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}. * - `tokenId` must be greater than `_sequentialUpTo()`. * - `tokenId` must not exist. * * See {_mintSpot}. * * Emits a {Transfer} event. */ function _safeMintSpot( address to, uint256 tokenId, bytes memory _data ) internal virtual { _mintSpot(to, tokenId); unchecked { if (to.code.length != 0) { uint256 currentSpotMinted = _spotMinted; if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) { _revert(TransferToNonERC721ReceiverImplementer.selector); } // This prevents reentrancy to `_safeMintSpot`. // It does not prevent reentrancy to `_safeMint`. if (_spotMinted != currentSpotMinted) revert(); } } } /** * @dev Equivalent to `_safeMintSpot(to, tokenId, '')`. */ function _safeMintSpot(address to, uint256 tokenId) internal virtual { _safeMintSpot(to, tokenId, ''); } // ============================================================= // APPROVAL OPERATIONS // ============================================================= /** * @dev Equivalent to `_approve(to, tokenId, false)`. */ function _approve(address to, uint256 tokenId) internal virtual { _approve(to, tokenId, false); } /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - `tokenId` must exist. * * Emits an {Approval} event. */ function _approve( address to, uint256 tokenId, bool approvalCheck ) internal virtual { address owner = ownerOf(tokenId); if (approvalCheck && _msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) { _revert(ApprovalCallerNotOwnerNorApproved.selector); } _tokenApprovals[tokenId].value = to; emit Approval(owner, to, tokenId); } // ============================================================= // BURN OPERATIONS // ============================================================= /** * @dev Equivalent to `_burn(tokenId, false)`. */ function _burn(uint256 tokenId) internal virtual { _burn(tokenId, false); } /** * @dev Destroys `tokenId`. * The approval is cleared when the token is burned. * * Requirements: * * - `tokenId` must exist. * * Emits a {Transfer} event. */ function _burn(uint256 tokenId, bool approvalCheck) internal virtual { uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId); address from = address(uint160(prevOwnershipPacked)); (uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId); if (approvalCheck) { // The nested ifs save around 20+ gas over a compound boolean condition. if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A())) if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector); } _beforeTokenTransfers(from, address(0), tokenId, 1); // Clear approvals from the previous owner. assembly { if approvedAddress { // This is equivalent to `delete _tokenApprovals[tokenId]`. sstore(approvedAddressSlot, 0) } } // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. // Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256. unchecked { // Updates: // - `balance -= 1`. // - `numberBurned += 1`. // // We can directly decrement the balance, and increment the number burned. // This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`. _packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1; // Updates: // - `address` to the last owner. // - `startTimestamp` to the timestamp of burning. // - `burned` to `true`. // - `nextInitialized` to `true`. _packedOwnerships[tokenId] = _packOwnershipData( from, (_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked) ); // If the next slot may not have been initialized (i.e. `nextInitialized == false`) . if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) { uint256 nextTokenId = tokenId + 1; // If the next slot's address is zero and not burned (i.e. packed value is zero). if (_packedOwnerships[nextTokenId] == 0) { // If the next slot is within bounds. if (nextTokenId != _currentIndex) { // Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`. _packedOwnerships[nextTokenId] = prevOwnershipPacked; } } } } emit Transfer(from, address(0), tokenId); _afterTokenTransfers(from, address(0), tokenId, 1); // Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times. unchecked { _burnCounter++; } } // ============================================================= // EXTRA DATA OPERATIONS // ============================================================= /** * @dev Directly sets the extra data for the ownership data `index`. */ function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual { uint256 packed = _packedOwnerships[index]; if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector); uint256 extraDataCasted; // Cast `extraData` with assembly to avoid redundant masking. assembly { extraDataCasted := extraData } packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA); _packedOwnerships[index] = packed; } /** * @dev Called during each token transfer to set the 24bit `extraData` field. * Intended to be overridden by the cosumer contract. * * `previousExtraData` - the value of `extraData` before transfer. * * Calling conditions: * * - When `from` and `to` are both non-zero, `from`'s `tokenId` will be * transferred to `to`. * - When `from` is zero, `tokenId` will be minted for `to`. * - When `to` is zero, `tokenId` will be burned by `from`. * - `from` and `to` are never both zero. */ function _extraData( address from, address to, uint24 previousExtraData ) internal view virtual returns (uint24) {} /** * @dev Returns the next extra data for the packed ownership data. * The returned result is shifted into position. */ function _nextExtraData( address from, address to, uint256 prevOwnershipPacked ) private view returns (uint256) { uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA); return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA; } // ============================================================= // OTHER OPERATIONS // ============================================================= /** * @dev Returns the message sender (defaults to `msg.sender`). * * If you are writing GSN compatible contracts, you need to override this function. */ function _msgSenderERC721A() internal view virtual returns (address) { return msg.sender; } /** * @dev Converts a uint256 to its ASCII string decimal representation. */ function _toString(uint256 value) internal pure virtual returns (string memory str) { assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0. let m := add(mload(0x40), 0xa0) // Update the free memory pointer to allocate. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. // prettier-ignore for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) // prettier-ignore if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /** * @dev For more efficient reverts. */ function _revert(bytes4 errorSelector) internal pure { assembly { mstore(0x00, errorSelector) revert(0x00, 0x04) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC2981 NFT Royalty Standard implementation. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol) abstract contract ERC2981 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The royalty fee numerator exceeds the fee denominator. error RoyaltyOverflow(); /// @dev The royalty receiver cannot be the zero address. error RoyaltyReceiverIsZeroAddress(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The default royalty info is given by: /// ``` /// let packed := sload(_ERC2981_MASTER_SLOT_SEED) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` /// /// The per token royalty info is given by. /// ``` /// mstore(0x00, tokenId) /// mstore(0x20, _ERC2981_MASTER_SLOT_SEED) /// let packed := sload(keccak256(0x00, 0x40)) /// let receiver := shr(96, packed) /// let royaltyFraction := xor(packed, shl(96, receiver)) /// ``` uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC2981 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Checks that `_feeDenominator` is non-zero. constructor() { require(_feeDenominator() != 0, "Fee denominator cannot be zero."); } /// @dev Returns the denominator for the royalty amount. /// Defaults to 10000, which represents fees in basis points. /// Override this function to return a custom amount if needed. function _feeDenominator() internal pure virtual returns (uint96) { return 10000; } /// @dev Returns true if this contract implements the interface defined by `interfaceId`. /// See: https://eips.ethereum.org/EIPS/eip-165 /// This function call must use less than 30000 gas. function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { let s := shr(224, interfaceId) // ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a. result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a)) } } /// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`. function royaltyInfo(uint256 tokenId, uint256 salePrice) public view virtual returns (address receiver, uint256 royaltyAmount) { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) let packed := sload(keccak256(0x00, 0x40)) receiver := shr(96, packed) if iszero(receiver) { packed := sload(mload(0x20)) receiver := shr(96, packed) } let x := salePrice let y := xor(packed, shl(96, receiver)) // `feeNumerator`. // Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`. // Out-of-gas revert. Should not be triggered in practice, but included for safety. returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y)))) royaltyAmount := div(mul(x, y), feeDenominator) } } /// @dev Sets the default royalty `receiver` and `feeNumerator`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator)) } } /// @dev Sets the default royalty `receiver` and `feeNumerator` to zero. function _deleteDefaultRoyalty() internal virtual { /// @solidity memory-safe-assembly assembly { sstore(_ERC2981_MASTER_SLOT_SEED, 0) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`. /// /// Requirements: /// - `receiver` must not be the zero address. /// - `feeNumerator` must not be greater than the fee denominator. function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual { uint256 feeDenominator = _feeDenominator(); /// @solidity memory-safe-assembly assembly { feeNumerator := shr(160, shl(160, feeNumerator)) if gt(feeNumerator, feeDenominator) { mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`. revert(0x1c, 0x04) } let packed := shl(96, receiver) if iszero(packed) { mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`. revert(0x1c, 0x04) } mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), or(packed, feeNumerator)) } } /// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero. function _resetTokenRoyalty(uint256 tokenId) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, tokenId) mstore(0x20, _ERC2981_MASTER_SLOT_SEED) sstore(keccak256(0x00, 0x40), 0) } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable2Step.sol) pragma solidity ^0.8.20; import {Ownable} from "./Ownable.sol"; /** * @dev Contract module which provides access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * This extension of the {Ownable} contract includes a two-step mechanism to transfer * ownership, where the new owner must call {acceptOwnership} in order to replace the * old one. This can help prevent common mistakes, such as transfers of ownership to * incorrect accounts, or to contracts that are unable to interact with the * permission system. * * The initial owner is specified at deployment time in the constructor for `Ownable`. This * can later be changed with {transferOwnership} and {acceptOwnership}. * * This module is used through inheritance. It will make available all functions * from parent (Ownable). */ abstract contract Ownable2Step is Ownable { address private _pendingOwner; event OwnershipTransferStarted(address indexed previousOwner, address indexed newOwner); /** * @dev Returns the address of the pending owner. */ function pendingOwner() public view virtual returns (address) { return _pendingOwner; } /** * @dev Starts the ownership transfer of the contract to a new account. Replaces the pending transfer if there is one. * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual override onlyOwner { _pendingOwner = newOwner; emit OwnershipTransferStarted(owner(), newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`) and deletes any pending owner. * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual override { delete _pendingOwner; super._transferOwnership(newOwner); } /** * @dev The new owner accepts the ownership transfer. */ function acceptOwnership() public virtual { address sender = _msgSender(); if (pendingOwner() != sender) { revert OwnableUnauthorizedAccount(sender); } _transferOwnership(sender); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `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) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Gas optimized verification of proof of inclusion for a leaf in a Merkle tree. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/MerkleProofLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/MerkleProof.sol) library MerkleProofLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* MERKLE PROOF VERIFICATION OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verify(bytes32[] memory proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if mload(proof) { // Initialize `offset` to the offset of `proof` elements in memory. let offset := add(proof, 0x20) // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(offset, shl(5, mload(proof))) // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, mload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), mload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether `leaf` exists in the Merkle tree with `root`, given `proof`. function verifyCalldata(bytes32[] calldata proof, bytes32 root, bytes32 leaf) internal pure returns (bool isValid) { /// @solidity memory-safe-assembly assembly { if proof.length { // Left shift by 5 is equivalent to multiplying by 0x20. let end := add(proof.offset, shl(5, proof.length)) // Initialize `offset` to the offset of `proof` in the calldata. let offset := proof.offset // Iterate over proof elements to compute root hash. for {} 1 {} { // Slot of `leaf` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(leaf, calldataload(offset))) // Store elements to hash contiguously in scratch space. // Scratch space is 64 bytes (0x00 - 0x3f) and both elements are 32 bytes. mstore(scratch, leaf) mstore(xor(scratch, 0x20), calldataload(offset)) // Reuse `leaf` to store the hash to reduce stack operations. leaf := keccak256(0x00, 0x40) offset := add(offset, 0x20) if iszero(lt(offset, end)) { break } } } isValid := eq(leaf, root) } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - The sum of the lengths of `proof` and `leaves` must never overflow. /// - Any non-zero word in the `flags` array is treated as true. /// - The memory offset of `proof` must be non-zero /// (i.e. `proof` is not pointing to the scratch space). function verifyMultiProof( bytes32[] memory proof, bytes32 root, bytes32[] memory leaves, bool[] memory flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // Cache the lengths of the arrays. let leavesLength := mload(leaves) let proofLength := mload(proof) let flagsLength := mload(flags) // Advance the pointers of the arrays to point to the data. leaves := add(0x20, leaves) proof := add(0x20, proof) flags := add(0x20, flags) // If the number of flags is correct. for {} eq(add(leavesLength, proofLength), add(flagsLength, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flagsLength) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. isValid := eq(mload(xor(leaves, mul(xor(proof, leaves), proofLength))), root) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof, shl(5, proofLength)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. leavesLength := shl(5, leavesLength) for { let i := 0 } iszero(eq(i, leavesLength)) { i := add(i, 0x20) } { mstore(add(hashesFront, i), mload(add(leaves, i))) } // Compute the back of the hashes. let hashesBack := add(hashesFront, leavesLength) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flagsLength := add(hashesBack, shl(5, flagsLength)) for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(mload(flags)) { // Loads the next proof. b := mload(proof) proof := add(proof, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag. flags := add(flags, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flagsLength)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof) ) break } } } /// @dev Returns whether all `leaves` exist in the Merkle tree with `root`, /// given `proof` and `flags`. /// /// Note: /// - Breaking the invariant `flags.length == (leaves.length - 1) + proof.length` /// will always return false. /// - Any non-zero word in the `flags` array is treated as true. /// - The calldata offset of `proof` must be non-zero /// (i.e. `proof` is from a regular Solidity function with a 4-byte selector). function verifyMultiProofCalldata( bytes32[] calldata proof, bytes32 root, bytes32[] calldata leaves, bool[] calldata flags ) internal pure returns (bool isValid) { // Rebuilds the root by consuming and producing values on a queue. // The queue starts with the `leaves` array, and goes into a `hashes` array. // After the process, the last element on the queue is verified // to be equal to the `root`. // // The `flags` array denotes whether the sibling // should be popped from the queue (`flag == true`), or // should be popped from the `proof` (`flag == false`). /// @solidity memory-safe-assembly assembly { // If the number of flags is correct. for {} eq(add(leaves.length, proof.length), add(flags.length, 1)) {} { // For the case where `proof.length + leaves.length == 1`. if iszero(flags.length) { // `isValid = (proof.length == 1 ? proof[0] : leaves[0]) == root`. // forgefmt: disable-next-item isValid := eq( calldataload( xor(leaves.offset, mul(xor(proof.offset, leaves.offset), proof.length)) ), root ) break } // The required final proof offset if `flagsLength` is not zero, otherwise zero. let proofEnd := add(proof.offset, shl(5, proof.length)) // We can use the free memory space for the queue. // We don't need to allocate, since the queue is temporary. let hashesFront := mload(0x40) // Copy the leaves into the hashes. // Sometimes, a little memory expansion costs less than branching. // Should cost less, even with a high free memory offset of 0x7d00. calldatacopy(hashesFront, leaves.offset, shl(5, leaves.length)) // Compute the back of the hashes. let hashesBack := add(hashesFront, shl(5, leaves.length)) // This is the end of the memory for the queue. // We recycle `flagsLength` to save on stack variables (sometimes save gas). flags.length := add(hashesBack, shl(5, flags.length)) // We don't need to make a copy of `proof.offset` or `flags.offset`, // as they are pass-by-value (this trick may not always save gas). for {} 1 {} { // Pop from `hashes`. let a := mload(hashesFront) // Pop from `hashes`. let b := mload(add(hashesFront, 0x20)) hashesFront := add(hashesFront, 0x40) // If the flag is false, load the next proof, // else, pops from the queue. if iszero(calldataload(flags.offset)) { // Loads the next proof. b := calldataload(proof.offset) proof.offset := add(proof.offset, 0x20) // Unpop from `hashes`. hashesFront := sub(hashesFront, 0x20) } // Advance to the next flag offset. flags.offset := add(flags.offset, 0x20) // Slot of `a` in scratch space. // If the condition is true: 0x20, otherwise: 0x00. let scratch := shl(5, gt(a, b)) // Hash the scratch space and push the result onto the queue. mstore(scratch, a) mstore(xor(scratch, 0x20), b) mstore(hashesBack, keccak256(0x00, 0x40)) hashesBack := add(hashesBack, 0x20) if iszero(lt(hashesBack, flags.length)) { break } } isValid := and( // Checks if the last value in the queue is same as the root. eq(mload(sub(hashesBack, 0x20)), root), // And whether all the proofs are used, if required. eq(proofEnd, proof.offset) ) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes32 array. function emptyProof() internal pure returns (bytes32[] calldata proof) { /// @solidity memory-safe-assembly assembly { proof.length := 0 } } /// @dev Returns an empty calldata bytes32 array. function emptyLeaves() internal pure returns (bytes32[] calldata leaves) { /// @solidity memory-safe-assembly assembly { leaves.length := 0 } } /// @dev Returns an empty calldata bool array. function emptyFlags() internal pure returns (bool[] calldata flags) { /// @solidity memory-safe-assembly assembly { flags.length := 0 } } }
pragma solidity ^0.8.20; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast { // configure function configureContract( address contractAddress, YieldMode _yield, GasMode gasMode, address governor ) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; function isAuthorized(address contractAddress) external returns (bool); // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate( address contractAddress, address recipientOfGas, uint256 minClaimRateBips ) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas( address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume ) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
pragma solidity ^0.8.20; interface IBlastPoints { function configurePointsOperator(address operator) external; function configurePointsOperatorOnBehalf(address contractAddress, address operator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice Emitted when `baseURI` is empty or `protocolFee` is above `MAX_BPS`. error InvalidParams(); /// @notice Emitted when the phase end is before the start. error InvalidWhitelistPhases(); /// @notice Emitted when the `lockupPeriod` value is not valid. error InvalidLockupPeriod(); /// @notice Emitted if the `_tokenId` for `tokenURI()` does not exist. error TokenDoesNotExist(); /// @notice Emitted if the public mint hasn't started or has already ended. error MintNotActive(); /// @notice Emitted if the whitelist phase hasn't started or has already ended. error WhitelistPhaseNotActive(); /// @notice Emitted if the amount for `mint()` or `whitelistMint()` would exceed the /// `maxSupply`. error MaxSupplyReached(); /// @notice Emitted if `_amount` for `mint()` exceeds the maximum amount mintable per tx. error MaxMintsReached(); /// @notice Emitted if `_amount` for `whitelistMint()` exceeds the maximum amount mintable /// per tx. error MaxWhitelistMintsReached(); /// @notice Emitted if the caller to `mint()` would exceed the max mints per address. error MaxTotalMintsReached(); /// @notice Emitted if the caller to `whitelistMint()` would exceed the max mints per /// address. error MaxTotalWhitelistMintsReached(); /// @notice Emitted when calls to withdraw funds fail. error WithdrawalFailed(); /// @notice Emitted if `msg.value` is too low in `mint()` or `whitelistMint()` or if /// the amount to `claimYield()` is too high. error InsufficientFunds(); /// @notice Emitted if the `_merkleProof` provided to `whitelistMint()` is invalid. error InvalidMerkleProof(); /// @notice Emitted if a function is called for an invalid mint mode. error InvalidMode(); /// @notice Emittted if the `_tokenId` for `refund()` was minted to the owner. error NonRefundable(); /// @notice Emitted if the lockup period for the refund has not ended. error LockupIncomplete(); /// @notice Emitted if the `_tokenId` for `refund()` has already been refunded. error RefundRenounced(); /// @notice Emitted if the `_tokenId` for `renounceRefund()` was minted to the owner. error NonRenounceable(); /// @notice Emitted if the caller to `renounceRefund()` is not the token owner. error Unauthorized(); /// @notice Emitted if the `_tokenId` for `renounceRefund()` has already been refunded. error Refunded(); /// @notice Emitted if `baseURI` has been locked. error BaseURILocked(); /// @notice Emitted if `contractURI` has been locked. error ContractURILocked(); /// @notice Emitted if a new max supply would be lower than present total supply. error InvalidMaxSupply(); /// @notice Emitted if `royaltyLocked` is true. error RoyaltyParamsLocked(); /// @notice Emitted if the default royalty is too high in 'setRoyaltyParams()` error InvalidDefaultRoyalty(); /// @notice Emitted if setters affecting mints are called while minting is live. error MintingActive();
// SPDX-License-Identifier: MIT pragma solidity ^0.8.23; /// @notice Struct for a single mint phase. /// @param start Timestamp for the phase's start. /// @param end Timestamp for the phase's end. /// @param whitelistMintPrice Price for a whitelist mint in wei. /// @param maxWhitelistMintsPerCall Maximum amount of whitelist mints in one call. /// @param maxTotalWhitelistMints Maximum amount of whitelist mints per address. /// @param merkleRoot Root hash for the merkle tree. struct WhitelistPhase { uint256 start; uint256 end; uint120 whitelistMintPrice; uint64 maxWhitelistMintsPerCall; uint64 maxTotalWhitelistMints; bytes32 merkleRoot; } /// @notice The configuration paramater storage of the contract. /// @param baseURI The base URI for the token URIs. /// @param contractURI The URI for the contract's metadata. /// @param mintsToOwner The amount the owner mints to themselves. /// @param maxSupply The maximum amount of tokens that can be minted. /// @param start Timestamp for the public mint's start. /// @param end Timestamp for the public mint's end. /// @param mintPrice Price for a mint in wei. /// @param maxMintsPerCall Maximum amount of mints in one call. /// @param maxTotalMints Maximum amount of mints per address. /// @param defaultRoyalty The default royalty percentage. /// @param royaltyReceiver The address that receives the royalties. /// @param whitelistPhases Array of up to three WhitelistPhase's. struct Params { string baseURI; string contractURI; uint256 mintsToOwner; uint256 maxSupply; uint256 start; uint256 end; uint120 mintPrice; uint64 maxMintsPerCall; uint64 maxTotalMints; uint16 defaultRoyalty; address royaltyReceiver; WhitelistPhase[] whitelistPhases; } /// @notice The locks for the contract. /// @param baseURILocked If the `baseURI` is locked. /// @param contractURILocked If the `contractURI` is locked. /// @param royaltyParamsLocked If the default royalty is locked. struct Locks { bool baseURILocked; bool contractURILocked; bool royaltyParamsLocked; } uint16 constant MAX_BPS = 5000; // 50% uint16 constant MAX_ROYALTY = 2000; // 20% address constant POINTS_OPERATOR = 0xf8a82748e7DF10D0684B758d02cF6c43AD83AD25; address constant PROTOCOL_RECEIVER = 0xa804b7d57a4A872dbfbE2987347403039aDe20dC; address constant BLAST_PYTH = 0xA2aa501b19aff244D90cc15a4Cf739D2725B5729; bytes32 constant ETHUSD_PRICE_FEED = 0xff61491a931112ddf1bd8147cd1b641375f79f5825126d665480874634fd0ace;
// SPDX-License-Identifier: MIT // ERC721A Contracts v4.3.0 // Creator: Chiru Labs pragma solidity ^0.8.4; /** * @dev Interface of ERC721A. */ interface IERC721A { /** * The caller must own the token or be an approved operator. */ error ApprovalCallerNotOwnerNorApproved(); /** * The token does not exist. */ error ApprovalQueryForNonexistentToken(); /** * Cannot query the balance for the zero address. */ error BalanceQueryForZeroAddress(); /** * Cannot mint to the zero address. */ error MintToZeroAddress(); /** * The quantity of tokens minted must be more than zero. */ error MintZeroQuantity(); /** * The token does not exist. */ error OwnerQueryForNonexistentToken(); /** * The caller must own the token or be an approved operator. */ error TransferCallerNotOwnerNorApproved(); /** * The token must be owned by `from`. */ error TransferFromIncorrectOwner(); /** * Cannot safely transfer to a contract that does not implement the * ERC721Receiver interface. */ error TransferToNonERC721ReceiverImplementer(); /** * Cannot transfer to the zero address. */ error TransferToZeroAddress(); /** * The token does not exist. */ error URIQueryForNonexistentToken(); /** * The `quantity` minted with ERC2309 exceeds the safety limit. */ error MintERC2309QuantityExceedsLimit(); /** * The `extraData` cannot be set on an unintialized ownership slot. */ error OwnershipNotInitializedForExtraData(); /** * `_sequentialUpTo()` must be greater than `_startTokenId()`. */ error SequentialUpToTooSmall(); /** * The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`. */ error SequentialMintExceedsLimit(); /** * Spot minting requires a `tokenId` greater than `_sequentialUpTo()`. */ error SpotMintTokenIdTooSmall(); /** * Cannot mint over a token that already exists. */ error TokenAlreadyExists(); /** * The feature is not compatible with spot mints. */ error NotCompatibleWithSpotMints(); // ============================================================= // STRUCTS // ============================================================= struct TokenOwnership { // The address of the owner. address addr; // Stores the start time of ownership with minimal overhead for tokenomics. uint64 startTimestamp; // Whether the token has been burned. bool burned; // Arbitrary data similar to `startTimestamp` that can be set via {_extraData}. uint24 extraData; } // ============================================================= // TOKEN COUNTERS // ============================================================= /** * @dev Returns the total number of tokens in existence. * Burned tokens will reduce the count. * To get the total number of tokens minted, please see {_totalMinted}. */ function totalSupply() external view returns (uint256); // ============================================================= // IERC165 // ============================================================= /** * @dev Returns true if this contract implements the interface defined by * `interfaceId`. See the corresponding * [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified) * to learn more about how these ids are created. * * This function call must use less than 30000 gas. */ function supportsInterface(bytes4 interfaceId) external view returns (bool); // ============================================================= // IERC721 // ============================================================= /** * @dev Emitted when `tokenId` token is transferred from `from` to `to`. */ event Transfer(address indexed from, address indexed to, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token. */ event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId); /** * @dev Emitted when `owner` enables or disables * (`approved`) `operator` to manage all of its assets. */ event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /** * @dev Returns the number of tokens in `owner`'s account. */ function balanceOf(address owner) external view returns (uint256 balance); /** * @dev Returns the owner of the `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function ownerOf(uint256 tokenId) external view returns (address owner); /** * @dev Safely transfers `tokenId` token from `from` to `to`, * checking first that contract recipients are aware of the ERC721 protocol * to prevent tokens from being forever locked. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must exist and be owned by `from`. * - If the caller is not `from`, it must be have been allowed to move * this token by either {approve} or {setApprovalForAll}. * - If `to` refers to a smart contract, it must implement * {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. * * Emits a {Transfer} event. */ function safeTransferFrom( address from, address to, uint256 tokenId, bytes calldata data ) external payable; /** * @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`. */ function safeTransferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Transfers `tokenId` from `from` to `to`. * * WARNING: Usage of this method is discouraged, use {safeTransferFrom} * whenever possible. * * Requirements: * * - `from` cannot be the zero address. * - `to` cannot be the zero address. * - `tokenId` token must be owned by `from`. * - If the caller is not `from`, it must be approved to move this token * by either {approve} or {setApprovalForAll}. * * Emits a {Transfer} event. */ function transferFrom( address from, address to, uint256 tokenId ) external payable; /** * @dev Gives permission to `to` to transfer `tokenId` token to another account. * The approval is cleared when the token is transferred. * * Only a single account can be approved at a time, so approving the * zero address clears previous approvals. * * Requirements: * * - The caller must own the token or be an approved operator. * - `tokenId` must exist. * * Emits an {Approval} event. */ function approve(address to, uint256 tokenId) external payable; /** * @dev Approve or remove `operator` as an operator for the caller. * Operators can call {transferFrom} or {safeTransferFrom} * for any token owned by the caller. * * Requirements: * * - The `operator` cannot be the caller. * * Emits an {ApprovalForAll} event. */ function setApprovalForAll(address operator, bool _approved) external; /** * @dev Returns the account approved for `tokenId` token. * * Requirements: * * - `tokenId` must exist. */ function getApproved(uint256 tokenId) external view returns (address operator); /** * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`. * * See {setApprovalForAll}. */ function isApprovedForAll(address owner, address operator) external view returns (bool); // ============================================================= // IERC721Metadata // ============================================================= /** * @dev Returns the token collection name. */ function name() external view returns (string memory); /** * @dev Returns the token collection symbol. */ function symbol() external view returns (string memory); /** * @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token. */ function tokenURI(uint256 tokenId) external view returns (string memory); // ============================================================= // IERC2309 // ============================================================= /** * @dev Emitted when tokens in `fromTokenId` to `toTokenId` * (inclusive) is transferred from `from` to `to`, as defined in the * [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard. * * See {_mintERC2309} for more details. */ event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.0) (access/Ownable.sol) pragma solidity ^0.8.20; import {Context} from "../utils/Context.sol"; /** * @dev Contract module which provides a basic access control mechanism, where * there is an account (an owner) that can be granted exclusive access to * specific functions. * * The initial owner is set to the address provided by the deployer. This can * later be changed with {transferOwnership}. * * This module is used through inheritance. It will make available the modifier * `onlyOwner`, which can be applied to your functions to restrict their use to * the owner. */ abstract contract Ownable is Context { address private _owner; /** * @dev The caller account is not authorized to perform an operation. */ error OwnableUnauthorizedAccount(address account); /** * @dev The owner is not a valid owner account. (eg. `address(0)`) */ error OwnableInvalidOwner(address owner); event OwnershipTransferred(address indexed previousOwner, address indexed newOwner); /** * @dev Initializes the contract setting the address provided by the deployer as the initial owner. */ constructor(address initialOwner) { if (initialOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(initialOwner); } /** * @dev Throws if called by any account other than the owner. */ modifier onlyOwner() { _checkOwner(); _; } /** * @dev Returns the address of the current owner. */ function owner() public view virtual returns (address) { return _owner; } /** * @dev Throws if the sender is not the owner. */ function _checkOwner() internal view virtual { if (owner() != _msgSender()) { revert OwnableUnauthorizedAccount(_msgSender()); } } /** * @dev Leaves the contract without owner. It will not be possible to call * `onlyOwner` functions. Can only be called by the current owner. * * NOTE: Renouncing ownership will leave the contract without an owner, * thereby disabling any functionality that is only available to the owner. */ function renounceOwnership() public virtual onlyOwner { _transferOwnership(address(0)); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Can only be called by the current owner. */ function transferOwnership(address newOwner) public virtual onlyOwner { if (newOwner == address(0)) { revert OwnableInvalidOwner(address(0)); } _transferOwnership(newOwner); } /** * @dev Transfers ownership of the contract to a new account (`newOwner`). * Internal function without access restriction. */ function _transferOwnership(address newOwner) internal virtual { address oldOwner = _owner; _owner = newOwner; emit OwnershipTransferred(oldOwner, newOwner); } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v5.0.1) (utils/Context.sol) pragma solidity ^0.8.20; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } function _contextSuffixLength() internal view virtual returns (uint256) { return 0; } }
{ "remappings": [ "ERC721A/=lib/ERC721A/contracts/", "gaslite-core/=lib/gaslite-core/src/", "multicall/=lib/multicall/src/", "@murky/=lib/murky/src/", "@openzeppelin/=lib/openzeppelin-contracts/contracts/", "@pythnetwork/pyth-sdk-solidity/=node_modules/@pythnetwork/pyth-sdk-solidity/", "@solady/=lib/solady/src/", "@ERC721A/=lib/gaslite-core/lib/ERC721A/", "@openzeppelin/contracts/=lib/openzeppelin-contracts/contracts/", "ds-test/=lib/forge-std/lib/ds-test/src/", "erc4626-tests/=lib/openzeppelin-contracts/lib/erc4626-tests/", "forge-std/=lib/forge-std/src/", "murky/=lib/murky/", "openzeppelin-contracts/=lib/openzeppelin-contracts/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "shanghai", "viaIR": true, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"components":[{"internalType":"string","name":"baseURI","type":"string"},{"internalType":"string","name":"contractURI","type":"string"},{"internalType":"uint256","name":"mintsToOwner","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"mintPrice","type":"uint120"},{"internalType":"uint64","name":"maxMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalMints","type":"uint64"},{"internalType":"uint16","name":"defaultRoyalty","type":"uint16"},{"internalType":"address","name":"royaltyReceiver","type":"address"},{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"whitelistMintPrice","type":"uint120"},{"internalType":"uint64","name":"maxWhitelistMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalWhitelistMints","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct WhitelistPhase[]","name":"whitelistPhases","type":"tuple[]"}],"internalType":"struct Params","name":"_params","type":"tuple"},{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"BaseURILocked","type":"error"},{"inputs":[],"name":"ContractURILocked","type":"error"},{"inputs":[],"name":"InsufficientFunds","type":"error"},{"inputs":[],"name":"InvalidDefaultRoyalty","type":"error"},{"inputs":[],"name":"InvalidMaxSupply","type":"error"},{"inputs":[],"name":"InvalidMerkleProof","type":"error"},{"inputs":[],"name":"InvalidParams","type":"error"},{"inputs":[],"name":"InvalidWhitelistPhases","type":"error"},{"inputs":[],"name":"MaxSupplyReached","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintNotActive","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"MintingActive","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"OwnableInvalidOwner","type":"error"},{"inputs":[{"internalType":"address","name":"account","type":"address"}],"name":"OwnableUnauthorizedAccount","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyParamsLocked","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","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":"WhitelistPhaseNotActive","type":"error"},{"inputs":[],"name":"WithdrawalFailed","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":[],"name":"BaseURIUpdated","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":[],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newMaxSupply","type":"uint256"}],"name":"MaxSupplyUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferStarted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"_royaltyReceiver","type":"address"},{"indexed":false,"internalType":"uint16","name":"_defaultRoyalty","type":"uint16"}],"name":"RoyaltyParamsUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"StopMint","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":"acceptOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"claimYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockRoyaltyParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"locks","outputs":[{"internalType":"bool","name":"baseURILocked","type":"bool"},{"internalType":"bool","name":"contractURILocked","type":"bool"},{"internalType":"bool","name":"royaltyParamsLocked","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes[]","name":"_calls","type":"bytes[]"}],"name":"ownerBatch","outputs":[{"internalType":"bytes[]","name":"results","type":"bytes[]"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"params","outputs":[{"internalType":"string","name":"baseURI","type":"string"},{"internalType":"string","name":"contractURI","type":"string"},{"internalType":"uint256","name":"mintsToOwner","type":"uint256"},{"internalType":"uint256","name":"maxSupply","type":"uint256"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"mintPrice","type":"uint120"},{"internalType":"uint64","name":"maxMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalMints","type":"uint64"},{"internalType":"uint16","name":"defaultRoyalty","type":"uint16"},{"internalType":"address","name":"royaltyReceiver","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"pendingOwner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_baseUri","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_contractURI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"_newMaxSupply","type":"uint256"}],"name":"setMaxSupply","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint120","name":"_mintPrice","type":"uint120"}],"name":"setMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_royaltyReceiver","type":"address"},{"internalType":"uint16","name":"_defaultRoyalty","type":"uint16"}],"name":"setRoyaltyParams","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_phase","type":"uint8"},{"internalType":"uint120","name":"_whitelistMintPrice","type":"uint120"}],"name":"setWhitelistMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"stopMint","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":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"transferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint8","name":"_phase","type":"uint8"},{"internalType":"bytes32[]","name":"_merkleProof","type":"bytes32[]"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"whitelistMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"whitelistPhases","outputs":[{"components":[{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"end","type":"uint256"},{"internalType":"uint120","name":"whitelistMintPrice","type":"uint120"},{"internalType":"uint64","name":"maxWhitelistMintsPerCall","type":"uint64"},{"internalType":"uint64","name":"maxTotalWhitelistMints","type":"uint64"},{"internalType":"bytes32","name":"merkleRoot","type":"bytes32"}],"internalType":"struct WhitelistPhase[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"_amount","type":"uint256"}],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60808060405234620001a457620034f29081380380926200002082620001bc565b8239818101818312620001a45781516001600160401b0393909290848411620001a45783906101809182910312620001a4576200005c6200023d565b9380830151868111620001a457848462000079928401016200025e565b855260a0810151868111620001a457848462000098928401016200025e565b602086015260c0810151604086015260e0810151606086015261010080820151848701526101208083015160a088015261014091620000d9838501620002d2565b60c08901526200010061016095620000f3878701620002e7565b60e08b01528501620002e7565b90880152620001136101a08401620002fc565b90870152620001266101c0830162000323565b908601526101e0810151868111620001a4578385916200014893010162000338565b9084015260a051848111620001a45782620001659183016200025e565b9160c051948511620001a45762000194946200018292016200025e565b906200018d6200030c565b9262000b20565b60405161242c9081620010a68239f35b5f80fd5b634e487b7160e01b5f52604160045260245ffd5b6080601f91909101601f19168101906001600160401b03821190821017620001e357604052565b620001a8565b60c081019081106001600160401b03821117620001e357604052565b6001600160401b038111620001e357604052565b601f909101601f19168101906001600160401b03821190821017620001e357604052565b6040519061018082016001600160401b03811183821017620001e357604052565b919080601f84011215620001a45782516001600160401b038111620001e357602090604051926200029983601f19601f850116018562000219565b818452828287010111620001a4575f5b818110620002be5750825f9394955001015290565b8581018301518482018401528201620002a9565b51906001600160781b0382168203620001a457565b51906001600160401b0382168203620001a457565b519061ffff82168203620001a457565b60e051906001600160a01b0382168203620001a457565b51906001600160a01b0382168203620001a457565b81601f82011215620001a45780519060206001600160401b038311620001e3576040936040519462000370838660051b018762000219565b848652828601918360c080970286010194818611620001a4578401925b8584106200039f575050505050505090565b8684830312620001a4578487918451620003b981620001e9565b865181528287015183820152620003d2868801620002d2565b868201526060620003e5818901620002e7565b908201526080620003f8818901620002e7565b9082015260a080880151908201528152019301926200038d565b5f910312620001a457565b6040513d5f823e3d90fd5b60405190602082016001600160401b03811183821017620001e3576040525f8252565b90600182811c921680156200047b575b60208310146200046757565b634e487b7160e01b5f52602260045260245ffd5b91607f16916200045b565b601f811162000493575050565b60025f5260205f20906020601f840160051c83019310620004d0575b601f0160051c01905b818110620004c4575050565b5f8155600101620004b8565b9091508190620004af565b601f8111620004e8575050565b60035f5260205f20906020601f840160051c8301931062000525575b601f0160051c01905b81811062000519575050565b5f81556001016200050d565b909150819062000504565b601f81116200053d575050565b600b5f5260205f20906020601f840160051c830193106200057a575b601f0160051c01905b8181106200056e575050565b5f815560010162000562565b909150819062000559565b601f811162000592575050565b600c5f5260205f20906020601f840160051c83019310620005cf575b601f0160051c01905b818110620005c3575050565b5f8155600101620005b7565b9091508190620005ae565b80519091906001600160401b038111620001e3576200060681620006006003546200044b565b620004db565b602080601f83116001146200064b575081906200063a93945f926200063f575b50508160011b915f199060031b1c19161790565b600355565b015190505f8062000626565b60035f52601f198316949091907fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b925f905b878210620006b75750508360019596106200069e575b505050811b01600355565b01515f1960f88460031b161c191690555f808062000693565b806001859682949686015181550195019301906200067d565b80519091906001600160401b038111620001e357620006fc81620006f6600b546200044b565b62000530565b602080601f831160011462000734575081906200072f93945f926200063f5750508160011b915f199060031b1c19161790565b600b55565b600b5f52601f198316949091907f0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9925f905b878210620007a057505083600195961062000787575b505050811b01600b55565b01515f1960f88460031b161c191690555f80806200077c565b8060018596829496860151815501950193019062000766565b80519091906001600160401b038111620001e357620007e581620007df600c546200044b565b62000585565b602080601f83116001146200081d575081906200081893945f926200063f5750508160011b915f199060031b1c19161790565b600c55565b600c5f52601f198316949091907fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7925f905b8782106200088957505083600195961062000870575b505050811b01600c55565b01515f1960f88460031b161c191690555f808062000865565b806001859682949686015181550195019301906200084f565b600281901b91906001600160fe1b03811603620008bb57565b634e487b7160e01b5f52601160045260245ffd5b805190680100000000000000008211620001e357601354826013558083106200099d575b5060135f526020908101905f80516020620034d28339815191525f925b8484106200091f575050505050565b600483826200099060019451869060a060039180518455602081015160018501556002840160018060781b03604083015116815490600160781b600160b81b03606085015160781b1690600160b81b600160f81b03608086015160b81b169260ff60f81b1617171790550151910155565b0192019301929062000910565b620009a890620008a2565b620009b383620008a2565b60135f525f80516020620034d283398151915291820191015b818110620009db5750620008f3565b805f600492555f60018201555f60028201555f600382015501620009cc565b61016062000b1e9162000a0e8151620006d0565b62000a1d6020820151620007b9565b6040810151600d556060810151600e556080810151600f5560a081015160105560c08101516011805460e084015161010085015160789190911b600160781b600160b81b03166001600160781b039094167fff00000000000000000000000000000000000000000000000000000000000000909216919091179290921760b89290921b600160b81b600160f81b031691909117905562000ad962000ac761012083015161ffff1690565b61ffff1661ffff196012541617601255565b61014081015162000b16906001600160a01b03166012805462010000600160b01b03191660109290921b62010000600160b01b0316919091179055565b0151620008cf565b565b929162000b2e918362000cdc565b734300000000000000000000000000000000000002803b15620001a4575f809160046040518094819363388a0bbd60e11b83525af1801562000cbf5762000cc5575b50732536fe9ab3f511540f2f9e2ec2a805005c3dd800803b15620001a4576040516336b91f2b60e01b815273f8a82748e7df10d0684b758d02cf6c43ad83ad256004820152905f908290602490829084905af1801562000cbf5762000ca1575b5081516020815191012062000be462000428565b6020815191012014801562000c81575b62000c6f5761014082015162000b1e9261016092909162000c3b906001600160a01b031662000c3462000c2d61012086015161ffff1690565b61ffff1690565b9062000e14565b60408201518062000c5c575b505062000c5481620009fa565b015162000f68565b62000c679162000e5c565b5f8062000c47565b604051635435b28960e11b8152600490fd5b506107d061ffff62000c9961012085015161ffff1690565b161162000bf4565b8062000cb162000cb89262000205565b8062000412565b5f62000bd0565b6200041d565b8062000cb162000cd59262000205565b5f62000b70565b815191939290916001600160401b038111620001e35762000d0a8162000d046002546200044b565b62000486565b602080601f831160011462000d825750908062000d439262000d4c9596975f926200063f5750508160011b915f199060031b1c19161790565b600255620005da565b5f80556001600160a01b0381161562000d6a5762000b1e9062001044565b604051631e4fbdf760e01b81525f6004820152602490fd5b60025f52601f198316969091907f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace925f905b89821062000dfb5750509083929160019462000d4c9798991062000de2575b505050811b01600255620005da565b01515f1960f88460031b161c191690555f808062000dd3565b8060018596829496860151815501950193019062000db4565b6001600160601b0390911690612710821162000e4f5760601b801562000e42571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b905f5491811562000f305760019162000eb360018060a01b038316926001831460e11b4260a01b17841762000e99875f52600460205260405f2090565b556001600160a01b03165f90815260056020526040902090565b6801000000000000000182028154019055811562000f2a57830192916001815b62000ee1575b505050505f55565b1562000f17575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a462000ed3565b8092019183830362000ee8578062000ed9565b62001097565b63b562e8dd60e01b5f5260045ffd5b805182101562000f545760209160051b010190565b634e487b7160e01b5f52603260045260245ffd5b90600382511162000fd5575f805b83518210156200103e5762000f8c828562000f3f565b5151906020918262000f9f858862000f3f565b5101511090811562001021575b811562000fe7575b5062000fd55760019062000fc9838662000f3f565b51015191019062000f76565b60405163097191df60e41b8152600490fd5b905062000ff5838662000f3f565b51511515908162001009575b505f62000fb4565b905062001017838662000f3f565b5151105f62001001565b90508162001030848762000f3f565b510151600f54109062000fac565b50509050565b600a80546001600160a01b0319908116909155600980549182166001600160a01b0393841690811790915591167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3565b622e076360e81b5f5260045ffdfe60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146102a457806306fdde031461029f578063081812fc1461029a57806309430a7e14610295578063095ea7b31461029057806318160ddd1461028b57806323b872dd146102865780632a55205a146102815780632e1a7d4d1461027c5780633ccfd60b14610277578063406cf2291461027257806340bd2e231461026d57806340c10f191461026857806342842e0e1461026357806353df5c7c1461025e57806355f804b3146102595780635e0cee0f146102545780636352211e1461024f5780636f8b44b01461024a57806370a0823114610245578063715018a61461024057806375eedb451461023b57806379ba5097146102365780638503e714146102315780638da5cb5b1461022c578063938e3d7b1461022757806395d89b41146102225780639d0172f31461021d578063a22cb46514610218578063b88d4fde14610213578063c87b56dd1461020e578063cff0ab9614610209578063d558296514610204578063e1c2ffad146101ff578063e30c3978146101fa578063e4be0c06146101f5578063e8a3d485146101f0578063e985e9c5146101eb578063f2fde38b146101e6578063f557ab03146101e15763f8bd83e1146101dc575f80fd5b611a9b565b611a5f565b6119f3565b611997565b611968565b611832565b6117fa565b6117d1565b611756565b611638565b611419565b611397565b6112ba565b611270565b6111cb565b61109f565b611077565b61104c565b610fca565b610e9b565b610da3565b610d4d565b610cde565b610caf565b610bd0565b610aae565b610a3e565b610a06565b61093d565b6108ec565b6108b7565b610883565b61080f565b610787565b610773565b61071d565b610673565b610521565b6104d2565b6103f2565b6102bf565b6001600160e01b03198116036102bb57565b5f80fd5b346102bb5760203660031901126102bb5760206004356102de816102a9565b6001600160e01b031981166301ffc9a760e01b811491908215610341575b8215610330575b508115610316575b506040519015158152f35b905060e01c6301ffc9a7632a55205a82149114175f61030b565b635b5e139f60e01b1491505f610303565b6380ac58cd60e01b811492506102fc565b5f5b8381106103635750505f910152565b8181015183820152602001610354565b9060209161038c81518092818552858086019101610352565b601f01601f1916010190565b90602091602081526064518060208301525f5b8181106103cb575060409293505f838284010152601f8019910116010190565b60848101518382016040015284016103ab565b9060206103ef928181520190610373565b90565b346102bb575f3660031901126102bb576040515f600254610412816114b5565b808452906020906001908181169081156104a8575060011461044f575b61044b8561043f8187038261135b565b604051918291826103de565b0390f35b60025f90815293507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8385106104955750505050810160200161043f8261044b61042f565b8054868601840152938201938101610479565b86955061044b9693506020925061043f94915060ff191682840152151560051b820101929361042f565b346102bb5760203660031901126102bb576004356104ef81612034565b15610512575f526006602052602060018060a01b0360405f205416604051908152f35b6333d1c03960e21b5f5260045ffd5b346102bb575f3660031901126102bb5760135461053d81611b01565b60409161054d604051928361135b565b8082526020808301918260135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0905f915b83831061060e57505050506040519281840190828552518091526040840192915f5b8281106105ae5785850386f35b8351805186528083015186840152878101516001600160781b0316888701526060808201516001600160401b03908116918801919091526080808301519091169087015260a0908101519086015260c090940193928101926001016105a1565b600485600192610620859a989a611b18565b81520192019201919095939561057f565b600435906001600160a01b03821682036102bb57565b602435906001600160a01b03821682036102bb57565b604435906001600160a01b03821682036102bb57565b60403660031901126102bb57610687610631565b602435906001600160a01b038061069d846120ae565b16908133036106ee575b835f52600660205260405f20921691826001600160601b0360a01b8254161790557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b5f82815260076020908152604080832033845290915290205460ff166106a7576367d9dca160e11b5f5260045ffd5b346102bb575f3660031901126102bb5760205f546001549003604051908152f35b60609060031901126102bb576001600160a01b039060043582811681036102bb579160243590811681036102bb579060443590565b61078561077f3661073e565b91611b7c565b005b346102bb5760403660031901126102bb576024356004355f5268aa4ec00224afccfdb7908160205260405f20548060601c9283156107fd575b5061044b908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b54606081901c9350905061044b6107c0565b346102bb5760203660031901126102bb5760043561082b61211e565b6015548082111561086657505f80808093816015555b335af161084c611d28565b501561085457005b6040516327fcd9d160e01b8152600490fd5b81810390811161087e575f8080938193601555610841565b611d14565b346102bb575f3660031901126102bb5761089b61211e565b5f80808047335af16108ab611d28565b5015610854575f601555005b346102bb575f3660031901126102bb576108cf61211e565b47601554810390811161087e575f80808093335af161084c611d28565b346102bb5760203660031901126102bb5760043561090861211e565b47601554810390811161087e57811161092b575f80808093335af161084c611d28565b60405163356680b760e01b8152600490fd5b60403660031901126102bb57610951610631565b602435600f54421080156109fb575b80156109ef575b6109dd57610976815f54611d57565b600e54106109cb576109a8816109a36109976011546001600160781b031690565b6001600160781b031690565b611d64565b341061092b57610785916109c66109c134601554611d57565b601555565b612132565b60405163d05cb60960e01b8152600490fd5b60405163914edb0f60e01b8152600490fd5b5060175460ff16610967565b504260105410610960565b610a0f3661073e565b6040519160208301938385106001600160401b03861117610a3957610785946040525f8452611f02565b611347565b346102bb575f3660031901126102bb57610a5661211e565b6014805460ff19166001179055005b9060206003198301126102bb576004356001600160401b03928382116102bb57806023830112156102bb5781600401359384116102bb57602484830101116102bb576024019190565b346102bb57610abc36610a65565b610ac461211e565b60ff60145416610bbe576001600160401b038111610a3957610af081610aeb600b546114b5565b611d77565b5f601f8211600114610b52578190610b1d935f92610b47575b50508160011b915f199060031b1c19161790565b600b555b7fa1731ca444c73d019f0dbb4ee5546c98730f4ffcdaa1c29776ab542aa64d5e1b5f80a1005b013590505f80610b09565b600b5f52601f198216925f805160206123d7833981519152915f5b858110610ba657508360019510610b8d575b505050811b01600b55610b21565b01355f19600384901b60f8161c191690555f8080610b7f565b90926020600181928686013581550194019101610b6d565b60405163696c636960e01b8152600490fd5b346102bb5760403660031901126102bb57610be9610631565b60243561ffff8116918282036102bb57610c0161211e565b60ff60145460101c16610c9d576107d08311610c8b57601280546001600160b01b031916601083901b62010000600160b01b03161761ffff84161790557f4db95622f7059a0983b8b21ce94db601f1f2e63da11a652d59d8d7f77c4ff1a192610c6a908261220c565b604080516001600160a01b0392909216825261ffff929092166020820152a1005b60405163a2a65b5360e01b8152600490fd5b604051635a214b2560e11b8152600490fd5b346102bb5760203660031901126102bb5760206001600160a01b03610cd56004356120ae565b16604051908152f35b346102bb5760203660031901126102bb57600435610cfa61211e565b610d02612251565b5f548110610d3b576020817f7810bd47de260c3e9ee10061cf438099dd12256c79485f12f94dbccc981e806c92600e55604051908152a1005b60405163066f305360e21b8152600490fd5b346102bb5760203660031901126102bb576001600160a01b03610d6e610631565b168015610d94575f52600560205260206001600160401b0360405f205416604051908152f35b6323d3ad8160e21b5f5260045ffd5b346102bb575f3660031901126102bb57610dbb61211e565b600a80546001600160a01b03199081169091556009805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b9181601f840112156102bb578235916001600160401b0383116102bb576020808501948460051b0101116102bb57565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310610e6d5750505050505090565b9091929394958480610e8b600193603f198682030187528a51610373565b9801930193019194939290610e5d565b346102bb5760203660031901126102bb57600480356001600160401b0381116102bb57610ecc903690600401610e08565b91610ed561211e565b610ede83611e3e565b925f5b818110610ef6576040518061044b8782610e38565b5f80610f03838588611e9b565b60409391610f15855180938193611ee1565b0390305af490610f23611d28565b9115610f4a575090600191610f388288611eee565b52610f438187611eee565b5001610ee1565b846044835110610f7157905162461bcd60e51b8152908190610f6d908201610398565b0390fd5b610f6d915191829162461bcd60e51b8352820160809060208152602560208201527f5472616e73616374696f6e20726576657274656420776974686f75742061207260408201526432b0b9b7b760d91b60608201520190565b346102bb575f3660031901126102bb57600a546001600160a01b033381831603611034576001600160601b0360a01b809216600a556009549133908316176009553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b346102bb575f3660031901126102bb5761106461211e565b6014805462ff0000191662010000179055005b346102bb575f3660031901126102bb576009546040516001600160a01b039091168152602090f35b346102bb576110ad36610a65565b6110b561211e565b60ff60145460081c166111b9576001600160401b038111610a39576110e4816110df600c546114b5565b611dd1565b5f601f821160011461113a578190611110935f92610b475750508160011b915f199060031b1c19161790565b600c555b7fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad9625f80a1005b600c5f52601f198216927fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7915f5b8581106111a157508360019510611188575b505050811b01600c55611114565b01355f19600384901b60f8161c191690555f808061117a565b90926020600181928686013581550194019101611168565b604051631fd0326960e01b8152600490fd5b346102bb575f3660031901126102bb576040515f6003546111eb816114b5565b808452906020906001908181169081156104a857506001146112175761044b8561043f8187038261135b565b60035f90815293507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b83851061125d5750505050810160200161043f8261044b61042f565b8054868601840152938201938101611241565b346102bb5760203660031901126102bb576004356001600160781b0381168091036102bb5761129d61211e565b6112a5612251565b6001600160781b031960115416176011555f80f35b346102bb5760403660031901126102bb576112d3610631565b602435908115158092036102bb57335f9081526007602090815260408083206001600160a01b0385168452909152902060ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b03821117610a3957604052565b6001600160401b038111610a3957601f01601f191660200190565b60803660031901126102bb576113ab610631565b6113b3610647565b606435916001600160401b0383116102bb57366023840112156102bb578260040135916113df8361137c565b926113ed604051948561135b565b80845236602482870101116102bb576020815f9260246107859801838801378501015260443591611f02565b346102bb5760203660031901126102bb5760043561143681612034565b156114a35760405190608082019060a083016040525f8252905b5f190190600a9060308282060183530490816114505761149761043f61044b92856080601f1992838101920301815260405193849161149160208401611f43565b90611fbc565b0390810183528261135b565b60405163677510db60e11b8152600490fd5b90600182811c921680156114e3575b60208310146114cf57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114c4565b604051905f82600c5491611500836114b5565b8083529260209060019081811690811561158c575060011461152d575b505061152b9250038361135b565b565b915092600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7935f925b828410611574575061152b9450505081016020015f8061151d565b85548885018301529485019487945092810192611559565b9150506020925061152b94915060ff191682840152151560051b8201015f8061151d565b9995909461014099946115ef8c6001600160781b03969f9e9b98956115e161ffff9c97610160808552840190610373565b916020818403910152610373565b60408d019e909e5260608c015260808b015260a08a01521660c08801526001600160401b0391821660e088015216610100860152166101208401526001600160a01b0316910152565b346102bb575f3660031901126102bb57604051600b54815f611659836114b5565b8083529260209060019081811690811561173257506001146116e6575b50506116849250038261135b565b61168c6114ed565b9061044b600d5491600e5493600f549160105490601154906001600160401b039260125495604051998a9961ffff60018060a01b038a60101c169916976001600160781b03888860b81c16988860781c169716958c6115b0565b915092600b5f525f805160206123d7833981519152935f925b82841061171a57506116849450505081016020015f80611676565b855487850183015294850194869450928101926116ff565b9150506020925061168494915060ff191682840152151560051b8201015f80611676565b346102bb575f3660031901126102bb5761176e61211e565b600160ff1960175416176017557f7810bd47de260c3e9ee10061cf438099dd12256c79485f12f94dbccc981e806c60205f5480600e55604051907fcbbaae1b89885aa88b0db407075a1f3e6df45931447d19c7da5f5b7471a729e55f80a18152a1005b346102bb575f3660031901126102bb576117e961211e565b6014805461ff001916610100179055005b346102bb575f3660031901126102bb57600a546040516001600160a01b039091168152602090f35b6004359060ff821682036102bb57565b60803660031901126102bb57611846611822565b6024356001600160401b0381116102bb57611865903690600401610e08565b919061186f61065d565b9261188561187f60643594611fd3565b50611b18565b80514210801561195b575b6119495761189f845f54611d57565b600e54106109cb576118c2846109a361099760408501516001600160781b031690565b341061092b57604080516001600160a01b038716602082019081528183018790529181526119209461191c949092909160a09161190c9161190460608261135b565b51902061200b565b602081519101209301519161238c565b1590565b61193757610785916109c66109c134601554611d57565b60405163582f497d60e11b8152600490fd5b60405163cbe8d62360e01b8152600490fd5b5042602082015110611890565b346102bb575f3660031901126102bb5761044b6119836114ed565b604051918291602083526020830190610373565b346102bb5760403660031901126102bb57602060ff6119e76119b7610631565b6119bf610647565b6001600160a01b039182165f9081526007865260408082209290931681526020919091522090565b54166040519015158152f35b346102bb5760203660031901126102bb57611a0c610631565b611a1461211e565b600a80546001600160a01b0319166001600160a01b039283169081179091556009549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102bb575f3660031901126102bb57606060145460ff6040519181811615158352818160081c161515602084015260101c1615156040820152f35b346102bb5760403660031901126102bb57611ab4611822565b602435906001600160781b0382168092036102bb57611ae4600291611ad761211e565b611adf612251565b611fd3565b500180546effffffffffffffffffffffffffffff19169091179055005b6001600160401b038111610a395760051b60200190565b6040516001600160401b03929160c0820184811183821017610a395760a0916003916040528395815485526001820154602086015260028201546001600160781b0381166040870152818160781c16606087015260b81c1660808501520154910152565b919091611b88826120ae565b6001600160a01b039182169390828116859003611d0f575f8481526006602052604090208054611bc76001600160a01b03881633908114908314171590565b611cc5575b611cbc575b506001600160a01b0385165f90815260056020526040902080545f190190556001600160a01b0382165f908152600560205260409020805460010190556001600160a01b0382164260a01b17600160e11b17611c35855f52600460205260405f2090565b55600160e11b811615611c77575b501680927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a415611c7257565b612090565b60018401611c8d815f52600460205260405f2090565b5415611c9a575b50611c43565b5f548114611c9457611cb4905f52600460205260405f2090565b555f80611c94565b5f90555f611bd1565b611d0561191c611cfe33611ce98b60018060a01b03165f52600760205260405f2090565b9060018060a01b03165f5260205260405f2090565b5460ff1690565b15611bcc57612081565b612073565b634e487b7160e01b5f52601160045260245ffd5b3d15611d52573d90611d398261137c565b91611d47604051938461135b565b82523d5f602084013e565b606090565b9190820180921161087e57565b8181029291811591840414171561087e57565b601f8111611d83575050565b600b5f525f805160206123d7833981519152906020601f840160051c83019310611dc7575b601f0160051c01905b818110611dbc575050565b5f8155600101611db1565b9091508190611da8565b601f8111611ddd575050565b600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7906020601f840160051c83019310611e34575b601f0160051c01905b818110611e29575050565b5f8155600101611e1e565b9091508190611e15565b90611e4882611b01565b611e55604051918261135b565b8281528092611e66601f1991611b01565b01905f5b828110611e7657505050565b806060602080938501015201611e6a565b634e487b7160e01b5f52603260045260245ffd5b9190811015611edc5760051b81013590601e19813603018212156102bb5701908135916001600160401b0383116102bb5760200182360381136102bb579190565b611e87565b908092918237015f815290565b8051821015611edc5760209160051b010190565b929190611f10828286611b7c565b803b611f1d575b50505050565b611f26936122d7565b15611f34575f808080611f17565b6368d2bf6b60e11b5f5260045ffd5b600b545f9291611f52826114b5565b91600190818116908115611fa95750600114611f6d57505050565b9091929350600b5f525f805160206123d7833981519152905f915b848310611f96575050500190565b8181602092548587015201920191611f88565b60ff191683525050811515909102019150565b90611fcf60209282815194859201610352565b0190565b601354811015611edc5760135f5260021b7f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001905f90565b9060405191602083015260208252604082018281106001600160401b03821117610a3957604052565b905f915f5481106120425750565b9091505b805f52600460205260405f2054806120675750801561087e575f1901612046565b600160e01b1615919050565b62a1148160e81b5f5260045ffd5b632ce44b5f60e11b5f5260045ffd5b633a954ecd60e21b5f5260045ffd5b636f96cda160e11b5f5260045ffd5b6120c0815f52600460205260405f2090565b549081156120d75750600160e01b811661209f5790565b90505f5481101561209f575b5f19015f818152600460205260409020549081156121175750600160e01b8116156103ef57636f96cda160e11b5f5260045ffd5b90506120e3565b6009546001600160a01b0316330361103457565b5f549180156121fd576001916001600160a01b0381164260a01b83851460e11b1717612166855f52600460205260405f2090565b556001600160a01b03165f81815260056020526040902080546801000000000000000184020190559081156121ef57830192916001815b6121aa575b505050505f55565b156121de575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461219d565b809201918383036121b057806121a2565b622e076360e81b5f5260045ffd5b63b562e8dd60e01b5f5260045ffd5b906001600160601b03169061271082116122445760601b8015612237571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b600f544211806122b7575b61228f576013545f5b818110612270575050565b61227981611fd3565b50544211806122a1575b61228f57600101612265565b604051633f19d52960e21b8152600490fd5b5060016122ad82611fd3565b5001544210612283565b50601054421061225c565b908160209103126102bb57516103ef816102a9565b9260209161231f935f60018060a01b0360405180978196829584630a85bd0160e11b9c8d86523360048701521660248501526044840152608060648401526084830190610373565b0393165af15f918161235b575b5061234d57612339611d28565b80511561234857805190602001fd5b611f34565b6001600160e01b0319161490565b61237e91925060203d602011612385575b612376818361135b565b8101906122c2565b905f61232c565b503d61236c565b8193929361239b575b50501490565b60059291831b8101915b8135808211851b91825260208092185260405f20910192828410156123cb5792906123a5565b509150505f8061239556fe0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212206dfbffba53e99fa15460fe4b5ca1d33f6ea127b3b4fee36ffbdf677bd9aac74064736f6c6343000818003366de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a090000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd10000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0a00000000000000000000000000000000000000000000000000000000663ed12000000000000000000000000000000000000000000000000000000000664022a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000258000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd10000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000005268747470733a2f2f626166796265696576756e6d706a6a7a723372357371783679616a6467746c72326775776635697a6a61697274656f6163696c676277366b6233712e697066732e7733732e6c696e6b2f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005a68747470733a2f2f62616679626569646777743779737968796d37643266706e6636716c70646269743464727970346b77646d64786f6e377766696765697a75666d652e697066732e7733732e6c696e6b2f6d65746164617461000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000663e98e000000000000000000000000000000000000000000000000000000000663ea6b40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014e988d650baa443cdf8e2d2a820d7d17aa249ebf1336a6a86b3078d638a079eb00000000000000000000000000000000000000000000000000000000663ea6f000000000000000000000000000000000000000000000000000000000663ed0e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000111494dd64001310539d8ed9be90173cac1aff895f314eaaf5f680f13c0e650db000000000000000000000000000000000000000000000000000000000000000b426c61737420566567617300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055645474153000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x60806040526004361015610011575f80fd5b5f3560e01c806301ffc9a7146102a457806306fdde031461029f578063081812fc1461029a57806309430a7e14610295578063095ea7b31461029057806318160ddd1461028b57806323b872dd146102865780632a55205a146102815780632e1a7d4d1461027c5780633ccfd60b14610277578063406cf2291461027257806340bd2e231461026d57806340c10f191461026857806342842e0e1461026357806353df5c7c1461025e57806355f804b3146102595780635e0cee0f146102545780636352211e1461024f5780636f8b44b01461024a57806370a0823114610245578063715018a61461024057806375eedb451461023b57806379ba5097146102365780638503e714146102315780638da5cb5b1461022c578063938e3d7b1461022757806395d89b41146102225780639d0172f31461021d578063a22cb46514610218578063b88d4fde14610213578063c87b56dd1461020e578063cff0ab9614610209578063d558296514610204578063e1c2ffad146101ff578063e30c3978146101fa578063e4be0c06146101f5578063e8a3d485146101f0578063e985e9c5146101eb578063f2fde38b146101e6578063f557ab03146101e15763f8bd83e1146101dc575f80fd5b611a9b565b611a5f565b6119f3565b611997565b611968565b611832565b6117fa565b6117d1565b611756565b611638565b611419565b611397565b6112ba565b611270565b6111cb565b61109f565b611077565b61104c565b610fca565b610e9b565b610da3565b610d4d565b610cde565b610caf565b610bd0565b610aae565b610a3e565b610a06565b61093d565b6108ec565b6108b7565b610883565b61080f565b610787565b610773565b61071d565b610673565b610521565b6104d2565b6103f2565b6102bf565b6001600160e01b03198116036102bb57565b5f80fd5b346102bb5760203660031901126102bb5760206004356102de816102a9565b6001600160e01b031981166301ffc9a760e01b811491908215610341575b8215610330575b508115610316575b506040519015158152f35b905060e01c6301ffc9a7632a55205a82149114175f61030b565b635b5e139f60e01b1491505f610303565b6380ac58cd60e01b811492506102fc565b5f5b8381106103635750505f910152565b8181015183820152602001610354565b9060209161038c81518092818552858086019101610352565b601f01601f1916010190565b90602091602081526064518060208301525f5b8181106103cb575060409293505f838284010152601f8019910116010190565b60848101518382016040015284016103ab565b9060206103ef928181520190610373565b90565b346102bb575f3660031901126102bb576040515f600254610412816114b5565b808452906020906001908181169081156104a8575060011461044f575b61044b8561043f8187038261135b565b604051918291826103de565b0390f35b60025f90815293507f405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace5b8385106104955750505050810160200161043f8261044b61042f565b8054868601840152938201938101610479565b86955061044b9693506020925061043f94915060ff191682840152151560051b820101929361042f565b346102bb5760203660031901126102bb576004356104ef81612034565b15610512575f526006602052602060018060a01b0360405f205416604051908152f35b6333d1c03960e21b5f5260045ffd5b346102bb575f3660031901126102bb5760135461053d81611b01565b60409161054d604051928361135b565b8082526020808301918260135f527f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0905f915b83831061060e57505050506040519281840190828552518091526040840192915f5b8281106105ae5785850386f35b8351805186528083015186840152878101516001600160781b0316888701526060808201516001600160401b03908116918801919091526080808301519091169087015260a0908101519086015260c090940193928101926001016105a1565b600485600192610620859a989a611b18565b81520192019201919095939561057f565b600435906001600160a01b03821682036102bb57565b602435906001600160a01b03821682036102bb57565b604435906001600160a01b03821682036102bb57565b60403660031901126102bb57610687610631565b602435906001600160a01b038061069d846120ae565b16908133036106ee575b835f52600660205260405f20921691826001600160601b0360a01b8254161790557f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9255f80a4005b5f82815260076020908152604080832033845290915290205460ff166106a7576367d9dca160e11b5f5260045ffd5b346102bb575f3660031901126102bb5760205f546001549003604051908152f35b60609060031901126102bb576001600160a01b039060043582811681036102bb579160243590811681036102bb579060443590565b61078561077f3661073e565b91611b7c565b005b346102bb5760403660031901126102bb576024356004355f5268aa4ec00224afccfdb7908160205260405f20548060601c9283156107fd575b5061044b908360601b1892835f1904831184023d3d3e6127106040519485940204908360209093929193604081019460018060a01b031681520152565b54606081901c9350905061044b6107c0565b346102bb5760203660031901126102bb5760043561082b61211e565b6015548082111561086657505f80808093816015555b335af161084c611d28565b501561085457005b6040516327fcd9d160e01b8152600490fd5b81810390811161087e575f8080938193601555610841565b611d14565b346102bb575f3660031901126102bb5761089b61211e565b5f80808047335af16108ab611d28565b5015610854575f601555005b346102bb575f3660031901126102bb576108cf61211e565b47601554810390811161087e575f80808093335af161084c611d28565b346102bb5760203660031901126102bb5760043561090861211e565b47601554810390811161087e57811161092b575f80808093335af161084c611d28565b60405163356680b760e01b8152600490fd5b60403660031901126102bb57610951610631565b602435600f54421080156109fb575b80156109ef575b6109dd57610976815f54611d57565b600e54106109cb576109a8816109a36109976011546001600160781b031690565b6001600160781b031690565b611d64565b341061092b57610785916109c66109c134601554611d57565b601555565b612132565b60405163d05cb60960e01b8152600490fd5b60405163914edb0f60e01b8152600490fd5b5060175460ff16610967565b504260105410610960565b610a0f3661073e565b6040519160208301938385106001600160401b03861117610a3957610785946040525f8452611f02565b611347565b346102bb575f3660031901126102bb57610a5661211e565b6014805460ff19166001179055005b9060206003198301126102bb576004356001600160401b03928382116102bb57806023830112156102bb5781600401359384116102bb57602484830101116102bb576024019190565b346102bb57610abc36610a65565b610ac461211e565b60ff60145416610bbe576001600160401b038111610a3957610af081610aeb600b546114b5565b611d77565b5f601f8211600114610b52578190610b1d935f92610b47575b50508160011b915f199060031b1c19161790565b600b555b7fa1731ca444c73d019f0dbb4ee5546c98730f4ffcdaa1c29776ab542aa64d5e1b5f80a1005b013590505f80610b09565b600b5f52601f198216925f805160206123d7833981519152915f5b858110610ba657508360019510610b8d575b505050811b01600b55610b21565b01355f19600384901b60f8161c191690555f8080610b7f565b90926020600181928686013581550194019101610b6d565b60405163696c636960e01b8152600490fd5b346102bb5760403660031901126102bb57610be9610631565b60243561ffff8116918282036102bb57610c0161211e565b60ff60145460101c16610c9d576107d08311610c8b57601280546001600160b01b031916601083901b62010000600160b01b03161761ffff84161790557f4db95622f7059a0983b8b21ce94db601f1f2e63da11a652d59d8d7f77c4ff1a192610c6a908261220c565b604080516001600160a01b0392909216825261ffff929092166020820152a1005b60405163a2a65b5360e01b8152600490fd5b604051635a214b2560e11b8152600490fd5b346102bb5760203660031901126102bb5760206001600160a01b03610cd56004356120ae565b16604051908152f35b346102bb5760203660031901126102bb57600435610cfa61211e565b610d02612251565b5f548110610d3b576020817f7810bd47de260c3e9ee10061cf438099dd12256c79485f12f94dbccc981e806c92600e55604051908152a1005b60405163066f305360e21b8152600490fd5b346102bb5760203660031901126102bb576001600160a01b03610d6e610631565b168015610d94575f52600560205260206001600160401b0360405f205416604051908152f35b6323d3ad8160e21b5f5260045ffd5b346102bb575f3660031901126102bb57610dbb61211e565b600a80546001600160a01b03199081169091556009805491821690555f906001600160a01b03167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08280a3005b9181601f840112156102bb578235916001600160401b0383116102bb576020808501948460051b0101116102bb57565b6020808201906020835283518092526040830192602060408460051b8301019501935f915b848310610e6d5750505050505090565b9091929394958480610e8b600193603f198682030187528a51610373565b9801930193019194939290610e5d565b346102bb5760203660031901126102bb57600480356001600160401b0381116102bb57610ecc903690600401610e08565b91610ed561211e565b610ede83611e3e565b925f5b818110610ef6576040518061044b8782610e38565b5f80610f03838588611e9b565b60409391610f15855180938193611ee1565b0390305af490610f23611d28565b9115610f4a575090600191610f388288611eee565b52610f438187611eee565b5001610ee1565b846044835110610f7157905162461bcd60e51b8152908190610f6d908201610398565b0390fd5b610f6d915191829162461bcd60e51b8352820160809060208152602560208201527f5472616e73616374696f6e20726576657274656420776974686f75742061207260408201526432b0b9b7b760d91b60608201520190565b346102bb575f3660031901126102bb57600a546001600160a01b033381831603611034576001600160601b0360a01b809216600a556009549133908316176009553391167f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e05f80a3005b60405163118cdaa760e01b8152336004820152602490fd5b346102bb575f3660031901126102bb5761106461211e565b6014805462ff0000191662010000179055005b346102bb575f3660031901126102bb576009546040516001600160a01b039091168152602090f35b346102bb576110ad36610a65565b6110b561211e565b60ff60145460081c166111b9576001600160401b038111610a39576110e4816110df600c546114b5565b611dd1565b5f601f821160011461113a578190611110935f92610b475750508160011b915f199060031b1c19161790565b600c555b7fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad9625f80a1005b600c5f52601f198216927fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7915f5b8581106111a157508360019510611188575b505050811b01600c55611114565b01355f19600384901b60f8161c191690555f808061117a565b90926020600181928686013581550194019101611168565b604051631fd0326960e01b8152600490fd5b346102bb575f3660031901126102bb576040515f6003546111eb816114b5565b808452906020906001908181169081156104a857506001146112175761044b8561043f8187038261135b565b60035f90815293507fc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b5b83851061125d5750505050810160200161043f8261044b61042f565b8054868601840152938201938101611241565b346102bb5760203660031901126102bb576004356001600160781b0381168091036102bb5761129d61211e565b6112a5612251565b6001600160781b031960115416176011555f80f35b346102bb5760403660031901126102bb576112d3610631565b602435908115158092036102bb57335f9081526007602090815260408083206001600160a01b0385168452909152902060ff1981541660ff841617905560405191825260018060a01b0316907f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160203392a3005b634e487b7160e01b5f52604160045260245ffd5b90601f801991011681019081106001600160401b03821117610a3957604052565b6001600160401b038111610a3957601f01601f191660200190565b60803660031901126102bb576113ab610631565b6113b3610647565b606435916001600160401b0383116102bb57366023840112156102bb578260040135916113df8361137c565b926113ed604051948561135b565b80845236602482870101116102bb576020815f9260246107859801838801378501015260443591611f02565b346102bb5760203660031901126102bb5760043561143681612034565b156114a35760405190608082019060a083016040525f8252905b5f190190600a9060308282060183530490816114505761149761043f61044b92856080601f1992838101920301815260405193849161149160208401611f43565b90611fbc565b0390810183528261135b565b60405163677510db60e11b8152600490fd5b90600182811c921680156114e3575b60208310146114cf57565b634e487b7160e01b5f52602260045260245ffd5b91607f16916114c4565b604051905f82600c5491611500836114b5565b8083529260209060019081811690811561158c575060011461152d575b505061152b9250038361135b565b565b915092600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7935f925b828410611574575061152b9450505081016020015f8061151d565b85548885018301529485019487945092810192611559565b9150506020925061152b94915060ff191682840152151560051b8201015f8061151d565b9995909461014099946115ef8c6001600160781b03969f9e9b98956115e161ffff9c97610160808552840190610373565b916020818403910152610373565b60408d019e909e5260608c015260808b015260a08a01521660c08801526001600160401b0391821660e088015216610100860152166101208401526001600160a01b0316910152565b346102bb575f3660031901126102bb57604051600b54815f611659836114b5565b8083529260209060019081811690811561173257506001146116e6575b50506116849250038261135b565b61168c6114ed565b9061044b600d5491600e5493600f549160105490601154906001600160401b039260125495604051998a9961ffff60018060a01b038a60101c169916976001600160781b03888860b81c16988860781c169716958c6115b0565b915092600b5f525f805160206123d7833981519152935f925b82841061171a57506116849450505081016020015f80611676565b855487850183015294850194869450928101926116ff565b9150506020925061168494915060ff191682840152151560051b8201015f80611676565b346102bb575f3660031901126102bb5761176e61211e565b600160ff1960175416176017557f7810bd47de260c3e9ee10061cf438099dd12256c79485f12f94dbccc981e806c60205f5480600e55604051907fcbbaae1b89885aa88b0db407075a1f3e6df45931447d19c7da5f5b7471a729e55f80a18152a1005b346102bb575f3660031901126102bb576117e961211e565b6014805461ff001916610100179055005b346102bb575f3660031901126102bb57600a546040516001600160a01b039091168152602090f35b6004359060ff821682036102bb57565b60803660031901126102bb57611846611822565b6024356001600160401b0381116102bb57611865903690600401610e08565b919061186f61065d565b9261188561187f60643594611fd3565b50611b18565b80514210801561195b575b6119495761189f845f54611d57565b600e54106109cb576118c2846109a361099760408501516001600160781b031690565b341061092b57604080516001600160a01b038716602082019081528183018790529181526119209461191c949092909160a09161190c9161190460608261135b565b51902061200b565b602081519101209301519161238c565b1590565b61193757610785916109c66109c134601554611d57565b60405163582f497d60e11b8152600490fd5b60405163cbe8d62360e01b8152600490fd5b5042602082015110611890565b346102bb575f3660031901126102bb5761044b6119836114ed565b604051918291602083526020830190610373565b346102bb5760403660031901126102bb57602060ff6119e76119b7610631565b6119bf610647565b6001600160a01b039182165f9081526007865260408082209290931681526020919091522090565b54166040519015158152f35b346102bb5760203660031901126102bb57611a0c610631565b611a1461211e565b600a80546001600160a01b0319166001600160a01b039283169081179091556009549091167f38d16b8cac22d99fc7c124b9cd0de2d3fa1faef420bfe791d8c362d765e227005f80a3005b346102bb575f3660031901126102bb57606060145460ff6040519181811615158352818160081c161515602084015260101c1615156040820152f35b346102bb5760403660031901126102bb57611ab4611822565b602435906001600160781b0382168092036102bb57611ae4600291611ad761211e565b611adf612251565b611fd3565b500180546effffffffffffffffffffffffffffff19169091179055005b6001600160401b038111610a395760051b60200190565b6040516001600160401b03929160c0820184811183821017610a395760a0916003916040528395815485526001820154602086015260028201546001600160781b0381166040870152818160781c16606087015260b81c1660808501520154910152565b919091611b88826120ae565b6001600160a01b039182169390828116859003611d0f575f8481526006602052604090208054611bc76001600160a01b03881633908114908314171590565b611cc5575b611cbc575b506001600160a01b0385165f90815260056020526040902080545f190190556001600160a01b0382165f908152600560205260409020805460010190556001600160a01b0382164260a01b17600160e11b17611c35855f52600460205260405f2090565b55600160e11b811615611c77575b501680927fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef5f80a415611c7257565b612090565b60018401611c8d815f52600460205260405f2090565b5415611c9a575b50611c43565b5f548114611c9457611cb4905f52600460205260405f2090565b555f80611c94565b5f90555f611bd1565b611d0561191c611cfe33611ce98b60018060a01b03165f52600760205260405f2090565b9060018060a01b03165f5260205260405f2090565b5460ff1690565b15611bcc57612081565b612073565b634e487b7160e01b5f52601160045260245ffd5b3d15611d52573d90611d398261137c565b91611d47604051938461135b565b82523d5f602084013e565b606090565b9190820180921161087e57565b8181029291811591840414171561087e57565b601f8111611d83575050565b600b5f525f805160206123d7833981519152906020601f840160051c83019310611dc7575b601f0160051c01905b818110611dbc575050565b5f8155600101611db1565b9091508190611da8565b601f8111611ddd575050565b600c5f527fdf6966c971051c3d54ec59162606531493a51404a002842f56009d7e5cf4a8c7906020601f840160051c83019310611e34575b601f0160051c01905b818110611e29575050565b5f8155600101611e1e565b9091508190611e15565b90611e4882611b01565b611e55604051918261135b565b8281528092611e66601f1991611b01565b01905f5b828110611e7657505050565b806060602080938501015201611e6a565b634e487b7160e01b5f52603260045260245ffd5b9190811015611edc5760051b81013590601e19813603018212156102bb5701908135916001600160401b0383116102bb5760200182360381136102bb579190565b611e87565b908092918237015f815290565b8051821015611edc5760209160051b010190565b929190611f10828286611b7c565b803b611f1d575b50505050565b611f26936122d7565b15611f34575f808080611f17565b6368d2bf6b60e11b5f5260045ffd5b600b545f9291611f52826114b5565b91600190818116908115611fa95750600114611f6d57505050565b9091929350600b5f525f805160206123d7833981519152905f915b848310611f96575050500190565b8181602092548587015201920191611f88565b60ff191683525050811515909102019150565b90611fcf60209282815194859201610352565b0190565b601354811015611edc5760135f5260021b7f66de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09001905f90565b9060405191602083015260208252604082018281106001600160401b03821117610a3957604052565b905f915f5481106120425750565b9091505b805f52600460205260405f2054806120675750801561087e575f1901612046565b600160e01b1615919050565b62a1148160e81b5f5260045ffd5b632ce44b5f60e11b5f5260045ffd5b633a954ecd60e21b5f5260045ffd5b636f96cda160e11b5f5260045ffd5b6120c0815f52600460205260405f2090565b549081156120d75750600160e01b811661209f5790565b90505f5481101561209f575b5f19015f818152600460205260409020549081156121175750600160e01b8116156103ef57636f96cda160e11b5f5260045ffd5b90506120e3565b6009546001600160a01b0316330361103457565b5f549180156121fd576001916001600160a01b0381164260a01b83851460e11b1717612166855f52600460205260405f2090565b556001600160a01b03165f81815260056020526040902080546801000000000000000184020190559081156121ef57830192916001815b6121aa575b505050505f55565b156121de575b5f8184845f7fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8180a461219d565b809201918383036121b057806121a2565b622e076360e81b5f5260045ffd5b63b562e8dd60e01b5f5260045ffd5b906001600160601b03169061271082116122445760601b8015612237571768aa4ec00224afccfdb755565b63b4457eaa5f526004601cfd5b63350a88b35f526004601cfd5b600f544211806122b7575b61228f576013545f5b818110612270575050565b61227981611fd3565b50544211806122a1575b61228f57600101612265565b604051633f19d52960e21b8152600490fd5b5060016122ad82611fd3565b5001544210612283565b50601054421061225c565b908160209103126102bb57516103ef816102a9565b9260209161231f935f60018060a01b0360405180978196829584630a85bd0160e11b9c8d86523360048701521660248501526044840152608060648401526084830190610373565b0393165af15f918161235b575b5061234d57612339611d28565b80511561234857805190602001fd5b611f34565b6001600160e01b0319161490565b61237e91925060203d602011612385575b612376818361135b565b8101906122c2565b905f61232c565b503d61236c565b8193929361239b575b50501490565b60059291831b8101915b8135808211851b91825260208092185260405f20910192828410156123cb5792906123a5565b509150505f8061239556fe0175b7a638427703f0dbe7bb9bbf987a2551717b34e79f33b5b1008d1fa01db9a26469706673582212206dfbffba53e99fa15460fe4b5ca1d33f6ea127b3b4fee36ffbdf677bd9aac74064736f6c63430008180033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000004a000000000000000000000000000000000000000000000000000000000000004e0000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd10000000000000000000000000000000000000000000000000000000000000180000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001a0a00000000000000000000000000000000000000000000000000000000663ed12000000000000000000000000000000000000000000000000000000000664022a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000258000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd10000000000000000000000000000000000000000000000000000000000000280000000000000000000000000000000000000000000000000000000000000005268747470733a2f2f626166796265696576756e6d706a6a7a723372357371783679616a6467746c72326775776635697a6a61697274656f6163696c676277366b6233712e697066732e7733732e6c696e6b2f0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000005a68747470733a2f2f62616679626569646777743779737968796d37643266706e6636716c70646269743464727970346b77646d64786f6e377766696765697a75666d652e697066732e7733732e6c696e6b2f6d65746164617461000000000000000000000000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000663e98e000000000000000000000000000000000000000000000000000000000663ea6b40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000000000000000000000000000000000000000000000000000014e988d650baa443cdf8e2d2a820d7d17aa249ebf1336a6a86b3078d638a079eb00000000000000000000000000000000000000000000000000000000663ea6f000000000000000000000000000000000000000000000000000000000663ed0e400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000111494dd64001310539d8ed9be90173cac1aff895f314eaaf5f680f13c0e650db000000000000000000000000000000000000000000000000000000000000000b426c61737420566567617300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000055645474153000000000000000000000000000000000000000000000000000000
-----Decoded View---------------
Arg [0] : _params (tuple): System.Collections.Generic.List`1[Nethereum.ABI.FunctionEncoding.ParameterOutput]
Arg [1] : _name (string): Blast Vegas
Arg [2] : _symbol (string): VEGAS
Arg [3] : _owner (address): 0xDcaE87821FA6CAEA05dBc2811126f4bc7fF73bd1
-----Encoded View---------------
41 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 00000000000000000000000000000000000000000000000000000000000004a0
Arg [2] : 00000000000000000000000000000000000000000000000000000000000004e0
Arg [3] : 000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd1
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000180
Arg [5] : 0000000000000000000000000000000000000000000000000000000000000200
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [7] : 0000000000000000000000000000000000000000000000000000000000001a0a
Arg [8] : 00000000000000000000000000000000000000000000000000000000663ed120
Arg [9] : 00000000000000000000000000000000000000000000000000000000664022a0
Arg [10] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [11] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [12] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [13] : 0000000000000000000000000000000000000000000000000000000000000258
Arg [14] : 000000000000000000000000dcae87821fa6caea05dbc2811126f4bc7ff73bd1
Arg [15] : 0000000000000000000000000000000000000000000000000000000000000280
Arg [16] : 0000000000000000000000000000000000000000000000000000000000000052
Arg [17] : 68747470733a2f2f626166796265696576756e6d706a6a7a7233723573717836
Arg [18] : 79616a6467746c72326775776635697a6a61697274656f6163696c676277366b
Arg [19] : 6233712e697066732e7733732e6c696e6b2f0000000000000000000000000000
Arg [20] : 000000000000000000000000000000000000000000000000000000000000005a
Arg [21] : 68747470733a2f2f62616679626569646777743779737968796d37643266706e
Arg [22] : 6636716c70646269743464727970346b77646d64786f6e377766696765697a75
Arg [23] : 666d652e697066732e7733732e6c696e6b2f6d65746164617461000000000000
Arg [24] : 0000000000000000000000000000000000000000000000000000000000000002
Arg [25] : 00000000000000000000000000000000000000000000000000000000663e98e0
Arg [26] : 00000000000000000000000000000000000000000000000000000000663ea6b4
Arg [27] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [28] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [29] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [30] : 4e988d650baa443cdf8e2d2a820d7d17aa249ebf1336a6a86b3078d638a079eb
Arg [31] : 00000000000000000000000000000000000000000000000000000000663ea6f0
Arg [32] : 00000000000000000000000000000000000000000000000000000000663ed0e4
Arg [33] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [34] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [35] : 0000000000000000000000000000000000000000000000000000000000000001
Arg [36] : 11494dd64001310539d8ed9be90173cac1aff895f314eaaf5f680f13c0e650db
Arg [37] : 000000000000000000000000000000000000000000000000000000000000000b
Arg [38] : 426c617374205665676173000000000000000000000000000000000000000000
Arg [39] : 0000000000000000000000000000000000000000000000000000000000000005
Arg [40] : 5645474153000000000000000000000000000000000000000000000000000000
Loading...
Loading
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.