Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 4,184 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Safe Transfer Fr... | 36517241 | 32 mins ago | IN | 0 ETH | 0.00001167 | ||||
| Safe Transfer Fr... | 36517162 | 33 mins ago | IN | 0 ETH | 0.00001296 | ||||
| Set Approval For... | 36024375 | 3 days ago | IN | 0 ETH | 0.00000564 | ||||
| Safe Transfer Fr... | 36008689 | 3 days ago | IN | 0 ETH | 0.00001431 | ||||
| Set Approval For... | 35817938 | 4 days ago | IN | 0 ETH | 0.00000566 | ||||
| Set Approval For... | 35702268 | 5 days ago | IN | 0 ETH | 0.00000564 | ||||
| Set Approval For... | 35471979 | 6 days ago | IN | 0 ETH | 0.00000564 | ||||
| Set Approval For... | 35386317 | 7 days ago | IN | 0 ETH | 0.00000491 | ||||
| Set Approval For... | 35364233 | 7 days ago | IN | 0 ETH | 0.00000564 | ||||
| Set Approval For... | 35092800 | 9 days ago | IN | 0 ETH | 0.00000565 | ||||
| Safe Transfer Fr... | 35059532 | 9 days ago | IN | 0 ETH | 0.0000144 | ||||
| Set Approval For... | 35055387 | 9 days ago | IN | 0 ETH | 0.00000496 | ||||
| Set Approval For... | 35017260 | 9 days ago | IN | 0 ETH | 0.00000445 | ||||
| Set Approval For... | 34966896 | 10 days ago | IN | 0 ETH | 0.00000564 | ||||
| Set Approval For... | 34955111 | 10 days ago | IN | 0 ETH | 0.00000433 | ||||
| Safe Transfer Fr... | 34939959 | 10 days ago | IN | 0 ETH | 0.00001163 | ||||
| Safe Transfer Fr... | 34939938 | 10 days ago | IN | 0 ETH | 0.00001156 | ||||
| Safe Transfer Fr... | 34939910 | 10 days ago | IN | 0 ETH | 0.00001351 | ||||
| Set Approval For... | 34917306 | 10 days ago | IN | 0 ETH | 0.00000539 | ||||
| Set Approval For... | 34897716 | 10 days ago | IN | 0 ETH | 0.0000042 | ||||
| Set Approval For... | 34780679 | 11 days ago | IN | 0 ETH | 0.00000444 | ||||
| Set Approval For... | 34714998 | 11 days ago | IN | 0 ETH | 0.00000419 | ||||
| Set Approval For... | 34503491 | 13 days ago | IN | 0 ETH | 0.00000535 | ||||
| Safe Transfer Fr... | 34391151 | 14 days ago | IN | 0 ETH | 0.00001222 | ||||
| Set Approval For... | 34195897 | 15 days ago | IN | 0 ETH | 0.00000444 |
Latest 25 internal transactions (View All)
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 15652727 | 178 days ago | 37.8 ETH | ||||
| 15652394 | 178 days ago | 0.036 ETH | ||||
| 15652381 | 178 days ago | 0.054 ETH | ||||
| 15652369 | 178 days ago | 0.018 ETH | ||||
| 15652349 | 178 days ago | 0.018 ETH | ||||
| 15652326 | 178 days ago | 0.018 ETH | ||||
| 15652325 | 178 days ago | 0.018 ETH | ||||
| 15652325 | 178 days ago | 0.018 ETH | ||||
| 15652324 | 178 days ago | 0.054 ETH | ||||
| 15652323 | 178 days ago | 0.018 ETH | ||||
| 15652320 | 178 days ago | 0.018 ETH | ||||
| 15652319 | 178 days ago | 0.036 ETH | ||||
| 15652319 | 178 days ago | 0.018 ETH | ||||
| 15652319 | 178 days ago | 0.018 ETH | ||||
| 15652318 | 178 days ago | 0.018 ETH | ||||
| 15652318 | 178 days ago | 0.018 ETH | ||||
| 15652318 | 178 days ago | 0.018 ETH | ||||
| 15652316 | 178 days ago | 0.018 ETH | ||||
| 15652315 | 178 days ago | 0.054 ETH | ||||
| 15652314 | 178 days ago | 0.036 ETH | ||||
| 15652313 | 178 days ago | 0.054 ETH | ||||
| 15652312 | 178 days ago | 0.036 ETH | ||||
| 15652311 | 178 days ago | 0.054 ETH | ||||
| 15652311 | 178 days ago | 0.018 ETH | ||||
| 15652309 | 178 days ago | 0.018 ETH |
Cross-Chain Transactions
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 Name:
Bearyz
Compiler Version
v0.8.30-1.0.1
ZkSolc Version
v1.5.15
Optimization Enabled:
Yes with Mode 3
Other Settings:
cancun EvmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.30;
// █▀ █▀▀ █▄▄ █▄█ █▀█ █▀█ █▀▀ █▀▄▀█ ▄▀█ ▀▄▀
// ▄█ █▄▄ █▄█ ░█░ █▀▄ █▀▀ █▄█ █░▀░█ █▀█ █░█
import {OwnableBasic} from "@limitbreak/creator-token-standards/src/access/OwnableBasic.sol";
import {ERC721AC} from "@limitbreak/creator-token-standards/src/erc721c/ERC721AC.sol";
import {
BasicRoyalties, ERC2981
} from "@limitbreak/creator-token-standards/src/programmable-royalties/BasicRoyalties.sol";
import {LibString} from "solady/src/utils/LibString.sol";
import {ReentrancyGuard} from "solady/src/utils/ReentrancyGuard.sol";
import {SignatureCheckerLib} from "solady/src/utils/ext/zksync/SignatureCheckerLib.sol";
/// @title Bearyz
/// @author RpGmAx
/// @notice An ERC721AC implementation for Bearyz NFTs collection with multiple minting phases. Post reveal metadata will be hosted on IPFS.
/// @dev Inherits from OwnableBasic, ERC721AC, BasicRoyalties, ReentrancyGuard
contract Bearyz is OwnableBasic, ERC721AC, BasicRoyalties, ReentrancyGuard {
/// @notice Errors used throughout the contract
error InvalidSignature();
error LockedURI();
error NoETHToWithdraw();
error WithdrawalFailed();
error NotMintablePhase();
error InsufficientPayment();
error MaxMintPerWalletExceeded();
error MaxSupplyReached();
error PayoutFailed();
error InvalidAmount();
error InvalidAddress();
error NotManager();
/// @notice Price for all minting phases
uint256 public price = 0.018 ether;
/// @notice Maximum mint per wallet for each phase
mapping(MintPhase => uint256) public maxMintPerWallet;
/// @notice Enum representing different minting phases
enum MintPhase {
WhitelistedGTD,
WhitelistedFCFS,
Public,
Closed
}
/// @notice Maximum supply
uint256 public maxSupply = 2500;
/// @notice Current active minting phase
MintPhase public currentPhase;
/// @notice NFT Generation hash
string public generationHash;
/// @notice Address authorized to sign whitelist messages
address private _signerAddress;
/// @notice Internal code used for signature verification
string private constant _INTERNAL_CODE = "BEARYZ-MINT";
/// @notice Base URI for token metadata
string private _uri;
/// @notice Tracks number of mints per wallet per phase
mapping(address => mapping(MintPhase => uint256)) public mintedPerPhase;
/// @notice Tracks if an address is a manager
mapping(address => bool) public isManager;
/// @notice Modifier to check if the caller is a manager
modifier onlyManager() {
if (!isManager[msg.sender]) revert NotManager();
_;
}
/// @notice Emitted when a new phase is set
event PhaseChanged(MintPhase indexed newPhase);
/// @notice Emitted when the base URI is updated
event BaseURIUpdated(string newURI);
/// @notice Emitted when the generation hash is updated
event GenerationHashUpdated(string newGenerationHash);
/// @notice Emitted when tokens are minted
event BearyzMinted(address indexed to, uint256 amount, uint256 startTokenId, uint256 endTokenId);
/// @notice Initializes the contract with the owner and signer
/// @param owner Address of the contract owner
/// @param signerAddress Address authorized to sign whitelist messages
/// @param royaltiesAddress Address of the royalties receiver
constructor(address owner, address signerAddress, address royaltiesAddress)
ERC721AC("Bearyz", "BEARYZ")
BasicRoyalties(royaltiesAddress, 500)
{
_uri = "https://www.bearycoin.xyz/api/bearyz/unrevealed/";
currentPhase = MintPhase.Closed;
_signerAddress = signerAddress;
_transferOwnership(owner);
// Initialize max mint per wallet for each phase
maxMintPerWallet[MintPhase.WhitelistedGTD] = 1;
maxMintPerWallet[MintPhase.WhitelistedFCFS] = 3;
maxMintPerWallet[MintPhase.Public] = 5;
// Set the owner as the initial manager
isManager[owner] = true;
}
// ============ MAIN FUNCTIONALITY ============
/// @notice Mints Bearyz based on the current active phase
/// @param amount Number of Bearyz to mint
/// @param signature Digital signature to verify eligibility (only used for WL phases)
function mint(uint256 amount, bytes calldata signature) external payable nonReentrant {
if (currentPhase == MintPhase.Closed) revert NotMintablePhase();
if (amount == 0) revert InvalidAmount();
if (currentPhase == MintPhase.Public) {
// Public phase has no signature verification
} else if (currentPhase == MintPhase.WhitelistedGTD || currentPhase == MintPhase.WhitelistedFCFS) {
if (!_verifyAddressSigner(uint256(currentPhase), msg.sender, signature)) revert InvalidSignature();
} else {
revert NotMintablePhase();
}
// Check max mint per wallet for all phases
uint256 phaseMaxMint = maxMintPerWallet[currentPhase];
if (phaseMaxMint > 0 && mintedPerPhase[msg.sender][currentPhase] + amount > phaseMaxMint) {
revert MaxMintPerWalletExceeded();
}
if (_totalMinted() + amount > maxSupply) revert MaxSupplyReached();
if (msg.value != amount * price) revert InsufficientPayment();
uint256 startTokenId = _nextTokenId();
uint256 endTokenId = startTokenId + amount - 1;
mintedPerPhase[msg.sender][currentPhase] += amount;
_mint(msg.sender, amount);
emit BearyzMinted(msg.sender, amount, startTokenId, endTokenId);
}
// ============ OWNER ADMIN FUNCTIONS ============
/// @notice Sets the signer address
/// @param newSignerAddress The new signer address
function setSignerAddress(address newSignerAddress) external onlyOwner {
_signerAddress = newSignerAddress;
}
/// @notice Sets the base URI for token metadata
/// @param uri_ New base URI
function setBaseURI(string memory uri_) external onlyOwner {
_uri = uri_;
emit BaseURIUpdated(uri_);
}
/// @notice Sets the NFT generation hash
/// @param newGenerationHash The new NFT generation hash
function setGenerationHash(string memory newGenerationHash) external onlyOwner {
generationHash = newGenerationHash;
emit GenerationHashUpdated(newGenerationHash);
}
/// @notice Sets the mint price (manager-only)
/// @param newPrice The new price in wei
function setPrice(uint256 newPrice) external onlyManager {
price = newPrice;
}
/// @notice Sets the max mint per wallet for a specific phase
/// @param phase The phase to update
/// @param newMaxMintPerWallet The new maximum mints per wallet
function setMaxMintPerWallet(MintPhase phase, uint256 newMaxMintPerWallet) external onlyOwner {
if (phase > MintPhase.Public) revert NotMintablePhase();
maxMintPerWallet[phase] = newMaxMintPerWallet;
}
/// @notice Sets the active phase (manager-only)
/// @param phase The phase to set as active
function setCurrentPhase(MintPhase phase) external onlyManager {
if (uint256(phase) > uint256(MintPhase.Closed)) revert NotMintablePhase();
currentPhase = phase;
emit PhaseChanged(phase);
}
/// @notice Sets a manager address
/// @param user The address to set as manager
/// @param enabled Whether the address is a manager
function setManager(address user, bool enabled) external onlyOwner {
isManager[user] = enabled;
}
/// @notice Owner mint function
/// @param to Address to mint the tokens to
/// @param amount Number of tokens to mint
function teamMint(address to, uint256 amount) external onlyOwner {
if (_totalMinted() + amount > maxSupply) revert MaxSupplyReached();
uint256 startTokenId = _nextTokenId();
uint256 endTokenId = startTokenId + amount - 1;
_mint(to, amount);
emit BearyzMinted(to, amount, startTokenId, endTokenId);
}
/// @notice Withdraws all ETH from the contract to the team address
function withdraw() external onlyOwner {
uint256 balance = address(this).balance;
if (balance == 0) revert NoETHToWithdraw();
(bool success,) = owner().call{value: balance}("");
if (!success) revert WithdrawalFailed();
}
// ============ VIEW FUNCTIONS ============
/// @notice Returns the current active phase
/// @return The current active phase
function getCurrentPhase() external view returns (MintPhase) {
return currentPhase;
}
/// @notice Returns the total number of minted Bearyz
/// @return The total number of minted Bearyz
function mintedBearyz() external view returns (uint256) {
return _totalMinted();
}
/// @notice Returns true if the contract implements the interface
/// @param interfaceId The interface ID to check
/// @return bool Whether the contract implements the interface
function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721AC, ERC2981) returns (bool) {
return ERC721AC.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId);
}
/// @notice Get token URI
/// @param tokenId Token ID
/// @return string Token URI with .json extension (old habit!)
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) revert URIQueryForNonexistentToken();
string memory baseURI = _baseURI();
return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, LibString.toString(tokenId), ".json")) : "";
}
// ============ INTERNAL FUNCTIONS ============
/// @notice Returns the base URI for token metadata
/// @return The base URI string
function _baseURI() internal view override returns (string memory) {
return _uri;
}
/// @notice Returns the starting token ID
/// @return uint256 The starting token ID (1)
function _startTokenId() internal view virtual override returns (uint256) {
return 1;
}
/// @notice Verifies the digital signature for mint eligibility
/// @param _phaseId The phase ID to verify against
/// @param _userAddress Address attempting to mint
/// @param _signature Digital signature to verify
/// @return bool Whether the signature is valid
function _verifyAddressSigner(uint256 _phaseId, address _userAddress, bytes calldata _signature)
internal
view
returns (bool)
{
return SignatureCheckerLib.isValidSignatureNowCalldata(
_signerAddress,
SignatureCheckerLib.toEthSignedMessageHash(
keccak256(abi.encodePacked(_INTERNAL_CODE, _phaseId, _userAddress))
),
_signature
);
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721A.sol';
/**
* @dev Interface of ERC721 token receiver.
*/
interface ERC721A__IERC721Receiver {
function onERC721Received(
address operator,
address from,
uint256 tokenId,
bytes calldata data
) external returns (bytes4);
}
/**
* @title ERC721A
*
* @dev Implementation of the [ERC721](https://eips.ethereum.org/EIPS/eip-721)
* Non-Fungible Token Standard, including the Metadata extension.
* Optimized for lower gas during batch mints.
*
* Token IDs are minted in sequential order (e.g. 0, 1, 2, 3, ...)
* starting from `_startTokenId()`.
*
* The `_sequentialUpTo()` function can be overriden to enable spot mints
* (i.e. non-consecutive mints) for `tokenId`s greater than `_sequentialUpTo()`.
*
* Assumptions:
*
* - An owner cannot have more than 2**64 - 1 (max value of uint64) of supply.
* - The maximum token ID cannot exceed 2**256 - 1 (max value of uint256).
*/
contract ERC721A is IERC721A {
// Bypass for a `--via-ir` bug (https://github.com/chiru-labs/ERC721A/pull/364).
struct TokenApprovalRef {
address value;
}
// =============================================================
// CONSTANTS
// =============================================================
// Mask of an entry in packed address data.
uint256 private constant _BITMASK_ADDRESS_DATA_ENTRY = (1 << 64) - 1;
// The bit position of `numberMinted` in packed address data.
uint256 private constant _BITPOS_NUMBER_MINTED = 64;
// The bit position of `numberBurned` in packed address data.
uint256 private constant _BITPOS_NUMBER_BURNED = 128;
// The bit position of `aux` in packed address data.
uint256 private constant _BITPOS_AUX = 192;
// Mask of all 256 bits in packed address data except the 64 bits for `aux`.
uint256 private constant _BITMASK_AUX_COMPLEMENT = (1 << 192) - 1;
// The bit position of `startTimestamp` in packed ownership.
uint256 private constant _BITPOS_START_TIMESTAMP = 160;
// The bit mask of the `burned` bit in packed ownership.
uint256 private constant _BITMASK_BURNED = 1 << 224;
// The bit position of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITPOS_NEXT_INITIALIZED = 225;
// The bit mask of the `nextInitialized` bit in packed ownership.
uint256 private constant _BITMASK_NEXT_INITIALIZED = 1 << 225;
// The bit position of `extraData` in packed ownership.
uint256 private constant _BITPOS_EXTRA_DATA = 232;
// Mask of all 256 bits in a packed ownership except the 24 bits for `extraData`.
uint256 private constant _BITMASK_EXTRA_DATA_COMPLEMENT = (1 << 232) - 1;
// The mask of the lower 160 bits for addresses.
uint256 private constant _BITMASK_ADDRESS = (1 << 160) - 1;
// The maximum `quantity` that can be minted with {_mintERC2309}.
// This limit is to prevent overflows on the address data entries.
// For a limit of 5000, a total of 3.689e15 calls to {_mintERC2309}
// is required to cause an overflow, which is unrealistic.
uint256 private constant _MAX_MINT_ERC2309_QUANTITY_LIMIT = 5000;
// The `Transfer` event signature is given by:
// `keccak256(bytes("Transfer(address,address,uint256)"))`.
bytes32 private constant _TRANSFER_EVENT_SIGNATURE =
0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef;
// =============================================================
// STORAGE
// =============================================================
// The next token ID to be minted.
uint256 private _currentIndex;
// The number of tokens burned.
uint256 private _burnCounter;
// Token name
string private _name;
// Token symbol
string private _symbol;
// Mapping from token ID to ownership details
// An empty struct value does not necessarily mean the token is unowned.
// See {_packedOwnershipOf} implementation for details.
//
// Bits Layout:
// - [0..159] `addr`
// - [160..223] `startTimestamp`
// - [224] `burned`
// - [225] `nextInitialized`
// - [232..255] `extraData`
mapping(uint256 => uint256) private _packedOwnerships;
// Mapping owner address to address data.
//
// Bits Layout:
// - [0..63] `balance`
// - [64..127] `numberMinted`
// - [128..191] `numberBurned`
// - [192..255] `aux`
mapping(address => uint256) private _packedAddressData;
// Mapping from token ID to approved address.
mapping(uint256 => TokenApprovalRef) private _tokenApprovals;
// Mapping from owner to operator approvals
mapping(address => mapping(address => bool)) private _operatorApprovals;
// The amount of tokens minted above `_sequentialUpTo()`.
// We call these spot mints (i.e. non-sequential mints).
uint256 private _spotMinted;
// =============================================================
// CONSTRUCTOR
// =============================================================
constructor(string memory name_, string memory symbol_) {
_name = name_;
_symbol = symbol_;
_currentIndex = _startTokenId();
if (_sequentialUpTo() < _startTokenId()) _revert(SequentialUpToTooSmall.selector);
}
// =============================================================
// TOKEN COUNTING OPERATIONS
// =============================================================
/**
* @dev Returns the starting token ID for sequential mints.
*
* Override this function to change the starting token ID for sequential mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _startTokenId() internal view virtual returns (uint256) {
return 0;
}
/**
* @dev Returns the maximum token ID (inclusive) for sequential mints.
*
* Override this function to return a value less than 2**256 - 1,
* but greater than `_startTokenId()`, to enable spot (non-sequential) mints.
*
* Note: The value returned must never change after any tokens have been minted.
*/
function _sequentialUpTo() internal view virtual returns (uint256) {
return type(uint256).max;
}
/**
* @dev Returns the next token ID to be minted.
*/
function _nextTokenId() internal view virtual returns (uint256) {
return _currentIndex;
}
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() public view virtual override returns (uint256 result) {
// Counter underflow is impossible as `_burnCounter` cannot be incremented
// more than `_currentIndex + _spotMinted - _startTokenId()` times.
unchecked {
// With spot minting, the intermediate `result` can be temporarily negative,
// and the computation must be unchecked.
result = _currentIndex - _burnCounter - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total amount of tokens minted in the contract.
*/
function _totalMinted() internal view virtual returns (uint256 result) {
// Counter underflow is impossible as `_currentIndex` does not decrement,
// and it is initialized to `_startTokenId()`.
unchecked {
result = _currentIndex - _startTokenId();
if (_sequentialUpTo() != type(uint256).max) result += _spotMinted;
}
}
/**
* @dev Returns the total number of tokens burned.
*/
function _totalBurned() internal view virtual returns (uint256) {
return _burnCounter;
}
/**
* @dev Returns the total number of tokens that are spot-minted.
*/
function _totalSpotMinted() internal view virtual returns (uint256) {
return _spotMinted;
}
// =============================================================
// ADDRESS DATA OPERATIONS
// =============================================================
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) public view virtual override returns (uint256) {
if (owner == address(0)) _revert(BalanceQueryForZeroAddress.selector);
return _packedAddressData[owner] & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens minted by `owner`.
*/
function _numberMinted(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_MINTED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the number of tokens burned by or on behalf of `owner`.
*/
function _numberBurned(address owner) internal view returns (uint256) {
return (_packedAddressData[owner] >> _BITPOS_NUMBER_BURNED) & _BITMASK_ADDRESS_DATA_ENTRY;
}
/**
* Returns the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
*/
function _getAux(address owner) internal view returns (uint64) {
return uint64(_packedAddressData[owner] >> _BITPOS_AUX);
}
/**
* Sets the auxiliary data for `owner`. (e.g. number of whitelist mint slots used).
* If there are multiple variables, please pack them into a uint64.
*/
function _setAux(address owner, uint64 aux) internal virtual {
uint256 packed = _packedAddressData[owner];
uint256 auxCasted;
// Cast `aux` with assembly to avoid redundant masking.
assembly {
auxCasted := aux
}
packed = (packed & _BITMASK_AUX_COMPLEMENT) | (auxCasted << _BITPOS_AUX);
_packedAddressData[owner] = packed;
}
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
// The interface IDs are constants representing the first 4 bytes
// of the XOR of all function selectors in the interface.
// See: [ERC165](https://eips.ethereum.org/EIPS/eip-165)
// (e.g. `bytes4(i.functionA.selector ^ i.functionB.selector ^ ...)`)
return
interfaceId == 0x01ffc9a7 || // ERC165 interface ID for ERC165.
interfaceId == 0x80ac58cd || // ERC165 interface ID for ERC721.
interfaceId == 0x5b5e139f; // ERC165 interface ID for ERC721Metadata.
}
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() public view virtual override returns (string memory) {
return _name;
}
/**
* @dev Returns the token collection symbol.
*/
function symbol() public view virtual override returns (string memory) {
return _symbol;
}
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) public view virtual override returns (string memory) {
if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
string memory baseURI = _baseURI();
return bytes(baseURI).length != 0 ? string(abi.encodePacked(baseURI, _toString(tokenId))) : '';
}
/**
* @dev Base URI for computing {tokenURI}. If set, the resulting URI for each
* token will be the concatenation of the `baseURI` and the `tokenId`. Empty
* by default, it can be overridden in child contracts.
*/
function _baseURI() internal view virtual returns (string memory) {
return '';
}
// =============================================================
// OWNERSHIPS OPERATIONS
// =============================================================
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) public view virtual override returns (address) {
return address(uint160(_packedOwnershipOf(tokenId)));
}
/**
* @dev Gas spent here starts off proportional to the maximum mint batch size.
* It gradually moves to O(1) as tokens get transferred around over time.
*/
function _ownershipOf(uint256 tokenId) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnershipOf(tokenId));
}
/**
* @dev Returns the unpacked `TokenOwnership` struct at `index`.
*/
function _ownershipAt(uint256 index) internal view virtual returns (TokenOwnership memory) {
return _unpackedOwnership(_packedOwnerships[index]);
}
/**
* @dev Returns whether the ownership slot at `index` is initialized.
* An uninitialized slot does not necessarily mean that the slot has no owner.
*/
function _ownershipIsInitialized(uint256 index) internal view virtual returns (bool) {
return _packedOwnerships[index] != 0;
}
/**
* @dev Initializes the ownership slot minted at `index` for efficiency purposes.
*/
function _initializeOwnershipAt(uint256 index) internal virtual {
if (_packedOwnerships[index] == 0) {
_packedOwnerships[index] = _packedOwnershipOf(index);
}
}
/**
* @dev Returns the packed ownership data of `tokenId`.
*/
function _packedOwnershipOf(uint256 tokenId) private view returns (uint256 packed) {
if (_startTokenId() <= tokenId) {
packed = _packedOwnerships[tokenId];
if (tokenId > _sequentialUpTo()) {
if (_packedOwnershipExists(packed)) return packed;
_revert(OwnerQueryForNonexistentToken.selector);
}
// If the data at the starting slot does not exist, start the scan.
if (packed == 0) {
if (tokenId >= _currentIndex) _revert(OwnerQueryForNonexistentToken.selector);
// Invariant:
// There will always be an initialized ownership slot
// (i.e. `ownership.addr != address(0) && ownership.burned == false`)
// before an unintialized ownership slot
// (i.e. `ownership.addr == address(0) && ownership.burned == false`)
// Hence, `tokenId` will not underflow.
//
// We can directly compare the packed value.
// If the address is zero, packed will be zero.
for (;;) {
unchecked {
packed = _packedOwnerships[--tokenId];
}
if (packed == 0) continue;
if (packed & _BITMASK_BURNED == 0) return packed;
// Otherwise, the token is burned, and we must revert.
// This handles the case of batch burned tokens, where only the burned bit
// of the starting slot is set, and remaining slots are left uninitialized.
_revert(OwnerQueryForNonexistentToken.selector);
}
}
// Otherwise, the data exists and we can skip the scan.
// This is possible because we have already achieved the target condition.
// This saves 2143 gas on transfers of initialized tokens.
// If the token is not burned, return `packed`. Otherwise, revert.
if (packed & _BITMASK_BURNED == 0) return packed;
}
_revert(OwnerQueryForNonexistentToken.selector);
}
/**
* @dev Returns the unpacked `TokenOwnership` struct from `packed`.
*/
function _unpackedOwnership(uint256 packed) private pure returns (TokenOwnership memory ownership) {
ownership.addr = address(uint160(packed));
ownership.startTimestamp = uint64(packed >> _BITPOS_START_TIMESTAMP);
ownership.burned = packed & _BITMASK_BURNED != 0;
ownership.extraData = uint24(packed >> _BITPOS_EXTRA_DATA);
}
/**
* @dev Packs ownership data into a single uint256.
*/
function _packOwnershipData(address owner, uint256 flags) private view returns (uint256 result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// `owner | (block.timestamp << _BITPOS_START_TIMESTAMP) | flags`.
result := or(owner, or(shl(_BITPOS_START_TIMESTAMP, timestamp()), flags))
}
}
/**
* @dev Returns the `nextInitialized` flag set if `quantity` equals 1.
*/
function _nextInitializedFlag(uint256 quantity) private pure returns (uint256 result) {
// For branchless setting of the `nextInitialized` flag.
assembly {
// `(quantity == 1) << _BITPOS_NEXT_INITIALIZED`.
result := shl(_BITPOS_NEXT_INITIALIZED, eq(quantity, 1))
}
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account. See {ERC721A-_approve}.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
*/
function approve(address to, uint256 tokenId) public payable virtual override {
_approve(to, tokenId, true);
}
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) public view virtual override returns (address) {
if (!_exists(tokenId)) _revert(ApprovalQueryForNonexistentToken.selector);
return _tokenApprovals[tokenId].value;
}
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool approved) public virtual override {
_operatorApprovals[_msgSenderERC721A()][operator] = approved;
emit ApprovalForAll(_msgSenderERC721A(), operator, approved);
}
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool) {
return _operatorApprovals[owner][operator];
}
/**
* @dev Returns whether `tokenId` exists.
*
* Tokens can be managed by their owner or approved accounts via {approve} or {setApprovalForAll}.
*
* Tokens start existing when they are minted. See {_mint}.
*/
function _exists(uint256 tokenId) internal view virtual returns (bool result) {
if (_startTokenId() <= tokenId) {
if (tokenId > _sequentialUpTo()) return _packedOwnershipExists(_packedOwnerships[tokenId]);
if (tokenId < _currentIndex) {
uint256 packed;
while ((packed = _packedOwnerships[tokenId]) == 0) --tokenId;
result = packed & _BITMASK_BURNED == 0;
}
}
}
/**
* @dev Returns whether `packed` represents a token that exists.
*/
function _packedOwnershipExists(uint256 packed) private pure returns (bool result) {
assembly {
// The following is equivalent to `owner != address(0) && burned == false`.
// Symbolically tested.
result := gt(and(packed, _BITMASK_ADDRESS), and(packed, _BITMASK_BURNED))
}
}
/**
* @dev Returns whether `msgSender` is equal to `approvedAddress` or `owner`.
*/
function _isSenderApprovedOrOwner(
address approvedAddress,
address owner,
address msgSender
) private pure returns (bool result) {
assembly {
// Mask `owner` to the lower 160 bits, in case the upper bits somehow aren't clean.
owner := and(owner, _BITMASK_ADDRESS)
// Mask `msgSender` to the lower 160 bits, in case the upper bits somehow aren't clean.
msgSender := and(msgSender, _BITMASK_ADDRESS)
// `msgSender == owner || msgSender == approvedAddress`.
result := or(eq(msgSender, owner), eq(msgSender, approvedAddress))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId`.
*/
function _getApprovedSlotAndAddress(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, address approvedAddress)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddress = _tokenApprovals[tokenId].value`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddress := sload(approvedAddressSlot)
}
}
// =============================================================
// TRANSFER OPERATIONS
// =============================================================
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
// Mask `from` to the lower 160 bits, in case the upper bits somehow aren't clean.
from = address(uint160(uint256(uint160(from)) & _BITMASK_ADDRESS));
if (address(uint160(prevOwnershipPacked)) != from) _revert(TransferFromIncorrectOwner.selector);
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
_beforeTokenTransfers(from, to, tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// We can directly increment and decrement the balances.
--_packedAddressData[from]; // Updates: `balance -= 1`.
++_packedAddressData[to]; // Updates: `balance += 1`.
// Updates:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transfering.
// - `burned` to `false`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_BITMASK_NEXT_INITIALIZED | _nextExtraData(from, to, prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
from, // `from`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
if (toMasked == 0) _revert(TransferToZeroAddress.selector);
_afterTokenTransfers(from, to, tokenId, 1);
}
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) public payable virtual override {
safeTransferFrom(from, to, tokenId, '');
}
/**
* @dev Safely transfers `tokenId` token from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes memory _data
) public payable virtual override {
transferFrom(from, to, tokenId);
if (to.code.length != 0)
if (!_checkContractOnERC721Received(from, to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
}
/**
* @dev Hook that is called before a set of serially-ordered token IDs
* are about to be transferred. This includes minting.
* And also called before burning one token.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Hook that is called after a set of serially-ordered token IDs
* have been transferred. This includes minting.
* And also called after one token has been burned.
*
* `startTokenId` - the first token ID to be transferred.
* `quantity` - the amount to be transferred.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` has been
* transferred to `to`.
* - When `from` is zero, `tokenId` has been minted for `to`.
* - When `to` is zero, `tokenId` has been burned by `from`.
* - `from` and `to` are never both zero.
*/
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual {}
/**
* @dev Private function to invoke {IERC721Receiver-onERC721Received} on a target contract.
*
* `from` - Previous owner of the given token ID.
* `to` - Target address that will receive the token.
* `tokenId` - Token ID to be transferred.
* `_data` - Optional data to send along with the call.
*
* Returns whether the call correctly returned the expected magic value.
*/
function _checkContractOnERC721Received(
address from,
address to,
uint256 tokenId,
bytes memory _data
) private returns (bool) {
try ERC721A__IERC721Receiver(to).onERC721Received(_msgSenderERC721A(), from, tokenId, _data) returns (
bytes4 retval
) {
return retval == ERC721A__IERC721Receiver(to).onERC721Received.selector;
} catch (bytes memory reason) {
if (reason.length == 0) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
assembly {
revert(add(32, reason), mload(reason))
}
}
}
// =============================================================
// MINT OPERATIONS
// =============================================================
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {Transfer} event for each mint.
*/
function _mint(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (quantity == 0) _revert(MintZeroQuantity.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are incredibly unrealistic.
// `balance` and `numberMinted` have a maximum limit of 2**64.
// `tokenId` has a maximum limit of 2**256.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
uint256 end = startTokenId + quantity;
uint256 tokenId = startTokenId;
if (end - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
do {
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
// The `!=` check ensures that large values of `quantity`
// that overflows uint256 will make the loop run out of gas.
} while (++tokenId != end);
_currentIndex = end;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Mints `quantity` tokens and transfers them to `to`.
*
* This function is intended for efficient minting only during contract creation.
*
* It emits only one {ConsecutiveTransfer} as defined in
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309),
* instead of a sequence of {Transfer} event(s).
*
* Calling this function outside of contract creation WILL make your contract
* non-compliant with the ERC721 standard.
* For full ERC721 compliance, substituting ERC721 {Transfer} event(s) with the ERC2309
* {ConsecutiveTransfer} event is only permissible during contract creation.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `quantity` must be greater than 0.
*
* Emits a {ConsecutiveTransfer} event.
*/
function _mintERC2309(address to, uint256 quantity) internal virtual {
uint256 startTokenId = _currentIndex;
if (to == address(0)) _revert(MintToZeroAddress.selector);
if (quantity == 0) _revert(MintZeroQuantity.selector);
if (quantity > _MAX_MINT_ERC2309_QUANTITY_LIMIT) _revert(MintERC2309QuantityExceedsLimit.selector);
_beforeTokenTransfers(address(0), to, startTokenId, quantity);
// Overflows are unrealistic due to the above check for `quantity` to be below the limit.
unchecked {
// Updates:
// - `balance += quantity`.
// - `numberMinted += quantity`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += quantity * ((1 << _BITPOS_NUMBER_MINTED) | 1);
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `quantity == 1`.
_packedOwnerships[startTokenId] = _packOwnershipData(
to,
_nextInitializedFlag(quantity) | _nextExtraData(address(0), to, 0)
);
if (startTokenId + quantity - 1 > _sequentialUpTo()) _revert(SequentialMintExceedsLimit.selector);
emit ConsecutiveTransfer(startTokenId, startTokenId + quantity - 1, address(0), to);
_currentIndex = startTokenId + quantity;
}
_afterTokenTransfers(address(0), to, startTokenId, quantity);
}
/**
* @dev Safely mints `quantity` tokens and transfers them to `to`.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each safe transfer.
* - `quantity` must be greater than 0.
*
* See {_mint}.
*
* Emits a {Transfer} event for each mint.
*/
function _safeMint(
address to,
uint256 quantity,
bytes memory _data
) internal virtual {
_mint(to, quantity);
unchecked {
if (to.code.length != 0) {
uint256 end = _currentIndex;
uint256 index = end - quantity;
do {
if (!_checkContractOnERC721Received(address(0), to, index++, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
} while (index < end);
// This prevents reentrancy to `_safeMint`.
// It does not prevent reentrancy to `_safeMintSpot`.
if (_currentIndex != end) revert();
}
}
}
/**
* @dev Equivalent to `_safeMint(to, quantity, '')`.
*/
function _safeMint(address to, uint256 quantity) internal virtual {
_safeMint(to, quantity, '');
}
/**
* @dev Mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - `to` cannot be the zero address.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* Emits a {Transfer} event for each mint.
*/
function _mintSpot(address to, uint256 tokenId) internal virtual {
if (tokenId <= _sequentialUpTo()) _revert(SpotMintTokenIdTooSmall.selector);
uint256 prevOwnershipPacked = _packedOwnerships[tokenId];
if (_packedOwnershipExists(prevOwnershipPacked)) _revert(TokenAlreadyExists.selector);
_beforeTokenTransfers(address(0), to, tokenId, 1);
// Overflows are incredibly unrealistic.
// The `numberMinted` for `to` is incremented by 1, and has a max limit of 2**64 - 1.
// `_spotMinted` is incremented by 1, and has a max limit of 2**256 - 1.
unchecked {
// Updates:
// - `address` to the owner.
// - `startTimestamp` to the timestamp of minting.
// - `burned` to `false`.
// - `nextInitialized` to `true` (as `quantity == 1`).
_packedOwnerships[tokenId] = _packOwnershipData(
to,
_nextInitializedFlag(1) | _nextExtraData(address(0), to, prevOwnershipPacked)
);
// Updates:
// - `balance += 1`.
// - `numberMinted += 1`.
//
// We can directly add to the `balance` and `numberMinted`.
_packedAddressData[to] += (1 << _BITPOS_NUMBER_MINTED) | 1;
// Mask `to` to the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint256(uint160(to)) & _BITMASK_ADDRESS;
if (toMasked == 0) _revert(MintToZeroAddress.selector);
assembly {
// Emit the `Transfer` event.
log4(
0, // Start of data (0, since no data).
0, // End of data (0, since no data).
_TRANSFER_EVENT_SIGNATURE, // Signature.
0, // `address(0)`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
++_spotMinted;
}
_afterTokenTransfers(address(0), to, tokenId, 1);
}
/**
* @dev Safely mints a single token at `tokenId`.
*
* Note: A spot-minted `tokenId` that has been burned can be re-minted again.
*
* Requirements:
*
* - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}.
* - `tokenId` must be greater than `_sequentialUpTo()`.
* - `tokenId` must not exist.
*
* See {_mintSpot}.
*
* Emits a {Transfer} event.
*/
function _safeMintSpot(
address to,
uint256 tokenId,
bytes memory _data
) internal virtual {
_mintSpot(to, tokenId);
unchecked {
if (to.code.length != 0) {
uint256 currentSpotMinted = _spotMinted;
if (!_checkContractOnERC721Received(address(0), to, tokenId, _data)) {
_revert(TransferToNonERC721ReceiverImplementer.selector);
}
// This prevents reentrancy to `_safeMintSpot`.
// It does not prevent reentrancy to `_safeMint`.
if (_spotMinted != currentSpotMinted) revert();
}
}
}
/**
* @dev Equivalent to `_safeMintSpot(to, tokenId, '')`.
*/
function _safeMintSpot(address to, uint256 tokenId) internal virtual {
_safeMintSpot(to, tokenId, '');
}
// =============================================================
// APPROVAL OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_approve(to, tokenId, false)`.
*/
function _approve(address to, uint256 tokenId) internal virtual {
_approve(to, tokenId, false);
}
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function _approve(
address to,
uint256 tokenId,
bool approvalCheck
) internal virtual {
address owner = ownerOf(tokenId);
if (approvalCheck && _msgSenderERC721A() != owner)
if (!isApprovedForAll(owner, _msgSenderERC721A())) {
_revert(ApprovalCallerNotOwnerNorApproved.selector);
}
_tokenApprovals[tokenId].value = to;
emit Approval(owner, to, tokenId);
}
// =============================================================
// BURN OPERATIONS
// =============================================================
/**
* @dev Equivalent to `_burn(tokenId, false)`.
*/
function _burn(uint256 tokenId) internal virtual {
_burn(tokenId, false);
}
/**
* @dev Destroys `tokenId`.
* The approval is cleared when the token is burned.
*
* Requirements:
*
* - `tokenId` must exist.
*
* Emits a {Transfer} event.
*/
function _burn(uint256 tokenId, bool approvalCheck) internal virtual {
uint256 prevOwnershipPacked = _packedOwnershipOf(tokenId);
address from = address(uint160(prevOwnershipPacked));
(uint256 approvedAddressSlot, address approvedAddress) = _getApprovedSlotAndAddress(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddress, from, _msgSenderERC721A()))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
// Clear approvals from the previous owner.
assembly {
if approvedAddress {
// This is equivalent to `delete _tokenApprovals[tokenId]`.
sstore(approvedAddressSlot, 0)
}
}
// Underflow of the sender's balance is impossible because we check for
// ownership above and the recipient's balance can't realistically overflow.
// Counter overflow is incredibly unrealistic as `tokenId` would have to be 2**256.
unchecked {
// Updates:
// - `balance -= 1`.
// - `numberBurned += 1`.
//
// We can directly decrement the balance, and increment the number burned.
// This is equivalent to `packed -= 1; packed += 1 << _BITPOS_NUMBER_BURNED;`.
_packedAddressData[from] += (1 << _BITPOS_NUMBER_BURNED) - 1;
// Updates:
// - `address` to the last owner.
// - `startTimestamp` to the timestamp of burning.
// - `burned` to `true`.
// - `nextInitialized` to `true`.
_packedOwnerships[tokenId] = _packOwnershipData(
from,
(_BITMASK_BURNED | _BITMASK_NEXT_INITIALIZED) | _nextExtraData(from, address(0), prevOwnershipPacked)
);
// If the next slot may not have been initialized (i.e. `nextInitialized == false`) .
if (prevOwnershipPacked & _BITMASK_NEXT_INITIALIZED == 0) {
uint256 nextTokenId = tokenId + 1;
// If the next slot's address is zero and not burned (i.e. packed value is zero).
if (_packedOwnerships[nextTokenId] == 0) {
// If the next slot is within bounds.
if (nextTokenId != _currentIndex) {
// Initialize the next slot to maintain correctness for `ownerOf(tokenId + 1)`.
_packedOwnerships[nextTokenId] = prevOwnershipPacked;
}
}
}
}
emit Transfer(from, address(0), tokenId);
_afterTokenTransfers(from, address(0), tokenId, 1);
// Overflow not possible, as `_burnCounter` cannot be exceed `_currentIndex + _spotMinted` times.
unchecked {
_burnCounter++;
}
}
// =============================================================
// EXTRA DATA OPERATIONS
// =============================================================
/**
* @dev Directly sets the extra data for the ownership data `index`.
*/
function _setExtraDataAt(uint256 index, uint24 extraData) internal virtual {
uint256 packed = _packedOwnerships[index];
if (packed == 0) _revert(OwnershipNotInitializedForExtraData.selector);
uint256 extraDataCasted;
// Cast `extraData` with assembly to avoid redundant masking.
assembly {
extraDataCasted := extraData
}
packed = (packed & _BITMASK_EXTRA_DATA_COMPLEMENT) | (extraDataCasted << _BITPOS_EXTRA_DATA);
_packedOwnerships[index] = packed;
}
/**
* @dev Called during each token transfer to set the 24bit `extraData` field.
* Intended to be overridden by the cosumer contract.
*
* `previousExtraData` - the value of `extraData` before transfer.
*
* Calling conditions:
*
* - When `from` and `to` are both non-zero, `from`'s `tokenId` will be
* transferred to `to`.
* - When `from` is zero, `tokenId` will be minted for `to`.
* - When `to` is zero, `tokenId` will be burned by `from`.
* - `from` and `to` are never both zero.
*/
function _extraData(
address from,
address to,
uint24 previousExtraData
) internal view virtual returns (uint24) {}
/**
* @dev Returns the next extra data for the packed ownership data.
* The returned result is shifted into position.
*/
function _nextExtraData(
address from,
address to,
uint256 prevOwnershipPacked
) private view returns (uint256) {
uint24 extraData = uint24(prevOwnershipPacked >> _BITPOS_EXTRA_DATA);
return uint256(_extraData(from, to, extraData)) << _BITPOS_EXTRA_DATA;
}
// =============================================================
// OTHER OPERATIONS
// =============================================================
/**
* @dev Returns the message sender (defaults to `msg.sender`).
*
* If you are writing GSN compatible contracts, you need to override this function.
*/
function _msgSenderERC721A() internal view virtual returns (address) {
return msg.sender;
}
/**
* @dev Converts a uint256 to its ASCII string decimal representation.
*/
function _toString(uint256 value) internal pure virtual returns (string memory str) {
assembly {
// The maximum value of a uint256 contains 78 digits (1 byte per digit), but
// we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned.
// We will need 1 word for the trailing zeros padding, 1 word for the length,
// and 3 words for a maximum of 78 digits. Total: 5 * 0x20 = 0xa0.
let m := add(mload(0x40), 0xa0)
// Update the free memory pointer to allocate.
mstore(0x40, m)
// Assign the `str` to the end.
str := sub(m, 0x20)
// Zeroize the slot after the string.
mstore(str, 0)
// Cache the end of the memory to calculate the length later.
let end := str
// We write the string from rightmost digit to leftmost digit.
// The following is essentially a do-while loop that also handles the zero case.
// prettier-ignore
for { let temp := value } 1 {} {
str := sub(str, 1)
// Write the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(str, add(48, mod(temp, 10)))
// Keep dividing `temp` until zero.
temp := div(temp, 10)
// prettier-ignore
if iszero(temp) { break }
}
let length := sub(end, str)
// Move the pointer 32 bytes leftwards to make room for the length.
str := sub(str, 0x20)
// Store the length.
mstore(str, length)
}
}
/**
* @dev For more efficient reverts.
*/
function _revert(bytes4 errorSelector) internal pure {
assembly {
mstore(0x00, errorSelector)
revert(0x00, 0x04)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
/**
* @dev Interface of ERC721A.
*/
interface IERC721A {
/**
* The caller must own the token or be an approved operator.
*/
error ApprovalCallerNotOwnerNorApproved();
/**
* The token does not exist.
*/
error ApprovalQueryForNonexistentToken();
/**
* Cannot query the balance for the zero address.
*/
error BalanceQueryForZeroAddress();
/**
* Cannot mint to the zero address.
*/
error MintToZeroAddress();
/**
* The quantity of tokens minted must be more than zero.
*/
error MintZeroQuantity();
/**
* The token does not exist.
*/
error OwnerQueryForNonexistentToken();
/**
* The caller must own the token or be an approved operator.
*/
error TransferCallerNotOwnerNorApproved();
/**
* The token must be owned by `from`.
*/
error TransferFromIncorrectOwner();
/**
* Cannot safely transfer to a contract that does not implement the
* ERC721Receiver interface.
*/
error TransferToNonERC721ReceiverImplementer();
/**
* Cannot transfer to the zero address.
*/
error TransferToZeroAddress();
/**
* The token does not exist.
*/
error URIQueryForNonexistentToken();
/**
* The `quantity` minted with ERC2309 exceeds the safety limit.
*/
error MintERC2309QuantityExceedsLimit();
/**
* The `extraData` cannot be set on an unintialized ownership slot.
*/
error OwnershipNotInitializedForExtraData();
/**
* `_sequentialUpTo()` must be greater than `_startTokenId()`.
*/
error SequentialUpToTooSmall();
/**
* The `tokenId` of a sequential mint exceeds `_sequentialUpTo()`.
*/
error SequentialMintExceedsLimit();
/**
* Spot minting requires a `tokenId` greater than `_sequentialUpTo()`.
*/
error SpotMintTokenIdTooSmall();
/**
* Cannot mint over a token that already exists.
*/
error TokenAlreadyExists();
/**
* The feature is not compatible with spot mints.
*/
error NotCompatibleWithSpotMints();
// =============================================================
// STRUCTS
// =============================================================
struct TokenOwnership {
// The address of the owner.
address addr;
// Stores the start time of ownership with minimal overhead for tokenomics.
uint64 startTimestamp;
// Whether the token has been burned.
bool burned;
// Arbitrary data similar to `startTimestamp` that can be set via {_extraData}.
uint24 extraData;
}
// =============================================================
// TOKEN COUNTERS
// =============================================================
/**
* @dev Returns the total number of tokens in existence.
* Burned tokens will reduce the count.
* To get the total number of tokens minted, please see {_totalMinted}.
*/
function totalSupply() external view returns (uint256);
// =============================================================
// IERC165
// =============================================================
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* [EIP section](https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified)
* to learn more about how these ids are created.
*
* This function call must use less than 30000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
// =============================================================
// IERC721
// =============================================================
/**
* @dev Emitted when `tokenId` token is transferred from `from` to `to`.
*/
event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
*/
event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);
/**
* @dev Emitted when `owner` enables or disables
* (`approved`) `operator` to manage all of its assets.
*/
event ApprovalForAll(address indexed owner, address indexed operator, bool approved);
/**
* @dev Returns the number of tokens in `owner`'s account.
*/
function balanceOf(address owner) external view returns (uint256 balance);
/**
* @dev Returns the owner of the `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function ownerOf(uint256 tokenId) external view returns (address owner);
/**
* @dev Safely transfers `tokenId` token from `from` to `to`,
* checking first that contract recipients are aware of the ERC721 protocol
* to prevent tokens from being forever locked.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must exist and be owned by `from`.
* - If the caller is not `from`, it must be have been allowed to move
* this token by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
*
* Emits a {Transfer} event.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId,
bytes calldata data
) external payable;
/**
* @dev Equivalent to `safeTransferFrom(from, to, tokenId, '')`.
*/
function safeTransferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Transfers `tokenId` from `from` to `to`.
*
* WARNING: Usage of this method is discouraged, use {safeTransferFrom}
* whenever possible.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenId` token must be owned by `from`.
* - If the caller is not `from`, it must be approved to move this token
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event.
*/
function transferFrom(
address from,
address to,
uint256 tokenId
) external payable;
/**
* @dev Gives permission to `to` to transfer `tokenId` token to another account.
* The approval is cleared when the token is transferred.
*
* Only a single account can be approved at a time, so approving the
* zero address clears previous approvals.
*
* Requirements:
*
* - The caller must own the token or be an approved operator.
* - `tokenId` must exist.
*
* Emits an {Approval} event.
*/
function approve(address to, uint256 tokenId) external payable;
/**
* @dev Approve or remove `operator` as an operator for the caller.
* Operators can call {transferFrom} or {safeTransferFrom}
* for any token owned by the caller.
*
* Requirements:
*
* - The `operator` cannot be the caller.
*
* Emits an {ApprovalForAll} event.
*/
function setApprovalForAll(address operator, bool _approved) external;
/**
* @dev Returns the account approved for `tokenId` token.
*
* Requirements:
*
* - `tokenId` must exist.
*/
function getApproved(uint256 tokenId) external view returns (address operator);
/**
* @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
*
* See {setApprovalForAll}.
*/
function isApprovedForAll(address owner, address operator) external view returns (bool);
// =============================================================
// IERC721Metadata
// =============================================================
/**
* @dev Returns the token collection name.
*/
function name() external view returns (string memory);
/**
* @dev Returns the token collection symbol.
*/
function symbol() external view returns (string memory);
/**
* @dev Returns the Uniform Resource Identifier (URI) for `tokenId` token.
*/
function tokenURI(uint256 tokenId) external view returns (string memory);
// =============================================================
// IERC2309
// =============================================================
/**
* @dev Emitted when tokens in `fromTokenId` to `toTokenId`
* (inclusive) is transferred from `from` to `to`, as defined in the
* [ERC2309](https://eips.ethereum.org/EIPS/eip-2309) standard.
*
* See {_mintERC2309} for more details.
*/
event ConsecutiveTransfer(uint256 indexed fromTokenId, uint256 toTokenId, address indexed from, address indexed to);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @dev Constant bytes32 value of 0x000...000
bytes32 constant ZERO_BYTES32 = bytes32(0);
/// @dev Constant value of 0
uint256 constant ZERO = 0;
/// @dev Constant value of 1
uint256 constant ONE = 1;
/// @dev Constant value representing an open order in storage
uint8 constant ORDER_STATE_OPEN = 0;
/// @dev Constant value representing a filled order in storage
uint8 constant ORDER_STATE_FILLED = 1;
/// @dev Constant value representing a cancelled order in storage
uint8 constant ORDER_STATE_CANCELLED = 2;
/// @dev Constant value representing the ERC721 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC721 = 721;
/// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC1155 = 1155;
/// @dev Constant value representing the ERC20 token type for signatures and transfer hooks
uint256 constant TOKEN_TYPE_ERC20 = 20;
/// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s`
bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff;
/// @dev EIP-712 typehash used for validating signature based stored approvals
bytes32 constant UPDATE_APPROVAL_TYPEHASH =
keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit without additional data
bytes32 constant SINGLE_USE_PERMIT_TYPEHASH =
keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)");
/// @dev EIP-712 typehash used for validating a single use permit with additional data
string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB =
"PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills
string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB =
"PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,";
/// @dev Pausable flag for stored approval transfers of ERC721 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0;
/// @dev Pausable flag for stored approval transfers of ERC1155 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1;
/// @dev Pausable flag for stored approval transfers of ERC20 assets
uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2;
/// @dev Pausable flag for single use permit transfers of ERC721 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3;
/// @dev Pausable flag for single use permit transfers of ERC1155 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4;
/// @dev Pausable flag for single use permit transfers of ERC20 assets
uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5;
/// @dev Pausable flag for order fill transfers of ERC1155 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6;
/// @dev Pausable flag for order fill transfers of ERC20 assets
uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "./OwnablePermissions.sol";
import "@openzeppelin/contracts/access/Ownable.sol";
abstract contract OwnableBasic is OwnablePermissions, Ownable {
function _requireCallerIsContractOwner() internal view virtual override {
_checkOwner();
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
abstract contract OwnablePermissions is Context {
function _requireCallerIsContractOwner() internal view virtual;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../utils/AutomaticValidatorTransferApproval.sol";
import "../utils/CreatorTokenBase.sol";
import "erc721a/contracts/ERC721A.sol";
import {TOKEN_TYPE_ERC721} from "@limitbreak/permit-c/Constants.sol";
/**
* @title ERC721AC
* @author Limit Break, Inc.
* @notice Extends Azuki's ERC721-A implementation with Creator Token functionality, which
* allows the contract owner to update the transfer validation logic by managing a security policy in
* an external transfer validation security policy registry. See {CreatorTokenTransferValidator}.
*/
abstract contract ERC721AC is ERC721A, CreatorTokenBase, AutomaticValidatorTransferApproval {
constructor(string memory name_, string memory symbol_) CreatorTokenBase() ERC721A(name_, symbol_) {}
/**
* @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved
* for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers.
*/
function isApprovedForAll(address owner, address operator) public view virtual override returns (bool isApproved) {
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(getTransferValidator());
}
}
}
/**
* @notice Indicates whether the contract implements the specified interface.
* @dev Overrides supportsInterface in ERC165.
* @param interfaceId The interface id
* @return true if the contract implements the specified interface, false otherwise
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return
interfaceId == type(ICreatorToken).interfaceId ||
interfaceId == type(ICreatorTokenLegacy).interfaceId ||
super.supportsInterface(interfaceId);
}
/**
* @notice Returns the function selector for the transfer validator's validation function to be called
* @notice for transaction simulation.
*/
function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) {
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
/// @dev Ties the erc721a _beforeTokenTransfers hook to more granular transfer validation logic
function _beforeTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual override {
for (uint256 i = 0; i < quantity;) {
_validateBeforeTransfer(from, to, startTokenId + i);
unchecked {
++i;
}
}
}
/// @dev Ties the erc721a _afterTokenTransfer hook to more granular transfer validation logic
function _afterTokenTransfers(
address from,
address to,
uint256 startTokenId,
uint256 quantity
) internal virtual override {
for (uint256 i = 0; i < quantity;) {
_validateAfterTransfer(from, to, startTokenId + i);
unchecked {
++i;
}
}
}
function _msgSenderERC721A() internal view virtual override returns (address) {
return _msgSender();
}
function _tokenType() internal pure override returns(uint16) {
return uint16(TOKEN_TYPE_ERC721);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICreatorToken {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ICreatorTokenLegacy {
event TransferValidatorUpdated(address oldValidator, address newValidator);
function getTransferValidator() external view returns (address validator);
function setTransferValidator(address validator) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidator {
function applyCollectionTransferPolicy(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId) external view;
function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external;
function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external;
function afterAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransfer(address operator, address token) external;
function afterAuthorizedTransfer(address token) external;
function beforeAuthorizedTransfer(address token, uint256 tokenId) external;
function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external;
function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
interface ITransferValidatorSetTokenType {
function setTokenTypeOfCollection(address collection, uint16 tokenType) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/token/common/ERC2981.sol";
/**
* @title BasicRoyaltiesBase
* @author Limit Break, Inc.
* @dev Base functionality of an NFT mix-in contract implementing the most basic form of programmable royalties.
*/
abstract contract BasicRoyaltiesBase is ERC2981 {
event DefaultRoyaltySet(address indexed receiver, uint96 feeNumerator);
event TokenRoyaltySet(uint256 indexed tokenId, address indexed receiver, uint96 feeNumerator);
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual override {
super._setDefaultRoyalty(receiver, feeNumerator);
emit DefaultRoyaltySet(receiver, feeNumerator);
}
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) internal virtual override {
super._setTokenRoyalty(tokenId, receiver, feeNumerator);
emit TokenRoyaltySet(tokenId, receiver, feeNumerator);
}
}
/**
* @title BasicRoyalties
* @author Limit Break, Inc.
* @notice Constructable BasicRoyalties Contract implementation.
*/
abstract contract BasicRoyalties is BasicRoyaltiesBase {
constructor(address receiver, uint96 feeNumerator) {
_setDefaultRoyalty(receiver, feeNumerator);
}
}
/**
* @title BasicRoyaltiesInitializable
* @author Limit Break, Inc.
* @notice Initializable BasicRoyalties Contract implementation to allow for EIP-1167 clones.
*/
abstract contract BasicRoyaltiesInitializable is BasicRoyaltiesBase {}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
/**
* @title AutomaticValidatorTransferApproval
* @author Limit Break, Inc.
* @notice Base contract mix-in that provides boilerplate code giving the contract owner the
* option to automatically approve a 721-C transfer validator implementation for transfers.
*/
abstract contract AutomaticValidatorTransferApproval is OwnablePermissions {
/// @dev Emitted when the automatic approval flag is modified by the creator.
event AutomaticApprovalOfTransferValidatorSet(bool autoApproved);
/// @dev If true, the collection's transfer validator is automatically approved to transfer holder's tokens.
bool public autoApproveTransfersFromValidator;
/**
* @notice Sets if the transfer validator is automatically approved as an operator for all token owners.
*
* @dev Throws when the caller is not the contract owner.
*
* @param autoApprove If true, the collection's transfer validator will be automatically approved to
* transfer holder's tokens.
*/
function setAutomaticApprovalOfTransfersFromValidator(bool autoApprove) external {
_requireCallerIsContractOwner();
autoApproveTransfersFromValidator = autoApprove;
emit AutomaticApprovalOfTransferValidatorSet(autoApprove);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "../access/OwnablePermissions.sol";
import "../interfaces/ICreatorToken.sol";
import "../interfaces/ICreatorTokenLegacy.sol";
import "../interfaces/ITransferValidator.sol";
import "./TransferValidation.sol";
import "../interfaces/ITransferValidatorSetTokenType.sol";
/**
* @title CreatorTokenBase
* @author Limit Break, Inc.
* @notice CreatorTokenBaseV3 is an abstract contract that provides basic functionality for managing token
* transfer policies through an implementation of ICreatorTokenTransferValidator/ICreatorTokenTransferValidatorV2/ICreatorTokenTransferValidatorV3.
* This contract is intended to be used as a base for creator-specific token contracts, enabling customizable transfer
* restrictions and security policies.
*
* <h4>Features:</h4>
* <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul>
* <ul>TransferValidation: Implements the basic token transfer validation interface.</ul>
*
* <h4>Benefits:</h4>
* <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul>
* <ul>Allows creators to enforce policies such as account and codehash blacklists, whitelists, and graylists.</ul>
* <ul>Can be easily integrated into other token contracts as a base contract.</ul>
*
* <h4>Intended Usage:</h4>
* <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and
* security policies.</ul>
* <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the
* creator token.</ul>
*
* <h4>Compatibility:</h4>
* <ul>Backward and Forward Compatible - V1/V2/V3 Creator Token Base will work with V1/V2/V3 Transfer Validators.</ul>
*/
abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken {
/// @dev Thrown when setting a transfer validator address that has no deployed code.
error CreatorTokenBase__InvalidTransferValidatorContract();
/// @dev The default transfer validator that will be used if no transfer validator has been set by the creator.
address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x721C008fdff27BF06E7E123956E2Fe03B63342e3);
/// @dev Used to determine if the default transfer validator is applied.
/// @dev Set to true when the creator sets a transfer validator address.
bool private isValidatorInitialized;
/// @dev Address of the transfer validator to apply to transactions.
address private transferValidator;
constructor() {
_emitDefaultTransferValidator();
_registerTokenType(DEFAULT_TRANSFER_VALIDATOR);
}
/**
* @notice Sets the transfer validator for the token contract.
*
* @dev Throws when provided validator contract is not the zero address and does not have code.
* @dev Throws when the caller is not the contract owner.
*
* @dev <h4>Postconditions:</h4>
* 1. The transferValidator address is updated.
* 2. The `TransferValidatorUpdated` event is emitted.
*
* @param transferValidator_ The address of the transfer validator contract.
*/
function setTransferValidator(address transferValidator_) public {
_requireCallerIsContractOwner();
bool isValidTransferValidator = transferValidator_.code.length > 0;
if(transferValidator_ != address(0) && !isValidTransferValidator) {
revert CreatorTokenBase__InvalidTransferValidatorContract();
}
emit TransferValidatorUpdated(address(getTransferValidator()), transferValidator_);
isValidatorInitialized = true;
transferValidator = transferValidator_;
_registerTokenType(transferValidator_);
}
/**
* @notice Returns the transfer validator contract address for this token contract.
*/
function getTransferValidator() public view override returns (address validator) {
validator = transferValidator;
if (validator == address(0)) {
if (!isValidatorInitialized) {
validator = DEFAULT_TRANSFER_VALIDATOR;
}
}
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the
* transfer validator is expected to pre-validate the transfer.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @param tokenId The token id being transferred.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 /*value*/) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId);
}
}
/**
* @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy.
* Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent
* and calling _validateBeforeTransfer so that checks can be properly applied during token transfers.
*
* @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the
* transfer validator is expected to pre-validate the transfer.
*
* @dev Used for ERC20 and ERC1155 token transfers which have an amount value to validate in the transfer validator.
* @dev The `tokenId` for ERC20 tokens should be set to `0`.
*
* @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is
* set to a non-zero address.
*
* @param caller The address of the caller.
* @param from The address of the sender.
* @param to The address of the receiver.
* @param tokenId The token id being transferred.
* @param amount The amount of token being transferred.
*/
function _preValidateTransfer(
address caller,
address from,
address to,
uint256 tokenId,
uint256 amount,
uint256 /*value*/) internal virtual override {
address validator = getTransferValidator();
if (validator != address(0)) {
if (msg.sender == validator) {
return;
}
ITransferValidator(validator).validateTransfer(caller, from, to, tokenId, amount);
}
}
function _tokenType() internal virtual pure returns(uint16);
function _registerTokenType(address validator) internal {
if (validator != address(0)) {
uint256 validatorCodeSize;
assembly {
validatorCodeSize := extcodesize(validator)
}
if(validatorCodeSize > 0) {
try ITransferValidatorSetTokenType(validator).setTokenTypeOfCollection(address(this), _tokenType()) {
} catch { }
}
}
}
/**
* @dev Used during contract deployment for constructable and cloneable creator tokens
* @dev to emit the `TransferValidatorUpdated` event signaling the validator for the contract
* @dev is the default transfer validator.
*/
function _emitDefaultTransferValidator() internal {
emit TransferValidatorUpdated(address(0), DEFAULT_TRANSFER_VALIDATOR);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import "@openzeppelin/contracts/utils/Context.sol";
/**
* @title TransferValidation
* @author Limit Break, Inc.
* @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks.
* Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows
* developers to validate or customize transfers within the context of a mint, a burn, or a transfer.
*/
abstract contract TransferValidation is Context {
/// @dev Thrown when the from and to address are both the zero address.
error ShouldNotMintToBurnAddress();
/*************************************************************************/
/* Transfers Without Amounts */
/*************************************************************************/
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {}
/*************************************************************************/
/* Transfers With Amounts */
/*************************************************************************/
/// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks.
function _validateBeforeTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_preValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_preValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_preValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
/// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks.
function _validateAfterTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual {
bool fromZeroAddress = from == address(0);
bool toZeroAddress = to == address(0);
if(fromZeroAddress && toZeroAddress) {
revert ShouldNotMintToBurnAddress();
} else if(fromZeroAddress) {
_postValidateMint(_msgSender(), to, tokenId, amount, msg.value);
} else if(toZeroAddress) {
_postValidateBurn(_msgSender(), from, tokenId, amount, msg.value);
} else {
_postValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value);
}
}
/// @dev Optional validation hook that fires before a mint
function _preValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a mint
function _postValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a burn
function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a burn
function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires before a transfer
function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
/// @dev Optional validation hook that fires after a transfer
function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)
pragma solidity ^0.8.0;
import "../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.
*
* By default, the owner account will be the one that deploys the contract. 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;
event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);
/**
* @dev Initializes the contract setting the deployer as the initial owner.
*/
constructor() {
_transferOwnership(_msgSender());
}
/**
* @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 {
require(owner() == _msgSender(), "Ownable: caller is not the owner");
}
/**
* @dev Leaves the contract without owner. It will not be possible to call
* `onlyOwner` functions anymore. Can only be called by the current owner.
*
* NOTE: Renouncing ownership will leave the contract without an owner,
* thereby removing 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 {
require(newOwner != address(0), "Ownable: new owner is the zero address");
_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 v4.6.0) (interfaces/IERC2981.sol)
pragma solidity ^0.8.0;
import "../utils/introspection/IERC165.sol";
/**
* @dev Interface for the NFT Royalty Standard.
*
* A standardized way to retrieve royalty payment information for non-fungible tokens (NFTs) to enable universal
* support for royalty payments across all NFT marketplaces and ecosystem participants.
*
* _Available since v4.5._
*/
interface IERC2981 is IERC165 {
/**
* @dev Returns how much royalty is owed and to whom, based on a sale price that may be denominated in any unit of
* exchange. The royalty amount is denominated and should be paid in that same unit of exchange.
*/
function royaltyInfo(uint256 tokenId, uint256 salePrice)
external
view
returns (address receiver, uint256 royaltyAmount);
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/common/ERC2981.sol)
pragma solidity ^0.8.0;
import "../../interfaces/IERC2981.sol";
import "../../utils/introspection/ERC165.sol";
/**
* @dev Implementation of the NFT Royalty Standard, a standardized way to retrieve royalty payment information.
*
* Royalty information can be specified globally for all token ids via {_setDefaultRoyalty}, and/or individually for
* specific token ids via {_setTokenRoyalty}. The latter takes precedence over the first.
*
* Royalty is specified as a fraction of sale price. {_feeDenominator} is overridable but defaults to 10000, meaning the
* fee is specified in basis points by default.
*
* IMPORTANT: ERC-2981 only specifies a way to signal royalty information and does not enforce its payment. See
* https://eips.ethereum.org/EIPS/eip-2981#optional-royalty-payments[Rationale] in the EIP. Marketplaces are expected to
* voluntarily pay royalties together with sales, but note that this standard is not yet widely supported.
*
* _Available since v4.5._
*/
abstract contract ERC2981 is IERC2981, ERC165 {
struct RoyaltyInfo {
address receiver;
uint96 royaltyFraction;
}
RoyaltyInfo private _defaultRoyaltyInfo;
mapping(uint256 => RoyaltyInfo) private _tokenRoyaltyInfo;
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override(IERC165, ERC165) returns (bool) {
return interfaceId == type(IERC2981).interfaceId || super.supportsInterface(interfaceId);
}
/**
* @inheritdoc IERC2981
*/
function royaltyInfo(uint256 _tokenId, uint256 _salePrice) public view virtual override returns (address, uint256) {
RoyaltyInfo memory royalty = _tokenRoyaltyInfo[_tokenId];
if (royalty.receiver == address(0)) {
royalty = _defaultRoyaltyInfo;
}
uint256 royaltyAmount = (_salePrice * royalty.royaltyFraction) / _feeDenominator();
return (royalty.receiver, royaltyAmount);
}
/**
* @dev The denominator with which to interpret the fee set in {_setTokenRoyalty} and {_setDefaultRoyalty} as a
* fraction of the sale price. Defaults to 10000 so fees are expressed in basis points, but may be customized by an
* override.
*/
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/**
* @dev Sets the royalty information that all ids in this contract will default to.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: invalid receiver");
_defaultRoyaltyInfo = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Removes default royalty information.
*/
function _deleteDefaultRoyalty() internal virtual {
delete _defaultRoyaltyInfo;
}
/**
* @dev Sets the royalty information for a specific token id, overriding the global default.
*
* Requirements:
*
* - `receiver` cannot be the zero address.
* - `feeNumerator` cannot be greater than the fee denominator.
*/
function _setTokenRoyalty(
uint256 tokenId,
address receiver,
uint96 feeNumerator
) internal virtual {
require(feeNumerator <= _feeDenominator(), "ERC2981: royalty fee will exceed salePrice");
require(receiver != address(0), "ERC2981: Invalid parameters");
_tokenRoyaltyInfo[tokenId] = RoyaltyInfo(receiver, feeNumerator);
}
/**
* @dev Resets royalty information for the token id back to the global default.
*/
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
delete _tokenRoyaltyInfo[tokenId];
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)
pragma solidity ^0.8.0;
/**
* @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;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/ERC165.sol)
pragma solidity ^0.8.0;
import "./IERC165.sol";
/**
* @dev Implementation of the {IERC165} interface.
*
* Contracts that want to implement ERC165 should inherit from this contract and override {supportsInterface} to check
* for the additional interface id that will be supported. For example:
*
* ```solidity
* function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
* return interfaceId == type(MyInterface).interfaceId || super.supportsInterface(interfaceId);
* }
* ```
*
* Alternatively, {ERC165Storage} provides an easier to use but more expensive implementation.
*/
abstract contract ERC165 is IERC165 {
/**
* @dev See {IERC165-supportsInterface}.
*/
function supportsInterface(bytes4 interfaceId) public view virtual override returns (bool) {
return interfaceId == type(IERC165).interfaceId;
}
}// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)
pragma solidity ^0.8.0;
/**
* @dev Interface of the ERC165 standard, as defined in the
* https://eips.ethereum.org/EIPS/eip-165[EIP].
*
* Implementers can declare support of contract interfaces, which can then be
* queried by others ({ERC165Checker}).
*
* For an implementation, see {ERC165}.
*/
interface IERC165 {
/**
* @dev Returns true if this contract implements the interface defined by
* `interfaceId`. See the corresponding
* https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
* to learn more about how these ids are created.
*
* This function call must use less than 30 000 gas.
*/
function supportsInterface(bytes4 interfaceId) external view returns (bool);
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for byte related operations.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol)
library LibBytes {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated bytes storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct BytesStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the bytes.
uint256 internal constant NOT_FOUND = type(uint256).max;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTE STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the bytes storage `$` to `s`.
function set(BytesStorage storage $, bytes memory s) internal {
/// @solidity memory-safe-assembly
assembly {
let n := mload(s)
let packed := or(0xff, shl(8, n))
for { let i := 0 } 1 {} {
if iszero(gt(n, 0xfe)) {
i := 0x1f
packed := or(n, shl(8, mload(add(s, i))))
if iszero(gt(n, i)) { break }
}
let o := add(s, 0x20)
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), mload(add(o, i)))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to `s`.
function setCalldata(BytesStorage storage $, bytes calldata s) internal {
/// @solidity memory-safe-assembly
assembly {
let packed := or(0xff, shl(8, s.length))
for { let i := 0 } 1 {} {
if iszero(gt(s.length, 0xfe)) {
i := 0x1f
packed := or(s.length, shl(8, shr(8, calldataload(s.offset))))
if iszero(gt(s.length, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
sstore(add(p, shr(5, i)), calldataload(add(s.offset, i)))
i := add(i, 0x20)
if iszero(lt(i, s.length)) { break }
}
break
}
sstore($.slot, packed)
}
}
/// @dev Sets the value of the bytes storage `$` to the empty bytes.
function clear(BytesStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty bytes "".
function isEmpty(BytesStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(BytesStorage storage $) internal view returns (uint256 result) {
result = uint256($._spacer);
/// @solidity memory-safe-assembly
assembly {
let n := and(0xff, result)
result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n))))
}
}
/// @dev Returns the value stored in `$`.
function get(BytesStorage storage $) internal view returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let o := add(result, 0x20)
let packed := sload($.slot)
let n := shr(8, packed)
for { let i := 0 } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
mstore(o, packed)
n := and(0xff, packed)
i := 0x1f
if iszero(gt(n, i)) { break }
}
mstore(0x00, $.slot)
for { let p := keccak256(0x00, 0x20) } 1 {} {
mstore(add(o, i), sload(add(p, shr(5, i))))
i := add(i, 0x20)
if iszero(lt(i, n)) { break }
}
break
}
mstore(result, n) // Store the length of the memory.
mstore(add(o, n), 0) // Zeroize the slot after the bytes.
mstore(0x40, add(add(o, n), 0x20)) // Allocate memory.
}
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(BytesStorage storage $, uint256 i) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
for { let packed := sload($.slot) } 1 {} {
if iszero(eq(or(packed, 0xff), packed)) {
if iszero(gt(i, 0x1e)) {
result := byte(i, packed)
break
}
if iszero(gt(i, and(0xff, packed))) {
mstore(0x00, $.slot)
let j := sub(i, 0x1f)
result := byte(and(j, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, j))))
}
break
}
if iszero(gt(i, shr(8, packed))) {
mstore(0x00, $.slot)
result := byte(and(i, 0x1f), sload(add(keccak256(0x00, 0x20), shr(5, i))))
}
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BYTES OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`.
function replace(bytes memory subject, bytes memory needle, bytes memory replacement)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let needleLen := mload(needle)
let replacementLen := mload(replacement)
let d := sub(result, subject) // Memory difference.
let i := add(subject, 0x20) // Subject bytes pointer.
mstore(0x00, add(i, mload(subject))) // End of subject.
if iszero(gt(needleLen, mload(subject))) {
let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `needleLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, needleLen), h)) {
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
// Copy the `replacement` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j)))
j := add(j, 0x20)
if iszero(lt(j, replacementLen)) { break }
}
d := sub(add(d, replacementLen), needleLen)
if needleLen {
i := add(i, needleLen)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(add(i, d), t)
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
}
let end := mload(0x00)
let n := add(sub(d, add(result, 0x20)), end)
// Copy the rest of the bytes one word at a time.
for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) }
let o := add(i, d)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
for { let subjectLen := mload(subject) } 1 {} {
if iszero(mload(needle)) {
result := from
if iszero(gt(from, subjectLen)) { break }
result := subjectLen
break
}
let needleLen := mload(needle)
let subjectStart := add(subject, 0x20)
subject := add(subjectStart, from)
let end := add(sub(add(subjectStart, subjectLen), needleLen), 1)
let m := shl(3, sub(0x20, and(needleLen, 0x1f)))
let s := mload(add(needle, 0x20))
if iszero(and(lt(subject, end), lt(from, subjectLen))) { break }
if iszero(lt(needleLen, 0x20)) {
for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} {
if iszero(shr(m, xor(mload(subject), s))) {
if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
/// needleing from left to right, starting from `from`. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
result := not(0) // Initialize to `NOT_FOUND`.
if gt(mload(subject), from) {
let start := add(subject, 0x20)
let end := add(start, mload(subject))
let m := div(not(0), 255) // `0x0101 ... `.
let h := mul(byte(0, needle), m) // Replicating needle mask.
m := not(shl(7, m)) // `0x7f7f ... `.
for { let i := add(start, from) } 1 {} {
let c := xor(mload(i), h) // Load 32-byte chunk and xor with mask.
c := not(or(or(add(and(c, m), m), c), m)) // Each needle byte will be `0x80`.
if c {
c := and(not(shr(shl(3, sub(end, i)), not(0))), c) // Truncate bytes past the end.
if c {
let r := shl(7, lt(0x8421084210842108cc6318c6db6d54be, c)) // Save bytecode.
r := or(shl(6, lt(0xffffffffffffffff, shr(r, c))), r)
// forgefmt: disable-next-item
result := add(sub(i, start), shr(3, xor(byte(and(0x1f, shr(byte(24,
mul(0x02040810204081, shr(r, c))), 0x8421084210842108cc6318c6db6d54be)),
0xc0c8c8d0c8e8d0d8c8e8e0e8d0d8e0f0c8d0e8d0e0e0d8f0d0d0e0d8f8f8f8f8), r)))
break
}
}
i := add(i, 0x20)
if iszero(lt(i, end)) { break }
}
}
}
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right. Optimized for byte needles.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOfByte(bytes memory subject, bytes1 needle)
internal
pure
returns (uint256 result)
{
return indexOfByte(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) {
return indexOf(subject, needle, 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from)
internal
pure
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
for {} 1 {} {
result := not(0) // Initialize to `NOT_FOUND`.
let needleLen := mload(needle)
if gt(needleLen, mload(subject)) { break }
let w := result
let fromMax := sub(mload(subject), needleLen)
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(needle, 0x20), needleLen) } 1 {} {
if eq(keccak256(subject, needleLen), 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 `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256)
{
return lastIndexOf(subject, needle, type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) {
return indexOf(subject, needle) != NOT_FOUND;
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
// Just using keccak256 directly is actually cheaper.
let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n))
result := lt(gt(n, mload(subject)), t)
}
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(bytes memory subject, bytes memory needle)
internal
pure
returns (bool result)
{
/// @solidity memory-safe-assembly
assembly {
let n := mload(needle)
let notInRange := gt(n, mload(subject))
// `subject + 0x20 + max(subject.length - needle.length, 0)`.
let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n)))
// Just using keccak256 directly is actually cheaper.
result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange)
}
}
/// @dev Returns `subject` repeated `times`.
function repeat(bytes memory subject, uint256 times)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(or(iszero(times), iszero(l))) {
result := mload(0x40)
subject := add(subject, 0x20)
let o := add(result, 0x20)
for {} 1 {} {
// Copy the `subject` one word at a time.
for { let j := 0 } 1 {} {
mstore(add(o, j), mload(add(subject, j)))
j := add(j, 0x20)
if iszero(lt(j, l)) { break }
}
o := add(o, l)
times := sub(times, 1)
if iszero(times) { break }
}
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets.
function slice(bytes memory subject, uint256 start, uint256 end)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
let l := mload(subject) // Subject length.
if iszero(gt(l, end)) { end := l }
if iszero(gt(l, start)) { start := l }
if lt(start, end) {
result := mload(0x40)
let n := sub(end, start)
let i := add(subject, start)
let w := not(0x1f)
// Copy the `subject` one word at a time, backwards.
for { let j := and(add(n, 0x1f), w) } 1 {} {
mstore(add(result, j), mload(add(i, j)))
j := add(j, w) // `sub(j, 0x20)`.
if iszero(j) { break }
}
let o := add(add(result, 0x20), n)
mstore(o, 0) // Zeroize the slot after the bytes.
mstore(0x40, add(o, 0x20)) // Allocate memory.
mstore(result, n) // Store the length.
}
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset.
function slice(bytes memory subject, uint256 start)
internal
pure
returns (bytes memory result)
{
result = slice(subject, start, type(uint256).max);
}
/// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive).
/// `start` and `end` are byte offsets. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start, uint256 end)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
end := xor(end, mul(xor(end, subject.length), lt(subject.length, end)))
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, end), sub(end, start))
}
}
/// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes.
/// `start` is a byte offset. Faster than Solidity's native slicing.
function sliceCalldata(bytes calldata subject, uint256 start)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
start := xor(start, mul(xor(start, subject.length), lt(subject.length, start)))
result.offset := add(subject.offset, start)
result.length := mul(lt(start, subject.length), sub(subject.length, start))
}
}
/// @dev Reduces the size of `subject` to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncate(bytes memory subject, uint256 n)
internal
pure
returns (bytes memory result)
{
/// @solidity memory-safe-assembly
assembly {
result := subject
mstore(mul(lt(n, mload(result)), result), n)
}
}
/// @dev Returns a copy of `subject`, with the length reduced to `n`.
/// If `n` is greater than the size of `subject`, this will be a no-op.
function truncatedCalldata(bytes calldata subject, uint256 n)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
result.offset := subject.offset
result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n)))
}
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(bytes memory subject, bytes memory needle)
internal
pure
returns (uint256[] memory result)
{
/// @solidity memory-safe-assembly
assembly {
let searchLen := mload(needle)
if iszero(gt(searchLen, mload(subject))) {
result := mload(0x40)
let i := add(subject, 0x20)
let o := add(result, 0x20)
let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1)
let h := 0 // The hash of `needle`.
if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) }
let s := mload(add(needle, 0x20))
for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} {
let t := mload(i)
// Whether the first `searchLen % 32` bytes of `subject` and `needle` matches.
if iszero(shr(m, xor(t, s))) {
if h {
if iszero(eq(keccak256(i, searchLen), h)) {
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
mstore(o, sub(i, add(subject, 0x20))) // Append to `result`.
o := add(o, 0x20)
i := add(i, searchLen) // Advance `i` by `searchLen`.
if searchLen {
if iszero(lt(i, subjectSearchEnd)) { break }
continue
}
}
i := add(i, 1)
if iszero(lt(i, subjectSearchEnd)) { break }
}
mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`.
// Allocate memory for result.
// We allocate one more word, so this array can be recycled for {split}.
mstore(0x40, add(o, 0x20))
}
}
}
/// @dev Returns an arrays of bytess based on the `delimiter` inside of the `subject` bytes.
function split(bytes memory subject, bytes memory delimiter)
internal
pure
returns (bytes[] 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))
for { let prevIndex := 0 } 1 {} {
let index := mload(indexPtr)
mstore(indexPtr, 0x60)
if iszero(eq(index, prevIndex)) {
let element := mload(0x40)
let l := sub(index, prevIndex)
mstore(element, l) // Store the length of the element.
// Copy the `subject` one word at a time, backwards.
for { let o := and(add(l, 0x1f), w) } 1 {} {
mstore(add(element, o), mload(add(add(subject, prevIndex), o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes.
// Allocate memory for the length and the bytes, rounded up to a multiple of 32.
mstore(0x40, add(element, and(add(l, 0x3f), w)))
mstore(indexPtr, element) // Store the `element` into the array.
}
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 bytes of `a` and `b`.
/// Cheaper than `bytes.concat()` and does not de-align the free memory pointer.
function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
let w := not(0x1f)
let aLen := mload(a)
// Copy `a` one word at a time, backwards.
for { let o := and(add(aLen, 0x20), w) } 1 {} {
mstore(add(result, o), mload(add(a, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let bLen := mload(b)
let output := add(result, aLen)
// Copy `b` one word at a time, backwards.
for { let o := and(add(bLen, 0x20), w) } 1 {} {
mstore(add(output, o), mload(add(b, o)))
o := add(o, w) // `sub(o, 0x20)`.
if iszero(o) { break }
}
let totalLen := add(aLen, bLen)
let last := add(add(result, 0x20), totalLen)
mstore(last, 0) // Zeroize the slot after the bytes.
mstore(result, totalLen) // Store the length.
mstore(0x40, add(last, 0x20)) // Allocate memory.
}
}
/// @dev Returns whether `a` equals `b`.
function eq(bytes memory a, bytes 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 bytes.
function eqs(bytes 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 Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) {
/// @solidity memory-safe-assembly
assembly {
let aLen := mload(a)
let bLen := mload(b)
let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f))
if n {
for { let i := 0x20 } 1 {} {
let x := mload(add(a, i))
let y := mload(add(b, i))
if iszero(or(xor(x, y), eq(i, n))) {
i := add(i, 0x20)
continue
}
result := sub(gt(x, y), lt(x, y))
break
}
}
// forgefmt: disable-next-item
if iszero(result) {
let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201
let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0)))
let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0)))
result := sub(gt(x, y), lt(x, y))
if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) }
}
}
}
/// @dev Directly returns `a` without copying.
function directReturn(bytes memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the bytes does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := add(mload(a), 0x40)
// Right pad with zeroes. Just in case the bytes is produced
// by a method that doesn't zero right pad.
mstore(add(retStart, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the bytes.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
/// @dev Directly returns `a` with minimal copying.
function directReturn(bytes[] memory a) internal pure {
/// @solidity memory-safe-assembly
assembly {
let n := mload(a) // `a.length`.
let o := add(a, 0x20) // Start of elements in `a`.
let u := a // Highest memory slot.
let w := not(0x1f)
for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } {
let c := add(o, shl(5, i)) // Location of pointer to `a[i]`.
let s := mload(c) // `a[i]`.
let l := mload(s) // `a[i].length`.
let r := and(l, 0x1f) // `a[i].length % 32`.
let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`.
// If `s` comes before `o`, or `s` is not zero right padded.
if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) {
let m := mload(0x40)
mstore(m, l) // Copy `a[i].length`.
for {} 1 {} {
mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards.
z := add(z, w) // `sub(z, 0x20)`.
if iszero(z) { break }
}
let e := add(add(m, 0x20), l)
mstore(e, 0) // Zeroize the slot after the copied bytes.
mstore(0x40, add(e, 0x20)) // Allocate memory.
s := m
}
mstore(c, sub(s, o)) // Convert to calldata offset.
let t := add(l, add(s, 0x20))
if iszero(lt(t, u)) { u := t }
}
let retStart := add(a, w) // Assumes `a` doesn't start from scratch space.
mstore(retStart, 0x20) // Store the return offset.
return(retStart, add(0x40, sub(u, retStart))) // End the transaction.
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(add(add(a, 0x20), offset))
}
}
/// @dev Returns the word at `offset`, without any bounds checks.
function loadCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes32 result)
{
/// @solidity memory-safe-assembly
assembly {
result := calldataload(add(a.offset, offset))
}
}
/// @dev Returns a slice representing a static struct in the calldata. Performs bounds checks.
function staticStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
result.offset := add(a.offset, offset)
result.length := sub(a.length, offset)
if or(shr(64, or(l, a.offset)), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns a slice representing a dynamic struct in the calldata. Performs bounds checks.
function dynamicStructInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(a.offset, s)
result.length := sub(a.length, s)
if or(shr(64, or(s, or(l, a.offset))), gt(offset, l)) { revert(l, 0x00) }
}
}
/// @dev Returns bytes in calldata. Performs bounds checks.
function bytesInCalldata(bytes calldata a, uint256 offset)
internal
pure
returns (bytes calldata result)
{
/// @solidity memory-safe-assembly
assembly {
let l := sub(a.length, 0x20)
let s := calldataload(add(a.offset, offset)) // Relative offset of `result` from `a.offset`.
result.offset := add(add(a.offset, s), 0x20)
result.length := calldataload(add(a.offset, s))
// forgefmt: disable-next-item
if or(shr(64, or(result.length, or(s, or(l, a.offset)))),
or(gt(add(s, result.length), l), gt(offset, l))) { revert(l, 0x00) }
}
}
/// @dev Returns empty calldata bytes. For silencing the compiler.
function emptyCalldata() internal pure returns (bytes calldata result) {
/// @solidity memory-safe-assembly
assembly {
result.length := 0
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {LibBytes} from "./LibBytes.sol";
/// @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 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Goated string storage struct that totally MOGs, no cap, fr.
/// Uses less gas and bytecode than Solidity's native string storage. It's meta af.
/// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight.
struct StringStorage {
bytes32 _spacer;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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();
/// @dev The input string must be a 7-bit ASCII.
error StringNot7BitASCII();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The constant returned when the `search` is not found in the string.
uint256 internal constant NOT_FOUND = type(uint256).max;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000;
/// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'.
uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000;
/// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.
uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000;
/// @dev Lookup for '0123456789'.
uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000;
/// @dev Lookup for '0123456789abcdefABCDEF'.
uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000;
/// @dev Lookup for '01234567'.
uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000;
/// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'.
uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00;
/// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'.
uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000;
/// @dev Lookup for ' \t\n\r\x0b\x0c'.
uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRING STORAGE OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the value of the string storage `$` to `s`.
function set(StringStorage storage $, string memory s) internal {
LibBytes.set(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to `s`.
function setCalldata(StringStorage storage $, string calldata s) internal {
LibBytes.setCalldata(bytesStorage($), bytes(s));
}
/// @dev Sets the value of the string storage `$` to the empty string.
function clear(StringStorage storage $) internal {
delete $._spacer;
}
/// @dev Returns whether the value stored is `$` is the empty string "".
function isEmpty(StringStorage storage $) internal view returns (bool) {
return uint256($._spacer) & 0xff == uint256(0);
}
/// @dev Returns the length of the value stored in `$`.
function length(StringStorage storage $) internal view returns (uint256) {
return LibBytes.length(bytesStorage($));
}
/// @dev Returns the value stored in `$`.
function get(StringStorage storage $) internal view returns (string memory) {
return string(LibBytes.get(bytesStorage($)));
}
/// @dev Returns the uint8 at index `i`. If out-of-bounds, returns 0.
function uint8At(StringStorage storage $, uint256 i) internal view returns (uint8) {
return LibBytes.uint8At(bytesStorage($), i);
}
/// @dev Helper to cast `$` to a `BytesStorage`.
function bytesStorage(StringStorage storage $)
internal
pure
returns (LibBytes.BytesStorage storage casted)
{
/// @solidity memory-safe-assembly
assembly {
casted.slot := $.slot
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* DECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the base 10 decimal representation of `value`.
function toString(uint256 value) internal pure returns (string memory result) {
/// @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.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end of the memory to calculate the length later.
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 {} {
result := add(result, w) // `sub(result, 1)`.
// Store the character to the pointer.
// The ASCII index of the '0' character is 48.
mstore8(result, add(48, mod(temp, 10)))
temp := div(temp, 10) // Keep dividing `temp` until zero.
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the base 10 decimal representation of `value`.
function toString(int256 value) internal pure returns (string memory result) {
if (value >= 0) return toString(uint256(value));
unchecked {
result = 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 n := mload(result) // Load the string length.
mstore(result, 0x2d) // Store the '-' character.
result := sub(result, 1) // Move back the string pointer by a byte.
mstore(result, add(n, 1)) // Update the string length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HEXADECIMAL OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2 + 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexString(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
result = toHexStringNoPrefix(value, byteCount);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store the length.
}
}
/// @dev Returns the hexadecimal representation of `value`,
/// left-padded to an input length of `byteCount` bytes.
/// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte,
/// giving a total length of `byteCount * 2` bytes.
/// Reverts if `byteCount` is too small for the output to contain all the digits.
function toHexStringNoPrefix(uint256 value, uint256 byteCount)
internal
pure
returns (string memory result)
{
/// @solidity memory-safe-assembly
assembly {
// We need 0x20 bytes for the trailing zeros padding, `byteCount * 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.
result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f)))
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
// Store "0123456789abcdef" in scratch space.
mstore(0x0f, 0x30313233343536373839616263646566)
let start := sub(result, add(byteCount, byteCount))
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 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(xor(result, start)) { break }
}
if temp {
mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`.
revert(0x1c, 0x04)
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := add(mload(result), 2) // Compute the length.
mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero.
result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store 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 result)
{
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present.
let n := mload(result) // Get the length.
result := add(result, o) // Move the pointer, accounting for leading zero.
mstore(result, sub(n, o)) // Store 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 result) {
/// @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.
result := add(mload(0x40), 0x80)
mstore(0x40, add(result, 0x20)) // Allocate memory.
mstore(result, 0) // Zeroize the slot after the string.
let end := result // Cache the end to calculate the length later.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
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 {} {
result := add(result, w) // `sub(result, 2)`.
mstore8(add(result, 1), mload(and(temp, 15)))
mstore8(result, mload(and(shr(4, temp), 15)))
temp := shr(8, temp)
if iszero(temp) { break }
}
let n := sub(end, result)
result := sub(result, 0x20)
mstore(result, n) // Store the length.
}
}
/// @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 result) {
result = toHexString(value);
/// @solidity memory-safe-assembly
assembly {
let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...`
let o := add(result, 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 result) {
result = toHexStringNoPrefix(value);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Allocate 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(result, 0x80))
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
result := add(result, 2)
mstore(result, 40) // Store the length.
let o := add(result, 0x20)
mstore(add(o, 40), 0) // Zeroize the slot after the string.
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 result) {
result = toHexStringNoPrefix(raw);
/// @solidity memory-safe-assembly
assembly {
let n := add(mload(result), 2) // Compute the length.
mstore(result, 0x3078) // Store the "0x" prefix.
result := sub(result, 2) // Move the pointer.
mstore(result, n) // Store 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 result) {
/// @solidity memory-safe-assembly
assembly {
let n := mload(raw)
result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix.
mstore(result, add(n, n)) // Store the length of the output.
mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup.
let o := add(result, 0x20)
let end := add(raw, n)
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 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 {
result := 1
let mask := shl(7, div(not(0), 255))
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)
}
}
}
/// @dev Returns if this string is a 7-bit ASCII string,
/// AND all characters are in the `allowed` lookup.
/// Note: If `s` is empty, returns true regardless of `allowed`.
function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
result := 1
if mload(s) {
let allowed_ := shr(128, shl(128, allowed))
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := and(result, shr(byte(0, mload(o)), allowed_))
o := add(o, 1)
if iszero(and(result, lt(o, end))) { break }
}
}
}
}
/// @dev Converts the bytes in the 7-bit ASCII string `s` to
/// an allowed lookup for use in `is7BitASCII(s, allowed)`.
/// To save runtime gas, you can cache the result in an immutable variable.
function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) {
/// @solidity memory-safe-assembly
assembly {
if mload(s) {
let o := add(s, 0x20)
for { let end := add(o, mload(s)) } 1 {} {
result := or(result, shl(byte(0, mload(o)), 1))
o := add(o, 1)
if iszero(lt(o, end)) { break }
}
if shr(128, result) {
mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`.
revert(0x1c, 0x04)
}
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* 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 `needle` replaced with `replacement`.
function replace(string memory subject, string memory needle, string memory replacement)
internal
pure
returns (string memory)
{
return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement)));
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.indexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from left to right.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function indexOf(string memory subject, string memory needle) internal pure returns (uint256) {
return LibBytes.indexOf(bytes(subject), bytes(needle), 0);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left, starting from `from`.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle, uint256 from)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from);
}
/// @dev Returns the byte index of the first location of `needle` in `subject`,
/// needleing from right to left.
/// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found.
function lastIndexOf(string memory subject, string memory needle)
internal
pure
returns (uint256)
{
return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max);
}
/// @dev Returns true if `needle` is found in `subject`, false otherwise.
function contains(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.contains(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` starts with `needle`.
function startsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.startsWith(bytes(subject), bytes(needle));
}
/// @dev Returns whether `subject` ends with `needle`.
function endsWith(string memory subject, string memory needle) internal pure returns (bool) {
return LibBytes.endsWith(bytes(subject), bytes(needle));
}
/// @dev Returns `subject` repeated `times`.
function repeat(string memory subject, uint256 times) internal pure returns (string memory) {
return string(LibBytes.repeat(bytes(subject), times));
}
/// @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)
{
return string(LibBytes.slice(bytes(subject), start, end));
}
/// @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) {
return string(LibBytes.slice(bytes(subject), start, type(uint256).max));
}
/// @dev Returns all the indices of `needle` in `subject`.
/// The indices are byte offsets.
function indicesOf(string memory subject, string memory needle)
internal
pure
returns (uint256[] memory)
{
return LibBytes.indicesOf(bytes(subject), bytes(needle));
}
/// @dev Returns an 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)
{
bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter));
/// @solidity memory-safe-assembly
assembly {
result := a
}
}
/// @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) {
return string(LibBytes.concat(bytes(a), bytes(b)));
}
/// @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 n := mload(subject)
if n {
result := mload(0x40)
let o := add(result, 0x20)
let d := sub(subject, result)
let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff)
for { let end := add(o, n) } 1 {} {
let b := byte(0, mload(add(d, o)))
mstore8(o, xor(and(shr(b, flags), 0x20), b))
o := add(o, 1)
if eq(o, end) { break }
}
mstore(result, n) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate 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) // Store the length.
let o := add(result, 0x20)
mstore(o, s) // Store the bytes of the string.
mstore(add(o, n), 0) // Zeroize the slot after the string.
mstore(0x40, add(result, 0x40)) // Allocate memory.
}
}
/// @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 {
result := mload(0x40)
let end := add(s, mload(s))
let o := add(result, 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(o, c)
o := add(o, 1)
continue
}
let t := shr(248, mload(c))
mstore(o, mload(and(t, 0x1f)))
o := add(o, shr(5, t))
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate 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 {
result := mload(0x40)
let o := add(result, 0x20)
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
// 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 { let end := add(s, mload(s)) } 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(o, c)
o := add(o, 1)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), c)
o := add(o, 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(o, mload(0x19)) // "\\u00XX".
o := add(o, 6)
continue
}
mstore8(o, 0x5c) // "\\".
mstore8(add(o, 1), mload(add(c, 8)))
o := add(o, 2)
}
if addDoubleQuotes {
mstore8(o, 34)
o := add(1, o)
}
mstore(o, 0) // Zeroize the slot after the string.
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(0x40, add(o, 0x20)) // Allocate 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 Encodes `s` so that it can be safely used in a URI,
/// just like `encodeURIComponent` in JavaScript.
/// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent
/// See: https://datatracker.ietf.org/doc/html/rfc2396
/// See: https://datatracker.ietf.org/doc/html/rfc3986
function encodeURIComponent(string memory s) internal pure returns (string memory result) {
/// @solidity memory-safe-assembly
assembly {
result := mload(0x40)
// Store "0123456789ABCDEF" in scratch space.
// Uppercased to be consistent with JavaScript's implementation.
mstore(0x0f, 0x30313233343536373839414243444546)
let o := add(result, 0x20)
for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} {
s := add(s, 1)
let c := and(mload(s), 0xff)
// If not in `[0-9A-Z-a-z-_.!~*'()]`.
if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) {
mstore8(o, 0x25) // '%'.
mstore8(add(o, 1), mload(and(shr(4, c), 15)))
mstore8(add(o, 2), mload(and(c, 15)))
o := add(o, 3)
continue
}
mstore8(o, c)
o := add(o, 1)
}
mstore(result, sub(o, add(result, 0x20))) // Store the length.
mstore(o, 0) // Zeroize the slot after the string.
mstore(0x40, add(o, 0x20)) // Allocate memory.
}
}
/// @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 Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`.
/// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1.
function cmp(string memory a, string memory b) internal pure returns (int256) {
return LibBytes.cmp(bytes(a), bytes(b));
}
/// @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 {
result := mload(0x40) // Grab the free memory pointer.
mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes).
mstore(result, 0) // Zeroize the length slot.
mstore(add(result, 0x1f), packed) // Store the length and bytes.
mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes.
}
}
/// @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 aLen := mload(a)
// We don't need to zero right pad the strings,
// since this is our own custom non-standard packing scheme.
result :=
mul(
or( // Load the length and the bytes of `a` and `b`.
shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))),
// `totalLen != 0 && totalLen < 31`. Abuses underflow.
// Assumes that the lengths are valid and within the block gas limit.
lt(sub(add(aLen, 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 {
resultA := mload(0x40) // Grab the free memory pointer.
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 {
/// @solidity memory-safe-assembly
assembly {
// Assumes that the string does not start from the scratch space.
let retStart := sub(a, 0x20)
let retUnpaddedSize := 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, retUnpaddedSize), 0)
mstore(retStart, 0x20) // Store the return offset.
// End the transaction, returning the string.
return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize)))
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Reentrancy guard mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol)
abstract contract ReentrancyGuard {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Unauthorized reentrant call.
error Reentrancy();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`.
/// 9 bytes is large enough to avoid collisions with lower slots,
/// but not too large to result in excessive bytecode bloat.
uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* REENTRANCY GUARD */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Guards a function from reentrancy.
modifier nonReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
sstore(_REENTRANCY_GUARD_SLOT, address())
}
_;
/// @solidity memory-safe-assembly
assembly {
sstore(_REENTRANCY_GUARD_SLOT, codesize())
}
}
/// @dev Guards a view function from read-only reentrancy.
modifier nonReadReentrant() virtual {
/// @solidity memory-safe-assembly
assembly {
if eq(sload(_REENTRANCY_GUARD_SLOT), address()) {
mstore(0x00, 0xab143c06) // `Reentrancy()`.
revert(0x1c, 0x04)
}
}
_;
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Signature verification helper that supports both ECDSA signatures from EOAs
/// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SignatureCheckerLib.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol)
///
/// @dev Note:
/// - The signature checking functions use the ecrecover precompile (0x1).
/// - Unlike ECDSA signatures, contract signatures are revocable.
/// - As of Solady version 0.0.134, all `bytes signature` variants accept both
/// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures.
/// See: https://eips.ethereum.org/EIPS/eip-2098
/// This is for calldata efficiency on smart accounts prevalent on L2s.
///
/// WARNING! Do NOT use signatures as unique identifiers:
/// - Use a nonce in the digest to prevent replay attacks on the same contract.
/// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts.
/// EIP-712 also enables readable signing of typed data for better user safety.
/// This implementation does NOT check if a signature is non-malleable.
library SignatureCheckerLib {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* SIGNATURE CHECKING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns whether `signature` is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
function copy(dst_, src_, n_) {
for { let i_ := 0 } lt(i_, n_) { i_ := add(0x20, i_) } {
mstore(add(dst_, i_), mload(add(src_, i_)))
}
}
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
switch mload(signature)
case 64 {
let vs := mload(add(signature, 0x40))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`.
mstore(0x60, mload(add(signature, 0x40))) // `s`.
}
default { break }
mstore(0x00, hash)
mstore(0x40, mload(add(signature, 0x20))) // `r`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
// Copy the `signature` over.
let n := add(0x20, mload(signature))
copy(add(m, 0x44), signature, n)
isValid := staticcall(gas(), signer, m, add(n, 0x44), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/// @dev Returns whether `signature` is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
switch signature.length
case 64 {
let vs := calldataload(add(signature.offset, 0x20))
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, calldataload(signature.offset)) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
}
case 65 {
mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`.
calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`.
}
default { break }
mstore(0x00, hash)
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), signature.length)
// Copy the `signature` over.
calldatacopy(add(m, 0x64), signature.offset, signature.length)
isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
mstore(0x00, hash)
mstore(0x20, add(shr(255, vs), 27)) // `v`.
mstore(0x40, r) // `r`.
mstore(0x60, shr(1, shl(1, vs))) // `s`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`.
/// If `signer.code.length == 0`, then validate with `ecrecover`, else
/// it will validate with ERC1271 on `signer`.
function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (bool isValid)
{
if (signer == address(0)) return isValid;
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
for {} 1 {} {
if iszero(extcodesize(signer)) {
mstore(0x00, hash)
mstore(0x20, and(v, 0xff)) // `v`.
mstore(0x40, r) // `r`.
mstore(0x60, s) // `s`.
let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20))
isValid := gt(returndatasize(), shl(96, xor(signer, recovered)))
mstore(0x60, 0) // Restore the zero slot.
mstore(0x40, m) // Restore the free memory pointer.
break
}
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), s) // `s`.
mstore8(add(m, 0xa4), v) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
break
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC1271 OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// Note: These ERC1271 operations do NOT have an ECDSA fallback.
/// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
function copy(dst_, src_, n_) {
for { let i_ := 0 } lt(i_, n_) { i_ := add(0x20, i_) } {
mstore(add(dst_, i_), mload(add(src_, i_)))
}
}
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
// Copy the `signature` over.
let n := add(0x20, mload(signature))
copy(add(m, 0x44), signature, n)
isValid := staticcall(gas(), signer, m, add(n, 0x44), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract.
function isValidERC1271SignatureNowCalldata(
address signer,
bytes32 hash,
bytes calldata signature
) internal view returns (bool isValid) {
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), signature.length)
// Copy the `signature` over.
calldatacopy(add(m, 0x64), signature.offset, signature.length)
isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/// @dev Returns whether the signature (`r`, `vs`) is valid for `hash`
/// for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`.
mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash`
/// for an ERC1271 `signer` contract.
function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s)
internal
view
returns (bool isValid)
{
/// @solidity memory-safe-assembly
assembly {
let m := mload(0x40)
let f := shl(224, 0x1626ba7e)
mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`.
mstore(add(m, 0x04), hash)
let d := add(m, 0x24)
mstore(d, 0x40) // The offset of the `signature` in the calldata.
mstore(add(m, 0x44), 65) // Length of the signature.
mstore(add(m, 0x64), r) // `r`.
mstore(add(m, 0x84), s) // `s`.
mstore8(add(m, 0xa4), v) // `v`.
isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20)
isValid := and(eq(mload(d), f), isValid)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* HASHING OPERATIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an Ethereum Signed Message, created from a `hash`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
/// JSON-RPC method as part of EIP-191.
function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, hash) // Store into scratch space for keccak256.
mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes.
result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`.
}
}
/// @dev Returns an Ethereum Signed Message, created from `s`.
/// This produces a hash corresponding to the one signed with the
/// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign)
/// JSON-RPC method as part of EIP-191.
/// Note: Supports lengths of `s` up to 999999 bytes.
function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) {
/// @solidity memory-safe-assembly
assembly {
let sLength := mload(s)
let o := 0x20
mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded.
mstore(0x00, 0x00)
// Convert the `s.length` to ASCII decimal representation: `base10(s.length)`.
for { let temp := sLength } 1 {} {
o := sub(o, 1)
mstore8(o, add(48, mod(temp, 10)))
temp := div(temp, 10)
if iszero(temp) { break }
}
let n := sub(0x3a, o) // Header length: `26 + 32 - o`.
// Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes.
returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20))
mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header.
result := keccak256(add(s, sub(0x20, n)), add(n, sLength))
mstore(s, sLength) // Restore the length.
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EMPTY CALLDATA HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns an empty calldata bytes.
function emptySignature() internal pure returns (bytes calldata signature) {
/// @solidity memory-safe-assembly
assembly {
signature.length := 0
}
}
}{
"codegen": "yul",
"enableEraVMExtensions": false,
"evmVersion": "cancun",
"forceEVMLA": false,
"libraries": {},
"metadata": {},
"optimizer": {
"disable_system_request_memoization": true,
"enabled": true,
"mode": "3",
"size_fallback": false
},
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"remappings": [
"erc721a/=lib/ERC721A/",
"solady/=lib/solady/",
"@limitbreak/creator-token-standards/=lib/creator-token-standards/",
"@openzeppelin/=lib/openzeppelin-contracts/",
"ds-test/=lib/forge-std/lib/ds-test/src/",
"forge-std/=lib/forge-std/src/",
"murky/=lib/murky/src/",
"@matterlabs/=lib/era-contracts/l2-contracts/lib/@matterlabs/",
"@limitbreak/permit-c/=lib/creator-token-standards/lib/PermitC/src/",
"@opensea/tstorish/=lib/creator-token-standards/lib/tstorish/src/",
"@rari-capital/solmate/=lib/creator-token-standards/lib/PermitC/lib/solmate/",
"ERC721A/=lib/ERC721A/contracts/",
"PermitC/=lib/creator-token-standards/lib/PermitC/",
"creator-token-standards/=lib/creator-token-standards/",
"era-contracts/=lib/era-contracts/",
"erc4626-tests/=lib/murky/lib/openzeppelin-contracts/lib/erc4626-tests/",
"forge-gas-metering/=lib/creator-token-standards/lib/PermitC/lib/forge-gas-metering/",
"openzeppelin-contracts-upgradeable-v4/=lib/era-contracts/lib/openzeppelin-contracts-upgradeable-v4/",
"openzeppelin-contracts-v4/=lib/era-contracts/lib/openzeppelin-contracts-v4/",
"openzeppelin-contracts/=lib/openzeppelin-contracts/",
"openzeppelin/=lib/creator-token-standards/lib/PermitC/lib/openzeppelin-contracts/contracts/",
"solmate/=lib/creator-token-standards/lib/PermitC/lib/solmate/src/",
"tstorish/=lib/creator-token-standards/lib/tstorish/src/"
],
"viaIR": true
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"signerAddress","type":"address"},{"internalType":"address","name":"royaltiesAddress","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"InsufficientPayment","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[],"name":"InvalidAmount","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"LockedURI","type":"error"},{"inputs":[],"name":"MaxMintPerWalletExceeded","type":"error"},{"inputs":[],"name":"MaxSupplyReached","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NoETHToWithdraw","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[],"name":"NotManager","type":"error"},{"inputs":[],"name":"NotMintablePhase","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"PayoutFailed","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","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":"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":[{"indexed":false,"internalType":"bool","name":"autoApproved","type":"bool"}],"name":"AutomaticApprovalOfTransferValidatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"amount","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"startTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTokenId","type":"uint256"}],"name":"BearyzMinted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"DefaultRoyaltySet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"newGenerationHash","type":"string"}],"name":"GenerationHashUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"enum Bearyz.MintPhase","name":"newPhase","type":"uint8"}],"name":"PhaseChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"receiver","type":"address"},{"indexed":false,"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"TokenRoyaltySet","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"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"autoApproveTransfersFromValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"currentPhase","outputs":[{"internalType":"enum Bearyz.MintPhase","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"generationHash","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":[],"name":"getCurrentPhase","outputs":[{"internalType":"enum Bearyz.MintPhase","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","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":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"isManager","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum Bearyz.MintPhase","name":"","type":"uint8"}],"name":"maxMintPerWallet","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"mintedBearyz","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"enum Bearyz.MintPhase","name":"","type":"uint8"}],"name":"mintedPerPhase","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"price","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"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":"bool","name":"autoApprove","type":"bool"}],"name":"setAutomaticApprovalOfTransfersFromValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"uri_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Bearyz.MintPhase","name":"phase","type":"uint8"}],"name":"setCurrentPhase","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newGenerationHash","type":"string"}],"name":"setGenerationHash","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setManager","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"enum Bearyz.MintPhase","name":"phase","type":"uint8"},{"internalType":"uint256","name":"newMaxMintPerWallet","type":"uint256"}],"name":"setMaxMintPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"setPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSignerAddress","type":"address"}],"name":"setSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","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":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"teamMint","outputs":[],"stateMutability":"nonpayable","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":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010005496eb34d9b8d9b6379c9f3e09c68bab228a38d2c3ff5d61d9e786a5fb400000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000060000000000000000000000000bea57adc5938002001209481dbb75760279688ab000000000000000000000000554fbc602cb6e2f488af7a30a5023b4ecc4419ac000000000000000000000000c88527406f9ca499f5640f0cb7d794d77928ed28
Deployed Bytecode
0x0001000000000002000c00000000000200000000000103550000008004000039000000400040043f000000600310027000000485033001970000000100200190000000200000c13d000000040030008c0000004a0000413d000000000201043b000000e002200270000004ad0020009c0000004c0000a13d000004ae0020009c000000c20000213d000004bd0020009c000001340000a13d000004be0020009c000001920000213d000004c20020009c0000046c0000613d000004c30020009c000004800000613d000004c40020009c0000004a0000c13d0000000001000416000000000001004b0000004a0000c13d0000000d01000039000004c70000013d0000000002000416000000000002004b0000004a0000c13d0000001f0230003900000486022001970000008002200039000000400020043f0000001f0530018f00000487063001980000008002600039000000300000613d000000000701034f000000007807043c0000000004840436000000000024004b0000002c0000c13d000000000005004b0000003d0000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000600030008c0000004a0000413d000000800a00043d0000048800a0009c0000004a0000213d000000a00100043d000b00000001001d000004880010009c0000004a0000213d000000c00100043d000a00000001001d000004880010009c000001cb0000a13d00000000010000190000121300010430000004cb0020009c000000f00000a13d000004cc0020009c000001140000a13d000004cd0020009c000001820000213d000004d10020009c000002b10000613d000004d20020009c000002ce0000613d000004d30020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000402100370000000000502043b0000048d0050009c0000004a0000213d0000002302500039000000000032004b0000004a0000813d0000000404500039000000000241034f000000000202043b0000048d0020009c000006610000213d0000001f062000390000051306600197000005140060009c000006610000213d00000024055000390000003f0660003900000513066001970000008006600039000000400060043f000000800020043f0000000005520019000000000035004b0000004a0000213d0000002003400039000000000431034f00000532052001980000001f0620018f000000a003500039000000820000613d000000a007000039000000000804034f000000008908043c0000000007970436000000000037004b0000007e0000c13d000000000006004b0000008f0000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000430435000000a00220003900000000000204350000000902000039000000000202041a00000488022001970000000003000411000000000032004b000006f30000c13d000000800300043d0000048d0030009c000006610000213d0000001102000039000000000402041a000000010040019000000001054002700000007f0550618f0000001f0050008c00000000060000390000000106002039000000000446013f00000001004001900000047a0000c13d0000000004000415000000200050008c000000b70000413d000000000020043f0000001f063000390000000506600270000005180660009a000000200030008c00000507060040410000001f055000390000000505500270000005180550009a000000000056004b000000b70000813d000000000006041b0000000106600039000000000056004b000000b30000413d0000000005000415000000000454004900000000040000020000001f0030008c000009020000a13d000000000020043f0000049005300198000009d60000c13d000000a0060000390000050704000041000009e40000013d000004af0020009c000001570000a13d000004b00020009c000001b30000213d000004b40020009c000004a40000613d000004b50020009c000004c30000613d000004b60020009c0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000a00000002001d0000002402100370000000000202043b000b00000002001d0000048d0020009c0000004a0000213d0000000b020000290000002302200039000000000032004b0000004a0000813d0000000b02000029000800040020003d0000000801100360000000000101043b000900000001001d0000048d0010009c0000004a0000213d0000000b010000290000002402100039000700000002001d0000000901200029000000000031004b0000004a0000213d000004ec01000041000000000301041a0000000002000410000000000023004b000006e50000c13d000004fe01000041000000000010043f000004ff010000410000121300010430000004da0020009c000001030000213d000004e10020009c000002070000a13d000004e20020009c000002df0000613d000004e30020009c000002e70000613d000004e40020009c0000004a0000c13d0000000001000416000000000001004b0000004a0000c13d0000001001000039000000000101041a000000ff0110018f000000040010008c000005130000813d000005d30000013d000004db0020009c000002200000a13d000004dc0020009c000002fa0000613d000004dd0020009c000003090000613d000004de0020009c0000004a0000c13d0000000001000416000000000001004b0000004a0000c13d0000052401000041000000800010043f0000000101000039000000a00010043f0000052501000041000012120001042e000004d40020009c000002470000a13d000004d50020009c000003100000613d000004d60020009c0000034f0000613d000004d70020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000004880020009c0000004a0000213d0000002401100370000000000101043b000b00000001001d000000030010008c0000004a0000213d000000000020043f0000001401000039000000200010043f00000040020000390000000001000019121111db0000040f0000000b0200002912110c690000040f000000000101041a0000052b0000013d000004c50020009c000002500000a13d000004c60020009c000003660000613d000004c70020009c000003720000613d000004c80020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000b00000001001d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000ff00100190000004bf0000613d0000000d01000039000006180000013d000004b70020009c000002690000a13d000004b80020009c0000037b0000613d000004b90020009c000003980000613d000004ba0020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000201043b000000000002004b000006d20000613d000000000100041a000000000021004b000006d20000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000000001004b000006b20000c13d0000000b02000029000000000002004b000000010220008a0000016c0000c13d00000b270000013d000004ce0020009c000003b60000613d000004cf0020009c000004200000613d000004d00020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b1211112d0000040f00000488011001970000052b0000013d000004bf0020009c000004cb0000613d000004c00020009c0000050b0000613d000004c10020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000b00000002001d000004880020009c0000004a0000213d0000002401100370000000000101043b000a00000001001d000000010010008c0000004a0000213d121111160000040f0000000b01000029000000000010043f0000001501000039000000200010043f00000040020000390000000001000019121111db0000040f000000000301041a00000533023001970000000a03000029000002f60000013d000004b10020009c000005190000613d000004b20020009c000005320000613d000004b30020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000004880010009c0000004a0000213d000000000010043f0000001501000039000000200010043f00000040020000390000000001000019121111db0000040f000000000101041a000000ff00100190000004260000013d000000400200043d000004890020009c000006610000813d0000004001200039000000400010043f000000060100003900000000041204360000048a030000410000000000340435000000400b00043d0000048b00b0009c000006610000213d0000004003b00039000000400030043f000000000c1b04360000048c0100004100000000001c043500000000030204330000048d0030009c000006610000213d0000000201000039000000000501041a000000010750019000000001065002700000007f0660618f0000001f0060008c00000000050000390000000105002039000000000075004b0000047a0000c13d0000000005000415000000200060008c000001fb0000413d000000000010043f0000001f0730003900000005077002700000048e0770009a000000200030008c0000048f070040410000001f0660003900000005066002700000048e0660009a000000000067004b000001fb0000813d000000000007041b0000000107700039000000000067004b000001f70000413d0000000006000415000000000565004900000000050000020000001f0030008c0000000105300210000005d60000a13d000000000010043f0000049007300198000006450000c13d00000020060000390000048f04000041000006510000013d000004e50020009c0000028c0000613d000004e60020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000201043b0000052a002001980000004a0000c13d00000001010000390000052b0020009c000005760000213d0000052f0020009c000005d30000613d000005300020009c000005d30000613d000005310020009c000000000100c019000000800010043f000004e701000041000012120001042e000004df0020009c000002930000613d000004e00020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000201043b000000000002004b000006e10000613d000000000100041a000000000021004b000006e10000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000000001004b000006d60000c13d0000000b02000029000000000002004b000000010220008a000002310000c13d00000b270000013d000004d80020009c0000042b0000613d000004d90020009c0000004a0000c13d000000000103001912110c3f0000040f12110cd50000040f0000000001000019000012120001042e000004c90020009c000004360000613d000004ca0020009c0000004a0000c13d0000000001000416000000000001004b0000004a0000c13d0000000901000039000000000201041a00000488032001970000000005000411000000000053004b0000054f0000c13d0000049302200197000000000021041b0000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d02000039000000030300003900000495040000410000000006000019000006360000013d000004bb0020009c000004450000613d000004bc0020009c0000004a0000c13d0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000004880020009c0000004a0000213d00000000030200190000002401100370000000000201043b0000000901000039000000000101041a00000488011001970000000004000411000000000041004b0000054f0000c13d000000000500041a000000010150008a000000000021001a00000b270000413d00000000012100190000000f04000039000000000404041a000000000041004b000005e00000a13d0000050801000041000000000010043f000004f80100004100001213000104300000000001000416000000000001004b0000004a0000c13d0000049601000041000000800010043f000004e701000041000012120001042e0000000001000416000000000001004b0000004a0000c13d0000000203000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000525013f00000001005001900000047a0000c13d000000800010043f000000000004004b000005600000613d000000000030043f000000000001004b0000055e0000613d0000048f030000410000000004000019000000000503041a000000a002400039000000000052043500000001033000390000002004400039000000000014004b000002a90000413d000005650000013d0000000001000416000000000001004b0000004a0000c13d0000000901000039000000000101041a00000488011001970000000002000411000000000021004b0000054f0000c13d0000051b010000410000000000100443000000000100041000000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c70000800a020000391211120c0000040f000000010020019000000b530000613d000000000301043b000000000003004b000006010000c13d0000051e01000041000000000010043f000004f8010000410000121300010430000000000103001912110c3f0000040f000b00000001001d000a00000002001d000900000003001d000000400100043d000800000001001d000000200200003912110c800000040f000000080400002900000000000404350000000b010000290000000a02000029000000090300002912110e770000040f0000000001000019000012120001042e0000000001000416000000000001004b0000004a0000c13d000000000100041a000000010110008a000000800010043f000004e701000041000012120001042e0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000b00000001001d000004880010009c0000004a0000213d121111160000040f0000001201000039000000000201041a00000493022001970000000b03000029000000000232019f000000000021041b0000000001000019000012120001042e000000440030008c0000004a0000413d0000000402100370000000000202043b000a00000002001d000004880020009c0000004a0000213d0000002401100370000000000101043b000000000001004b0000057f0000c13d0000052801000041000000000010043f000004f80100004100001213000104300000000001000416000000000001004b0000004a0000c13d12110cca0000040f000000800010043f000004e701000041000012120001042e0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000002402100370000000000202043b000b00000002001d0000000401100370000000000101043b000000000010043f0000000c01000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000400400043d0000048b0040009c000006610000213d000000000101043b0000004002400039000000400020043f000000000101041a0000002003400039000000a0021002700000000000230435000004880110019800000000001404350000033f0000c13d000000400400043d0000048b0040009c000006610000213d0000004001400039000000400010043f0000000b01000039000000000101041a0000002003400039000000a002100270000000000023043500000488011001970000000000140435000a00000004001d0000000b0100002912110e690000040f0000000a020000290000000002020433000027100110011a000000400300043d0000002004300039000000000014043500000488012001970000000000130435000004850030009c0000048503008041000000400130021000000521011001c7000012120001042e0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000000030020008c0000004a0000213d0000002401100370000000000401043b0000000901000039000000000101041a00000488011001970000000003000411000000000031004b0000054f0000c13d000000030020008c000006150000c13d0000052001000041000000000010043f000004f80100004100001213000104300000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000000030010008c0000004a0000213d12110c510000040f000000000101041a0000052b0000013d0000000001000416000000000001004b0000004a0000c13d0000000901000039000000000101041a0000048801100197000000800010043f000004e701000041000012120001042e000000840030008c0000004a0000413d0000000402100370000000000202043b000b00000002001d000004880020009c0000004a0000213d0000002402100370000000000202043b000a00000002001d000004880020009c0000004a0000213d0000006402100370000000000402043b0000048d0040009c0000004a0000213d0000002302400039000000000032004b0000004a0000813d0000000402400039000000000221034f000000000202043b0000004401100370000000000101043b000900000001001d000000240140003912110c920000040f0000000004010019000002d90000013d0000000001000416000000000001004b0000004a0000c13d0000001103000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000525013f00000001005001900000047a0000c13d000000800010043f000000000004004b000005600000613d000000000030043f000000000001004b0000055e0000613d00000507030000410000000004000019000000000503041a000000a002400039000000000052043500000001033000390000002004400039000000000014004b000003ae0000413d000005650000013d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000402100370000000000502043b0000048d0050009c0000004a0000213d0000002302500039000000000032004b0000004a0000813d0000000404500039000000000241034f000000000202043b0000048d0020009c000006610000213d0000001f062000390000051306600197000005140060009c000006610000213d00000024055000390000003f0660003900000513066001970000008006600039000000400060043f000000800020043f0000000005520019000000000035004b0000004a0000213d0000002003400039000000000431034f00000532052001980000001f0620018f000000a003500039000003e00000613d000000a007000039000000000804034f000000008908043c0000000007970436000000000037004b000003dc0000c13d000000000006004b000003ed0000613d000000000454034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f0000000000430435000000a00220003900000000000204350000000902000039000000000202041a00000488022001970000000003000411000000000032004b000006f30000c13d000000800300043d0000048d0030009c000006610000213d0000001302000039000000000402041a000000010040019000000001054002700000007f0550618f0000001f0050008c00000000060000390000000106002039000000000446013f00000001004001900000047a0000c13d0000000004000415000000200050008c000004150000413d000000000020043f0000001f063000390000000506600270000004a00660009a000000200030008c000004a3060040410000001f055000390000000505500270000004a00550009a000000000056004b000004150000813d000000000006041b0000000106600039000000000056004b000004110000413d0000000005000415000000000454004900000000040000020000001f0030008c0000090d0000a13d000000000020043f000004900530019800000a360000c13d000000a006000039000004a30400004100000a440000013d0000000001000416000000000001004b0000004a0000c13d0000000a01000039000000000101041a00000509001001980000000001000039000000010100c039000000800010043f000004e701000041000012120001042e0000000001000416000000000001004b0000004a0000c13d0000000101000039000000000101041a0000053401100167000000000200041a0000000001120019000000800010043f000004e701000041000012120001042e0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000004880010009c0000004a0000213d000000000001004b000005cb0000c13d0000051201000041000000000010043f000004f80100004100001213000104300000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000b00000001001d000004880010009c0000004a0000213d0000000901000039000000000101041a00000488011001970000000002000411000000000021004b0000054f0000c13d000004990100004100000000001004430000000b0100002900000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b0000000b04000029000000000004004b000007030000613d000000000001004b000007030000c13d0000050c01000041000000000010043f000004f80100004100001213000104300000000001000416000000000001004b0000004a0000c13d0000000303000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000525013f0000000100500190000005580000613d0000052201000041000000000010043f0000002201000039000000040010043f000005230100004100001213000104300000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000201043b000000000002004b0000000001000039000000010100c039000000010020008c0000004a0000213d0000000903000039000000000303041a00000488033001970000000004000411000000000043004b0000054f0000c13d000000000002004b00000000020000190000050b0200c0410000000a03000039000000000403041a0000050a04400197000000000224019f000000000023041b000000800010043f0000000001000414000004850010009c0000048501008041000000c0011002100000050e011001c70000800d0200003900000001030000390000050f040000410000062a0000013d0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000101043b000b00000001001d000000030010008c0000004a0000213d0000000001000411000000000010043f0000001501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000ff001001900000061c0000c13d0000051101000041000000000010043f000004f80100004100001213000104300000000001000416000000000001004b0000004a0000c13d0000000f01000039000000000101041a000000800010043f000004e701000041000012120001042e0000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000202043b000b00000002001d000004880020009c0000004a0000213d0000002401100370000000000101043b000a00000001001d000000010010008c0000004a0000213d0000000001000411000000000010043f0000000701000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b0000000b02000029000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000201041a00000533022001970000000a03000029000000000232019f000000000021041b000000400100043d0000000000310435000004850010009c000004850100804100000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000492011001c70000800d0200003900000003030000390000050d0400004100000000050004110000000b06000029000006360000013d0000000001000416000000000001004b0000004a0000c13d0000001001000039000000000101041a000000ff0110018f000000030010008c000005d30000a13d0000052201000041000000000010043f0000002101000039000000040010043f000005230100004100001213000104300000000002000416000000000002004b0000004a0000c13d000000440030008c0000004a0000413d0000000402100370000000000302043b000004880030009c0000004a0000213d0000002401100370000000000201043b000004880020009c0000004a0000213d0000000001030019121110e00000040f000000000001004b0000000001000039000000010100c039000000400200043d0000000000120435000004850020009c00000485020080410000004001200210000004eb011001c7000012120001042e0000000002000416000000000002004b0000004a0000c13d000000240030008c0000004a0000413d0000000401100370000000000601043b000004880060009c0000004a0000213d0000000901000039000000000201041a00000488032001970000000005000411000000000053004b0000054f0000c13d000000000006004b0000062b0000c13d000004ab01000041000000800010043f0000002001000039000000840010043f0000002601000039000000a40010043f000004e801000041000000c40010043f000004e901000041000000e40010043f000004ea010000410000121300010430000004ab01000041000000800010043f0000002001000039000000840010043f000000a40010043f0000051701000041000000c40010043f0000051f010000410000121300010430000000800010043f000000000004004b000005600000613d000000000030043f000000000001004b0000063b0000c13d0000008002000039000005650000013d0000053302200197000000a00020043f000000000001004b000000a0020000390000008002006039000000600220008a000000800100003912110c800000040f000000400100043d000b00000001001d000000800200003912110c0a0000040f0000000b020000290000000001210049000004850010009c00000485010080410000006001100210000004850020009c00000485020080410000004002200210000000000121019f000012120001042e0000052c0020009c000005d30000613d0000052d0020009c000005d30000613d0000052e0020009c000005d30000613d000000800000043f000004e701000041000012120001042e000900000001001d000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000000001004b000005a70000c13d000000000100041a0000000902000029000000000021004b000003050000a13d000000010220008a000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000000001004b0000000b02000029000005940000613d0000050100100198000003050000c13d000b04880010019b00000000020004110000000b0020006c000007630000c13d0000000901000029000000000010043f0000000601000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000201041a00000493022001970000000a06000029000000000262019f000000000021041b0000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d02000039000000040300003900000527040000410000000b050000290000000907000029000006360000013d000000000010043f0000000501000039000000200010043f00000040020000390000000001000019121111db0000040f000000000101041a0000048d01100197000000800010043f000004e701000041000012120001042e000000000003004b0000000002000019000005da0000613d00000000020404330000000303300210000005340330027f0000053403300167000000000232016f000000000252019f0000065c0000013d000000000025001a00000b270000413d000b00000025001e00000b270000613d0000000001030019000a00000003001d000900000002001d000800000005001d121111610000040f0000000b01000029000000010110008a000000400200043d0000004003200039000000000013043500000020012000390000000803000029000000000031043500000009010000290000000000120435000004850020009c000004850200804100000040012002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f000004fb011001c70000800d020000390000000203000039000004fc040000410000000a050000290000062a0000013d0000000901000039000000000101041a00000000020004140000048804100197000004850020009c0000048502008041000000c00120021000000494011001c700008009020000390000000005000019121112070000040f00000060031002700000048503300198000007320000c13d0000000100200190000006390000c13d0000051d01000041000000000010043f000004f80100004100001213000104300000000001020019000b00000004001d12110c510000040f0000000b02000029000000000021041b0000000001000019000012120001042e0000001001000039000000000201041a00000533022001970000000b05000029000000000252019f000000000021041b0000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000002030000390000050004000041000006360000013d0000049302200197000000000262019f000000000021041b0000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000003030000390000049504000041121112070000040f00000001002001900000004a0000613d0000000001000019000012120001042e00000510030000410000000004000019000000000503041a000000a002400039000000000052043500000001033000390000002004400039000000000014004b0000063d0000413d000005650000013d0000048f040000410000002006000039000000010870008a0000000508800270000004910880009a00000000096200190000000009090433000000000094041b00000020066000390000000104400039000000000084004b0000064a0000c13d000000000037004b0000065b0000613d0000000303300210000000f80330018f000005340330027f000005340330016700000000026200190000000002020433000000000232016f000000000024041b00000001025001bf000000000021041b000000000400041500000000050b04330000048d0050009c000006670000a13d0000052201000041000000000010043f0000004101000039000000040010043f000005230100004100001213000104300000000303000039000000000103041a000000010010019000000001071002700000007f0770618f0000001f0070008c00000000020000390000000102002039000000000112013f00000001001001900000047a0000c13d00070000000b001d0000000006000415000000200070008c00060000000a001d0000069b0000413d000300000007001d000400000006001d000900000005001d000800000004001d00050000000c001d000000000030043f0000000001000414000004850010009c0000048501008041000000c00110021000000492011001c700008010020000391211120c0000040f00000001002001900000004a0000613d00000009050000290000001f025000390000000502200270000000200050008c0000000002004019000000000301043b00000003010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b0000000303000039000000050c000029000000080400002900000004060000290000069b0000813d000000000002041b0000000102200039000000000012004b000006970000413d000000000100041500000000011600490000000001000002000000200050008c000007580000413d000900000005001d000800000004001d000000000030043f0000000001000414000004850010009c0000048501008041000000c00110021000000492011001c700008010020000391211120c0000040f00000001002001900000004a0000613d00000009020000290000049002200198000000000101043b000007f00000c13d0000002003000039000007fd0000013d0000050100100198000006d20000c13d00000000020004150000001306000039000000000306041a000000010730019000000001013002700000007f0110618f0000001f0010008c00000000040000390000000104002039000000000434013f00000001004001900000047a0000c13d000000400500043d0000000004150436000000000007004b000007d20000613d000000000060043f000000000001004b0000000003000019000007d70000613d000004a30600004100000000030000190000000007340019000000000806041a000000000087043500000001066000390000002003300039000000000013004b000006ca0000413d000007d70000013d0000050601000041000000000010043f000004f801000041000012130001043000000501001001980000000a01000029000006e10000c13d000000000010043f0000000601000039000000200010043f00000040020000390000000001000019121111db0000040f000000000101041a000001900000013d0000052901000041000000000010043f000004f8010000410000121300010430000000000021041b0000001001000039000000000101041a000000ff0110018f000000030010008c000005130000213d000600000001001d000003620000613d0000000a0000006b0000085d0000c13d000004fd01000041000000000010043f000004f8010000410000121300010430000000400100043d000000440210003900000517030000410000000000320435000004ab02000041000000000021043500000024021000390000002003000039000000000032043500000004021000390000000000320435000004850010009c00000485010080410000004001100210000004ac011001c700001213000104300000000a01000039000000000101041a00000488011001980000070c0000c13d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000400200043d000000200320003900000000004304350000000000120435000004850020009c000004850200804100000040012002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000497011001c70000800d0200003900000001030000390000049804000041121112070000040f00000001002001900000004a0000613d0000000902000039000000000102041a0000050a011001970000050b011001c7000000000012041b0000000a03000039000000000103041a00000493011001970000000b011001af000000000013041b0000000001000415000a00000001001d0000000b0000006b000007940000c13d00000000010004150000000a0110006900000000010000020000000001000019000012120001042e0000001f0430003900000486044001970000003f044000390000051c04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000048d0040009c000006610000213d0000000100600190000006610000c13d000000400040043f0000001f0430018f0000000006350436000004870530019800000000035600190000074a0000613d000000000701034f000000007807043c0000000006860436000000000036004b000007460000c13d000000000004004b0000060f0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000060f0000013d000000000005004b00000000010000190000080c0000613d0000000301500210000005340110027f000005340110016700000000020c0433000000000112016f0000000102500210000000000121019f0000080c0000013d0000000b01000029000000000010043f0000000701000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b00000000020004110000048802200197000800000002001d000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000000ff00100190000005ad0000c13d0000000a01000039000000000101041a0000050900100198000007900000613d00000488011001980000078e0000c13d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000080010006b000005ad0000613d0000052601000041000000000010043f000004f8010000410000121300010430000004990100004100000000001004430000000b0100002900000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b000000000001004b0000072d0000613d000004990100004100000000001004430000000b0100002900000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b000000000001004b0000004a0000613d000000400300043d0000002401300039000002d10200003900000000002104350000049b010000410000000000130435000000040130003900000000020004100000000000210435000004850030009c000900000003001d0000048501000041000000000103401900000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f0000049c011001c70000000b02000029121112070000040f00000001002001900000072d0000613d00000009010000290000048d0010009c000006610000213d0000000901000029000000400010043f0000072d0000013d00000533033001970000000000340435000000000001004b000000200300003900000000030060390000003f0330003900000532063001970000000003560019000000000063004b000000000600003900000001060040390000048d0030009c000006610000213d0000000100600190000006610000c13d000000400030043f000000000300041500000000023200490000000002000002000000400200043d0000000003050433000000000003004b000008d70000c13d000005050020009c000006610000213d0000002001200039000000400010043f0000000000020435000000400300043d000009d30000013d000000010320008a0000000503300270000000000431001900000020030000390000000104400039000000070600002900000000056300190000000005050433000000000051041b00000020033000390000000101100039000000000041004b000007f60000c13d0000000905000029000000000052004b000008080000613d0000000302500210000000f80220018f000005340220027f000005340220016700000007033000290000000003030433000000000223016f000000000021041b000000010150021000000001011001bf00000003030000390000000804000029000000000013041b0000000001000415000000000114004900000000010000020000000101000039000000000010041b000000000100041100000488061001970000000901000039000000000201041a0000049304200197000000000464019f000000000041041b00000000010004140000048805200197000004850010009c0000048501008041000000c00110021000000494011001c70000800d020000390000049504000041121112070000040f00000001002001900000004a0000613d000000400100043d0000002002100039000004960300004100000000003204350000000000010435000004850010009c000004850100804100000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000497011001c70000800d0200003900000001030000390000049804000041121112070000040f00000001002001900000004a0000613d0000000001000415000900000001001d00000499010000410000000000100443000004960100004100000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b000000000001004b000009500000c13d0000000001000415000000090110006900000000010000020000000001000415000900000001001d000000400100043d0000000a0000006b00000a960000c13d0000004402100039000004aa030000410000000000320435000000240210003900000019030000390000000000320435000004ab02000041000000000021043500000004021000390000002003000039000006fd0000013d0000000601000029000000020010008c000009180000c13d0000000601000029000000000010043f0000000e01000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a000b00000001001d000000000001004b00000b010000c13d000000000100041a000b00000001001d000000010110008a0000000a0010002a00000b270000413d0000000a011000290000000f02000039000000000202041a000000000021004b000002880000213d0000000d01000039000000000201041a0000000a012000b90000000a031000fa000000000023004b00000b270000c13d0000000002000416000000000012004b00000b540000c13d0000000b020000290000000a0020002a00000b270000413d0000000b020000290009000a0020002e00000b270000613d00000000010004110000048801100197000000000010043f0000001401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b0000000602000029000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000401041a0000000a0040002a00000b270000413d000000090300002900090001003000920000000a020000290000000003240019000000000031041b0000000001000411121111610000040f000000400100043d00000040021000390000000903000029000000000032043500000020021000390000000b0300002900000000003204350000000a020000290000000000210435000004850010009c000004850100804100000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f000004fb011001c70000800d020000390000000203000039000004fc040000410000000005000411121112070000040f00000001002001900000004a0000613d0000000001000412000c00000001001d0000800201000039000000240300003900000000040004150000000c0440008a00000005044002100000049902000041121111f00000040f000004ec02000041000000000012041b0000000001000019000012120001042e000000a003200039000000400030043f000000800320003900000000000304350000000a090000290000000006030019000000090090008c0000000a3990011a000000f807300210000000010360008a00000000080304330000050208800197000000000787019f00000503077001c70000000000730435000008dc0000213d00000000026200490000008102200039000000210660008a0000000000260435000000000505043300000532095001970000001f0850018f000000400200043d0000002007200039000000000074004b0000097e0000813d000000000009004b000008fe0000613d000000000b840019000000000a870019000000200aa0008a000000200bb0008a000000000c9a0019000000000d9b0019000000000d0d04330000000000dc0435000000200990008c000008f80000c13d000000000008004b000009940000613d000000000a0700190000098a0000013d000000000003004b0000000004000019000009060000613d000000a00400043d0000000305300210000005340550027f0000053405500167000000000454016f0000000103300210000000000334019f000009ef0000013d000000000003004b0000000004000019000009110000613d000000a00400043d0000000305300210000005340550027f0000053405500167000000000454016f0000000103300210000000000334019f00000a4f0000013d0000001201000039000000000101041a000500000001001d0000000b01000039000000800010043f000004ed01000041000000a00010043f000000e00100043d000004ee01100197000004ed011001c7000000e00010043f0000000601000029000000eb0010043f000000000100041100000060011002100000010b0010043f0000003f01000039000000c00010043f0000012001000039000000400010043f0000000001000414000004850010009c0000048501008041000000c001100210000004ef011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000200010043f000004f001000041000000000010043f0000000001000414000004850010009c0000048501008041000000c001100210000004f1011001c700008010020000391211120c0000040f00000001002001900000004a0000613d0000000502000029000304880020019c000000000101043b000200000001001d0000000001000415000400000001001d00000b2d0000c13d000000000100041500000004011000690000000001000002000004f701000041000000000010043f000004f801000041000012130001043000000499010000410000000000100443000004960100004100000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b000000000001004b0000004a0000613d000000400300043d0000002401300039000002d10200003900000000002104350000049b010000410000000000130435000000040130003900000000020004100000000000210435000004850030009c000800000003001d0000048501000041000000000103401900000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f0000049c011001c70000049602000041121112070000040f00000001002001900000084a0000613d00000008010000290000048d0010009c000006610000213d0000000801000029000000400010043f0000084a0000013d000000000a970019000000000009004b000009870000613d000000000b040019000000000c07001900000000bd0b0434000000000cdc04360000000000ac004b000009830000c13d000000000008004b000009940000613d0000000004940019000000030880021000000000090a043300000000098901cf000000000989022f00000000040404330000010008800089000000000484022f00000000048401cf000000000494019f00000000004a043500000000047500190000000000040435000000000506043300000532075001970000001f0650018f000000000043004b000009ab0000813d000000000007004b000009a70000613d00000000096300190000000008640019000000200880008a000000200990008a000000000a780019000000000b790019000000000b0b04330000000000ba0435000000200770008c000009a10000c13d000000000006004b000009c10000613d0000000008040019000009b70000013d0000000008740019000000000007004b000009b40000613d0000000009030019000000000a040019000000009b090434000000000aba043600000000008a004b000009b00000c13d000000000006004b000009c10000613d00000000037300190000000306600210000000000708043300000000076701cf000000000767022f00000000030304330000010006600089000000000363022f00000000036301cf000000000373019f000000000038043500000000034500190000050404000041000000000043043500000000032300490000001b0430008a0000000000420435000000240330003900000532013001970000000004210019000000000014004b000000000100003900000001010040390000048d0040009c000006610000213d0000000100100190000006610000c13d0000000003040019000000400040043f0000000001030019000b00000003001d0000056b0000013d00000507040000410000002007000039000000010650008a0000000506600270000005190660009a000000000807001900000080077000390000000007070433000000000074041b00000020078000390000000104400039000000000064004b000009db0000c13d000000a006800039000000000035004b000009ed0000613d0000000305300210000000f80550018f000005340550027f00000534055001670000000006060433000000000556016f000000000054041b000000010330021000000001033001bf000000000032041b0000002003000039000000400200043d0000000004320436000000800300043d000000000034043500000532063001970000001f0530018f0000004004200039000000a10040008c00000a0a0000413d000000000006004b00000a050000613d000000000854001900000080075001bf000000200880008a0000000009680019000000000a670019000000000a0a04330000000000a90435000000200660008c000009ff0000c13d000000000005004b00000a200000613d000000a006000039000000000704001900000a160000013d0000000007640019000000000006004b00000a130000613d000000a0080000390000000009040019000000008a0804340000000009a90436000000000079004b00000a0f0000c13d000000000005004b00000a200000613d000000a0066000390000000305500210000000000807043300000000085801cf000000000858022f00000000060604330000010005500089000000000656022f00000000055601cf000000000585019f00000000005704350000001f053000390000053201500197000000000343001900000000000304350000004001100039000004850010009c00000485010080410000006001100210000004850020009c00000485020080410000004002200210000000000121019f0000000002000414000004850020009c0000048502008041000000c002200210000000000121019f00000494011001c70000800d0200003900000001030000390000051a04000041000004a30000013d000004a3040000410000002007000039000000010650008a0000000506600270000005150660009a000000000807001900000080077000390000000007070433000000000074041b00000020078000390000000104400039000000000064004b00000a3b0000c13d000000a006800039000000000035004b00000a4d0000613d0000000305300210000000f80550018f000005340550027f00000534055001670000000006060433000000000556016f000000000054041b000000010330021000000001033001bf000000000032041b0000002003000039000000400200043d0000000004320436000000800300043d000000000034043500000532063001970000001f0530018f0000004004200039000000a10040008c00000a6a0000413d000000000006004b00000a650000613d000000000854001900000080075001bf000000200880008a0000000009680019000000000a670019000000000a0a04330000000000a90435000000200660008c00000a5f0000c13d000000000005004b00000a800000613d000000a006000039000000000704001900000a760000013d0000000007640019000000000006004b00000a730000613d000000a0080000390000000009040019000000008a0804340000000009a90436000000000079004b00000a6f0000c13d000000000005004b00000a800000613d000000a0066000390000000305500210000000000807043300000000085801cf000000000858022f00000000060604330000010005500089000000000656022f00000000055601cf000000000585019f00000000005704350000001f053000390000053201500197000000000343001900000000000304350000004001100039000004850010009c00000485010080410000006001100210000004850020009c00000485020080410000004002200210000000000121019f0000000002000414000004850020009c0000048502008041000000c002200210000000000121019f00000494011001c70000800d0200003900000001030000390000051604000041000004a30000013d0000048b0010009c000006610000213d0000004002100039000000400020043f0000002002100039000001f40300003900000000003204350000000a0500002900000000005104350000049d015001c70000000b02000039000000000012041b000000400100043d0000000000310435000004850010009c000004850100804100000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000492011001c70000800d0200003900000002030000390000049e04000041121112070000040f00000001002001900000004a0000613d0000000001000415000000090110006900000000010000020000049f010000410000000d02000039000000000012041b000009c4010000390000000f02000039000000000012041b0000001301000039000000000301041a000000010030019000000001023002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000334013f00000001003001900000047a0000c13d000000200020008c00000ad30000413d000000410020008c00000ad30000413d0000001f022000390000000502200270000004a00220009a000004a103000041000000000003041b0000000103300039000000000023004b00000acf0000413d0000006102000039000000000021041b000000000010043f000004a201000041000004a302000041000000000012041b000004a401000041000004a502000041000000000012041b0000001001000039000000000201041a000005330220019700000003022001bf000000000021041b0000001201000039000000000201041a00000493022001970000000b022001af000000000021041b000000060100002912110bf50000040f000004a6010000410000000102000039000000000021041b000004a7010000410000000302000039000000000021041b0000000501000039000004a802000041000000000012041b0000000601000029000000000010043f0000001501000039000000200010043f00000040020000390000000001000019121111db0000040f000000000201041a000005330220019700000001022001bf000000000021041b000000200100003900000100001004430000012000000443000004a901000041000012120001042e00000000010004110000048801100197000000000010043f0000001401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b0000000602000029000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000004a0000613d000000000101043b000000000101041a0000000a0010002a00000b270000413d0000000a011000290000000b0010006c000008720000a13d000004f901000041000000000010043f000004f80100004100001213000104300000052201000041000000000010043f0000001101000039000000040010043f00000523010000410000121300010430000000400100043d000100000001001d00000499010000410000000000100443000000030100002900000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000b530000613d000000000101043b000000000001004b00000b580000c13d00000009010000290000048d01100197000000400010008c00000bb60000613d000000410010008c000009490000c13d0000000b0100002900000064011000390000000001100367000000000101043b000000f801100270000000200010043f000000070100002900000000011003670000004002000039000000001301043c0000000002320436000000800020008c00000b4e0000c13d00000bc30000013d000000000001042f000004fa01000041000000000010043f000004f801000041000012130001043000000001050000290000006402500039000000440150003900000024065000390000000403500039000004f2040000410000000000450435000000020400002900000000004304350000004003000039000b00000006001d00000000003604350000000904000029000000000041043500000532034001980000001f0440018f00000000013200190000000705000029000000000550036700000b710000613d000000000605034f000000006706043c0000000002720436000000000012004b00000b6d0000c13d000000000004004b00000b7e0000613d000000000235034f0000000303400210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f00000000002104350000000101000029000004850010009c000004850100804100000040011002100000000902000029000004f30020009c000004f3020080410000006002200210000000000112019f0000000002000414000004850020009c0000048502008041000000c002200210000000000121019f000004f40110009a00000003020000291211120c0000040f00000060031002700000048503300197000000200030008c00000020030080390000001f0430018f00000020053001900000000b0350002900000b9d0000613d000000000601034f0000000b07000029000000006806043c0000000007870436000000000037004b00000b990000c13d000000000004004b00000baa0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000b010000290000000001010433000000000300041500000004033000690000000003000002000004f20010009c00000000010000390000000101006039000000000121016f0000000100100190000008600000c13d0000094c0000013d000000080400002900000040014000390000000001100367000000000101043b000000ff031002700000001b03300039000000200030043f00000020034000390000000002300367000000000202043b000000400020043f000004f501100197000000600010043f0000000201000029000000000010043f0000000001000414000004850010009c0000048501008041000000c001100210000004f6011001c700000001020000391211120c0000040f000000010900003900000060031002700000048503300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00000bdb0000613d000000000701034f000000007807043c0000000009890436000000000049004b00000bd70000c13d000000010220018f000000000005004b00000be90000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f00000000001404350000000001020433000000600000043f0000000102000029000000400020043f000000000200041500000004022000690000000002000002000000050110014f0000006001100210000000000013004b000008600000213d0000094c0000013d00000488061001970000000901000039000000000201041a0000049303200197000000000363019f000000000031041b00000000010004140000048805200197000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000003030000390000049504000041121112070000040f000000010020019000000c080000613d000000000001042d00000000010000190000121300010430000000200300003900000000033104360000000042020434000000000023043500000532062001970000001f0520018f0000004001100039000000000014004b00000c230000813d000000000006004b00000c1f0000613d00000000085400190000000007510019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c00000c190000c13d000000000005004b00000c390000613d000000000701001900000c2f0000013d0000000007610019000000000006004b00000c2c0000613d00000000080400190000000009010019000000008a0804340000000009a90436000000000079004b00000c280000c13d000000000005004b00000c390000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f0000000000470435000000000412001900000000000404350000001f0220003900000532022001970000000001120019000000000001042d000004f50010009c00000c4f0000213d000000630010008c00000c4f0000a13d00000000030003670000000401300370000000000101043b000004880010009c00000c4f0000213d0000002402300370000000000202043b000004880020009c00000c4f0000213d0000004403300370000000000303043b000000000001042d00000000010000190000121300010430000000040010008c00000c610000813d000000000010043f0000000e01000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000c670000613d000000000101043b000000000001042d0000052201000041000000000010043f0000002101000039000000040010043f0000052301000041000012130001043000000000010000190000121300010430000000040020008c00000c780000813d000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000c7e0000613d000000000101043b000000000001042d0000052201000041000000000010043f0000002101000039000000040010043f00000523010000410000121300010430000000000100001900001213000104300000001f0220003900000532022001970000000001120019000000000021004b000000000200003900000001020040390000048d0010009c00000c8c0000213d000000010020019000000c8c0000c13d000000400010043f000000000001042d0000052201000041000000000010043f0000004101000039000000040010043f00000523010000410000121300010430000005350020009c00000cc20000813d00000000040100190000001f0120003900000513011001970000003f011000390000053605100197000000400100043d0000000005510019000000000015004b000000000600003900000001060040390000048d0050009c00000cc20000213d000000010060019000000cc20000c13d000000400050043f00000000052104360000000006420019000000000036004b00000cc80000213d00000532062001980000001f0720018f0000000004400367000000000365001900000cb20000613d000000000804034f0000000009050019000000008a08043c0000000009a90436000000000039004b00000cae0000c13d000000000007004b00000cbf0000613d000000000464034f0000000306700210000000000703043300000000076701cf000000000767022f000000000404043b0000010006600089000000000464022f00000000046401cf000000000474019f000000000043043500000000022500190000000000020435000000000001042d0000052201000041000000000010043f0000004101000039000000040010043f00000523010000410000121300010430000000000100001900001213000104300000000a01000039000000000101041a000004880110019800000ccf0000613d000000000001042d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000000001042d0009000000000002000500000002001d000700000001001d000800000003001d000000000003004b00000e2e0000613d0000000801000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b000000000101041a000000000001004b00000d030000c13d000000000100041a000000080010006c00000e2e0000a13d0000000802000029000000010220008a000900000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b000000000101041a000000000001004b000000090200002900000cf00000613d000005010010019800000e2e0000c13d00000007020000290000048802200197000600000001001d0000048801100197000700000002001d000000000021004b00000e330000c13d0000000801000029000000000010043f0000000601000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000301043b000000000403041a000000000600041100000488056001970000000702000029000000000025004b00000d540000613d000000000045004b00000d540000613d000200000004001d000300000003001d000000000020043f0000000701000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c70000801002000039000400000005001d1211120c0000040f0000000403000029000000010020019000000e2c0000613d000000000101043b000000000030043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000405000029000000010020019000000e2c0000613d000000000101043b000000000101041a000000ff00100190000000070200002900000003030000290000000204000029000000000600041100000d540000c13d0000000a01000039000000000101041a000005090010019800000e3f0000613d000004880110019800000d520000c13d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000000015004b00000e3f0000c13d00000005010000290000048801100197000000000002004b000900000001001d00000d9d0000613d000000000001004b00000d9f0000613d00000000070004150000000a01000039000000000101041a000004880810019800000e1f0000613d000000000086004b00000e260000613d000100000007001d000400000005001d000200000004001d000300000003001d00000499010000410000000000100443000500000008001d00000004008004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f000000010020019000000e320000613d000000000101043b000000000001004b000000040300002900000e2c0000613d000000400400043d0000006401400039000000080200002900000000002104350000004401400039000000090200002900000000002104350000002401400039000000070200002900000000002104350000052401000041000000000014043500000004014000390000000000310435000004850040009c000400000004001d0000048501000041000000000104401900000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000539011001c700000005020000291211120c0000040f000000010020019000000e430000613d0000000401000029000005350010009c00000003030000290000000204000029000000010700002900000e630000813d000000400010043f000000070200002900000e260000013d000000000001004b00000e3b0000613d000000000004004b00000da20000613d000000000003041b000000000020043f0000000501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000901000029000000000010043f0000000501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b000000000201041a0000000102200039000000000021041b0000053a0100004100000000001004430000000001000414000004850010009c0000048501008041000000c0011002100000053b011001c70000800b020000391211120c0000040f000000010020019000000e320000613d000000000101043b000500000001001d0000000801000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d0000000502000029000000a0022002100000000906000029000000000262019f0000053c022001c7000000000101043b000000000021041b00000006010000290000053c0010019800000e0f0000c13d00000008010000290000000101100039000500000001001d000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b000000000101041a000000000001004b000000090600002900000e0f0000c13d000000000100041a000000050010006b00000e0f0000613d0000000501000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f000000010020019000000e2c0000613d000000000101043b0000000602000029000000000021041b00000009060000290000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000004030000390000053d0400004100000007050000290000000807000029121112070000040f000000010020019000000e2c0000613d000000090000006b00000e370000613d000000000001042d0000000901000039000000000101041a000005090010019800000e260000c13d0000049608000041000000000086004b00000d620000c13d000000000100041500000000011700490000000001000002000000000004004b00000da10000c13d00000da20000013d000000000100001900001213000104300000052801000041000000000010043f000004f8010000410000121300010430000000000001042f0000053701000041000000000010043f000004f80100004100001213000104300000053e01000041000000000010043f000004f80100004100001213000104300000053f01000041000000000010043f000004f80100004100001213000104300000053801000041000000000010043f000004f801000041000012130001043000000060061002700000001f0460018f0000048705600198000000400200043d000000000352001900000e4f0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b00000e4b0000c13d0000048506600197000000000004004b00000e5d0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000004850020009c00000485020080410000004002200210000000000112019f00001213000104300000052201000041000000000010043f0000004101000039000000040010043f00000523010000410000121300010430000000000301001900000000011200a9000000000003004b00000e700000613d00000000033100d9000000000023004b00000e710000c13d000000000001042d0000052201000041000000000010043f0000001101000039000000040010043f00000523010000410000121300010430000c000000000002000500000004001d000800000002001d000a00000001001d000b00000003001d000000000003004b0000106a0000613d0000000b01000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000101041a000000000001004b00000ea60000c13d000000000100041a0000000b0010006c0000106a0000a13d0000000b02000029000000010220008a000c00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000101041a000000000001004b0000000c0200002900000e930000613d00000501001001980000106a0000c13d0000000a020000290000048802200197000700000001001d0000048801100197000c00000002001d000000000021004b0000106f0000c13d0000000b01000029000000000010043f0000000601000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000301043b000000000403041a00000000050004110000048802500197000900000002001d0000000c0020006c00000ef50000613d000000090040006b00000ef50000613d000400000004001d000600000003001d0000000c01000029000000000010043f0000000701000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b0000000902000029000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000101041a000000ff0010019000000006030000290000000404000029000000000500041100000ef50000c13d0000000a01000039000000000101041a00000509001001980000107f0000613d000004880110019800000ef30000c13d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000090010006b0000107f0000c13d000000080100002900000488021001970000000c0000006b000a00000002001d00000f3c0000613d000000000002004b00000f3e0000613d00000000020004150000000a01000039000000000101041a00000488061001980000105b0000613d000000000065004b000010620000613d000200000002001d000400000004001d000600000003001d00000499010000410000000000100443000300000006001d00000004006004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f00000001002001900000106e0000613d000000000101043b000000000001004b000010680000613d000000400300043d00000064013000390000000b02000029000000000021043500000044013000390000000a02000029000000000021043500000024013000390000000c02000029000000000021043500000524010000410000000000130435000000040130003900000009020000290000000000210435000004850030009c000100000003001d0000048501000041000000000103401900000040011002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000539011001c700000003020000291211120c0000040f0000000100200190000010c00000613d0000000101000029000005350010009c000000060300002900000004040000290000000202000029000010b10000813d000000400010043f000010620000013d000000000002004b0000107b0000613d000000000004004b00000f410000613d000000000003041b0000000c01000029000000000010043f0000000501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000a01000029000000000010043f0000000501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000201041a0000000102200039000000000021041b0000053a0100004100000000001004430000000001000414000004850010009c0000048501008041000000c0011002100000053b011001c70000800b020000391211120c0000040f00000001002001900000106e0000613d000000000101043b000600000001001d0000000b01000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d0000000602000029000000a0022002100000000a06000029000000000262019f0000053c022001c7000000000101043b000000000021041b00000007010000290000053c0010019800000faf0000c13d0000000b010000290000000101100039000600000001001d000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b000000000101041a000000000001004b0000000a0600002900000faf0000c13d000000000100041a000000060010006b00000faf0000613d0000000601000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000010680000613d000000000101043b0000000702000029000000000021041b0000000a060000290000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000004030000390000053d040000410000000c050000290000000b07000029121112070000040f0000000100200190000010680000613d0000000a0000006b000010730000613d00000499010000410000000000100443000000080100002900000004001004430000000001000414000004850010009c0000048501008041000000c0011002100000049a011001c700008002020000391211120c0000040f00000001002001900000106e0000613d000000000101043b000000000001004b0000105a0000613d0000000001000415000800000001001d000000400c00043d0000006401c000390000008002000039000700000002001d00000000002104350000004401c000390000000b0200002900000000002104350000002401c000390000000c020000290000000000210435000005400100004100000000001c04350000000401c00039000000090200002900000000002104350000008402c00039000000050100002900000000410104340000000000120435000000200b00008a0000000006b1016f0000001f0510018f000000a403c00039000000000034004b00000ffb0000813d000000000006004b00000ff60000613d00000000085400190000000007530019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c00000ff00000c13d000000000005004b0000000a02000029000010120000613d0000000007030019000010080000013d0000000007630019000000000006004b000010040000613d00000000080400190000000009030019000000008a0804340000000009a90436000000000079004b000010000000c13d000000000005004b0000000a02000029000010120000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f00000000004704350000001f041000390000000004b4016f00000000013100190000000000010435000000a401400039000004850010009c000004850100804100000060011002100000048500c0009c000004850300004100000000030c40190000004003300210000000000131019f0000000003000414000004850030009c0000048503008041000000c003300210000000000131019f000c0000000c001d121112070000040f0000000c0b00002900000060031002700000048503300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000010360000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000010320000c13d000000000006004b000010430000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f00000000006504350000000100200190000010770000613d0000001f01400039000000600210018f0000000001b20019000000000021004b000000000200003900000001020040390000048d0010009c000010b10000213d0000000100200190000010b10000c13d000000400010043f000000200030008c000010680000413d00000000010b04330000052a00100198000010680000c13d000000000200041500000008022000690000000002000002000005400010009c000010ad0000c13d000000000001042d0000000901000039000000000101041a0000050900100198000010620000c13d0000049606000041000000000065004b00000f030000c13d000000000100041500000000011200490000000001000002000000000004004b00000f400000c13d00000f410000013d000000000100001900001213000104300000052801000041000000000010043f000004f8010000410000121300010430000000000001042f0000053701000041000000000010043f000004f80100004100001213000104300000053e01000041000000000010043f000004f8010000410000121300010430000000000003004b000010830000c13d0000006002000039000010aa0000013d0000053f01000041000000000010043f000004f80100004100001213000104300000053801000041000000000010043f000004f80100004100001213000104300000001f0230003900000486022001970000003f022000390000051c04200197000000400200043d0000000004420019000000000024004b000000000500003900000001050040390000048d0040009c000010b10000213d0000000100500190000010b10000c13d000000400040043f0000001f0430018f00000000063204360000048705300198000700000006001d00000000035600190000109d0000613d000000000601034f0000000707000029000000006806043c0000000007870436000000000037004b000010990000c13d000000000004004b000010aa0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000001020433000000000001004b000010b70000c13d0000054101000041000000000010043f000004f80100004100001213000104300000052201000041000000000010043f0000004101000039000000040010043f000005230100004100001213000104300000000702000029000004850020009c00000485020080410000004002200210000004850010009c00000485010080410000006001100210000000000121019f000012130001043000000060061002700000001f0460018f0000048705600198000000400200043d0000000003520019000010cc0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000038004b000010c80000c13d0000048506600197000000000004004b000010da0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000006001600210000004850020009c00000485020080410000004002200210000000000112019f00001213000104300001000000000002000100000002001d0000048801100197000000000010043f0000000701000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000011140000613d000000000101043b00000001020000290000048802200197000100000002001d000000000020043f000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f0000000100200190000011140000613d000000000101043b000000000101041a000000ff01100190000011030000613d000000000001042d0000000a01000039000000000101041a0000050900100198000011120000613d00000488011001980000110e0000c13d0000000901000039000000000101041a000005090010019800000000010000190000049601006041000000010010006b00000000010000390000000101006039000000000001042d0000000001000019000000000001042d000000000100001900001213000104300000000901000039000000000101041a00000488011001970000000002000411000000000021004b0000111d0000c13d000000000001042d000000400100043d000000440210003900000517030000410000000000320435000004ab02000041000000000021043500000024021000390000002003000039000000000032043500000004021000390000000000320435000004850010009c00000485010080410000004001100210000004ac011001c700001213000104300001000000000002000000000001004b0000115d0000613d000100000001001d000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000115b0000613d000000000101043b000000000101041a000000000001004b000011580000c13d000000000100041a0000000102000029000000000021004b0000115d0000a13d000000010220008a000100000002001d000000000020043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000115b0000613d000000000101043b000000000101041a000000000001004b0000000102000029000011450000613d00000501001001980000115d0000c13d000000000001042d000000000100001900001213000104300000052801000041000000000010043f000004f80100004100001213000104300004000000000002000000000002004b000011cb0000613d000304880010019c000011cf0000613d000000000300041a0000053401300167000000010420008a000000000014004b000011d30000213d0000000101100039000000000041004b00000000040000390000000104008039000000000001004b00000001040060390000000100400190000011740000c13d000011730000013d000200000002001d000400000003001d0000053a0100004100000000001004430000000001000414000004850010009c0000048501008041000000c0011002100000053b011001c70000800b020000391211120c0000040f0000000100200190000011d90000613d000000000101043b000100000001001d0000000401000029000000000010043f0000000401000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000001002001900000000204000029000011c90000613d0000000102000029000000a002200210000000010040008c00000000030000190000053c03006041000000000223019f0000000303000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f0000000001000414000004850010009c0000048501008041000000c00110021000000497011001c700008010020000391211120c0000040f00000002040000290000000100200190000011c90000613d000000000101043b00000542024000d1000000000301041a0000000002230019000000000021041b000200040040002d0000000001000019000011c00000013d00000004070000290000000001000414000004850010009c0000048501008041000000c00110021000000494011001c70000800d0200003900000004030000390000053d0400004100000000050000190000000306000029000400000007001d121112070000040f00000001002001900000000101000039000011c90000613d0000000100100190000011b00000613d00000004070000290000000107700039000000020070006c000011b10000c13d0000000201000029000000000010041b000000000001042d000000000100001900001213000104300000054301000041000000000010043f000004f80100004100001213000104300000053f01000041000000000010043f000004f80100004100001213000104300000052201000041000000000010043f0000001101000039000000040010043f00000523010000410000121300010430000000000001042f000000000001042f000004850010009c00000485010080410000004001100210000004850020009c00000485020080410000006002200210000000000112019f0000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000494011001c700008010020000391211120c0000040f0000000100200190000011ee0000613d000000000101043b000000000001042d0000000001000019000012130001043000000000050100190000000000200443000000040030008c000011f70000a13d000000050140027000000000010100310000000400100443000004850030009c000004850300804100000060013002100000000002000414000004850020009c0000048502008041000000c002200210000000000112019f00000544011001c700000000020500191211120c0000040f0000000100200190000012060000613d000000000101043b000000000001042d000000000001042f0000120a002104210000000102000039000000000001042d0000000002000019000000000001042d0000120f002104230000000102000039000000000001042d0000000002000019000000000001042d0000121100000432000012120001042e000012130001043000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffc042656172797a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf42454152595a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffbfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a532405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5ace000000000000000000000000000000000000000000000000ffffffffffffffe0bfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a5310200000000000000000000000000000000000020000000000000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0000000000000000000000000721c008fdff27bf06e7e123956e2fe03b63342e30200000000000000000000000000000000000040000000000000000000000000cc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000fb2de5d70000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000440000000000000000000000000000000000000000000001f400000000000000000000000000000000000000008a8bae378cb731c5c40b632330c6836c2f916f48edb967699c86736f9a6a76ef000000000000000000000000000000000000000000000000003ff2e795f500009921700258681c2163fa1703a84c40f13d756cf2bf4f2d7a26c3f9afe3095f7066de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a09268747470733a2f2f7777772e6265617279636f696e2e78797a2f6170692f626566de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a0906172797a2f756e72657665616c65642f0000000000000000000000000000000066de8ffda797e3de9c05e8fc57b3bf0ec28a930d40b0d285d93c06501cf6a091e710864318d4a32f37d6ce54cb3fadbef648dd12d8dbdf53973564d56b7f881ca7c5ba7114a813b50159add3a36832908dc83db71d0b9a24c2ad0f83be9582079adb202b1492743bc00c81d33cdc6423fa8c79109027eb6a845391e8fc1f04810000000200000000000000000000000000000040000001000000000000000000455243323938313a20696e76616c69642072656365697665720000000000000008c379a00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000640000000000000000000000000000000000000000000000000000000000000000000000000000000070a0823000000000000000000000000000000000000000000000000000000000a9fc664d00000000000000000000000000000000000000000000000000000000cd3f290f00000000000000000000000000000000000000000000000000000000e985e9c400000000000000000000000000000000000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f3ae241500000000000000000000000000000000000000000000000000000000cd3f291000000000000000000000000000000000000000000000000000000000d5abeb0100000000000000000000000000000000000000000000000000000000db7fd40800000000000000000000000000000000000000000000000000000000b88d4fdd00000000000000000000000000000000000000000000000000000000b88d4fde00000000000000000000000000000000000000000000000000000000bd8cd55000000000000000000000000000000000000000000000000000000000c87b56dd00000000000000000000000000000000000000000000000000000000a9fc664e00000000000000000000000000000000000000000000000000000000add5a4fa0000000000000000000000000000000000000000000000000000000095d89b4000000000000000000000000000000000000000000000000000000000a22cb46400000000000000000000000000000000000000000000000000000000a22cb46500000000000000000000000000000000000000000000000000000000a3a40ea500000000000000000000000000000000000000000000000000000000a5e90eee0000000000000000000000000000000000000000000000000000000095d89b41000000000000000000000000000000000000000000000000000000009e05d24000000000000000000000000000000000000000000000000000000000a035b1fe0000000000000000000000000000000000000000000000000000000087cc86410000000000000000000000000000000000000000000000000000000087cc8642000000000000000000000000000000000000000000000000000000008da5cb5b0000000000000000000000000000000000000000000000000000000091b7f5ed0000000000000000000000000000000000000000000000000000000070a0823100000000000000000000000000000000000000000000000000000000715018a60000000000000000000000000000000000000000000000000000000018160ddc000000000000000000000000000000000000000000000000000000003ccfd60a0000000000000000000000000000000000000000000000000000000055f804b20000000000000000000000000000000000000000000000000000000055f804b3000000000000000000000000000000000000000000000000000000006221d13c000000000000000000000000000000000000000000000000000000006352211e000000000000000000000000000000000000000000000000000000003ccfd60b0000000000000000000000000000000000000000000000000000000042842e0e000000000000000000000000000000000000000000000000000000004933147d000000000000000000000000000000000000000000000000000000002a552059000000000000000000000000000000000000000000000000000000002a55205a000000000000000000000000000000000000000000000000000000002b542ad300000000000000000000000000000000000000000000000000000000350debcb0000000000000000000000000000000000000000000000000000000018160ddd0000000000000000000000000000000000000000000000000000000023b872dd0000000000000000000000000000000000000000000000000000000006fdde0200000000000000000000000000000000000000000000000000000000095ea7b200000000000000000000000000000000000000000000000000000000095ea7b300000000000000000000000000000000000000000000000000000000098144d4000000000000000000000000000000000000000000000000000000000d705df60000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000081812fc000000000000000000000000000000000000000000000000000000000268f01d000000000000000000000000000000000000000000000000000000000268f01e00000000000000000000000000000000000000000000000000000000046dc16600000000000000000000000000000000000000000000000000000000055ad42e00000000000000000000000000000000000000000000000000000000014635460000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000200000008000000000000000004f776e61626c653a206e6577206f776e657220697320746865207a65726f20616464726573730000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008400000080000000000000000000000000000000000000000000000000000000200000000000000000000000000000000000000000000000000000000000000000000000929eee149b4bd2126842454152595a2d4d494e540000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffff020000000000000000000000000000000000003f000000e000000000000000000000000019457468657265756d205369676e6564204d6573736167653a0a3332020000000000000000000000000000000000003c0000000400000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffff9bffffffffffffffffffffffffffffffffffffff9c0000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000800000000000000000000000008baa579f000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004000000000000000000000000979afdba00000000000000000000000000000000000000000000000000000000cd1c88670000000000000000000000000000000000000000000000000000000002000000000000000000000000000000000000600000000000000000000000004c37c524941e0b532e5d1191d1f25c5437915d42cdd2d221b8c724dc68f51fec2c5211c60000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab143c0600000000000000000000000000000000000000040000001c0000000000000000a6dcc92f45df25789d5639b7a0c97ba1edf3bb1c0b5dd3376fd96a0db87c4642000000010000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff30000000000000000000000000000000000000000000000000000000000000002e6a736f6e000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdfa14c4b500000000000000000000000000000000000000000000000000000000031ecc21a745e3968a04e9570e4425bc18fa8019c68028196b546d1669c200c68d05cb609000000000000000000000000000000000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff000000000000000000000001000000000000000000000000000000000000000032483afb0000000000000000000000000000000000000000000000000000000017307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3102000000000000000000000000000000000000200000008000000000000000006787c7f9a80aa0f5ceddab2c54f1f5169c0b88e75dd5e19d5e858a64144c7dbcc2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85bc0fc8a8a000000000000000000000000000000000000000000000000000000008f4eb60400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001ffffffffffffffe0000000000000000000000000000000000000000000000000ffffffffffffff409921700258681c2163fa1703a84c40f13d756cf2bf4f2d7a26c3f9afe3095f6f6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41ad4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572ce133de58ba1c6975fb16a8f1bbda43e7057fe6397fd7e694ab92e9963dff398ce133de58ba1c6975fb16a8f1bbda43e7057fe6397fd7e694ab92e9963dff39746063465ae761051ce965ce8adc6c50d2bf4650ee4652d1df33bd1228c9f6aec9cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f3900000000000000000000000000000000000000000000000000000003ffffffe027fcd9d100000000000000000000000000000000000000000000000000000000cff858f9000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000064000000800000000000000000908367940000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000caee23ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000800000000000000000cfb3b942000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925df2d9b4200000000000000000000000000000000000000000000000000000000cf4700e40000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ac58ccffffffffffffffffffffffffffffffffffffffffffffffffffffffff80ac58cd00000000000000000000000000000000000000000000000000000000a07d229a00000000000000000000000000000000000000000000000000000000ad0d7f6c0000000000000000000000000000000000000000000000000000000001ffc9a7000000000000000000000000000000000000000000000000000000002a55205a000000000000000000000000000000000000000000000000000000005b5e139f00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000003ffffffffffffffe0a11481000000000000000000000000000000000000000000000000000000000059c896be000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000000000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d9553913202000002000000000000000000000000000000040000000000000000000000000000000200000000000000000000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efea553b34000000000000000000000000000000000000000000000000000000005cbd944100000000000000000000000000000000000000000000000000000000150b7a0200000000000000000000000000000000000000000000000000000000d1a57ed6000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000010000000000000001b562e8dd0000000000000000000000000000000000000000000000000000000002000002000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a2646970667358221220473a1aa960c4e065a980de7494c8593a2fee4bfc255cbfea47d610caca9421a064736f6c6378247a6b736f6c633a312e352e31353b736f6c633a302e382e33303b6c6c766d3a312e302e310055
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
000000000000000000000000bea57adc5938002001209481dbb75760279688ab000000000000000000000000554fbc602cb6e2f488af7a30a5023b4ecc4419ac000000000000000000000000c88527406f9ca499f5640f0cb7d794d77928ed28
-----Decoded View---------------
Arg [0] : owner (address): 0xBEA57ADC5938002001209481Dbb75760279688AB
Arg [1] : signerAddress (address): 0x554fbC602cb6E2f488AF7a30A5023b4eCc4419ac
Arg [2] : royaltiesAddress (address): 0xC88527406F9cA499f5640F0cB7d794d77928ed28
-----Encoded View---------------
3 Constructor Arguments found :
Arg [0] : 000000000000000000000000bea57adc5938002001209481dbb75760279688ab
Arg [1] : 000000000000000000000000554fbc602cb6e2f488af7a30a5023b4ecc4419ac
Arg [2] : 000000000000000000000000c88527406f9ca499f5640f0cb7d794d77928ed28
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$211.34
Net Worth in ETH
0.071853
Token Allocations
ETH
100.00%
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|---|---|---|---|---|
| ETH | 100.00% | $2,935.21 | 0.072 | $211.34 |
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.