Source Code
Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 83,797 transactions
| Transaction Hash |
|
Block
|
From
|
To
|
|||||
|---|---|---|---|---|---|---|---|---|---|
| Set Approval For... | 36384068 | 4 hrs ago | IN | 0 ETH | 0.00000498 | ||||
| Set Approval For... | 36364671 | 7 hrs ago | IN | 0 ETH | 0.00000501 | ||||
| Set Approval For... | 36341252 | 10 hrs ago | IN | 0 ETH | 0.00000501 | ||||
| Set Approval For... | 36298716 | 16 hrs ago | IN | 0 ETH | 0.00000419 | ||||
| Set Approval For... | 36298701 | 16 hrs ago | IN | 0 ETH | 0.00000451 | ||||
| Set Approval For... | 36297968 | 16 hrs ago | IN | 0 ETH | 0.00000451 | ||||
| Set Approval For... | 36282254 | 18 hrs ago | IN | 0 ETH | 0.00000409 | ||||
| Safe Transfer Fr... | 36171607 | 36 hrs ago | IN | 0 ETH | 0.00000715 | ||||
| Set Approval For... | 36155248 | 39 hrs ago | IN | 0 ETH | 0.0000044 | ||||
| Set Approval For... | 36132551 | 44 hrs ago | IN | 0 ETH | 0.00000611 | ||||
| Set Approval For... | 36132095 | 44 hrs ago | IN | 0 ETH | 0.00000419 | ||||
| Set Approval For... | 36132085 | 44 hrs ago | IN | 0 ETH | 0.00000419 | ||||
| Safe Transfer Fr... | 36128612 | 45 hrs ago | IN | 0 ETH | 0.00000468 | ||||
| Safe Transfer Fr... | 36128601 | 45 hrs ago | IN | 0 ETH | 0.00000611 | ||||
| Set Approval For... | 36127291 | 45 hrs ago | IN | 0 ETH | 0.00000572 | ||||
| Set Approval For... | 36056855 | 2 days ago | IN | 0 ETH | 0.00000469 | ||||
| Set Approval For... | 36056455 | 2 days ago | IN | 0 ETH | 0.00000498 | ||||
| Set Approval For... | 35996574 | 2 days ago | IN | 0 ETH | 0.00000611 | ||||
| Set Approval For... | 35980539 | 2 days ago | IN | 0 ETH | 0.00000503 | ||||
| Set Approval For... | 35980436 | 2 days ago | IN | 0 ETH | 0.00000567 | ||||
| Set Approval For... | 35962556 | 3 days ago | IN | 0 ETH | 0.00000856 | ||||
| Set Approval For... | 35961681 | 3 days ago | IN | 0 ETH | 0.00000612 | ||||
| Set Approval For... | 35959289 | 3 days ago | IN | 0 ETH | 0.00000567 | ||||
| Set Approval For... | 35959227 | 3 days ago | IN | 0 ETH | 0.0000044 | ||||
| Set Approval For... | 35956940 | 3 days ago | IN | 0 ETH | 0.00000443 |
Latest 1 internal transaction
Advanced mode:
| Parent Transaction Hash | Block | From | To | |||
|---|---|---|---|---|---|---|
| 7615498 | 273 days ago | Contract Creation | 0 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:
Weapon721
Compiler Version
v0.8.28+commit.7893614a
ZkSolc Version
v1.5.10
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.27;
import {ERC721AQueryable, ERC721A, IERC721A} from "ERC721A/extensions/ERC721AQueryable.sol";
import {ERC721ABatchTransferable} from "ERC721A/extensions/ERC721ABatchTransferable.sol";
import {ERC721ABatchBurnable} from "ERC721A/extensions/ERC721ABatchBurnable.sol";
import {OwnableRoles} from "solady/auth/OwnableRoles.sol";
import {ERC2981} from "solady/tokens/ERC2981.sol";
import {LibMap} from "solady/utils/LibMap.sol";
/// @author Onchain-Heros (https://www.onchainheroes.xyz)
/// @author atarpara (https://www.github.com/atarpara)
contract Weapon721 is ERC721AQueryable, ERC721ABatchTransferable, ERC721ABatchBurnable, ERC2981, OwnableRoles {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The validator `setTokenTypeOfCollection` call failed.
error InvalidValidator();
/// @dev The validator called failed.
error ValidatorCalledFailed();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Emits when the validator of the collection is updated.
event TransferValidatorUpdated(address oldValidator, address newValidator);
/// @dev Emits when the automatic approval of the transfer validator is set.
event AutomaticApprovalOfTransferValidatorSet(bool autoApproved);
/// @dev Emits when weapon is generated for `to`.
event WeaponGenerated(address to, uint256 qty);
/// @dev Emits when weapon `metadata` is generated for `id`.
event WeaponMetadataGenerated(uint256 id, uint32 metadata);
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The baseURI for a token.
string internal baseURI;
/// @dev The validator of the collection.
address validator;
/// @dev The flag to set the automatic approval of the transfer validator.
bool autoApproveTransfersFromValidator;
/// @dev Bit Layout :
/// [0..7] : Weapon ratity
/// [8..15] : Weapon Type
/// [16..23] : Weapn max sharpness
/// [24..31] : Weapn max durability
LibMap.Uint32Map internal metadataMap;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CONSTRUCTOR */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// todo rename token and symbol
constructor(address _owner) ERC721A("OCH_GACHA_WEAPON", "OGW") {
_initializeOwner(_owner);
// Set transfer validator
_setValidator(0x3203c3f64312AF9344e42EF8Aa45B97C9DFE4594);
// Sets default royalty to 2.5%
_setDefaultRoyalty(_owner, 250);
}
/// @dev The baseURI for a token.
/// Requirements:
/// - Caller must be the owner.
function setBaseURI(string memory baseURI_) external onlyOwner {
baseURI = baseURI_;
}
/// @dev Returns `baseURI`.
function _baseURI() internal view override(ERC721A) returns (string memory) {
return baseURI;
}
/// @dev Start minting token id from `1`.
function _startTokenId() internal pure override returns (uint256) {
return 1;
}
/// @dev Mints `qty` tokens to `to` from `currentIndex`.
function mint(address to, uint256 qty) public onlyRoles(_ROLE_0) returns (uint256) {
uint256 currentIndex = _nextTokenId();
_mint(to, qty);
// Emits `WeaponGenerated`.
emit WeaponGenerated(to, qty);
return currentIndex;
}
/// @dev Sets `metadata` value to `tokenId`.
function setMetadata(uint256 tokenId, uint32 metadata) public onlyRoles(_ROLE_0) {
LibMap.set(metadataMap, tokenId, metadata);
// Emits `WeaponMetadataGenerated`.
emit WeaponMetadataGenerated(tokenId, metadata);
}
/// @dev Gets rarity of `tokenId`.
function getMetadata(uint256 tokenId) external view returns (uint32) {
if (!_exists(tokenId)) _revert(URIQueryForNonexistentToken.selector);
return LibMap.get(metadataMap, tokenId);
}
/// @dev Mints a weapon to `to` with provided `weaponRarity`, `weaponType`, `mSharpness`, and `mDurability`.
/// Requirements :
/// - Only callable by owner.
function manualMint(address to, uint256 weaponRarity, uint256 weaponType, uint256 mSharpness, uint256 mDurability)
external
onlyOwner
{
uint256 currentIndex = _nextTokenId();
_mint(to, 1);
// Emits `WeaponGenerated`.
emit WeaponGenerated(to, 1);
uint32 metadata = uint32(mDurability << 24 | mSharpness << 16 | weaponType << 8 | weaponRarity);
LibMap.set(metadataMap, currentIndex, metadata);
// Emits `WeaponMetadataGenerated`.
emit WeaponMetadataGenerated(currentIndex, metadata);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC721C Functions */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns if the operator is allowed to transfer the tokens from the owner.
function isApprovedForAll(address owner, address operator)
public
view
virtual
override(IERC721A, ERC721A)
returns (bool isApproved)
{
isApproved = super.isApprovedForAll(owner, operator);
if (!isApproved) {
if (autoApproveTransfersFromValidator) {
isApproved = operator == address(validator);
}
}
}
/// @dev Returns the validator of the collection.
function getTransferValidator() public view virtual returns (address) {
return validator;
}
/// @dev Returns the function signature for transfer validation.
function getTransferValidationFunction()
public
view
virtual
returns (bytes4 functionSignature, bool isViewFunction)
{
functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)"));
isViewFunction = true;
}
/// @dev Sets the `validator` of the collection.
function setValidator(address _validator) public onlyOwner {
_setValidator(_validator);
}
/// @dev See {ERC721AQueryable.supportsInterface}.
function supportsInterface(bytes4 interfaceId)
public
view
virtual
override(IERC721A, ERC721A, ERC2981)
returns (bool)
{
return interfaceId == bytes4(0xad0d7f6c) || interfaceId == bytes4(0xa07d229a)
|| ERC2981.supportsInterface(interfaceId) || ERC721A.supportsInterface(interfaceId);
}
/// @dev Sets the `autoApproveTransfersFromValidator` flag.
function setAutomaticApprovalOfTransfersFromValidator(bool autoApprove) external onlyOwner {
autoApproveTransfersFromValidator = autoApprove;
emit AutomaticApprovalOfTransferValidatorSet(autoApprove);
}
/// @dev Sets the default royalty `receiver` and `feeNumerator`.
function setDefaultRoyalty(address receiver, uint96 feeNumerator) external onlyOwner {
_setDefaultRoyalty(receiver, feeNumerator);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* Intenral Functions */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Sets the `validator` and calls `setTokenTypeOfCollection` on `validator`.
function _setValidator(address _validator) internal {
/// Emits `TransferValidatorUpdated` event.
emit TransferValidatorUpdated(validator, _validator);
validator = _validator;
/// Register the token type of the collection on `validator`.
(bool success,) = address(_validator).call(
abi.encodeWithSignature("setTokenTypeOfCollection(address,uint16)", address(this), 721)
);
/// Reverts if the call fails.
if (!success) revert InvalidValidator();
}
/// @dev Hook that is called before any token transfer.
/// Note : Ignore `quantity` because it's always 1 for transfer.
function _beforeTokenTransfers(address from, address to, uint256 id, uint256 /*quantity*/ )
internal
virtual
override(ERC721A)
{
// only for transfer
if (from != address(0) && to != address(0)) {
// Checks if caller is validator
if (msg.sender != validator) {
// Call validateTransfer function on `validator`.
(bool success,) = address(validator).call(
abi.encodeWithSignature(
"validateTransfer(address,address,address,uint256)", msg.sender, from, to, id
)
);
if (!success) revert ValidatorCalledFailed();
}
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721AQueryable.sol';
import '../ERC721A.sol';
/**
* @title ERC721AQueryable.
*
* @dev ERC721A subclass with convenience query functions.
*/
abstract contract ERC721AQueryable is ERC721A, IERC721AQueryable {
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
*
* - `addr = address(0)`
* - `startTimestamp = 0`
* - `burned = false`
* - `extraData = 0`
*
* If the `tokenId` is burned:
*
* - `addr = <Address of owner before token was burned>`
* - `startTimestamp = <Timestamp when token was burned>`
* - `burned = true`
* - `extraData = <Extra data when token was burned>`
*
* Otherwise:
*
* - `addr = <Address of owner>`
* - `startTimestamp = <Timestamp of start of ownership>`
* - `burned = false`
* - `extraData = <Extra data at start of ownership>`
*/
function explicitOwnershipOf(uint256 tokenId)
public
view
virtual
override
returns (TokenOwnership memory ownership)
{
unchecked {
if (tokenId >= _startTokenId()) {
if (tokenId > _sequentialUpTo()) return _ownershipAt(tokenId);
if (tokenId < _nextTokenId()) {
// If the `tokenId` is within bounds,
// scan backwards for the initialized ownership slot.
while (!_ownershipIsInitialized(tokenId)) --tokenId;
return _ownershipAt(tokenId);
}
}
}
}
/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] calldata tokenIds)
external
view
virtual
override
returns (TokenOwnership[] memory)
{
TokenOwnership[] memory ownerships;
uint256 i = tokenIds.length;
assembly {
// Grab the free memory pointer.
ownerships := mload(0x40)
// Store the length.
mstore(ownerships, i)
// Allocate one word for the length,
// `tokenIds.length` words for the pointers.
i := shl(5, i) // Multiply `i` by 32.
mstore(0x40, add(add(ownerships, 0x20), i))
}
while (i != 0) {
uint256 tokenId;
assembly {
i := sub(i, 0x20)
tokenId := calldataload(add(tokenIds.offset, i))
}
TokenOwnership memory ownership = explicitOwnershipOf(tokenId);
assembly {
// Store the pointer of `ownership` in the `ownerships` array.
mstore(add(add(ownerships, 0x20), i), ownership)
}
}
return ownerships;
}
/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) external view virtual override returns (uint256[] memory) {
return _tokensOfOwnerIn(owner, start, stop);
}
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) external view virtual override returns (uint256[] memory) {
// If spot mints are enabled, full-range scan is disabled.
if (_sequentialUpTo() != type(uint256).max) _revert(NotCompatibleWithSpotMints.selector);
uint256 start = _startTokenId();
uint256 stop = _nextTokenId();
uint256[] memory tokenIds;
if (start != stop) tokenIds = _tokensOfOwnerIn(owner, start, stop);
return tokenIds;
}
/**
* @dev Helper function for returning an array of token IDs owned by `owner`.
*
* Note that this function is optimized for smaller bytecode size over runtime gas,
* since it is meant to be called off-chain.
*/
function _tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) private view returns (uint256[] memory tokenIds) {
unchecked {
if (start >= stop) _revert(InvalidQueryRange.selector);
// Set `start = max(start, _startTokenId())`.
if (start < _startTokenId()) start = _startTokenId();
uint256 nextTokenId = _nextTokenId();
// If spot mints are enabled, scan all the way until the specified `stop`.
uint256 stopLimit = _sequentialUpTo() != type(uint256).max ? stop : nextTokenId;
// Set `stop = min(stop, stopLimit)`.
if (stop >= stopLimit) stop = stopLimit;
// Number of tokens to scan.
uint256 tokenIdsMaxLength = balanceOf(owner);
// Set `tokenIdsMaxLength` to zero if the range contains no tokens.
if (start >= stop) tokenIdsMaxLength = 0;
// If there are one or more tokens to scan.
if (tokenIdsMaxLength != 0) {
// Set `tokenIdsMaxLength = min(balanceOf(owner), tokenIdsMaxLength)`.
if (stop - start <= tokenIdsMaxLength) tokenIdsMaxLength = stop - start;
uint256 m; // Start of available memory.
assembly {
// Grab the free memory pointer.
tokenIds := mload(0x40)
// Allocate one word for the length, and `tokenIdsMaxLength` words
// for the data. `shl(5, x)` is equivalent to `mul(32, x)`.
m := add(tokenIds, shl(5, add(tokenIdsMaxLength, 1)))
mstore(0x40, m)
}
// We need to call `explicitOwnershipOf(start)`,
// because the slot at `start` may not be initialized.
TokenOwnership memory ownership = explicitOwnershipOf(start);
address currOwnershipAddr;
// If the starting slot exists (i.e. not burned),
// initialize `currOwnershipAddr`.
// `ownership.address` will not be zero,
// as `start` is clamped to the valid token ID range.
if (!ownership.burned) currOwnershipAddr = ownership.addr;
uint256 tokenIdsIdx;
// Use a do-while, which is slightly more efficient for this case,
// as the array will at least contain one element.
do {
if (_sequentialUpTo() != type(uint256).max) {
// Skip the remaining unused sequential slots.
if (start == nextTokenId) start = _sequentialUpTo() + 1;
// Reset `currOwnershipAddr`, as each spot-minted token is a batch of one.
if (start > _sequentialUpTo()) currOwnershipAddr = address(0);
}
ownership = _ownershipAt(start); // This implicitly allocates memory.
assembly {
switch mload(add(ownership, 0x40))
// if `ownership.burned == false`.
case 0 {
// if `ownership.addr != address(0)`.
// The `addr` already has it's upper 96 bits clearned,
// since it is written to memory with regular Solidity.
if mload(ownership) {
currOwnershipAddr := mload(ownership)
}
// if `currOwnershipAddr == owner`.
// The `shl(96, x)` is to make the comparison agnostic to any
// dirty upper 96 bits in `owner`.
if iszero(shl(96, xor(currOwnershipAddr, owner))) {
tokenIdsIdx := add(tokenIdsIdx, 1)
mstore(add(tokenIds, shl(5, tokenIdsIdx)), start)
}
}
// Otherwise, reset `currOwnershipAddr`.
// This handles the case of batch burned tokens
// (burned bit of first slot set, remaining slots left uninitialized).
default {
currOwnershipAddr := 0
}
start := add(start, 1)
// Free temporary memory implicitly allocated for ownership
// to avoid quadratic memory expansion costs.
mstore(0x40, m)
}
} while (!(start == stop || tokenIdsIdx == tokenIdsMaxLength));
// Store the length of the array.
assembly {
mstore(tokenIds, tokenIdsIdx)
}
}
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../ERC721A.sol';
import './IERC721ABatchTransferable.sol';
/**
* @title ERC721ABatchTransferable.
*
* @dev ERC721A token optimized for batch transfers.
*/
abstract contract ERC721ABatchTransferable is ERC721A, IERC721ABatchTransferable {
function batchTransferFrom(
address from,
address to,
uint256[] memory tokenIds
) public payable virtual override {
_batchTransferFrom(_msgSenderERC721A(), from, to, tokenIds);
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory tokenIds
) public payable virtual override {
_safeBatchTransferFrom(_msgSenderERC721A(), from, to, tokenIds, '');
}
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory tokenIds,
bytes memory _data
) public payable virtual override {
_safeBatchTransferFrom(_msgSenderERC721A(), from, to, tokenIds, _data);
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './ERC721ABurnable.sol';
import './IERC721ABatchBurnable.sol';
/**
* @title ERC721ABatchBurnable.
*
* @dev ERC721A token optimized for batch burns.
*/
abstract contract ERC721ABatchBurnable is ERC721ABurnable, IERC721ABatchBurnable {
function batchBurn(uint256[] memory tokenIds) public virtual override {
_batchBurn(_msgSenderERC721A(), tokenIds);
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
import {Ownable} from "./Ownable.sol";
/// @notice Simple single owner and multiroles authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/OwnableRoles.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract OwnableRoles is Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The `user`'s roles is updated to `roles`.
/// Each bit of `roles` represents whether the role is set.
event RolesUpdated(address indexed user, uint256 indexed roles);
/// @dev `keccak256(bytes("RolesUpdated(address,uint256)"))`.
uint256 private constant _ROLES_UPDATED_EVENT_SIGNATURE =
0x715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe26;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The role slot of `user` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _ROLE_SLOT_SEED))
/// let roleSlot := keccak256(0x00, 0x20)
/// ```
/// This automatically ignores the upper bits of the `user` in case
/// they are not clean, as well as keep the `keccak256` under 32-bytes.
///
/// Note: This is equivalent to `uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))`.
uint256 private constant _ROLE_SLOT_SEED = 0x8b78c6d8;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Overwrite the roles directly without authorization guard.
function _setRoles(address user, uint256 roles) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Store the new value.
sstore(keccak256(0x0c, 0x20), roles)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), roles)
}
}
/// @dev Updates the roles directly without authorization guard.
/// If `on` is true, each set bit of `roles` will be turned on,
/// otherwise, each set bit of `roles` will be turned off.
function _updateRoles(address user, uint256 roles, bool on) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
let roleSlot := keccak256(0x0c, 0x20)
// Load the current value.
let current := sload(roleSlot)
// Compute the updated roles if `on` is true.
let updated := or(current, roles)
// Compute the updated roles if `on` is false.
// Use `and` to compute the intersection of `current` and `roles`,
// `xor` it with `current` to flip the bits in the intersection.
if iszero(on) { updated := xor(current, and(current, roles)) }
// Then, store the new value.
sstore(roleSlot, updated)
// Emit the {RolesUpdated} event.
log3(0, 0, _ROLES_UPDATED_EVENT_SIGNATURE, shr(96, mload(0x0c)), updated)
}
}
/// @dev Grants the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn on.
function _grantRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, true);
}
/// @dev Removes the roles directly without authorization guard.
/// Each bit of `roles` represents the role to turn off.
function _removeRoles(address user, uint256 roles) internal virtual {
_updateRoles(user, roles, false);
}
/// @dev Throws if the sender does not have any of the `roles`.
function _checkRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Throws if the sender is not the owner,
/// and does not have any of the `roles`.
/// Checks for ownership first, then lazily checks for roles.
function _checkOwnerOrRoles(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Throws if the sender does not have any of the `roles`,
/// and is not the owner.
/// Checks for roles first, then lazily checks for ownership.
function _checkRolesOrOwner(uint256 roles) internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, caller())
// Load the stored value, and if the `and` intersection
// of the value and `roles` is zero, revert.
if iszero(and(sload(keccak256(0x0c, 0x20)), roles)) {
// If the caller is not the stored owner.
// Note: `_ROLE_SLOT_SEED` is equal to `_OWNER_SLOT_NOT`.
if iszero(eq(caller(), sload(not(_ROLE_SLOT_SEED)))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
}
/// @dev Convenience function to return a `roles` bitmap from an array of `ordinals`.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _rolesFromOrdinals(uint8[] memory ordinals) internal pure returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
for { let i := shl(5, mload(ordinals)) } i { i := sub(i, 0x20) } {
// We don't need to mask the values of `ordinals`, as Solidity
// cleans dirty upper bits when storing variables into memory.
roles := or(shl(mload(add(ordinals, i)), 1), roles)
}
}
}
/// @dev Convenience function to return an array of `ordinals` from the `roles` bitmap.
/// This is meant for frontends like Etherscan, and is therefore not fully optimized.
/// Not recommended to be called on-chain.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ordinalsFromRoles(uint256 roles) internal pure returns (uint8[] memory ordinals) {
/// @solidity memory-safe-assembly
assembly {
// Grab the pointer to the free memory.
ordinals := mload(0x40)
let ptr := add(ordinals, 0x20)
let o := 0
// The absence of lookup tables, De Bruijn, etc., here is intentional for
// smaller bytecode, as this function is not meant to be called on-chain.
for { let t := roles } 1 {} {
mstore(ptr, o)
// `shr` 5 is equivalent to multiplying by 0x20.
// Push back into the ordinals array if the bit is set.
ptr := add(ptr, shl(5, and(t, 1)))
o := add(o, 1)
t := shr(o, roles)
if iszero(t) { break }
}
// Store the length of `ordinals`.
mstore(ordinals, shr(5, sub(ptr, add(ordinals, 0x20))))
// Allocate the memory.
mstore(0x40, ptr)
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to grant `user` `roles`.
/// If the `user` already has a role, then it will be an no-op for the role.
function grantRoles(address user, uint256 roles) public payable virtual onlyOwner {
_grantRoles(user, roles);
}
/// @dev Allows the owner to remove `user` `roles`.
/// If the `user` does not have a role, then it will be an no-op for the role.
function revokeRoles(address user, uint256 roles) public payable virtual onlyOwner {
_removeRoles(user, roles);
}
/// @dev Allow the caller to remove their own roles.
/// If the caller does not have a role, then it will be an no-op for the role.
function renounceRoles(uint256 roles) public payable virtual {
_removeRoles(msg.sender, roles);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the roles of `user`.
function rolesOf(address user) public view virtual returns (uint256 roles) {
/// @solidity memory-safe-assembly
assembly {
// Compute the role slot.
mstore(0x0c, _ROLE_SLOT_SEED)
mstore(0x00, user)
// Load the stored value.
roles := sload(keccak256(0x0c, 0x20))
}
}
/// @dev Returns whether `user` has any of `roles`.
function hasAnyRole(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles != 0;
}
/// @dev Returns whether `user` has all of `roles`.
function hasAllRoles(address user, uint256 roles) public view virtual returns (bool) {
return rolesOf(user) & roles == roles;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by an account with `roles`.
modifier onlyRoles(uint256 roles) virtual {
_checkRoles(roles);
_;
}
/// @dev Marks a function as only callable by the owner or by an account
/// with `roles`. Checks for ownership first, then lazily checks for roles.
modifier onlyOwnerOrRoles(uint256 roles) virtual {
_checkOwnerOrRoles(roles);
_;
}
/// @dev Marks a function as only callable by an account with `roles`
/// or the owner. Checks for roles first, then lazily checks for ownership.
modifier onlyRolesOrOwner(uint256 roles) virtual {
_checkRolesOrOwner(roles);
_;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ROLE CONSTANTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// IYKYK
uint256 internal constant _ROLE_0 = 1 << 0;
uint256 internal constant _ROLE_1 = 1 << 1;
uint256 internal constant _ROLE_2 = 1 << 2;
uint256 internal constant _ROLE_3 = 1 << 3;
uint256 internal constant _ROLE_4 = 1 << 4;
uint256 internal constant _ROLE_5 = 1 << 5;
uint256 internal constant _ROLE_6 = 1 << 6;
uint256 internal constant _ROLE_7 = 1 << 7;
uint256 internal constant _ROLE_8 = 1 << 8;
uint256 internal constant _ROLE_9 = 1 << 9;
uint256 internal constant _ROLE_10 = 1 << 10;
uint256 internal constant _ROLE_11 = 1 << 11;
uint256 internal constant _ROLE_12 = 1 << 12;
uint256 internal constant _ROLE_13 = 1 << 13;
uint256 internal constant _ROLE_14 = 1 << 14;
uint256 internal constant _ROLE_15 = 1 << 15;
uint256 internal constant _ROLE_16 = 1 << 16;
uint256 internal constant _ROLE_17 = 1 << 17;
uint256 internal constant _ROLE_18 = 1 << 18;
uint256 internal constant _ROLE_19 = 1 << 19;
uint256 internal constant _ROLE_20 = 1 << 20;
uint256 internal constant _ROLE_21 = 1 << 21;
uint256 internal constant _ROLE_22 = 1 << 22;
uint256 internal constant _ROLE_23 = 1 << 23;
uint256 internal constant _ROLE_24 = 1 << 24;
uint256 internal constant _ROLE_25 = 1 << 25;
uint256 internal constant _ROLE_26 = 1 << 26;
uint256 internal constant _ROLE_27 = 1 << 27;
uint256 internal constant _ROLE_28 = 1 << 28;
uint256 internal constant _ROLE_29 = 1 << 29;
uint256 internal constant _ROLE_30 = 1 << 30;
uint256 internal constant _ROLE_31 = 1 << 31;
uint256 internal constant _ROLE_32 = 1 << 32;
uint256 internal constant _ROLE_33 = 1 << 33;
uint256 internal constant _ROLE_34 = 1 << 34;
uint256 internal constant _ROLE_35 = 1 << 35;
uint256 internal constant _ROLE_36 = 1 << 36;
uint256 internal constant _ROLE_37 = 1 << 37;
uint256 internal constant _ROLE_38 = 1 << 38;
uint256 internal constant _ROLE_39 = 1 << 39;
uint256 internal constant _ROLE_40 = 1 << 40;
uint256 internal constant _ROLE_41 = 1 << 41;
uint256 internal constant _ROLE_42 = 1 << 42;
uint256 internal constant _ROLE_43 = 1 << 43;
uint256 internal constant _ROLE_44 = 1 << 44;
uint256 internal constant _ROLE_45 = 1 << 45;
uint256 internal constant _ROLE_46 = 1 << 46;
uint256 internal constant _ROLE_47 = 1 << 47;
uint256 internal constant _ROLE_48 = 1 << 48;
uint256 internal constant _ROLE_49 = 1 << 49;
uint256 internal constant _ROLE_50 = 1 << 50;
uint256 internal constant _ROLE_51 = 1 << 51;
uint256 internal constant _ROLE_52 = 1 << 52;
uint256 internal constant _ROLE_53 = 1 << 53;
uint256 internal constant _ROLE_54 = 1 << 54;
uint256 internal constant _ROLE_55 = 1 << 55;
uint256 internal constant _ROLE_56 = 1 << 56;
uint256 internal constant _ROLE_57 = 1 << 57;
uint256 internal constant _ROLE_58 = 1 << 58;
uint256 internal constant _ROLE_59 = 1 << 59;
uint256 internal constant _ROLE_60 = 1 << 60;
uint256 internal constant _ROLE_61 = 1 << 61;
uint256 internal constant _ROLE_62 = 1 << 62;
uint256 internal constant _ROLE_63 = 1 << 63;
uint256 internal constant _ROLE_64 = 1 << 64;
uint256 internal constant _ROLE_65 = 1 << 65;
uint256 internal constant _ROLE_66 = 1 << 66;
uint256 internal constant _ROLE_67 = 1 << 67;
uint256 internal constant _ROLE_68 = 1 << 68;
uint256 internal constant _ROLE_69 = 1 << 69;
uint256 internal constant _ROLE_70 = 1 << 70;
uint256 internal constant _ROLE_71 = 1 << 71;
uint256 internal constant _ROLE_72 = 1 << 72;
uint256 internal constant _ROLE_73 = 1 << 73;
uint256 internal constant _ROLE_74 = 1 << 74;
uint256 internal constant _ROLE_75 = 1 << 75;
uint256 internal constant _ROLE_76 = 1 << 76;
uint256 internal constant _ROLE_77 = 1 << 77;
uint256 internal constant _ROLE_78 = 1 << 78;
uint256 internal constant _ROLE_79 = 1 << 79;
uint256 internal constant _ROLE_80 = 1 << 80;
uint256 internal constant _ROLE_81 = 1 << 81;
uint256 internal constant _ROLE_82 = 1 << 82;
uint256 internal constant _ROLE_83 = 1 << 83;
uint256 internal constant _ROLE_84 = 1 << 84;
uint256 internal constant _ROLE_85 = 1 << 85;
uint256 internal constant _ROLE_86 = 1 << 86;
uint256 internal constant _ROLE_87 = 1 << 87;
uint256 internal constant _ROLE_88 = 1 << 88;
uint256 internal constant _ROLE_89 = 1 << 89;
uint256 internal constant _ROLE_90 = 1 << 90;
uint256 internal constant _ROLE_91 = 1 << 91;
uint256 internal constant _ROLE_92 = 1 << 92;
uint256 internal constant _ROLE_93 = 1 << 93;
uint256 internal constant _ROLE_94 = 1 << 94;
uint256 internal constant _ROLE_95 = 1 << 95;
uint256 internal constant _ROLE_96 = 1 << 96;
uint256 internal constant _ROLE_97 = 1 << 97;
uint256 internal constant _ROLE_98 = 1 << 98;
uint256 internal constant _ROLE_99 = 1 << 99;
uint256 internal constant _ROLE_100 = 1 << 100;
uint256 internal constant _ROLE_101 = 1 << 101;
uint256 internal constant _ROLE_102 = 1 << 102;
uint256 internal constant _ROLE_103 = 1 << 103;
uint256 internal constant _ROLE_104 = 1 << 104;
uint256 internal constant _ROLE_105 = 1 << 105;
uint256 internal constant _ROLE_106 = 1 << 106;
uint256 internal constant _ROLE_107 = 1 << 107;
uint256 internal constant _ROLE_108 = 1 << 108;
uint256 internal constant _ROLE_109 = 1 << 109;
uint256 internal constant _ROLE_110 = 1 << 110;
uint256 internal constant _ROLE_111 = 1 << 111;
uint256 internal constant _ROLE_112 = 1 << 112;
uint256 internal constant _ROLE_113 = 1 << 113;
uint256 internal constant _ROLE_114 = 1 << 114;
uint256 internal constant _ROLE_115 = 1 << 115;
uint256 internal constant _ROLE_116 = 1 << 116;
uint256 internal constant _ROLE_117 = 1 << 117;
uint256 internal constant _ROLE_118 = 1 << 118;
uint256 internal constant _ROLE_119 = 1 << 119;
uint256 internal constant _ROLE_120 = 1 << 120;
uint256 internal constant _ROLE_121 = 1 << 121;
uint256 internal constant _ROLE_122 = 1 << 122;
uint256 internal constant _ROLE_123 = 1 << 123;
uint256 internal constant _ROLE_124 = 1 << 124;
uint256 internal constant _ROLE_125 = 1 << 125;
uint256 internal constant _ROLE_126 = 1 << 126;
uint256 internal constant _ROLE_127 = 1 << 127;
uint256 internal constant _ROLE_128 = 1 << 128;
uint256 internal constant _ROLE_129 = 1 << 129;
uint256 internal constant _ROLE_130 = 1 << 130;
uint256 internal constant _ROLE_131 = 1 << 131;
uint256 internal constant _ROLE_132 = 1 << 132;
uint256 internal constant _ROLE_133 = 1 << 133;
uint256 internal constant _ROLE_134 = 1 << 134;
uint256 internal constant _ROLE_135 = 1 << 135;
uint256 internal constant _ROLE_136 = 1 << 136;
uint256 internal constant _ROLE_137 = 1 << 137;
uint256 internal constant _ROLE_138 = 1 << 138;
uint256 internal constant _ROLE_139 = 1 << 139;
uint256 internal constant _ROLE_140 = 1 << 140;
uint256 internal constant _ROLE_141 = 1 << 141;
uint256 internal constant _ROLE_142 = 1 << 142;
uint256 internal constant _ROLE_143 = 1 << 143;
uint256 internal constant _ROLE_144 = 1 << 144;
uint256 internal constant _ROLE_145 = 1 << 145;
uint256 internal constant _ROLE_146 = 1 << 146;
uint256 internal constant _ROLE_147 = 1 << 147;
uint256 internal constant _ROLE_148 = 1 << 148;
uint256 internal constant _ROLE_149 = 1 << 149;
uint256 internal constant _ROLE_150 = 1 << 150;
uint256 internal constant _ROLE_151 = 1 << 151;
uint256 internal constant _ROLE_152 = 1 << 152;
uint256 internal constant _ROLE_153 = 1 << 153;
uint256 internal constant _ROLE_154 = 1 << 154;
uint256 internal constant _ROLE_155 = 1 << 155;
uint256 internal constant _ROLE_156 = 1 << 156;
uint256 internal constant _ROLE_157 = 1 << 157;
uint256 internal constant _ROLE_158 = 1 << 158;
uint256 internal constant _ROLE_159 = 1 << 159;
uint256 internal constant _ROLE_160 = 1 << 160;
uint256 internal constant _ROLE_161 = 1 << 161;
uint256 internal constant _ROLE_162 = 1 << 162;
uint256 internal constant _ROLE_163 = 1 << 163;
uint256 internal constant _ROLE_164 = 1 << 164;
uint256 internal constant _ROLE_165 = 1 << 165;
uint256 internal constant _ROLE_166 = 1 << 166;
uint256 internal constant _ROLE_167 = 1 << 167;
uint256 internal constant _ROLE_168 = 1 << 168;
uint256 internal constant _ROLE_169 = 1 << 169;
uint256 internal constant _ROLE_170 = 1 << 170;
uint256 internal constant _ROLE_171 = 1 << 171;
uint256 internal constant _ROLE_172 = 1 << 172;
uint256 internal constant _ROLE_173 = 1 << 173;
uint256 internal constant _ROLE_174 = 1 << 174;
uint256 internal constant _ROLE_175 = 1 << 175;
uint256 internal constant _ROLE_176 = 1 << 176;
uint256 internal constant _ROLE_177 = 1 << 177;
uint256 internal constant _ROLE_178 = 1 << 178;
uint256 internal constant _ROLE_179 = 1 << 179;
uint256 internal constant _ROLE_180 = 1 << 180;
uint256 internal constant _ROLE_181 = 1 << 181;
uint256 internal constant _ROLE_182 = 1 << 182;
uint256 internal constant _ROLE_183 = 1 << 183;
uint256 internal constant _ROLE_184 = 1 << 184;
uint256 internal constant _ROLE_185 = 1 << 185;
uint256 internal constant _ROLE_186 = 1 << 186;
uint256 internal constant _ROLE_187 = 1 << 187;
uint256 internal constant _ROLE_188 = 1 << 188;
uint256 internal constant _ROLE_189 = 1 << 189;
uint256 internal constant _ROLE_190 = 1 << 190;
uint256 internal constant _ROLE_191 = 1 << 191;
uint256 internal constant _ROLE_192 = 1 << 192;
uint256 internal constant _ROLE_193 = 1 << 193;
uint256 internal constant _ROLE_194 = 1 << 194;
uint256 internal constant _ROLE_195 = 1 << 195;
uint256 internal constant _ROLE_196 = 1 << 196;
uint256 internal constant _ROLE_197 = 1 << 197;
uint256 internal constant _ROLE_198 = 1 << 198;
uint256 internal constant _ROLE_199 = 1 << 199;
uint256 internal constant _ROLE_200 = 1 << 200;
uint256 internal constant _ROLE_201 = 1 << 201;
uint256 internal constant _ROLE_202 = 1 << 202;
uint256 internal constant _ROLE_203 = 1 << 203;
uint256 internal constant _ROLE_204 = 1 << 204;
uint256 internal constant _ROLE_205 = 1 << 205;
uint256 internal constant _ROLE_206 = 1 << 206;
uint256 internal constant _ROLE_207 = 1 << 207;
uint256 internal constant _ROLE_208 = 1 << 208;
uint256 internal constant _ROLE_209 = 1 << 209;
uint256 internal constant _ROLE_210 = 1 << 210;
uint256 internal constant _ROLE_211 = 1 << 211;
uint256 internal constant _ROLE_212 = 1 << 212;
uint256 internal constant _ROLE_213 = 1 << 213;
uint256 internal constant _ROLE_214 = 1 << 214;
uint256 internal constant _ROLE_215 = 1 << 215;
uint256 internal constant _ROLE_216 = 1 << 216;
uint256 internal constant _ROLE_217 = 1 << 217;
uint256 internal constant _ROLE_218 = 1 << 218;
uint256 internal constant _ROLE_219 = 1 << 219;
uint256 internal constant _ROLE_220 = 1 << 220;
uint256 internal constant _ROLE_221 = 1 << 221;
uint256 internal constant _ROLE_222 = 1 << 222;
uint256 internal constant _ROLE_223 = 1 << 223;
uint256 internal constant _ROLE_224 = 1 << 224;
uint256 internal constant _ROLE_225 = 1 << 225;
uint256 internal constant _ROLE_226 = 1 << 226;
uint256 internal constant _ROLE_227 = 1 << 227;
uint256 internal constant _ROLE_228 = 1 << 228;
uint256 internal constant _ROLE_229 = 1 << 229;
uint256 internal constant _ROLE_230 = 1 << 230;
uint256 internal constant _ROLE_231 = 1 << 231;
uint256 internal constant _ROLE_232 = 1 << 232;
uint256 internal constant _ROLE_233 = 1 << 233;
uint256 internal constant _ROLE_234 = 1 << 234;
uint256 internal constant _ROLE_235 = 1 << 235;
uint256 internal constant _ROLE_236 = 1 << 236;
uint256 internal constant _ROLE_237 = 1 << 237;
uint256 internal constant _ROLE_238 = 1 << 238;
uint256 internal constant _ROLE_239 = 1 << 239;
uint256 internal constant _ROLE_240 = 1 << 240;
uint256 internal constant _ROLE_241 = 1 << 241;
uint256 internal constant _ROLE_242 = 1 << 242;
uint256 internal constant _ROLE_243 = 1 << 243;
uint256 internal constant _ROLE_244 = 1 << 244;
uint256 internal constant _ROLE_245 = 1 << 245;
uint256 internal constant _ROLE_246 = 1 << 246;
uint256 internal constant _ROLE_247 = 1 << 247;
uint256 internal constant _ROLE_248 = 1 << 248;
uint256 internal constant _ROLE_249 = 1 << 249;
uint256 internal constant _ROLE_250 = 1 << 250;
uint256 internal constant _ROLE_251 = 1 << 251;
uint256 internal constant _ROLE_252 = 1 << 252;
uint256 internal constant _ROLE_253 = 1 << 253;
uint256 internal constant _ROLE_254 = 1 << 254;
uint256 internal constant _ROLE_255 = 1 << 255;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple ERC2981 NFT Royalty Standard implementation.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC2981.sol)
/// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/token/common/ERC2981.sol)
abstract contract ERC2981 {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The royalty fee numerator exceeds the fee denominator.
error RoyaltyOverflow();
/// @dev The royalty receiver cannot be the zero address.
error RoyaltyReceiverIsZeroAddress();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The default royalty info is given by:
/// ```
/// let packed := sload(_ERC2981_MASTER_SLOT_SEED)
/// let receiver := shr(96, packed)
/// let royaltyFraction := xor(packed, shl(96, receiver))
/// ```
///
/// The per token royalty info is given by.
/// ```
/// mstore(0x00, tokenId)
/// mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
/// let packed := sload(keccak256(0x00, 0x40))
/// let receiver := shr(96, packed)
/// let royaltyFraction := xor(packed, shl(96, receiver))
/// ```
uint256 private constant _ERC2981_MASTER_SLOT_SEED = 0xaa4ec00224afccfdb7;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* ERC2981 */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Checks that `_feeDenominator` is non-zero.
constructor() {
require(_feeDenominator() != 0, "Fee denominator cannot be zero.");
}
/// @dev Returns the denominator for the royalty amount.
/// Defaults to 10000, which represents fees in basis points.
/// Override this function to return a custom amount if needed.
function _feeDenominator() internal pure virtual returns (uint96) {
return 10000;
}
/// @dev Returns true if this contract implements the interface defined by `interfaceId`.
/// See: https://eips.ethereum.org/EIPS/eip-165
/// This function call must use less than 30000 gas.
function supportsInterface(bytes4 interfaceId) public view virtual returns (bool result) {
/// @solidity memory-safe-assembly
assembly {
let s := shr(224, interfaceId)
// ERC165: 0x01ffc9a7, ERC2981: 0x2a55205a.
result := or(eq(s, 0x01ffc9a7), eq(s, 0x2a55205a))
}
}
/// @dev Returns the `receiver` and `royaltyAmount` for `tokenId` sold at `salePrice`.
function royaltyInfo(uint256 tokenId, uint256 salePrice)
public
view
virtual
returns (address receiver, uint256 royaltyAmount)
{
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
let packed := sload(keccak256(0x00, 0x40))
receiver := shr(96, packed)
if iszero(receiver) {
packed := sload(mload(0x20))
receiver := shr(96, packed)
}
let x := salePrice
let y := xor(packed, shl(96, receiver)) // `feeNumerator`.
// Overflow check, equivalent to `require(y == 0 || x <= type(uint256).max / y)`.
// Out-of-gas revert. Should not be triggered in practice, but included for safety.
returndatacopy(returndatasize(), returndatasize(), mul(y, gt(x, div(not(0), y))))
royaltyAmount := div(mul(x, y), feeDenominator)
}
}
/// @dev Sets the default royalty `receiver` and `feeNumerator`.
///
/// Requirements:
/// - `receiver` must not be the zero address.
/// - `feeNumerator` must not be greater than the fee denominator.
function _setDefaultRoyalty(address receiver, uint96 feeNumerator) internal virtual {
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
feeNumerator := shr(160, shl(160, feeNumerator))
if gt(feeNumerator, feeDenominator) {
mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
revert(0x1c, 0x04)
}
let packed := shl(96, receiver)
if iszero(packed) {
mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
revert(0x1c, 0x04)
}
sstore(_ERC2981_MASTER_SLOT_SEED, or(packed, feeNumerator))
}
}
/// @dev Sets the default royalty `receiver` and `feeNumerator` to zero.
function _deleteDefaultRoyalty() internal virtual {
/// @solidity memory-safe-assembly
assembly {
sstore(_ERC2981_MASTER_SLOT_SEED, 0)
}
}
/// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId`.
///
/// Requirements:
/// - `receiver` must not be the zero address.
/// - `feeNumerator` must not be greater than the fee denominator.
function _setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator)
internal
virtual
{
uint256 feeDenominator = _feeDenominator();
/// @solidity memory-safe-assembly
assembly {
feeNumerator := shr(160, shl(160, feeNumerator))
if gt(feeNumerator, feeDenominator) {
mstore(0x00, 0x350a88b3) // `RoyaltyOverflow()`.
revert(0x1c, 0x04)
}
let packed := shl(96, receiver)
if iszero(packed) {
mstore(0x00, 0xb4457eaa) // `RoyaltyReceiverIsZeroAddress()`.
revert(0x1c, 0x04)
}
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
sstore(keccak256(0x00, 0x40), or(packed, feeNumerator))
}
}
/// @dev Sets the royalty `receiver` and `feeNumerator` for `tokenId` to zero.
function _resetTokenRoyalty(uint256 tokenId) internal virtual {
/// @solidity memory-safe-assembly
assembly {
mstore(0x00, tokenId)
mstore(0x20, _ERC2981_MASTER_SLOT_SEED)
sstore(keccak256(0x00, 0x40), 0)
}
}
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Library for storage of packed unsigned integers.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibMap.sol)
library LibMap {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STRUCTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev A uint8 map in storage.
struct Uint8Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint16 map in storage.
struct Uint16Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint32 map in storage.
struct Uint32Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint40 map in storage. Useful for storing timestamps up to 34841 A.D.
struct Uint40Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint64 map in storage.
struct Uint64Map {
mapping(uint256 => uint256) map;
}
/// @dev A uint128 map in storage.
struct Uint128Map {
mapping(uint256 => uint256) map;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* GETTERS / SETTERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the uint8 value at `index` in `map`.
function get(Uint8Map storage map, uint256 index) internal view returns (uint8 result) {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(5, index))
result := byte(and(31, not(index)), sload(keccak256(0x00, 0x40)))
}
}
/// @dev Updates the uint8 value at `index` in `map`.
function set(Uint8Map storage map, uint256 index, uint8 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(5, index))
let s := keccak256(0x00, 0x40) // Storage slot.
mstore(0x00, sload(s))
mstore8(and(31, not(index)), value)
sstore(s, mload(0x00))
}
}
/// @dev Returns the uint16 value at `index` in `map`.
function get(Uint16Map storage map, uint256 index) internal view returns (uint16 result) {
result = uint16(map.map[index >> 4] >> ((index & 15) << 4));
}
/// @dev Updates the uint16 value at `index` in `map`.
function set(Uint16Map storage map, uint256 index, uint16 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(4, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(4, and(index, 15)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint32 value at `index` in `map`.
function get(Uint32Map storage map, uint256 index) internal view returns (uint32 result) {
result = uint32(map.map[index >> 3] >> ((index & 7) << 5));
}
/// @dev Updates the uint32 value at `index` in `map`.
function set(Uint32Map storage map, uint256 index, uint32 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(3, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(5, and(index, 7)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint40 value at `index` in `map`.
function get(Uint40Map storage map, uint256 index) internal view returns (uint40 result) {
unchecked {
result = uint40(map.map[index / 6] >> ((index % 6) * 40));
}
}
/// @dev Updates the uint40 value at `index` in `map`.
function set(Uint40Map storage map, uint256 index, uint40 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, div(index, 6))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := mul(40, mod(index, 6)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint64 value at `index` in `map`.
function get(Uint64Map storage map, uint256 index) internal view returns (uint64 result) {
result = uint64(map.map[index >> 2] >> ((index & 3) << 6));
}
/// @dev Updates the uint64 value at `index` in `map`.
function set(Uint64Map storage map, uint256 index, uint64 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(2, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(6, and(index, 3)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the uint128 value at `index` in `map`.
function get(Uint128Map storage map, uint256 index) internal view returns (uint128 result) {
result = uint128(map.map[index >> 1] >> ((index & 1) << 7));
}
/// @dev Updates the uint128 value at `index` in `map`.
function set(Uint128Map storage map, uint256 index, uint128 value) internal {
/// @solidity memory-safe-assembly
assembly {
mstore(0x20, map.slot)
mstore(0x00, shr(1, index))
let s := keccak256(0x00, 0x40) // Storage slot.
let o := shl(7, and(index, 1)) // Storage slot offset (bits).
let v := sload(s) // Storage slot value.
let m := 0xffffffffffffffffffffffffffffffff // Value mask.
sstore(s, xor(v, shl(o, and(m, xor(shr(o, v), value)))))
}
}
/// @dev Returns the value at `index` in `map`.
function get(mapping(uint256 => uint256) storage map, uint256 index, uint256 bitWidth)
internal
view
returns (uint256 result)
{
unchecked {
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
result = (map[_rawDiv(index, d)] >> (_rawMod(index, d) * bitWidth)) & m;
}
}
/// @dev Updates the value at `index` in `map`.
function set(
mapping(uint256 => uint256) storage map,
uint256 index,
uint256 value,
uint256 bitWidth
) internal {
unchecked {
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
uint256 o = _rawMod(index, d) * bitWidth; // Storage slot offset (bits).
map[_rawDiv(index, d)] ^= (((map[_rawDiv(index, d)] >> o) ^ value) & m) << o;
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* BINARY SEARCH */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
// The following functions search in the range of [`start`, `end`)
// (i.e. `start <= index < end`).
// The range must be sorted in ascending order.
// `index` precedence: equal to > nearest before > nearest after.
// An invalid search range will simply return `(found = false, index = start)`.
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint8Map storage map, uint8 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 8);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint16Map storage map, uint16 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 16);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint32Map storage map, uint32 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 32);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint40Map storage map, uint40 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 40);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint64Map storage map, uint64 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 64);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(Uint128Map storage map, uint128 needle, uint256 start, uint256 end)
internal
view
returns (bool found, uint256 index)
{
return searchSorted(map.map, needle, start, end, 128);
}
/// @dev Returns whether `map` contains `needle`, and the index of `needle`.
function searchSorted(
mapping(uint256 => uint256) storage map,
uint256 needle,
uint256 start,
uint256 end,
uint256 bitWidth
) internal view returns (bool found, uint256 index) {
unchecked {
if (start >= end) end = start;
uint256 t;
uint256 o = start - 1; // Offset to derive the actual index.
uint256 l = 1; // Low.
uint256 d = _rawDiv(256, bitWidth); // Bucket size.
uint256 m = (1 << bitWidth) - 1; // Value mask.
uint256 h = end - start; // High.
while (true) {
index = (l & h) + ((l ^ h) >> 1);
if (l > h) break;
t = (map[_rawDiv(index + o, d)] >> (_rawMod(index + o, d) * bitWidth)) & m;
if (t == needle) break;
if (needle <= t) h = index - 1;
else l = index + 1;
}
/// @solidity memory-safe-assembly
assembly {
m := or(iszero(index), iszero(bitWidth))
found := iszero(or(xor(t, needle), m))
index := add(o, xor(index, mul(xor(index, 1), m)))
}
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PRIVATE HELPERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns `x / y`, returning 0 if `y` is zero.
function _rawDiv(uint256 x, uint256 y) private pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := div(x, y)
}
}
/// @dev Returns `x % y`, returning 0 if `y` is zero.
function _rawMod(uint256 x, uint256 y) private pure returns (uint256 z) {
/// @solidity memory-safe-assembly
assembly {
z := mod(x, y)
}
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721A.sol';
/**
* @dev Interface of ERC721AQueryable.
*/
interface IERC721AQueryable is IERC721A {
/**
* Invalid query range (`start` >= `stop`).
*/
error InvalidQueryRange();
/**
* @dev Returns the `TokenOwnership` struct at `tokenId` without reverting.
*
* If the `tokenId` is out of bounds:
*
* - `addr = address(0)`
* - `startTimestamp = 0`
* - `burned = false`
* - `extraData = 0`
*
* If the `tokenId` is burned:
*
* - `addr = <Address of owner before token was burned>`
* - `startTimestamp = <Timestamp when token was burned>`
* - `burned = true`
* - `extraData = <Extra data when token was burned>`
*
* Otherwise:
*
* - `addr = <Address of owner>`
* - `startTimestamp = <Timestamp of start of ownership>`
* - `burned = false`
* - `extraData = <Extra data at start of ownership>`
*/
function explicitOwnershipOf(uint256 tokenId) external view returns (TokenOwnership memory);
/**
* @dev Returns an array of `TokenOwnership` structs at `tokenIds` in order.
* See {ERC721AQueryable-explicitOwnershipOf}
*/
function explicitOwnershipsOf(uint256[] memory tokenIds) external view returns (TokenOwnership[] memory);
/**
* @dev Returns an array of token IDs owned by `owner`,
* in the range [`start`, `stop`)
* (i.e. `start <= tokenId < stop`).
*
* This function allows for tokens to be queried if the collection
* grows too big for a single call of {ERC721AQueryable-tokensOfOwner}.
*
* Requirements:
*
* - `start < stop`
*/
function tokensOfOwnerIn(
address owner,
uint256 start,
uint256 stop
) external view returns (uint256[] memory);
/**
* @dev Returns an array of token IDs owned by `owner`.
*
* This function scans the ownership mapping and is O(`totalSupply`) in complexity.
* It is meant to be called off-chain.
*
* See {ERC721AQueryable-tokensOfOwnerIn} for splitting the scan into
* multiple smaller scans if the collection is large enough to cause
* an out-of-gas error (10K collections should be fine).
*/
function tokensOfOwner(address owner) external view returns (uint256[] memory);
}// 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] == uint256(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 == uint256(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 == uint256(0)) continue;
if (packed & _BITMASK_BURNED == uint256(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 == uint256(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]) == uint256(0)) --tokenId;
result = packed & _BITMASK_BURNED == uint256(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(
uint256 approvedAddressValue,
uint256 ownerMasked,
uint256 msgSenderMasked
) private pure returns (bool result) {
assembly {
result := or(eq(msgSenderMasked, ownerMasked), eq(msgSenderMasked, approvedAddressValue))
}
}
/**
* @dev Returns the storage slot and value for the approved address of `tokenId` casted to a uint256.
*/
function _getApprovedSlotAndValue(uint256 tokenId)
private
view
returns (uint256 approvedAddressSlot, uint256 approvedAddressValue)
{
TokenApprovalRef storage tokenApproval = _tokenApprovals[tokenId];
// The following is equivalent to `approvedAddressValue = uint160(_tokenApprovals[tokenId].value)`.
assembly {
approvedAddressSlot := tokenApproval.slot
approvedAddressValue := 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);
uint256 fromMasked = uint160(from);
if (uint160(prevOwnershipPacked) != fromMasked) _revert(TransferFromIncorrectOwner.selector);
(uint256 approvedAddressSlot, uint256 approvedAddressValue) = _getApprovedSlotAndValue(tokenId);
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddressValue, fromMasked, uint160(_msgSenderERC721A())))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
_beforeTokenTransfers(from, to, tokenId, 1);
assembly {
if approvedAddressValue {
sstore(approvedAddressSlot, 0) // Equivalent to `delete _tokenApprovals[tokenId]`.
}
}
// 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 == uint256(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] == uint256(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 the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint160(to);
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.
fromMasked, // `from`.
toMasked, // `to`.
tokenId // `tokenId`.
)
}
if (toMasked == uint256(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 Equivalent to `_batchTransferFrom(from, to, tokenIds)`.
*/
function _batchTransferFrom(
address from,
address to,
uint256[] memory tokenIds
) internal virtual {
_batchTransferFrom(address(0), from, to, tokenIds);
}
/**
* @dev Transfers `tokenIds` in batch from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenIds` tokens must be owned by `from`.
* - `tokenIds` must be strictly ascending.
* - If `by` is not `from`, it must be approved to move these tokens
* by either {approve} or {setApprovalForAll}.
*
* `by` is the address that to check token approval for.
* If token approval check is not needed, pass in `address(0)` for `by`.
*
* Emits a {Transfer} event for each transfer.
*/
function _batchTransferFrom(
address by,
address from,
address to,
uint256[] memory tokenIds
) internal virtual {
uint256 byMasked = uint160(by);
uint256 fromMasked = uint160(from);
uint256 toMasked = uint160(to);
// Disallow transfer to zero address.
if (toMasked == uint256(0)) _revert(TransferToZeroAddress.selector);
// Whether `by` may transfer the tokens.
bool mayTransfer = _orERC721A(byMasked == uint256(0), byMasked == fromMasked) || isApprovedForAll(from, by);
// Early return if `tokenIds` is empty.
if (tokenIds.length == uint256(0)) return;
// The next `tokenId` to be minted (i.e. `_nextTokenId()`).
uint256 end = _currentIndex;
// Pointer to start and end (exclusive) of `tokenIds`.
(uint256 ptr, uint256 ptrEnd) = _mdataERC721A(tokenIds);
uint256 prevTokenId;
uint256 prevOwnershipPacked;
unchecked {
do {
uint256 tokenId = _mloadERC721A(ptr);
uint256 miniBatchStart = tokenId;
// Revert `tokenId` is out of bounds.
if (_orERC721A(tokenId < _startTokenId(), end <= tokenId))
_revert(OwnerQueryForNonexistentToken.selector);
// Revert if `tokenIds` is not strictly ascending.
if (prevOwnershipPacked != 0)
if (tokenId <= prevTokenId) _revert(TokenIdsNotStrictlyAscending.selector);
// Scan backwards for an initialized packed ownership slot.
// ERC721A's invariant guarantees that there will always be an initialized slot as long as
// the start of the backwards scan falls within `[_startTokenId() .. _nextTokenId())`.
for (uint256 j = tokenId; (prevOwnershipPacked = _packedOwnerships[j]) == uint256(0); ) --j;
// If the initialized slot is burned, revert.
if (prevOwnershipPacked & _BITMASK_BURNED != 0) _revert(OwnerQueryForNonexistentToken.selector);
// Check that `tokenId` is owned by `from`.
if (uint160(prevOwnershipPacked) != fromMasked) _revert(TransferFromIncorrectOwner.selector);
do {
(uint256 approvedAddressSlot, uint256 approvedAddressValue) = _getApprovedSlotAndValue(tokenId);
_beforeTokenTransfers(address(uint160(fromMasked)), address(uint160(toMasked)), tokenId, 1);
// Revert if the sender is not authorized to transfer the token.
if (!mayTransfer)
if (byMasked != approvedAddressValue) _revert(TransferCallerNotOwnerNorApproved.selector);
assembly {
if approvedAddressValue {
sstore(approvedAddressSlot, 0) // Equivalent to `delete _tokenApprovals[tokenId]`.
}
// Emit the `Transfer` event.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, fromMasked, toMasked, tokenId)
}
if (_mloadERC721A(ptr += 0x20) != ++tokenId) break;
if (ptr == ptrEnd) break;
} while (_packedOwnerships[tokenId] == uint256(0));
// Updates tokenId:
// - `address` to the next owner.
// - `startTimestamp` to the timestamp of transferring.
// - `burned` to `false`.
// - `nextInitialized` to `false`, as it is optional.
_packedOwnerships[miniBatchStart] = _packOwnershipData(
address(uint160(toMasked)),
_nextExtraData(address(uint160(fromMasked)), address(uint160(toMasked)), prevOwnershipPacked)
);
uint256 miniBatchLength = tokenId - miniBatchStart;
// Update the address data.
_packedAddressData[address(uint160(fromMasked))] -= miniBatchLength;
_packedAddressData[address(uint160(toMasked))] += miniBatchLength;
// Initialize the next slot if needed.
if (tokenId != end)
if (_packedOwnerships[tokenId] == uint256(0)) _packedOwnerships[tokenId] = prevOwnershipPacked;
// Perform the after hook for the batch.
_afterTokenTransfers(
address(uint160(fromMasked)),
address(uint160(toMasked)),
miniBatchStart,
miniBatchLength
);
// Set the `prevTokenId` for checking that the `tokenIds` is strictly ascending.
prevTokenId = tokenId - 1;
} while (ptr != ptrEnd);
}
}
/**
* @dev Safely transfers `tokenIds` in batch from `from` to `to`.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenIds` tokens must be owned by `from`.
* - If `by` is not `from`, it must be approved to move these tokens
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each transferred token.
*
* `by` is the address that to check token approval for.
* If token approval check is not needed, pass in `address(0)` for `by`.
*
* Emits a {Transfer} event for each transfer.
*/
function _safeBatchTransferFrom(
address by,
address from,
address to,
uint256[] memory tokenIds,
bytes memory _data
) internal virtual {
_batchTransferFrom(by, from, to, tokenIds);
unchecked {
if (to.code.length != 0) {
for ((uint256 ptr, uint256 ptrEnd) = _mdataERC721A(tokenIds); ptr != ptrEnd; ptr += 0x20) {
if (!_checkContractOnERC721Received(from, to, _mloadERC721A(ptr), _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 == uint256(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 == uint256(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 the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint160(to);
if (toMasked == uint256(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 == uint256(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 the lower 160 bits, in case the upper bits somehow aren't clean.
uint256 toMasked = uint160(to);
if (toMasked == uint256(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);
uint256 fromMasked = uint160(prevOwnershipPacked);
address from = address(uint160(fromMasked));
(uint256 approvedAddressSlot, uint256 approvedAddressValue) = _getApprovedSlotAndValue(tokenId);
if (approvalCheck) {
// The nested ifs save around 20+ gas over a compound boolean condition.
if (!_isSenderApprovedOrOwner(approvedAddressValue, fromMasked, uint160(_msgSenderERC721A())))
if (!isApprovedForAll(from, _msgSenderERC721A())) _revert(TransferCallerNotOwnerNorApproved.selector);
}
_beforeTokenTransfers(from, address(0), tokenId, 1);
assembly {
if approvedAddressValue {
sstore(approvedAddressSlot, 0) // Equivalent to `delete _tokenApprovals[tokenId]`.
}
}
// 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 == uint256(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] == uint256(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++;
}
}
/**
* @dev Destroys `tokenIds`.
* Approvals are not cleared when tokenIds are burned.
*
* Requirements:
*
* - `tokenIds` must exist.
* - `tokenIds` must be strictly ascending.
* - `by` must be approved to burn these tokens by either {approve} or {setApprovalForAll}.
*
* `by` is the address that to check token approval for.
* If token approval check is not needed, pass in `address(0)` for `by`.
*
* Emits a {Transfer} event for each token burned.
*/
function _batchBurn(address by, uint256[] memory tokenIds) internal virtual {
// Early return if `tokenIds` is empty.
if (tokenIds.length == uint256(0)) return;
// The next `tokenId` to be minted (i.e. `_nextTokenId()`).
uint256 end = _currentIndex;
// Pointer to start and end (exclusive) of `tokenIds`.
(uint256 ptr, uint256 ptrEnd) = _mdataERC721A(tokenIds);
uint256 prevOwnershipPacked;
address prevTokenOwner;
uint256 prevTokenId;
bool mayBurn;
unchecked {
do {
uint256 tokenId = _mloadERC721A(ptr);
uint256 miniBatchStart = tokenId;
// Revert `tokenId` is out of bounds.
if (_orERC721A(tokenId < _startTokenId(), end <= tokenId))
_revert(OwnerQueryForNonexistentToken.selector);
// Revert if `tokenIds` is not strictly ascending.
if (prevOwnershipPacked != 0)
if (tokenId <= prevTokenId) _revert(TokenIdsNotStrictlyAscending.selector);
// Scan backwards for an initialized packed ownership slot.
// ERC721A's invariant guarantees that there will always be an initialized slot as long as
// the start of the backwards scan falls within `[_startTokenId() .. _nextTokenId())`.
for (uint256 j = tokenId; (prevOwnershipPacked = _packedOwnerships[j]) == uint256(0); ) --j;
// If the initialized slot is burned, revert.
if (prevOwnershipPacked & _BITMASK_BURNED != 0) _revert(OwnerQueryForNonexistentToken.selector);
address tokenOwner = address(uint160(prevOwnershipPacked));
if (tokenOwner != prevTokenOwner) {
prevTokenOwner = tokenOwner;
mayBurn = _orERC721A(by == address(0), tokenOwner == by) || isApprovedForAll(tokenOwner, by);
}
do {
(uint256 approvedAddressSlot, uint256 approvedAddressValue) = _getApprovedSlotAndValue(tokenId);
_beforeTokenTransfers(tokenOwner, address(0), tokenId, 1);
// Revert if the sender is not authorized to transfer the token.
if (!mayBurn)
if (uint160(by) != approvedAddressValue) _revert(TransferCallerNotOwnerNorApproved.selector);
assembly {
if approvedAddressValue {
sstore(approvedAddressSlot, 0) // Equivalent to `delete _tokenApprovals[tokenId]`.
}
// Emit the `Transfer` event.
log4(0, 0, _TRANSFER_EVENT_SIGNATURE, and(_BITMASK_ADDRESS, tokenOwner), 0, tokenId)
}
if (_mloadERC721A(ptr += 0x20) != ++tokenId) break;
if (ptr == ptrEnd) break;
} while (_packedOwnerships[tokenId] == uint256(0));
// Updates tokenId:
// - `address` to the same `tokenOwner`.
// - `startTimestamp` to the timestamp of transferring.
// - `burned` to `true`.
// - `nextInitialized` to `false`, as it is optional.
_packedOwnerships[miniBatchStart] = _packOwnershipData(
tokenOwner,
_BITMASK_BURNED | _nextExtraData(tokenOwner, address(0), prevOwnershipPacked)
);
uint256 miniBatchLength = tokenId - miniBatchStart;
// Update the address data.
_packedAddressData[tokenOwner] += (miniBatchLength << _BITPOS_NUMBER_BURNED) - miniBatchLength;
// Initialize the next slot if needed.
if (tokenId != end)
if (_packedOwnerships[tokenId] == uint256(0)) _packedOwnerships[tokenId] = prevOwnershipPacked;
// Perform the after hook for the batch.
_afterTokenTransfers(tokenOwner, address(0), miniBatchStart, miniBatchLength);
// Set the `prevTokenId` for checking that the `tokenIds` is strictly ascending.
prevTokenId = tokenId - 1;
} while (ptr != ptrEnd);
// Increment the overall burn counter.
_burnCounter += tokenIds.length;
}
}
// =============================================================
// 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 == uint256(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;
}
// =============================================================
// PRIVATE HELPERS
// =============================================================
/**
* @dev Returns a memory pointer to the start of `a`'s data.
*/
function _mdataERC721A(uint256[] memory a) private pure returns (uint256 start, uint256 end) {
assembly {
start := add(a, 0x20)
end := add(start, shl(5, mload(a)))
}
}
/**
* @dev Returns the uint256 at `p` in memory.
*/
function _mloadERC721A(uint256 p) private pure returns (uint256 result) {
assembly {
result := mload(p)
}
}
/**
* @dev Branchless boolean or.
*/
function _orERC721A(bool a, bool b) private pure returns (bool result) {
assembly {
result := or(iszero(iszero(a)), iszero(iszero(b)))
}
}
// =============================================================
// 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.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721A.sol';
/**
* @dev Interface of ERC721ABatchTransferable.
*/
interface IERC721ABatchTransferable is IERC721A {
/**
* @dev Transfers `tokenIds` in batch from `from` to `to`. See {ERC721A-_batchTransferFrom}.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenIds` tokens must be owned by `from`.
* - If the caller is not `from`, it must be approved to move these tokens
* by either {approve} or {setApprovalForAll}.
*
* Emits a {Transfer} event for each transfer.
*/
function batchTransferFrom(
address from,
address to,
uint256[] memory tokenIds
) external payable;
/**
* @dev Equivalent to `safeBatchTransferFrom(from, to, tokenIds, '')`.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory tokenIds
) external payable;
/**
* @dev Safely transfers `tokenIds` in batch from `from` to `to`. See {ERC721A-_safeBatchTransferFrom}.
*
* Requirements:
*
* - `from` cannot be the zero address.
* - `to` cannot be the zero address.
* - `tokenIds` tokens must be owned by `from`.
* - If the caller is not `from`, it must be approved to move these tokens
* by either {approve} or {setApprovalForAll}.
* - If `to` refers to a smart contract, it must implement
* {IERC721Receiver-onERC721Received}, which is called for each transferred token.
*
* Emits a {Transfer} event for each transfer.
*/
function safeBatchTransferFrom(
address from,
address to,
uint256[] memory tokenIds,
bytes memory _data
) external payable;
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721ABurnable.sol';
import '../ERC721A.sol';
/**
* @title ERC721ABurnable.
*
* @dev ERC721A token that can be irreversibly burned (destroyed).
*/
abstract contract ERC721ABurnable is ERC721A, IERC721ABurnable {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) public virtual override {
_burn(tokenId, true);
}
}// SPDX-License-Identifier: MIT
// ERC721A Contracts v4.2.3
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import './IERC721ABurnable.sol';
/**
* @dev Interface of ERC721ABatchBurnable.
*/
interface IERC721ABatchBurnable is IERC721ABurnable {
function batchBurn(uint256[] memory tokenIds) external;
}// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;
/// @notice Simple single owner authorization mixin.
/// @author Solady (https://github.com/vectorized/solady/blob/main/src/auth/Ownable.sol)
///
/// @dev Note:
/// This implementation does NOT auto-initialize the owner to `msg.sender`.
/// You MUST call the `_initializeOwner` in the constructor / initializer.
///
/// While the ownable portion follows
/// [EIP-173](https://eips.ethereum.org/EIPS/eip-173) for compatibility,
/// the nomenclature for the 2-step ownership handover may be unique to this codebase.
abstract contract Ownable {
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* CUSTOM ERRORS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The caller is not authorized to call the function.
error Unauthorized();
/// @dev The `newOwner` cannot be the zero address.
error NewOwnerIsZeroAddress();
/// @dev The `pendingOwner` does not have a valid handover request.
error NoHandoverRequest();
/// @dev Cannot double-initialize.
error AlreadyInitialized();
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* EVENTS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The ownership is transferred from `oldOwner` to `newOwner`.
/// This event is intentionally kept the same as OpenZeppelin's Ownable to be
/// compatible with indexers and [EIP-173](https://eips.ethereum.org/EIPS/eip-173),
/// despite it not being as lightweight as a single argument event.
event OwnershipTransferred(address indexed oldOwner, address indexed newOwner);
/// @dev An ownership handover to `pendingOwner` has been requested.
event OwnershipHandoverRequested(address indexed pendingOwner);
/// @dev The ownership handover to `pendingOwner` has been canceled.
event OwnershipHandoverCanceled(address indexed pendingOwner);
/// @dev `keccak256(bytes("OwnershipTransferred(address,address)"))`.
uint256 private constant _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE =
0x8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0;
/// @dev `keccak256(bytes("OwnershipHandoverRequested(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE =
0xdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d;
/// @dev `keccak256(bytes("OwnershipHandoverCanceled(address)"))`.
uint256 private constant _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE =
0xfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* STORAGE */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev The owner slot is given by:
/// `bytes32(~uint256(uint32(bytes4(keccak256("_OWNER_SLOT_NOT")))))`.
/// It is intentionally chosen to be a high value
/// to avoid collision with lower slots.
/// The choice of manual storage layout is to enable compatibility
/// with both regular and upgradeable contracts.
bytes32 internal constant _OWNER_SLOT =
0xffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927;
/// The ownership handover slot of `newOwner` is given by:
/// ```
/// mstore(0x00, or(shl(96, user), _HANDOVER_SLOT_SEED))
/// let handoverSlot := keccak256(0x00, 0x20)
/// ```
/// It stores the expiry timestamp of the two-step ownership handover.
uint256 private constant _HANDOVER_SLOT_SEED = 0x389a75e1;
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* INTERNAL FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Override to return true to make `_initializeOwner` prevent double-initialization.
function _guardInitializeOwner() internal pure virtual returns (bool guard) {}
/// @dev Initializes the owner directly without authorization guard.
/// This function must be called upon initialization,
/// regardless of whether the contract is upgradeable or not.
/// This is to enable generalization to both regular and upgradeable contracts,
/// and to save gas in case the initial owner is not the caller.
/// For performance reasons, this function will not check if there
/// is an existing owner.
function _initializeOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
if sload(ownerSlot) {
mstore(0x00, 0x0dc149f0) // `AlreadyInitialized()`.
revert(0x1c, 0x04)
}
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
} else {
/// @solidity memory-safe-assembly
assembly {
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Store the new value.
sstore(_OWNER_SLOT, newOwner)
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, 0, newOwner)
}
}
}
/// @dev Sets the owner directly without authorization guard.
function _setOwner(address newOwner) internal virtual {
if (_guardInitializeOwner()) {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, or(newOwner, shl(255, iszero(newOwner))))
}
} else {
/// @solidity memory-safe-assembly
assembly {
let ownerSlot := _OWNER_SLOT
// Clean the upper 96 bits.
newOwner := shr(96, shl(96, newOwner))
// Emit the {OwnershipTransferred} event.
log3(0, 0, _OWNERSHIP_TRANSFERRED_EVENT_SIGNATURE, sload(ownerSlot), newOwner)
// Store the new value.
sstore(ownerSlot, newOwner)
}
}
}
/// @dev Throws if the sender is not the owner.
function _checkOwner() internal view virtual {
/// @solidity memory-safe-assembly
assembly {
// If the caller is not the stored owner, revert.
if iszero(eq(caller(), sload(_OWNER_SLOT))) {
mstore(0x00, 0x82b42900) // `Unauthorized()`.
revert(0x1c, 0x04)
}
}
}
/// @dev Returns how long a two-step ownership handover is valid for in seconds.
/// Override to return a different value if needed.
/// Made internal to conserve bytecode. Wrap it in a public function if needed.
function _ownershipHandoverValidFor() internal view virtual returns (uint64) {
return 48 * 3600;
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC UPDATE FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Allows the owner to transfer the ownership to `newOwner`.
function transferOwnership(address newOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
if iszero(shl(96, newOwner)) {
mstore(0x00, 0x7448fbae) // `NewOwnerIsZeroAddress()`.
revert(0x1c, 0x04)
}
}
_setOwner(newOwner);
}
/// @dev Allows the owner to renounce their ownership.
function renounceOwnership() public payable virtual onlyOwner {
_setOwner(address(0));
}
/// @dev Request a two-step ownership handover to the caller.
/// The request will automatically expire in 48 hours (172800 seconds) by default.
function requestOwnershipHandover() public payable virtual {
unchecked {
uint256 expires = block.timestamp + _ownershipHandoverValidFor();
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to `expires`.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), expires)
// Emit the {OwnershipHandoverRequested} event.
log2(0, 0, _OWNERSHIP_HANDOVER_REQUESTED_EVENT_SIGNATURE, caller())
}
}
}
/// @dev Cancels the two-step ownership handover to the caller, if any.
function cancelOwnershipHandover() public payable virtual {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, caller())
sstore(keccak256(0x0c, 0x20), 0)
// Emit the {OwnershipHandoverCanceled} event.
log2(0, 0, _OWNERSHIP_HANDOVER_CANCELED_EVENT_SIGNATURE, caller())
}
}
/// @dev Allows the owner to complete the two-step ownership handover to `pendingOwner`.
/// Reverts if there is no existing ownership handover requested by `pendingOwner`.
function completeOwnershipHandover(address pendingOwner) public payable virtual onlyOwner {
/// @solidity memory-safe-assembly
assembly {
// Compute and set the handover slot to 0.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
let handoverSlot := keccak256(0x0c, 0x20)
// If the handover does not exist, or has expired.
if gt(timestamp(), sload(handoverSlot)) {
mstore(0x00, 0x6f5e8818) // `NoHandoverRequest()`.
revert(0x1c, 0x04)
}
// Set the handover slot to 0.
sstore(handoverSlot, 0)
}
_setOwner(pendingOwner);
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* PUBLIC READ FUNCTIONS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Returns the owner of the contract.
function owner() public view virtual returns (address result) {
/// @solidity memory-safe-assembly
assembly {
result := sload(_OWNER_SLOT)
}
}
/// @dev Returns the expiry timestamp for the two-step ownership handover to `pendingOwner`.
function ownershipHandoverExpiresAt(address pendingOwner)
public
view
virtual
returns (uint256 result)
{
/// @solidity memory-safe-assembly
assembly {
// Compute the handover slot.
mstore(0x0c, _HANDOVER_SLOT_SEED)
mstore(0x00, pendingOwner)
// Load the handover slot.
result := sload(keccak256(0x0c, 0x20))
}
}
/*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/
/* MODIFIERS */
/*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/
/// @dev Marks a function as only callable by the owner.
modifier onlyOwner() virtual {
_checkOwner();
_;
}
}// SPDX-License-Identifier: MIT
// 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();
/**
* The `tokenIds` must be strictly ascending.
*/
error TokenIdsNotStrictlyAscending();
/**
* `_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
// ERC721A Contracts v4.3.0
// Creator: Chiru Labs
pragma solidity ^0.8.4;
import '../IERC721A.sol';
/**
* @dev Interface of ERC721ABurnable.
*/
interface IERC721ABurnable is IERC721A {
/**
* @dev Burns `tokenId`. See {ERC721A-_burn}.
*
* Requirements:
*
* - The caller must own `tokenId` or be an approved operator.
*/
function burn(uint256 tokenId) external;
}{
"viaIR": false,
"codegen": "yul",
"remappings": [
"@limitbreak/permit-c/=lib/creator-token-standards/lib/PermitC/src/",
"@opensea/tstorish/=lib/creator-token-standards/lib/tstorish/src/",
"@openzeppelin/=lib/creator-token-standards/lib/openzeppelin-contracts/",
"@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/",
"delegate-registry/=lib/delegate-registry/",
"ds-test/=lib/creator-token-standards/lib/forge-std/lib/ds-test/src/",
"erc4626-tests/=lib/delegate-registry/lib/openzeppelin-contracts/lib/erc4626-tests/",
"erc721a/=lib/creator-token-standards/lib/ERC721A/",
"forge-gas-metering/=lib/creator-token-standards/lib/PermitC/lib/forge-gas-metering/",
"forge-std/=lib/forge-std/src/",
"forge-zksync-std/=lib/forge-zksync-std/src/",
"murky/=lib/creator-token-standards/lib/murky/",
"openzeppelin-contracts/=lib/creator-token-standards/lib/openzeppelin-contracts/",
"openzeppelin/=lib/delegate-registry/lib/openzeppelin-contracts/contracts/",
"solady/=lib/solady/src/",
"solmate/=lib/creator-token-standards/lib/PermitC/lib/solmate/src/",
"tstorish/=lib/creator-token-standards/lib/tstorish/src/"
],
"evmVersion": "cancun",
"outputSelection": {
"*": {
"*": [
"abi"
]
}
},
"optimizer": {
"enabled": true,
"mode": "3",
"size_fallback": false,
"disable_system_request_memoization": true
},
"metadata": {},
"libraries": {},
"enableEraVMExtensions": false,
"forceEVMLA": false
}Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"InvalidValidator","type":"error"},{"inputs":[],"name":"MintERC2309QuantityExceedsLimit","type":"error"},{"inputs":[],"name":"MintToZeroAddress","type":"error"},{"inputs":[],"name":"MintZeroQuantity","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenIdsNotStrictlyAscending","type":"error"},{"inputs":[],"name":"TransferCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"URIQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"inputs":[],"name":"ValidatorCalledFailed","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":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":"pendingOwner","type":"address"}],"name":"OwnershipHandoverCanceled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"pendingOwner","type":"address"}],"name":"OwnershipHandoverRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"oldOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"uint256","name":"roles","type":"uint256"}],"name":"RolesUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Transfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldValidator","type":"address"},{"indexed":false,"internalType":"address","name":"newValidator","type":"address"}],"name":"TransferValidatorUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"qty","type":"uint256"}],"name":"WeaponGenerated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"id","type":"uint256"},{"indexed":false,"internalType":"uint32","name":"metadata","type":"uint32"}],"name":"WeaponMetadataGenerated","type":"event"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchBurn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"batchTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"explicitOwnershipOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership","name":"ownership","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"explicitOwnershipsOf","outputs":[{"components":[{"internalType":"address","name":"addr","type":"address"},{"internalType":"uint64","name":"startTimestamp","type":"uint64"},{"internalType":"bool","name":"burned","type":"bool"},{"internalType":"uint24","name":"extraData","type":"uint24"}],"internalType":"struct IERC721A.TokenOwnership[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getMetadata","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"grantRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAllRoles","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"hasAnyRole","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"weaponRarity","type":"uint256"},{"internalType":"uint256","name":"weaponType","type":"uint256"},{"internalType":"uint256","name":"mSharpness","type":"uint256"},{"internalType":"uint256","name":"mDurability","type":"uint256"}],"name":"manualMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"qty","type":"uint256"}],"name":"mint","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"ownershipHandoverExpiresAt","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"renounceRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"},{"internalType":"uint256","name":"roles","type":"uint256"}],"name":"revokeRoles","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"user","type":"address"}],"name":"rolesOf","outputs":[{"internalType":"uint256","name":"roles","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"salePrice","type":"uint256"}],"name":"royaltyInfo","outputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint256","name":"royaltyAmount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"},{"internalType":"bytes","name":"_data","type":"bytes"}],"name":"safeBatchTransferFrom","outputs":[],"stateMutability":"payable","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":"baseURI_","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setDefaultRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint32","name":"metadata","type":"uint32"}],"name":"setMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_validator","type":"address"}],"name":"setValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"tokensOfOwner","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint256","name":"start","type":"uint256"},{"internalType":"uint256","name":"stop","type":"uint256"}],"name":"tokensOfOwnerIn","outputs":[{"internalType":"uint256[]","name":"","type":"uint256[]"}],"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":"payable","type":"function"}]Contract Creation Code
9c4d535b0000000000000000000000000000000000000000000000000000000000000000010006d575e74e90c15a74aebfa1ac1d6dbfa5b04e674baa3589df06e5da884d000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000200000000000000000000000001b2c84dd7957b1e207cd7b01ded77984ec16fdef
Deployed Bytecode
0x0003000000000002000b00000000000200000060031002700000062703300197000200000031035500010000000103550000008004000039000000400040043f0000000100200190000000810000c13d000000040030008c000000a30000413d000000000201043b000000e002200270000006400020009c000000a50000a13d000006410020009c000000b60000213d000006510020009c000001110000213d000006590020009c000001ac0000213d0000065d0020009c000003070000613d0000065e0020009c000003170000613d0000065f0020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000502043b0000062f0050009c000000a30000213d0000002302500039000000000032004b000000a30000813d0000000406500039000000000261034f000000000202043b0000062f0020009c000000f80000213d0000001f07200039000006c5077001970000003f07700039000006c5077001970000063c0070009c000000f80000213d00000024055000390000008007700039000000400070043f000000800020043f0000000005520019000000000035004b000000a30000213d0000002003600039000000000331034f000006c5052001980000001f0620018f000000a001500039000000460000613d000000a007000039000000000803034f000000008908043c0000000007970436000000000017004b000000420000c13d000000000006004b000000530000613d000000000353034f0000000305600210000000000601043300000000065601cf000000000656022f000000000303043b0000010005500089000000000353022f00000000035301cf000000000363019f0000000000310435000000a00120003900000000000104350000063401000041000000000101041a0000000002000411000000000012004b000008510000c13d000000800200043d0000062f0020009c000000f80000213d0000000901000039000000000501041a000000010050019000000001035002700000007f0330618f0000001f0030008c00000000060000390000000106002039000000000565013f00000001005001900000099e0000c13d000000200030008c000000790000413d000000000010043f0000001f052000390000000505500270000006a20550009a000000200020008c0000068e050040410000001f033000390000000503300270000006a20330009a000000000035004b000000790000813d000000000005041b0000000105500039000000000035004b000000750000413d0000001f0020008c00000d360000a13d000000000010043f000006c50420019800000e330000c13d000000a0050000390000068e0300004100000e410000013d0000000002000416000000000002004b000000a30000c13d0000001f0230003900000628022001970000008002200039000000400020043f0000001f0530018f00000629063001980000008002600039000000910000613d000000000701034f000000007807043c0000000004840436000000000024004b0000008d0000c13d000000000005004b0000009e0000613d000000000161034f0000000304500210000000000502043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f0000000000120435000000200030008c000000a30000413d000000800900043d0000062a0090009c000000e30000a13d00000000010000190000189900010430000006600020009c000000fe0000a13d000006610020009c0000011e0000213d000006690020009c000001bd0000213d0000066d0020009c0000032f0000613d0000066e0020009c000003580000613d0000066f0020009c000000a30000c13d000000000103001918970eec0000040f18970f6a0000040f0000000001000019000018980001042e000006420020009c0000014a0000213d0000064a0020009c000002000000213d0000064e0020009c0000036b0000613d0000064f0020009c0000038e0000613d000006500020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000201043b000000000002004b00000a450000613d000000000100041a000000000021004b00000a450000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000a060000c13d0000000b02000029000000000002004b000000010220008a000000cd0000c13d000002280000013d000000400200043d0000062b0020009c000000f80000813d0000004001200039000000400010043f000000100100003900000000041204360000062c010000410000000000140435000000400b00043d0000062d00b0009c000000f80000213d0000004001b00039000000400010043f0000000303000039000000000c3b04360000062e0100004100000000001c0435000000000a0204330000062f00a0009c000002e40000a13d000006b301000041000000000010043f0000004101000039000000040010043f000006b4010000410000189900010430000006700020009c000001810000a13d000006710020009c0000022e0000213d000006750020009c000003d10000613d000006760020009c0000042a0000613d000006770020009c000000a30000c13d0000000001000416000000000001004b000000a30000c13d000006b501000041000000800010043f0000000101000039000000a00010043f000006b601000041000018980001042e000006520020009c0000023c0000213d000006560020009c000004330000613d000006570020009c000004480000613d000006580020009c000000a30000c13d0000000001000416000000000001004b000000a30000c13d00000634010000410000042e0000013d000006620020009c0000029f0000213d000006660020009c0000045c0000613d000006670020009c000004a60000613d000006680020009c000000a30000c13d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b000a00000002001d0000062a0020009c000000a30000213d0000002401100370000000000101043b000800000001001d000006a8010000410000000c0010043f0000000001000411000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a0000000100100190000008510000613d000000080000006b00000a5d0000c13d000006ab01000041000000000010043f00000689010000410000189900010430000006430020009c000002b50000213d000006470020009c000004b10000613d000006480020009c000005ec0000613d000006490020009c000000a30000c13d000000240030008c000000a30000413d0000000401100370000000000101043b000b00000001001d0000062a0010009c000000a30000213d0000063401000041000000000101041a0000000002000411000000000012004b000008510000c13d0000067e010000410000000c0010043f0000000b01000029000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000900000001001d000000000101041a000a00000001001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b0000000a0010006c00000b820000a13d0000068501000041000000000010043f00000681010000410000189900010430000006780020009c000002ce0000a13d000006790020009c000005ff0000613d0000067a0020009c000006180000613d0000067b0020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000201043b000000000002004b00000a220000613d000000000100041a000000000021004b00000a220000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000a170000c13d0000000b02000029000000000002004b000000010220008a000001960000c13d000002280000013d0000065a0020009c000006370000613d0000065b0020009c000006750000613d0000065c0020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b0000062a0010009c000000a30000213d189710ec0000040f0000067e0000013d0000066a0020009c000006850000613d0000066b0020009c000006b10000613d0000066c0020009c000000a30000c13d000000840030008c000000a30000413d0000000402100370000000000202043b000b00000002001d0000062a0020009c000000a30000213d0000002402100370000000000202043b000a00000002001d0000062a0020009c000000a30000213d0000004402100370000000000202043b0000062f0020009c000000a30000213d0000002304200039000000000034004b000000a30000813d0000000404200039000000000441034f000000000504043b0000062f0050009c000000f80000213d00000005045002100000003f0640003900000687066001970000063c0060009c000000f80000213d0000008006600039000000400060043f000000800050043f00000024022000390000000004240019000000000034004b000000a30000213d000000000005004b000001f10000613d0000008005000039000000000621034f000000000606043b000000200550003900000000006504350000002002200039000000000042004b000001ea0000413d0000006401100370000000000101043b0000062f0010009c000000a30000213d0000000401100039000000000203001918970efe0000040f0000000005010019000000000100041100000080040000390000000b020000290000000a03000029189713db0000040f0000000001000019000018980001042e0000064b0020009c000006fa0000613d0000064c0020009c000007120000613d0000064d0020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000201043b000000000002004b00000a450000613d000000000100041a000000000021004b00000a450000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000a260000c13d0000000b02000029000000000002004b000000010220008a000002130000c13d000006b301000041000000000010043f0000001101000039000000040010043f000006b4010000410000189900010430000006720020009c000007230000613d000006730020009c000007950000613d000006740020009c000000a30000c13d000000240030008c000000a30000413d0000000401100370000000000201043b0000000001000411189718530000040f0000000001000019000018980001042e000006530020009c000007a00000613d000006540020009c000007bf0000613d000006550020009c000000a30000c13d000000640030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b000700000002001d0000062a0020009c000000a30000213d0000004402100370000000000202043b0000002401100370000000000301043b000000000023004b000009740000813d000000000100041a000000000012004b0000000002018019000600000002001d000000010030008c000000010300a0390000000701000029000000000001004b000009e50000613d000a00000003001d000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000400600000003d000000000101043b0000000a03000029000000060230006b00000e530000a13d000000000101041a0000062f0110019800000e530000613d000000000012004b0000000002018019000500000002001d0000000501200210000000400200043d000400000002001d00000000012100190000002001100039000000400010043f000900000001001d0000063c0010009c000000f80000213d00000009020000290000008001200039000000400010043f0000006001200039000000000001043500000040012000390000000000010435000000200120003900000000000104350000000000020435000000000100041a000000000031004b000000000100001900000c280000a13d0000000a01000029000b00000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000d400000c13d0000000b01000029000000010110008a0000028b0000013d000006630020009c000008220000613d000006640020009c000008330000613d000006650020009c000000a30000c13d000000440030008c000000a30000413d0000000402100370000000000202043b000b00000002001d0000062a0020009c000000a30000213d0000002401100370000000000101043b000a00000001001d1897165f0000040f0000000b010000290000000a02000029189718530000040f0000000001000019000018980001042e000006440020009c000008400000613d000006450020009c000008550000613d000006460020009c000000a30000c13d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b0000062a0010009c000000a30000213d0000067e020000410000000c0020043f000000000010043f0000000c010000390000002002000039189718780000040f000000000101041a000000800010043f0000067f01000041000018980001042e0000067c0020009c000008610000613d0000067d0020009c000000a30000c13d000000000103001918970e780000040f000b00000001001d000a00000002001d000900000003001d000000400100043d000800000001001d000000200200003918970e660000040f0000000805000029000000000005043500000000010004110000000b020000290000000a030000290000000904000029189713db0000040f0000000001000019000018980001042e0000000201000039000000000501041a000000010650019000000001055002700000007f0550618f0000001f0050008c00000000070000390000000107002039000000000076004b0000099e0000c13d000000200050008c000002ff0000413d000000000010043f0000001f06a000390000000506600270000006300660009a0000002000a0008c00000631060040410000001f055000390000000505500270000006300550009a000000000056004b000002ff0000813d000000000006041b0000000106600039000000000056004b000002fb0000413d0000001f00a0008c000008740000a13d000000000010043f000006c506a00198000009780000c13d00000020050000390000063104000041000009840000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b0000062a0020009c000000a30000213d0000002401100370000000000101043b000b00000001001d0000000001020019189710db0000040f0000000b00100180000005fc0000013d0000067e010000410000000c0010043f0000000001000411000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000001041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d020000390000000203000039000006a404000041000006ab0000013d000000440030008c000000a30000413d0000000402100370000000000202043b0000062a0020009c000000a30000213d0000002401100370000000000401043b0000063401000041000000000101041a0000000003000411000000000013004b000008510000c13d000b00000004001d000006a8010000410000000c0010043f000000000020043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a0000000b062001af000000000061041b0000000c0100043d00000000020004140000006005100270000006270020009c0000062702008041000000c00120021000000635011001c70000800d020000390000000303000039000006b004000041000006ac0000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b0000062a0020009c000000a30000213d0000002401100370000000000101043b000b00000001001d0000000001020019189710db0000040f0000000b0110017f0000000b0010006c000000000100003900000001010060390000067e0000013d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b000000a30000c13d0000063402000041000000000202041a0000000003000411000000000023004b000008510000c13d0000000a02000039000000000302041a0000069503300197000000000001004b0000000004000019000006960400c041000000000343019f000000000032041b000000800010043f0000000001000414000006270010009c0000062701008041000000c00110021000000697011001c70000800d0200003900000001030000390000069804000041000006f90000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b000b00000002001d0000062a0020009c000000a30000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b000000a30000c13d0000000001000411000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b0000000b02000029000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a000006c6022001970000000a03000029000000000232019f000000000021041b000000400100043d0000000000310435000006270010009c000006270100804100000040011002100000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000633011001c70000800d020000390000000303000039000006940400004100000000050004110000000b06000029000006ac0000013d000000440030008c000000a30000413d0000000402100370000000000202043b000a00000002001d0000062a0020009c000000a30000213d0000002401100370000000000101043b000000000001004b0000083c0000613d000900000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b000004050000c13d000000000100041a0000000902000029000000000021004b0000083c0000a13d000b00000002001d0000000b01000029000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b000003f20000613d0000068a001001980000083c0000c13d000b062a0010019b00000000020004110000000b0020006c00000bbd0000c13d0000000901000029000000000010043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000a020000290000062a06200197000000000101043b000000000201041a0000063a02200197000000000262019f000000000021041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d020000390000000403000039000006b8040000410000000b050000290000000907000029000006ac0000013d0000000001000416000000000001004b000000a30000c13d0000000a01000039000000000101041a0000062a01100197000000800010043f0000067f01000041000018980001042e0000063401000041000000000101041a0000000005000411000000000015004b000008510000c13d0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d020000390000000303000039000006360400004100000000060000191897188d0000040f0000000100200190000000a30000613d0000063401000041000000000001041b0000000001000019000018980001042e000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b000600000001001d0000062a0010009c000000a30000213d000000000100041a000000000001004b000009740000613d0005000100100094000009e10000c13d00000080010000390000006002000039000b00000001001d18970f5b0000040f0000088b0000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000002402100370000000000202043b000b00000002001d0000000401100370000000000101043b000000000010043f0000063e01000041000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a000006ac0020009c000004780000213d0000063e01000041000000000201041a000006ac012001980000000003000019000000010300c08a000000000313c0d90000000b0030006b0000000003000019000000000301201900000000040000310000000005430019000000000045004b000000a30000213d000006c5053001980000001f0630018f000000020740036700000000035400190000048d0000613d000000000807034f000000008908043c0000000004940436000000000034004b000004890000c13d0000006002200270000000000006004b0000049b0000613d000000000457034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f00000000004304350000000b011000b9000027100110011a000000400300043d000000200430003900000000001404350000000000230435000006270030009c00000627030080410000004001300210000006ad011001c7000018980001042e000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b0000062a0010009c000000a30000213d189710db0000040f0000067e0000013d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b0000062f0020009c000000a30000213d0000002304200039000000000034004b000000a30000813d0000000404200039000000000441034f000000000504043b0000062f0050009c000000f80000213d00000005045002100000003f0640003900000687066001970000063c0060009c000000f80000213d0000008006600039000000400060043f000000800050043f00000024022000390000000004240019000000000034004b000000a30000213d000000000005004b000006af0000613d0000008003000039000000000521034f000000000505043b000000200330003900000000005304350000002002200039000000000042004b000004d10000413d000000800100043d000000000001004b000006af0000613d0000000002000411000000a004000039000000000500041a000300000005001d0006062a0020019b0000000501100210000700a00010003d00000001020000390000000001000019000400000000001d000800000000001d000004ec0000013d000000010140008a0000000a04000029000000070040006c000000000200001900000e5b0000613d000a00000004001d0000000003040433000500000003001d000000000003004b0000083c0000613d0000000504000029000000030040006b0000083c0000a13d0000000504000029000000000014004b0000000001000039000000010100a039000006c702200167000000000112016f000000010010019000000e620000c13d000b00000004001d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b04000029000000010440008a000000000101043b000000000101041a000000000001004b000004fc0000613d0000068a001001980000083c0000c13d000100000001001d0000062a0310019700000004020000290000062a01200197000000000013004b000900000003001d0000054c0000613d000000060000006b000800010000003d00000000020300190000054c0000613d000000060030006c000800010000003d00000000020300190000054c0000613d000000000030043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b0000000602000029000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000800ff00100194000000090300002900000000020300190000054c0000c13d0000000a01000039000000000101041a0000068b001001980000054a0000613d0000000002000411000000000121013f0000062a0010019800000000010000390000000101006039000800000001001d0000054b0000013d000800000000001d0000000002030019000400000002001d000000050400002900000000010000190000000100100190000b00000004001d000005630000613d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b0000000b04000029000005920000c13d000000000040043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b07000029000000000101043b000000000201041a000000080000006b000005760000c13d000000060020006b00000d320000c13d000000000002004b00000009050000290000057a0000613d000000000001041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c0400004100000000060000191897188d0000040f0000000100200190000000a30000613d0000000b0100002900000001031000390000000a010000290000002001100039000000070010006c000a00000001001d000005930000613d0000000004010433000000000034004b00000001010000390000054f0000613d000005930000013d0000000003040019000b00000003001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b000200000001001d0000000501000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000202000029000000a0022002100000000903000029000000000232019f0000068a022001c7000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b04000029000000050240006a0000068d022000d1000000000101043b000000000301041a0000000002230019000000000021041b000000030040006c000004e70000613d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b0000000b04000029000004e70000c13d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b0000000102000029000000000021041b0000000b04000029000004e70000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000302043b0000062a0030009c000000a30000213d0000002401100370000000000201043b0000062a0020009c000000a30000213d0000000001030019189713ab0000040f000000000001004b0000000001000039000000010100c0390000067e0000013d000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b0000062a0020009c000000a30000213d0000002401100370000000000101043b000006ac0010009c000000a30000213d0000063403000041000000000303041a0000000004000411000000000034004b000008510000c13d000006ac01100197000027110010008c00000a9d0000413d000006bd01000041000000000010043f000006810100004100001899000104300000000001000416000000000001004b000000a30000c13d0000000203000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000552013f00000001005001900000099e0000c13d000000800010043f000000000004004b0000087f0000613d000000000030043f000000000001004b0000000002000019000008840000613d00000631030000410000000002000019000000000403041a000000a005200039000000000045043500000001033000390000002002200039000000000012004b0000062f0000413d000008840000013d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b0000062f0020009c000000a30000213d0000002304200039000000000034004b000000a30000813d000a00040020003d0000000a04100360000000000404043b0000062f0040009c000000a30000213d000000050540021000000000025200190000002402200039000000000032004b000000a30000213d0000000006050019000000800040043f000000a002500039000000400020043f000000000004004b00000aa30000c13d00000020010000390000000001120436000000800300043d00000000003104350000004001200039000000000003004b0000088c0000613d000000800400003900000000050000190000002004400039000000000604043300000000870604340000062a07700197000000000771043600000000080804330000062f08800197000000000087043500000040076000390000000007070433000000000007004b0000000007000039000000010700c0390000004008100039000000000078043500000060066000390000000006060433000006a1066001970000006007100039000000000067043500000080011000390000000105500039000000000035004b0000065c0000413d0000088c0000013d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b189716690000040f0000062a01100197000000400200043d0000000000120435000006270020009c0000062702008041000000400120021000000686011001c7000018980001042e0000067e010000410000000c0010043f0000000001000411000000000010043f000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b000b00000001001d0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b0000000b02000029000006ae0220009a000000000021041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d020000390000000203000039000006af0400004100000000050004111897188d0000040f0000000100200190000000a30000613d0000000001000019000018980001042e000000440030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b000b00000002001d0000002401100370000000000101043b000a00000001001d000006270010009c000000a30000213d000006a8010000410000000c0010043f0000000001000411000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a0000000100100190000008510000613d0000000b01000039000000200010043f0000000b010000290000000301100270000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b050000290000000502500210000000e00220018f000000000101043b000000000301041a000000000423022f0000000a06000029000000000464013f000006270440019700000000022401cf000000000232013f000000000021041b000000400100043d000000200210003900000000006204350000000000510435000006270010009c000006270100804100000040011002100000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000638011001c70000800d0200003900000001030000390000069c04000041000006ac0000013d000000840030008c000000a30000413d0000000402100370000000000202043b000b00000002001d0000062a0020009c000000a30000213d0000002402100370000000000202043b000a00000002001d0000062a0020009c000000a30000213d0000006402100370000000000202043b0000062f0020009c000000a30000213d0000004401100370000000000101043b000900000001001d0000000401200039000000000203001918970efe0000040f00000000040100190000082d0000013d000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b1897134d0000040f000000400200043d000b00000002001d18970f480000040f0000000b01000029000006270010009c0000062701008041000000400110021000000692011001c7000018980001042e000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b000b00000001001d0000062a0010009c000000a30000213d0000063401000041000000000101041a0000000002000411000000000012004b000008510000c13d0000000a01000039000000000101041a0000062a01100197000000800010043f0000000b01000029000000a00010043f0000000001000414000006270010009c0000062701008041000000c001100210000006b1011001c70000800d02000039000000010300003900000639040000411897188d0000040f0000000100200190000000a30000613d0000000a03000039000000000103041a0000063a011001970000000b02000029000000000121019f000000000013041b000000400100043d0000004404100039000002d103000039000000000034043500000020051000390000063b03000041000000000035043500000000030004100000062a0330019700000024041000390000000000340435000000440300003900000000003104350000063c0010009c000000f80000213d0000008003100039000000400030043f000006270050009c000006270500804100000040035002100000000001010433000006270010009c00000627010080410000006001100210000000000131019f0000000003000414000006270030009c0000062703008041000000c003300210000000000131019f1897188d0000040f00020000000103550000006003100270000006270030019d0000062703300198000007920000613d0000001f0430003900000628044001970000003f044000390000063d04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000062f0040009c000000f80000213d0000000100600190000000f80000c13d000000400040043f0000001f0430018f000000000635043600000629053001980000000003560019000007850000613d000000000701034f000000007807043c0000000006860436000000000036004b000007810000c13d000000000004004b000007920000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000100200190000006af0000c13d00000b7e0000013d0000000001000416000000000001004b000000a30000c13d0000000101000039000000000101041a000006c701100167000000000200041a0000000001120019000000800010043f0000067f01000041000018980001042e0000000001000416000000000001004b000000a30000c13d0000000303000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000552013f00000001005001900000099e0000c13d000000800010043f000000000004004b0000087f0000613d000000000030043f000000000001004b0000000002000019000008840000613d0000069d030000410000000002000019000000000403041a000000a005200039000000000045043500000001033000390000002002200039000000000012004b000007b70000413d000008840000013d000000a40030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000402100370000000000202043b000b00000002001d0000062a0020009c000000a30000213d0000008402100370000000000302043b0000006402100370000000000402043b0000004402100370000000000502043b0000002401100370000000000601043b0000063401000041000000000101041a0000000002000411000000000012004b000008510000c13d000600000006001d000700000005001d000800000004001d000900000003001d000000000100041a000a00000001001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b000500000001001d0000000a01000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000502000029000000a0022002100000000b03000029000000000223019f00000699022001c7000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a0000069a0220009a000000000021041b0000000b0000006b00000a980000613d0000000001000019000000010010019000000c750000c13d0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c0400004100000000050000190000000b060000290000000a070000291897188d0000040f00000001002001900000000101000039000008100000c13d000000a30000013d000000000103001918970eec0000040f000b00000001001d000a00000002001d000900000003001d000000400100043d000800000001001d000000200200003918970e660000040f000000080400002900000000000404350000000b010000290000000a020000290000000903000029189711040000040f0000000001000019000018980001042e000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000101043b000000000001004b000008950000c13d000006b901000041000000000010043f00000689010000410000189900010430000000240030008c000000a30000413d0000000401100370000000000101043b0000062a0010009c000000a30000213d0000063402000041000000000202041a0000000003000411000000000023004b000008510000c13d000000000001004b00000b850000c13d0000068001000041000000000010043f00000681010000410000189900010430000006bb01000041000000000010043f00000681010000410000189900010430000000000103001918970e780000040f0000000004010019000000000502001900000000060300190000000001000411000000000204001900000000030500190000000004060019189716b30000040f0000000001000019000018980001042e000000240030008c000000a30000413d0000000002000416000000000002004b000000a30000c13d0000000401100370000000000201043b000006be00200198000000a30000c13d000006bf03200197000006c00030009c0000086f0000613d000006c10030009c000009e90000c13d0000000102000039000000010120018f000000800010043f0000067f01000041000018980001042e00000000000a004b0000000002000019000008780000613d00000000020404330000000304a00210000006c70440027f000006c704400167000000000242016f0000000104a00210000000000242019f000009900000013d000006c602200197000000a00020043f000000000001004b000000200200003900000000020060390000002002200039000000800100003918970e660000040f000000400100043d000b00000001001d000000800200003918970eb70000040f0000000b020000290000000001210049000006270010009c00000627010080410000006001100210000006270020009c00000627020080410000004002200210000000000121019f000018980001042e000a00000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a000000000002004b000008be0000c13d000000000100041a0000000a02000029000000000021004b0000083c0000a13d0000000001020019000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a000000000002004b0000000b01000029000008ab0000613d0000068a002001980000000a010000290000083c0000c13d000b00000002001d000000000010043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b020000290000062a02200197000000000101043b000800000001001d000000000301041a0000000001000411000900000002001d000000000021004b000009020000613d000000000031004b000009020000613d000700000003001d0000000901000029000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b00000000020004110000062a02200197000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000ff0010019000000007030000290000000002000411000009020000c13d0000000a01000039000000000101041a0000068b0010019800000d320000613d000000000121013f0000062a0010019800000d320000c13d000000000003004b000009060000613d0000000801000029000000000001041b0000000901000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000201041a000006a60220009a000000000021041b000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b000800000001001d0000000a01000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000802000029000000a00220021000000009022001af000006a7022001c7000000000101043b000000000021041b0000000b010000290000069900100198000009600000c13d0000000a010000290000000101100039000800000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b000009600000c13d000000000100041a000000080010006b000009600000613d0000000801000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b0000000b02000029000000000021041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c04000041000000090500002900000000060000190000000a070000291897188d0000040f0000000100200190000000a30000613d0000000101000039000000000201041a0000000102200039000000000021041b0000000001000019000018980001042e0000069e01000041000000000010043f0000068901000041000018990001043000000631040000410000002005000039000000010760008a0000000507700270000006320770009a00000000082500190000000008080433000000000084041b00000020055000390000000104400039000000000074004b0000097d0000c13d0000000000a6004b0000098e0000813d0000000306a00210000000f80660018f000006c70660027f000006c70660016700000000022500190000000002020433000000000262016f000000000024041b0000000102a0021000000001022001bf000000000021041b00000000040b04330000062f0040009c000000f80000213d000000000103041a000000010010019000000001051002700000007f0550618f0000001f0050008c00000000020000390000000102002039000000000121013f0000000100100190000009a40000613d000006b301000041000000000010043f0000002201000039000000040010043f000006b4010000410000189900010430000000200050008c000b00000009001d000009ca0000413d000700000005001d000900000004001d00080000000c001d000a0000000b001d000000000030043f0000000001000414000006270010009c0000062701008041000000c00110021000000633011001c70000801002000039189718920000040f0000000b090000290000000100200190000000a30000613d00000009040000290000001f024000390000000502200270000000200040008c0000000002004019000000000301043b00000007010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b00000003030000390000000a0b000029000000080c000029000009ca0000813d000000000002041b0000000102200039000000000012004b000009c60000413d000000200040008c000009fb0000413d000900000004001d000a0000000b001d000000000030043f0000000001000414000006270010009c0000062701008041000000c00110021000000633011001c70000801002000039189718920000040f0000000b090000290000000100200190000000a30000613d0000000908000029000006c502800198000000000101043b0000000a0700002900000b060000c13d0000002006000039000000030300003900000b130000013d000400000001001d0000000601000029000000000001004b00000a490000c13d0000069f01000041000000000010043f00000689010000410000189900010430000000e004200270000006660040009c000000000200003900000001020060390000067c0040009c00000001022061bf000008700000613d000006660040009c000008700000613d000006c20030009c0000086f0000613d000006c30030009c0000086f0000613d000006c40030009c0000000102000039000008700000613d0000000002000019000008700000013d000000000004004b000000000100001900000b1f0000613d0000000301400210000006c70110027f000006c70110016700000000020c0433000000000112016f0000000102400210000000000121019f00000b1f0000013d0000068a001001980000000a0200002900000a450000c13d0000000301200270000000000010043f0000000b01000039000000200010043f00000040020000390000000001000019189718780000040f0000000a020000290000000502200210000000e00220018f000000000101041a000000000121022f00000627011001970000067e0000013d0000068a001001980000000a0100002900000a220000c13d000000000010043f0000000601000039000000200010043f00000040020000390000000001000019189718780000040f000000000101041a0000067d0000013d000006ba01000041000000000010043f000006890100004100001899000104300000068a0010019800000a450000c13d0000000903000039000000000203041a000000010620019000000001012002700000007f0110618f0000001f0010008c00000000040000390000000104002039000000000442013f00000001004001900000099e0000c13d000000400500043d0000000004150436000000000006004b00000c0e0000613d000000000030043f000000000001004b000000000200001900000c130000613d0000068e0300004100000000020000190000000006240019000000000703041a000000000076043500000001033000390000002002200039000000000012004b00000a3d0000413d00000c130000013d0000069301000041000000000010043f00000689010000410000189900010430000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400300043d000000000101043b000000000101041a0000062f0110019800000b8e0000c13d00000000010300190000006002000039000004590000013d000000000100041a000700000001001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f000000010020019000000a9c0000613d000000000101043b000b00000001001d0000000701000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000b02000029000000a0022002100000000803000029000000010030008c00000000030000190000069903006041000000000223019f0000000a03000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000802000029000006a9022000d1000000000101043b000000000301041a0000000002230019000000000021041b0000000a0000006b00000d710000c13d000006aa01000041000000000010043f00000689010000410000189900010430000000000001042f000000000002004b00000b880000c13d000006bc01000041000000000010043f00000681010000410000189900010430000006a00040009c000000f80000213d0000000a03600029000000000331034f000000000403043b0000008003200039000000400030043f0000006003200039000000000003043500000040032000390000000000030435000000200320003900000000000304350000000000020435000000000004004b00000afb0000613d000000000300041a000000000043004b00000afb0000a13d000900000006001d000b00000004001d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000acb0000c13d0000000b04000029000000010440008a00000ab70000013d000000400100043d0000063c0010009c0000000b03000029000000f80000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000030043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400200043d0000063c0020009c0000000906000029000000f80000213d000000000301034f0000000101000367000000000303043b000000000303041a0000008004200039000000400040043f0000006004200039000000e80530027000000000005404350000068a003001980000000004000039000000010400c039000000400520003900000000004504350000062a043001970000000004420436000000a0033002700000062f033001970000000000340435000000200460008c00000080036000390000000000230435000000400200043d000006530000613d0000000a03400029000000000331034f0000063c0020009c000000000604001900000aa70000a13d000000f80000013d000000010320008a0000000503300270000000000431001900000020060000390000000104400039000000030300003900000000057600190000000005050433000000000051041b00000020066000390000000101100039000000000041004b00000b0c0000c13d000000000082004b00000b1d0000813d0000000302800210000000f80220018f000006c70220027f000006c70220016700000000047600190000000004040433000000000224016f000000000021041b000000010180021000000001011001bf000000000013041b0000000101000039000000000010041b0000062a069001970000063401000041000000000061041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d02000039000006360400004100000000050000191897188d0000040f0000000100200190000000a30000613d0000000a01000039000000000101041a000000400200043d0000002003200039000006370400004100000000004304350000062a011001970000000000120435000006270020009c000006270200804100000040012002100000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000638011001c70000800d02000039000000010300003900000639040000411897188d0000040f0000000100200190000000a30000613d0000000a02000039000000000102041a0000063a0110019700000637011001c7000000000012041b000000400100043d0000004402100039000002d103000039000000000032043500000020021000390000063b03000041000000000032043500000000030004100000062a0330019700000024041000390000000000340435000000440300003900000000003104350000063c0010009c000000f80000213d0000008003100039000000400030043f000006270020009c000006270200804100000040022002100000000001010433000006270010009c00000627010080410000006001100210000000000121019f0000000002000414000006270020009c0000062702008041000000c002200210000000000121019f00000637020000411897188d0000040f00020000000103550000006003100270000006270030019d000006270330019800000be80000c13d00000001002001900000000b0100002900000b7e0000613d000000600110021200000a9f0000613d000000fa011001bf0000063e02000041000000000012041b0000002001000039000001000010044300000120000004430000063f01000041000018980001042e000006b201000041000000000010043f000006890100004100001899000104300000000901000029000000000001041b0000000b010000291897169d0000040f0000000001000019000018980001042e0000006002200210000000000121019f0000063e02000041000000000012041b0000000001000019000018980001042e000000050010006b00000000020100190000000502004029000500000002001d0000000501200210000800000003001d00000000011300190000002001100039000000400010043f000900000001001d0000063c0010009c000000f80000213d00000009020000290000008001200039000000400010043f0000006001200039000000000001043500000040012000390000000000010435000000200120003900000000000104350000000000020435000000000100041a000000020010008c000000000100001900000cb70000413d0000000101000039000b00000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000000001004b00000dab0000c13d0000000b01000029000000010110008a00000ba90000013d0000000b01000029000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b00000000020004110000062a02200197000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000000101043b000000000101041a000000ff001001900000040b0000c13d0000000a01000039000000000101041a0000068b0010019800000be40000613d0000000002000411000000000121013f0000062a001001980000040b0000613d000006b701000041000000000010043f000006890100004100001899000104300000001f0430003900000628044001970000003f044000390000063d04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000062f0040009c000000f80000213d0000000100600190000000f80000c13d000000400040043f0000001f0430018f00000000063504360000062905300198000000000356001900000c000000613d000000000701034f000000007807043c0000000006860436000000000036004b00000bfc0000c13d000000000004004b00000b710000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f000000000013043500000b710000013d000006c6022001970000000000240435000000000001004b000000200200003900000000020060390000003f02200039000006c5032001970000000002530019000000000032004b000000000300003900000001030040390000062f0020009c000000f80000213d0000000100300190000000f80000c13d000000400020043f0000000003050433000000000003004b00000d070000c13d000006910020009c000000f80000213d0000002001200039000000400010043f0000000000020435000000400300043d00000e300000013d000b00000001001d000800000000001d00000000010000190000000a0500002900000c320000013d000b00000000001d0000000901000029000000400010043f00000001055000390000000101000039000000010010019000000c390000613d000000060050006c00000e500000613d0000000802000029000000050020006c00000e500000613d000000400100043d0000063c0010009c000000f80000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000a00000005001d000000000050043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400200043d0000063c0020009c0000000a05000029000000f80000213d000000000101043b000000000101041a0000006003200039000000e804100270000000000043043500000040032000390000068a001001980000000004000039000000010400c0390000000000430435000000a0031002700000062f03300197000000200420003900000000003404350000062a01100197000000000012043500000c2d0000c13d000000000001004b00000000020100190000000b02006029000b00000002001d000000070120014f0000062a0010019800000c2e0000c13d00000008010000290000000101100039000800000001001d00000005011002100000000401100029000000000051043500000c2e0000013d0000000a010000290000000101100039000000000010041b000000400100043d0000000b02000029000000000221043600000001030000390000000000320435000006270010009c000006270100804100000040011002100000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000638011001c70000800d020000390000069b040000411897188d0000040f0000000100200190000000a30000613d0000000b01000039000000200010043f0000000a010000290000000301100270000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d0000000702000029000000080220021000000006022001af00000008030000290000001003300210000000000232019f00000009030000290000001803300210000000000232019f0000000a060000290000000503600210000000e00330018f000000000101043b000000000401041a000000000534022f000000000525013f000006270550019700000000033501cf000000000343013f000000000031041b0000062701200197000000400200043d000000200320003900000000001304350000000000620435000006270020009c000006270200804100000040012002100000000002000414000006f10000013d000a00000001001d0000000105000039000700000000001d0000000001000019000000080200002900000cc30000013d000a00000000001d00000008020000290000000901000029000000400010043f00000001055000390000000101000039000000010010019000000cca0000613d000000040050006c00000e570000613d0000000703000029000000050030006c00000e570000613d000000400100043d0000063c0010009c000000f80000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000b00000005001d000000000050043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400200043d0000063c0020009c0000000b05000029000000f80000213d000000000101043b000000000101041a0000006003200039000000e804100270000000000043043500000040032000390000068a001001980000000004000039000000010400c0390000000000430435000000a0031002700000062f03300197000000200420003900000000003404350000062a01100197000000000012043500000cbd0000c13d000000000001004b00000000020100190000000a02006029000a00000002001d000000060120014f0000062a00100198000000080200002900000cbf0000c13d00000007010000290000000101100039000700000001001d00000005011002100000000001210019000000000051043500000cbf0000013d000000a003200039000000400030043f000000800320003900000000000304350000000a090000290000000006030019000000090090008c0000000a3990011a000000f807300210000000010360008a00000000080304330000068f08800197000000000787019f00000690077001c7000000000073043500000d0c0000213d00000000026200490000008102200039000000210660008a00000000002604350000000005050433000006c5095001970000001f0850018f000000400200043d0000002007200039000000000074004b00000ddc0000813d000000000009004b00000d2e0000613d000000000b840019000000000a870019000000200aa0008a000000200bb0008a000000000c9a0019000000000d9b0019000000000d0d04330000000000dc0435000000200990008c00000d280000c13d000000000008004b00000df20000613d000000000a07001900000de80000013d000006a501000041000000000010043f00000689010000410000189900010430000000000002004b000000000300001900000d3a0000613d000000a00300043d0000000304200210000006c70440027f000006c704400167000000000443016f000000010320021000000e4c0000013d000000400100043d0000063c0010009c000000f80000213d0000008002100039000000400020043f00000060021000390000000000020435000000400210003900000000000204350000002002100039000000000002043500000000000104350000000b01000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400200043d0000063c0020009c000000f80000213d000000000101043b000000000101041a0000008003200039000000400030043f0000006003200039000000e804100270000000000043043500000040032000390000068a001001980000000004000039000000010400c0390000000000430435000000a0031002700000062f03300197000000200420003900000000003404350000062a011001970000000000120435000b00000000001d000b00000001601d00000c290000013d0000000702000029000900080020002d000b00000002001d000000000100001900000d860000013d0000000b070000290000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c0400004100000000050000190000000a06000029000b00000007001d1897188d0000040f00000001002001900000000101000039000000a30000613d000000010010019000000d760000613d0000000b070000290000000107700039000000090070006c00000d770000c13d0000000901000029000000000010041b000000400100043d0000002002100039000000080300002900000000003204350000000a020000290000000000210435000006270010009c000006270100804100000040011002100000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000638011001c70000800d0200003900000001030000390000069b040000411897188d0000040f0000000100200190000000a30000613d000000400100043d00000007020000290000000000210435000006270010009c0000062701008041000000400110021000000686011001c7000018980001042e000000400100043d0000063c0010009c000000f80000213d0000008002100039000000400020043f00000060021000390000000000020435000000400210003900000000000204350000002002100039000000000002043500000000000104350000000b01000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000000a30000613d000000400200043d0000063c0020009c000000f80000213d000000000101043b000000000101041a0000008003200039000000400030043f0000006003200039000000e804100270000000000043043500000040032000390000068a001001980000000004000039000000010400c0390000000000430435000000a0031002700000062f03300197000000200420003900000000003404350000062a011001970000000000120435000a00000000001d000a00000001601d00000cb80000013d000000000a970019000000000009004b00000de50000613d000000000b040019000000000c07001900000000bd0b0434000000000cdc04360000000000ac004b00000de10000c13d000000000008004b00000df20000613d0000000004940019000000030880021000000000090a043300000000098901cf000000000989022f00000000040404330000010008800089000000000484022f00000000048401cf000000000494019f00000000004a0435000000000475001900000000000404350000000005060433000006c5075001970000001f0650018f000000000043004b00000e090000813d000000000007004b00000e050000613d00000000096300190000000008640019000000200880008a000000200990008a000000000a780019000000000b790019000000000b0b04330000000000ba0435000000200770008c00000dff0000c13d000000000006004b00000e1f0000613d000000000804001900000e150000013d0000000008740019000000000007004b00000e120000613d0000000009030019000000000a040019000000009b090434000000000aba043600000000008a004b00000e0e0000c13d000000000006004b00000e1f0000613d00000000037300190000000306600210000000000708043300000000076701cf000000000767022f00000000030304330000010006600089000000000363022f00000000036301cf000000000373019f0000000000380435000000000345001900000000000304350000000003230049000000200430008a00000000004204350000001f03300039000006c5013001970000000004210019000000000014004b000000000100003900000001010040390000062f0040009c000000f80000213d0000000100100190000000f80000c13d0000000003040019000000400040043f0000000001030019000b00000003001d0000088a0000013d0000068e030000410000002006000039000000010540008a0000000505500270000006a30550009a000000000706001900000080066000390000000006060433000000000063041b00000020067000390000000103300039000000000053004b00000e380000c13d000000a005700039000000000024004b00000e4a0000813d0000000304200210000000f80440018f000006c70440027f000006c7044001670000000005050433000000000445016f000000000043041b00000001030000390000000104200210000000000234019f000000000021041b0000000001000019000018980001042e000000040100002900000008020000290000000000210435000000400100043d000b00000001001d00000004020000290000045a0000013d00000007010000290000000000120435000000400100043d000004590000013d0000000101000039000000000201041a000000800300043d0000000002320019000000000021041b0000000001000019000018980001042e0000068801000041000000000010043f000006890100004100001899000104300000001f02200039000006c5022001970000000001120019000000000021004b000000000200003900000001020040390000062f0010009c00000e720000213d000000010020019000000e720000c13d000000400010043f000000000001042d000006b301000041000000000010043f0000004101000039000000040010043f000006b4010000410000189900010430000006c80010009c00000eaf0000213d0000000004010019000000630010008c00000eaf0000a13d00000001050003670000000401500370000000000101043b0000062a0010009c00000eaf0000213d0000002402500370000000000202043b0000062a0020009c00000eaf0000213d0000004403500370000000000603043b0000062f0060009c00000eaf0000213d0000002303600039000000000043004b00000eaf0000813d0000000403600039000000000335034f000000000703043b000006c90070009c00000eb10000813d00000005087002100000003f038000390000068709300197000000400300043d0000000009930019000000000039004b000000000a000039000000010a0040390000062f0090009c00000eb10000213d0000000100a0019000000eb10000c13d000000400090043f000000000073043500000024066000390000000008680019000000000048004b00000eaf0000213d000000000007004b00000eae0000613d0000000004030019000000000765034f000000000707043b000000200440003900000000007404350000002006600039000000000086004b00000ea70000413d000000000001042d00000000010000190000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b40100004100001899000104300000002003000039000000000331043600000000420204340000000000230435000006c5062001970000001f0520018f0000004001100039000000000014004b00000ed00000813d000000000006004b00000ecc0000613d00000000085400190000000007510019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c00000ec60000c13d000000000005004b00000ee60000613d000000000701001900000edc0000013d0000000007610019000000000006004b00000ed90000613d00000000080400190000000009010019000000008a0804340000000009a90436000000000079004b00000ed50000c13d000000000005004b00000ee60000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f0000000000470435000000000412001900000000000404350000001f02200039000006c5022001970000000001120019000000000001042d000006c80010009c00000efc0000213d000000630010008c00000efc0000a13d00000001030003670000000401300370000000000101043b0000062a0010009c00000efc0000213d0000002402300370000000000202043b0000062a0020009c00000efc0000213d0000004403300370000000000303043b000000000001042d0000000001000019000018990001043000000000030100190000001f01100039000000000021004b0000000004000019000006ca04004041000006ca05200197000006ca01100197000000000651013f000000000051004b0000000001000019000006ca01002041000006ca0060009c000000000104c019000000000001004b00000f460000613d0000000105000367000000000135034f000000000401043b000006c90040009c00000f400000813d0000001f01400039000006c5011001970000003f01100039000006c507100197000000400100043d0000000007710019000000000017004b000000000800003900000001080040390000062f0070009c00000f400000213d000000010080019000000f400000c13d0000002008300039000000400070043f00000000034104360000000007840019000000000027004b00000f460000213d000000000585034f000006c5064001980000001f0740018f000000000263001900000f300000613d000000000805034f0000000009030019000000008a08043c0000000009a90436000000000029004b00000f2c0000c13d000000000007004b00000f3d0000613d000000000565034f0000000306700210000000000702043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f000000000052043500000000024300190000000000020435000000000001042d000006b301000041000000000010043f0000004101000039000000040010043f000006b40100004100001899000104300000000001000019000018990001043000000000430104340000062a03300197000000000332043600000000040404330000062f04400197000000000043043500000040031000390000000003030433000000000003004b0000000003000039000000010300c03900000040042000390000000000340435000000600220003900000060011000390000000001010433000006a1011001970000000000120435000000000001042d00000020030000390000000004310436000000000302043300000000003404350000004001100039000000000003004b00000f690000613d00000000040000190000002002200039000000000502043300000000015104360000000104400039000000000034004b00000f630000413d000000000001042d0007000000000002000300000002001d000500000001001d000600000003001d000000000003004b000010c00000613d0000000601000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000101041a000000000001004b00000f980000c13d000000000100041a000000060010006c000010c00000a13d0000000602000029000000010220008a000700000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000101041a000000000001004b000000070200002900000f850000613d0000068a00100198000010c00000c13d00000005020000290000062a02200197000400000001001d0000062a01100197000500000002001d000000000021004b000010c40000c13d0000000601000029000000000010043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000a01043b000000000b0a041a00000000050004110000000509000029000000000095004b00000fe10000613d0000000000b5004b00000fe10000613d00010000000b001d00020000000a001d000000000090043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b00000000020004110000062a02200197000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000101041a000000ff001001900000000509000029000000020a000029000000010b000029000000000500041100000fe10000c13d0000000a01000039000000000101041a0000068b00100198000010d30000613d000000000151013f0000062a00100198000010d30000c13d00000003010000290007062a0010019b000000000009004b000010400000613d000000070000006b000010400000613d0000000a01000039000000000101041a0000062a02100197000000000025004b000010400000613d000000400100043d000000840310003900000006040000290000000000430435000000640310003900000007040000290000000000430435000000440310003900000000009304350000002003100039000006b50400004100000000004304350000062a045001970000002405100039000000000045043500000084040000390000000000410435000006cc0010009c000010cd0000813d000000c004100039000000400040043f000006270030009c000006270300804100000040033002100000000001010433000006270010009c00000627010080410000006001100210000000000131019f0000000003000414000006270030009c0000062703008041000000c003300210000000000131019f00020000000a001d00010000000b001d1897188d0000040f000000010b000029000000020a000029000000050900002900020000000103550000006003100270000006270030019d00000627033001980000103e0000613d0000001f0430003900000628044001970000003f044000390000063d04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000062f0040009c000010cd0000213d0000000100600190000010cd0000c13d000000400040043f0000001f0430018f000000000635043600000629053001980000000003560019000010310000613d000000000701034f000000007807043c0000000006860436000000000036004b0000102d0000c13d000000000004004b0000103e0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000100200190000010d70000613d00000000000b004b000010430000613d00000000000a041b000000000090043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000701000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000201041a0000000102200039000000000021041b000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f0000000100200190000010c80000613d000000000101043b000300000001001d0000000601000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d0000000302000029000000a00220021000000007022001af00000699022001c7000000000101043b000000000021041b00000004010000290000069900100198000010ad0000c13d00000006010000290000000101100039000300000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b000000000101041a000000000001004b000010ad0000c13d000000000100041a000000030010006b000010ad0000613d0000000301000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000010be0000613d000000000101043b0000000402000029000000000021041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c040000410000000505000029000000070600002900000006070000291897188d0000040f0000000100200190000010be0000613d000000070000006b000010c90000613d000000000001042d00000000010000190000189900010430000006b901000041000000000010043f00000689010000410000189900010430000006cb01000041000000000010043f00000689010000410000189900010430000000000001042f000006ce01000041000000000010043f00000689010000410000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b4010000410000189900010430000006a501000041000000000010043f00000689010000410000189900010430000006cd01000041000000000010043f00000689010000410000189900010430000006a8020000410000000c0020043f000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000010ea0000613d000000000101043b000000000101041a000000000001042d000000000100001900001899000104300000062a01100198000010fe0000613d000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000011020000613d000000000101043b000000000101041a0000062f01100197000000000001042d0000069f01000041000000000010043f00000689010000410000189900010430000000000100001900001899000104300008000000000002000200000004001d000500000002001d000600000001001d000700000003001d000000000003004b000012f70000613d0000000701000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000101041a000000000001004b000011330000c13d000000000100041a000000070010006c000012f70000a13d0000000702000029000000010220008a000800000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000101041a000000000001004b0000000802000029000011200000613d0000068a00100198000012f70000c13d00000006020000290000062a02200197000400000001001d0000062a01100197000600000002001d000000000021004b000012fc0000c13d0000000701000029000000000010043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000901043b000000000a09041a0000000002000411000000060020006c0000117c0000613d00000000010004110000000000a1004b0000117c0000613d00010000000a001d000300000009001d0000000601000029000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b00000000020004110000062a02200197000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000101041a000000ff001001900000000309000029000000010a0000290000117c0000c13d0000000a01000039000000000101041a0000068b00100198000013080000613d0000000002000411000000000121013f0000062a00100198000013080000c13d00000005010000290008062a0010019b000000060000006b000011dd0000613d000000080000006b000011dd0000613d0000000a01000039000000000101041a0000062a021001970000000001000411000000000021004b000011dd0000613d000000400100043d0000008403100039000000070400002900000000004304350000006403100039000000080400002900000000004304350000004403100039000000060400002900000000004304350000002003100039000006b504000041000000000043043500000000040004110000062a044001970000002405100039000000000045043500000084040000390000000000410435000006cc0010009c0000133a0000813d000000c004100039000000400040043f000006270030009c000006270300804100000040033002100000000001010433000006270010009c00000627010080410000006001100210000000000131019f0000000003000414000006270030009c0000062703008041000000c003300210000000000131019f000300000009001d00010000000a001d1897188d0000040f000000010a000029000000030900002900020000000103550000006003100270000006270030019d0000062703300198000011db0000613d0000001f0430003900000628044001970000003f044000390000063d04400197000000400500043d0000000004450019000000000054004b000000000600003900000001060040390000062f0040009c0000133a0000213d00000001006001900000133a0000c13d000000400040043f0000001f0430018f000000000635043600000629053001980000000003560019000011ce0000613d000000000701034f000000007807043c0000000006860436000000000036004b000011ca0000c13d000000000004004b000011db0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000100200190000013400000613d00000000000a004b000011e00000613d000000000009041b0000000601000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000201041a000000010220008a000000000021041b0000000801000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000201041a0000000102200039000000000021041b000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f0000000100200190000012fb0000613d000000000101043b000300000001001d0000000701000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d0000000302000029000000a00220021000000008022001af00000699022001c7000000000101043b000000000021041b000000040100002900000699001001980000124b0000c13d00000007010000290000000101100039000300000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b000000000101041a000000000001004b0000124b0000c13d000000000100041a000000030010006b0000124b0000613d0000000301000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000012f50000613d000000000101043b0000000402000029000000000021041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c040000410000000605000029000000080600002900000007070000291897188d0000040f0000000100200190000012f50000613d000000080000006b000013000000613d000006cf010000410000000000100443000000050100002900000004001004430000000001000414000006270010009c0000062701008041000000c001100210000006d0011001c70000800202000039189718920000040f0000000100200190000012fb0000613d000000000101043b000000000001004b000012f40000613d000000400b00043d0000006401b000390000008002000039000500000002001d00000000002104350000004401b00039000000070200002900000000002104350000002401b0003900000006020000290000000000210435000006d10100004100000000001b043500000000010004110000062a011001970000000402b0003900000000001204350000008402b00039000000020100002900000000410104340000000000120435000006c5061001970000001f0510018f000000a403b00039000000000034004b000012950000813d000000000006004b000012910000613d00000000085400190000000007530019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c0000128b0000c13d000000000005004b000012ab0000613d0000000007030019000012a10000013d0000000007630019000000000006004b0000129e0000613d00000000080400190000000009030019000000008a0804340000000009a90436000000000079004b0000129a0000c13d000000000005004b000012ab0000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f00000000004704350000001f04100039000006c50240019700000000013100190000000000010435000000a401200039000006270010009c000006270100804100000060011002100000062700b0009c000006270200004100000000020b40190000004002200210000000000121019f0000000002000414000006270020009c0000062702008041000000c002200210000000000121019f000000080200002900080000000b001d1897188d0000040f000000080b00002900000060031002700000062703300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b0019000012d00000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000012cc0000c13d000000000006004b000012dd0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000013040000613d0000001f01400039000000600210018f0000000001b20019000000000021004b000000000200003900000001020040390000062f0010009c0000133a0000213d00000001002001900000133a0000c13d000000400010043f000000200030008c000012f50000413d00000000010b0433000006be00100198000012f50000c13d000006bf01100197000006d10010009c000013360000c13d000000000001042d00000000010000190000189900010430000006b901000041000000000010043f00000689010000410000189900010430000000000001042f000006cb01000041000000000010043f00000689010000410000189900010430000006ce01000041000000000010043f00000689010000410000189900010430000000000003004b0000130c0000c13d0000006002000039000013330000013d000006a501000041000000000010043f000006890100004100001899000104300000001f0230003900000628022001970000003f022000390000063d04200197000000400200043d0000000004420019000000000024004b000000000500003900000001050040390000062f0040009c0000133a0000213d00000001005001900000133a0000c13d000000400040043f0000001f0430018f00000000063204360000062905300198000500000006001d0000000003560019000013260000613d000000000601034f0000000507000029000000006806043c0000000007870436000000000037004b000013220000c13d000000000004004b000013330000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000001020433000000000001004b000013440000c13d000006d201000041000000000010043f00000689010000410000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b4010000410000189900010430000006cd01000041000000000010043f000006890100004100001899000104300000000502000029000006270020009c00000627020080410000004002200210000006270010009c00000627010080410000006001100210000000000121019f000018990001043000010000000000020000000003010019000000400100043d000006d30010009c000013a50000813d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000003004b000013a20000613d000000000200041a000000000032004b000013a20000a13d000100000003001d000000000030043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000013a30000613d000000000101043b000000000101041a000000000001004b000013740000c13d0000000103000029000000010330008a000013600000013d000000400100043d0000063c0010009c0000000103000029000013a50000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000030043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000013a30000613d000000000301034f000000400100043d0000063c0010009c000013a50000213d000000000203043b000000000202041a0000008003100039000000400030043f0000006003100039000000e80420027000000000004304350000068a002001980000000003000039000000010300c039000000400410003900000000003404350000062a032001970000000003310436000000a0022002700000062f022001970000000000230435000000000001042d00000000010000190000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b40100004100001899000104300001000000000002000100000002001d0000062a01100197000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000013d90000613d000000000101043b00000001020000290000062a02200197000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000013d90000613d0000000102000029000000000101043b000000000101041a000000ff01100190000013ce0000613d000000000001042d0000000a01000039000000000101041a0000068b00100198000013d70000613d000000000121013f0000062a0010019800000000010000390000000101006039000000000001042d0000000001000019000000000001042d000000000100001900001899000104300011000000000002000300000005001d000200000004001d0000000004010019000e062a0030019c0000165b0000613d000100000003001d0000062a012001970000062a02400198000c00010000003d000f00000001001d000900000002001d000014140000613d000000000012004b000014140000613d001100000004001d000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b0000000902000029000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b000000000101041a000c00ff001001940000001102000029000014140000c13d0000000a01000039000000000101041a0000068b00100198000014130000613d000000000121013f0000062a0010019800000000010000390000000101006039000c00000001001d000014140000013d000c00000000001d00000002010000290000000012010434000600000001001d000000000002004b000015590000613d001100000002001d000000000100041a000700000001001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f00000001002001900000165a0000613d000000110200002900000005022002100000000603000029000d00000032001d000000000101043b000000a0011002100004000e001001b300000001020000390000000001000019000014360000013d000000010120008a00000010030000290000000d0030006c0000000002000019000015590000613d001000000003001d0000000004030433000000000004004b0000160d0000613d000000070040006b0000160d0000a13d000000000014004b0000000001000039000000010100a039000006c702200167000000000112016f0000000100100190000800000004001d000016110000c13d001100000004001d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d0000001104000029000000010440008a000000000101043b000000000101041a000000000001004b000014440000613d0000068a0010019800000008030000290000160d0000c13d000500000001001d0000062a011001970000000f0010006c000016150000c13d00000000010000190000000100100190001100000003001d000014730000613d000000000030043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b000000000101041a000000000001004b0000001103000029000014fe0000c13d000000000030043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000901043b000000000a09041a0000000f05000029000000000005004b000014de0000613d0000000a01000039000000000101041a0000062a021001970000000001000411000000000021004b000014de0000613d000000400100043d00000084031000390000001104000029000000000043043500000064031000390000000e040000290000000000430435000000440310003900000000005304350000002003100039000006b504000041000000000043043500000000040004110000062a044001970000002405100039000000000045043500000084040000390000000000410435000006cc0010009c0000164b0000813d000000c004100039000000400040043f000006270030009c000006270300804100000040033002100000000001010433000006270010009c00000627010080410000006001100210000000000131019f0000000003000414000006270030009c0000062703008041000000c003300210000000000131019f000b00000009001d000a0000000a001d1897188d0000040f0000000a0a0000290000000b0900002900020000000103550000006003100270000006270030019d0000062703300198000014db0000613d0000001f0430003900000628044001970000003f044000390000063d05400197000000400400043d0000000005540019000000000045004b000000000600003900000001060040390000062f0050009c0000164b0000213d00000001006001900000164b0000c13d000000400050043f000000000634043600000629053001980000000004560019000014ce0000613d000000000701034f000000007807043c0000000006860436000000000046004b000014ca0000c13d0000001f03300190000014db0000613d000000000151034f0000000303300210000000000504043300000000053501cf000000000535022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000151019f000000000014043500000001002001900000000f05000029000016090000613d0000000c0000006b000014e20000c13d0000000900a0006b000016050000c13d00000000000a004b000014e50000613d000000000009041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c040000410000000e0600002900000011070000291897188d0000040f0000000100200190000016030000613d00000011010000290000000104100039000000100200002900000020022000390000000003020433000000000043004b001000000002001d000014ff0000c13d0000000d0020006c00000001010000390000145f0000c13d000014ff0000013d0000000004030019001100000004001d0000000801000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b0000000402000029000000000021041b0000000f01000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d0000001103000029000b000800300072000000000101043b000000000201041a0000000b0220006a000000000021041b0000000e01000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b000000000201041a0000000b02200029000000000021041b0000001102000029000000070020006c000014310000613d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b000000000101041a000000000001004b0000001102000029000014310000c13d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016030000613d000000000101043b0000000502000029000000000021041b0000001102000029000014310000013d000006cf010000410000000000100443000000010100002900000004001004430000000001000414000006270010009c0000062701008041000000c001100210000006d0011001c70000800202000039189718920000040f00000001002001900000165a0000613d000000000101043b000000000001004b0000000f030000290000000602000029000016020000613d000000020100002900000000010104330000000501100212000016020000613d000c00000021001d000000400a00043d0000000301000029001000200010003d0000000001000411000d062a0010019b000b00800000003d000000200900008a0000000021020434000600000002001d0000006402a00039000000800400003900000000004204350000004402a0003900000000001204350000002401a000390000000000310435000006d10100004100000000001a04350000000401a000390000000d020000290000000000210435000000030100002900000000010104330000008402a000390000000000120435000000000491016f0000001f0310018f000000a402a00039000000100020006b0000159e0000813d000000000004004b000015990000613d00000003053000290000000006320019000000200660008a0000000007460019000000000845001900000000080804330000000000870435000000200440008c000015930000c13d000000000003004b000015b40000613d00000010040000290000000005020019000015aa0000013d0000000005420019000000000004004b000015a70000613d0000001006000029000000000702001900000000680604340000000007870436000000000057004b000015a30000c13d000000000003004b000015b40000613d00000010044000290000000303300210000000000605043300000000063601cf000000000636022f00000000040404330000010003300089000000000434022f00000000033401cf000000000363019f00000000003504350000001f03100039000000000393016f00000000012100190000000000010435000000a401300039000006270010009c000006270100804100000060011002100000062700a0009c000006270200004100000000020a40190000004002200210000000000121019f0000000002000414000006270020009c0000062702008041000000c002200210000000000121019f0000000e0200002900110000000a001d1897188d0000040f000000110a00002900000060031002700000062703300197000000200030008c00000020040000390000000004034019000000200640019000000000056a0019000015d80000613d000000000701034f00000000080a0019000000007907043c0000000008980436000000000058004b000015d40000c13d0000001f07400190000015e50000613d000000000661034f0000000307700210000000000805043300000000087801cf000000000878022f000000000606043b0000010007700089000000000676022f00000000067601cf000000000686019f0000000000650435000000000003001f00020000000103550000000100200190000000200900008a000016190000613d0000001f01400039000000600210018f0000000001a20019000000000021004b000000000200003900000001020040390000062f0010009c0000164b0000213d00000001002001900000164b0000c13d000000400010043f000000200030008c000016030000413d00000000020a0433000006be00200198000016030000c13d000006bf02200197000006d10020009c000016470000c13d00000006020000290000000c0020006c000000000a0100190000000f03000029000015770000c13d000000000001042d00000000010000190000189900010430000006a501000041000000000010043f00000689010000410000189900010430000006cd01000041000000000010043f00000689010000410000189900010430000006b901000041000000000010043f000006890100004100001899000104300000068801000041000000000010043f00000689010000410000189900010430000006cb01000041000000000010043f00000689010000410000189900010430000000000003004b0000161d0000c13d0000006002000039000016440000013d0000001f0230003900000628022001970000003f022000390000063d04200197000000400200043d0000000004420019000000000024004b000000000500003900000001050040390000062f0040009c0000164b0000213d00000001005001900000164b0000c13d000000400040043f0000001f0430018f00000000063204360000062905300198000b00000006001d0000000003560019000016370000613d000000000601034f0000000b07000029000000006806043c0000000007870436000000000037004b000016330000c13d000000000004004b000016440000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000001020433000000000001004b000016510000c13d000006d201000041000000000010043f00000689010000410000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b40100004100001899000104300000000b02000029000006270020009c00000627020080410000004002200210000006270010009c00000627010080410000006001100210000000000121019f0000189900010430000000000001042f000006ce01000041000000000010043f000006890100004100001899000104300000063401000041000000000101041a0000000002000411000000000012004b000016650000c13d000000000001042d000006bb01000041000000000010043f000006810100004100001899000104300001000000000002000000000001004b000016990000613d000100000001001d000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016970000613d000000000101043b000000000101041a000000000001004b000016940000c13d000000000100041a0000000102000029000000000021004b000016990000a13d000000010220008a000100000002001d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000016970000613d000000000101043b000000000101041a000000000001004b0000000102000029000016810000613d0000068a00100198000016990000c13d000000000001042d00000000010000190000189900010430000006b901000041000000000010043f0000068901000041000018990001043000010000000000020000063402000041000000000502041a00000000020004140000062a06100197000006270020009c0000062702008041000000c00120021000000635011001c70000800d0200003900000003030000390000063604000041000100000006001d1897188d0000040f0000000100200190000016b10000613d00000634010000410000000102000029000000000021041b000000000001042d00000000010000190000189900010430000d0000000000020000000005010019000a062a0030019c0000184e0000613d0000062a012001970000062a02500198000800010000003d000b00000001001d000500000002001d000016e90000613d000000000012004b000016e90000613d000c00000005001d000d00000004001d000000000010043f0000000701000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b0000000502000029000000000020043f000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b000000000101041a000800ff001001940000000d040000290000000c02000029000016e90000c13d0000000a01000039000000000101041a0000068b001001980000182d0000613d000000000121013f0000062a0010019800000000010000390000000101006039000800000001001d0000000012040434000000000002004b000018310000613d000d00000002001d000c00000001001d000000000100041a000300000001001d000006830100004100000000001004430000000001000414000006270010009c0000062701008041000000c00110021000000684011001c70000800b02000039189718920000040f0000000100200190000018520000613d0000000d0200002900000005022002100000000c03000029000900000032001d000000000101043b000000a0011002100001000a001001b3000000010200003900000000010000190000170a0000013d000000010120008a0000000c03000029000000090030006c0000000002000019000018310000613d000c00000003001d0000000004030433000000000004004b000018420000613d000000030040006b000018420000a13d000000000014004b0000000001000039000000010100a039000006c702200167000000000112016f0000000100100190000400000004001d000018460000c13d000d00000004001d000000000040043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d0000000d04000029000000010440008a000000000101043b000000000101041a000000000001004b000017180000613d0000068a001001980000000403000029000018420000c13d000200000001001d0000062a011001970000000b0010006c0000184a0000c13d00000000010000190000000100100190000d00000003001d000017470000613d000000000030043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b000000000101041a000000000001004b0000000d03000029000017d20000c13d000000000030043f0000000601000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000a01043b000000000b0a041a0000000b05000029000000000005004b000017b20000613d0000000a01000039000000000101041a0000062a021001970000000001000411000000000021004b000017b20000613d000000400100043d00000084031000390000000d04000029000000000043043500000064031000390000000a040000290000000000430435000000440310003900000000005304350000002003100039000006b504000041000000000043043500000000040004110000062a044001970000002405100039000000000045043500000084040000390000000000410435000006cc0010009c000018380000813d000000c004100039000000400040043f000006270030009c000006270300804100000040033002100000000001010433000006270010009c00000627010080410000006001100210000000000131019f0000000003000414000006270030009c0000062703008041000000c003300210000000000131019f00070000000a001d00060000000b001d1897188d0000040f000000060b000029000000070a0000290000000b0500002900020000000103550000006003100270000006270030019d0000062703300198000017b00000613d0000001f0430003900000628044001970000003f044000390000063d06400197000000400400043d0000000007640019000000000047004b000000000600003900000001060040390000062f0070009c000018380000213d0000000100600190000018380000c13d000000400070043f000000000634043600000629093001980000000004960019000017a30000613d000000000701034f000000007807043c0000000006860436000000000046004b0000179f0000c13d0000001f03300190000017b00000613d000000000191034f0000000303300210000000000604043300000000063601cf000000000636022f000000000101043b0000010003300089000000000131022f00000000013101cf000000000161019f000000000014043500000001002001900000183e0000613d000000080000006b000017b60000c13d0000000500b0006b000018340000c13d00000000000b004b000017b90000613d00000000000a041b0000000001000414000006270010009c0000062701008041000000c00110021000000635011001c70000800d0200003900000004030000390000068c040000410000000a060000290000000d070000291897188d0000040f0000000100200190000018320000613d0000000d0100002900000001041000390000000c0100002900000020011000390000000003010433000000000043004b000c00000001001d000017d30000c13d000000090010006c0000000101000039000017330000c13d000017d30000013d0000000004030019000d00000004001d0000000401000029000000000010043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b0000000102000029000000000021041b0000000b01000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d0000000d030000290007000400300072000000000101043b000000000201041a000000070220006a000000000021041b0000000a01000029000000000010043f0000000501000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b000000000201041a0000000702200029000000000021041b0000000d02000029000000030020006c000017050000613d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b000000000101041a000000000001004b0000000d02000029000017050000c13d000000000020043f0000000401000039000000200010043f0000000001000414000006270010009c0000062701008041000000c00110021000000638011001c70000801002000039189718920000040f0000000100200190000018320000613d000000000101043b0000000202000029000000000021041b0000000d02000029000017050000013d000800000000001d0000000012040434000000000002004b000016ec0000c13d000000000001042d00000000010000190000189900010430000006a501000041000000000010043f00000689010000410000189900010430000006b301000041000000000010043f0000004101000039000000040010043f000006b4010000410000189900010430000006cd01000041000000000010043f00000689010000410000189900010430000006b901000041000000000010043f000006890100004100001899000104300000068801000041000000000010043f00000689010000410000189900010430000006cb01000041000000000010043f00000689010000410000189900010430000006ce01000041000000000010043f00000689010000410000189900010430000000000001042f0001000000000002000100000002001d000006a8020000410000000c0020043f000000000010043f0000000001000414000006270010009c0000062701008041000000c00110021000000682011001c70000801002000039189718920000040f0000000100200190000018750000613d000000010200008a000000010220014f000000000101043b000000000301041a000000000623016f000000000061041b0000000c0100043d00000000020004140000006005100270000006270020009c0000062702008041000000c00120021000000635011001c70000800d020000390000000303000039000006b0040000411897188d0000040f0000000100200190000018750000613d000000000001042d00000000010000190000189900010430000000000001042f000006270010009c00000627010080410000004001100210000006270020009c00000627020080410000006002200210000000000112019f0000000002000414000006270020009c0000062702008041000000c002200210000000000112019f00000635011001c70000801002000039189718920000040f00000001002001900000188b0000613d000000000101043b000000000001042d0000000001000019000018990001043000001890002104210000000102000039000000000001042d0000000002000019000000000001042d00001895002104230000000102000039000000000001042d0000000002000019000000000001042d0000189700000432000018980001042e00001899000104300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000000ffffffe0000000000000000000000000ffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000ffffffffffffffc04f43485f47414348415f574541504f4e00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf4f47570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffbfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a532405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acebfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a5310200000000000000000000000000000000000020000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392702000000000000000000000000000000000000000000000000000000000000008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e00000000000000000000000003203c3f64312af9344e42ef8aa45b97c9dfe45940200000000000000000000000000000000000040000000000000000000000000cc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aacffffffffffffffffffffffff0000000000000000000000000000000000000000fb2de5d700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff7f00000000000000000000000000000000000000000000000000000003ffffffe00000000000000000000000000000000000000000000000aa4ec00224afccfdb7000000020000000000000000000000000000004000000100000000000000000000000000000000000000000000000000000000000000000000000000514e62fb000000000000000000000000000000000000000000000000000000009e05d23f00000000000000000000000000000000000000000000000000000000dc8e92e900000000000000000000000000000000000000000000000000000000f2fde38a00000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000f3993d1100000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000dc8e92ea00000000000000000000000000000000000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000b88d4fdd00000000000000000000000000000000000000000000000000000000b88d4fde00000000000000000000000000000000000000000000000000000000c23dc68f00000000000000000000000000000000000000000000000000000000c87b56dd000000000000000000000000000000000000000000000000000000009e05d24000000000000000000000000000000000000000000000000000000000a22cb46500000000000000000000000000000000000000000000000000000000a574cea400000000000000000000000000000000000000000000000000000000715018a50000000000000000000000000000000000000000000000000000000095d89b400000000000000000000000000000000000000000000000000000000095d89b4100000000000000000000000000000000000000000000000000000000988ac76c0000000000000000000000000000000000000000000000000000000099a2557a00000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000008462151c000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000005bbb2176000000000000000000000000000000000000000000000000000000005bbb2177000000000000000000000000000000000000000000000000000000006352211e0000000000000000000000000000000000000000000000000000000070a0823100000000000000000000000000000000000000000000000000000000514e62fc0000000000000000000000000000000000000000000000000000000054d1f13d0000000000000000000000000000000000000000000000000000000055f804b3000000000000000000000000000000000000000000000000000000001c10893e000000000000000000000000000000000000000000000000000000002a5520590000000000000000000000000000000000000000000000000000000042842e0d0000000000000000000000000000000000000000000000000000000042842e0e0000000000000000000000000000000000000000000000000000000042966c68000000000000000000000000000000000000000000000000000000004a4ee7b1000000000000000000000000000000000000000000000000000000002a55205a000000000000000000000000000000000000000000000000000000002de948070000000000000000000000000000000000000000000000000000000040c10f190000000000000000000000000000000000000000000000000000000025692961000000000000000000000000000000000000000000000000000000002569296200000000000000000000000000000000000000000000000000000000283a877c0000000000000000000000000000000000000000000000000000000028cfbd46000000000000000000000000000000000000000000000000000000001c10893f000000000000000000000000000000000000000000000000000000001cd64df40000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000095ea7b2000000000000000000000000000000000000000000000000000000001327d3d7000000000000000000000000000000000000000000000000000000001327d3d80000000000000000000000000000000000000000000000000000000018160ddd00000000000000000000000000000000000000000000000000000000183a4f6e00000000000000000000000000000000000000000000000000000000095ea7b300000000000000000000000000000000000000000000000000000000098144d4000000000000000000000000000000000000000000000000000000000d705df60000000000000000000000000000000000000000000000000000000004634d8c0000000000000000000000000000000000000000000000000000000004634d8d0000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000081812fc0000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000034601ec00000000000000000000000000000000000000000000000000000000389a75e10000000000000000000000000000000000000020000000800000000000000000000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c000000000000000002000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d955391320200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000000000006f5e881800000000000000000000000000000000000000200000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe09fc3da3700000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000400000000000000000000000000000001000000000000000000000000000000000000000000000000000000000000000000000000000000ff0000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000000000000ffffffffffffffffffffffffffffffff6e1540171b6c0c960b71a7020d9f60077f6af931a8bbf590da0223dacf75c7af00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffdf0000000000000000000000000000000000000080000000000000000000000000a14c4b500000000000000000000000000000000000000000000000000000000017307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31ffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffff000000000000000000000001000000000000000000000000000000000000000002000000000000000000000000000000000000200000008000000000000000006787c7f9a80aa0f5ceddab2c54f1f5169c0b88e75dd5e19d5e858a64144c7dbc0000000200000000000000000000000000000000000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffeffffffffffffffffefa2132cc0f35015fb48ecdcb238f0e28f3399cdfb45aff2aec2891a3083dac275f8e8eb303499c568ebebe58d5a7ab9202171b1ffc3c7b18c23bc1a3d5e9224c2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85b32c1995a000000000000000000000000000000000000000000000000000000008f4eb6040000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000007fffffffffffff60000000000000000000000000000000000000000000000000000000000ffffff91eabfe8e493f369f48e58fdf2609ff8809506ce57440a6f25fddc25308a385191eabfe8e493f369f48e58fdf2609ff8809506ce57440a6f25fddc25308a3850fa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c9259c896be00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff000000000000000000000000000000010000000300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000008b78c6d800000000000000000000000000000000000000000000000100000000000000012e07630000000000000000000000000000000000000000000000000000000000b562e8dd000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000040000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d715ad5ce61fc9595c7b415289d59cf203f23a94fa06f04af7e489a0a76e1fe260200000000000000000000000000000000000040000000800000000000000000682a6e7c000000000000000000000000000000000000000000000000000000004e487b71000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000024000000000000000000000000caee23ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000800000000000000000cfb3b942000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925df2d9b4200000000000000000000000000000000000000000000000000000000cf4700e4000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000082b4290000000000000000000000000000000000000000000000000000000000b4457eaa00000000000000000000000000000000000000000000000000000000350a88b300000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000a07d229a00000000000000000000000000000000000000000000000000000000ad0d7f6c0000000000000000000000000000000000000000000000000000000001ffc9a70000000000000000000000000000000000000000000000000000000080ac58cd000000000000000000000000000000000000000000000000000000005b5e139f00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000100000000000000008000000000000000000000000000000000000000000000000000000000000000a114810000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff404a54f5ba00000000000000000000000000000000000000000000000000000000ea553b34000000000000000000000000000000000000000000000000000000001806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000150b7a0200000000000000000000000000000000000000000000000000000000d1a57ed600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff807a3d1889c9a77ee463f3c1ab35465050f7cf457d0f01b1a9dde6a9702c36ab31
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
0000000000000000000000001b2c84dd7957b1e207cd7b01ded77984ec16fdef
-----Decoded View---------------
Arg [0] : _owner (address): 0x1B2C84dd7957b1e207Cd7b01Ded77984eC16fDEf
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 0000000000000000000000001b2c84dd7957b1e207cd7b01ded77984ec16fdef
Loading...
Loading
Loading...
Loading
Loading...
Loading
Net Worth in USD
$0.00
Net Worth in ETH
0
Multichain Portfolio | 35 Chains
| Chain | Token | Portfolio % | Price | Amount | Value |
|---|
Loading...
Loading
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.