Overview
ETH Balance
0 ETH
ETH Value
$0.00More Info
Private Name Tags
ContractCreator
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Latest 1 internal transaction
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
6716768 | 7 days ago | Contract Creation | 0 ETH |
Loading...
Loading
This contract may be a proxy contract. Click on More Options and select Is this a proxy? to confirm and enable the "Read as Proxy" & "Write as Proxy" tabs.
Contract Source Code Verified (Exact Match)
Contract Name:
FinalBosu
Compiler Version
v0.8.28+commit.7893614a
ZkSolc Version
v1.5.12
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.28; import {UUPSUpgradeable} from "@openzeppelin/contracts/proxy/utils/UUPSUpgradeable.sol"; import {Ownable} from "solady/src/auth/Ownable.sol"; import {SafeTransferLib} from "solady/src/utils/ext/zksync/SafeTransferLib.sol"; import {ReentrancyGuard} from "solady/src/utils/ReentrancyGuard.sol"; import {EIP712} from "solady/src/utils/EIP712.sol"; import {SignatureCheckerLib} from "solady/src/utils/SignatureCheckerLib.sol"; import {LibString} from "solady/src/utils/LibString.sol"; import {ERC2981} from "solady/src/tokens/ERC2981.sol"; import {ERC721ACExtendable, ERC721A, IERC721A} from "./extensions/ERC721ACExtendable.sol"; import {IExclusiveDelegateResolver} from "./interfaces/IExclusiveDelegateResolver.sol"; /** * @title FinalBosu * @author @finalbosux */ contract FinalBosu is ERC721ACExtendable, Ownable, ERC2981, ReentrancyGuard, EIP712, UUPSUpgradeable { error SaleNotActive(uint256 currentTime, uint256 startTime, uint256 endTime); error InvalidQuantity(uint256 requested, uint256 maxAllowed); error InvalidPrice(uint256 sent, uint256 required); error MaxSupplyReached(uint256 requested, uint256 remaining); error InvalidAddress(); error ClaimNotActive(); error InsufficientAllocation(uint256 requested, uint256 available); error PublicMintClosed(); error TradeNotEnabled(); error InvalidSignature(); error DelegateResolverNotSet(); error NotDelegated(); error ArrayLengthMismatch(); error MaxPerWalletExceeded(uint256 requested, uint256 alreadyMinted, uint256 maxAllowed); error ReclaimWindowNotOpen(uint256 currentTime, uint256 reclaimStartTime); error UnauthorizedCaller(); error EmptyTokenList(); error NotAuthorized(); error ContractAlreadyInitialized(); error InvalidTime(uint256 startTime, uint256 endTime); /** @dev Types of minting operations for accounting */ enum MintType { Public, Treasury, Presale, Legacy, Reclaim, FinalBoss } event PublicMint(address indexed to, uint256 quantity); event PreSaleClaim(address indexed to, uint256 quantity); event LegacyClaim(address indexed to, uint256 quantity); event TreasuryMint(address indexed to, uint256 quantity); event ReclaimUnclaimedNFTs(uint256 quantity); event FinalBossMint(address indexed to, uint256 quantity); event BaseURIUpdated(string baseURI); event TradingStatusUpdated(bool enabled); event PublicMintTimeWindowUpdated(uint256 startTime, uint256 endTime); event PublicMintPriceUpdated(uint256 newPrice); event TreasuryUpdated(address oldTreasury, address newTreasury); event SignerAddressUpdated(address oldSigner, address newSigner); event DelegateResolverUpdated(address oldDelegateResolver, address newDelegateResolver); event ClaimEndTimeUpdated(uint256 endTime, uint256 reclaimTime); event ReclaimStartTimeUpdated(uint256 reclaimTime); event MaxPerWalletUpdated(uint16 newMax); event TimeBasedReductionUpdated(bool enabled); event HiddenURIUpdated(string hiddenURI); event RevealStatusUpdated(bool revealed); event Initialized(address owner); uint256 public constant MAX_SUPPLY = 8888; uint256 public constant TREASURY_RESERVE = 888; uint256 public constant PRESALE_RESERVE = 4000; uint256 public constant LEGACY_RESERVE = 555; uint256 public constant PUBLIC_SUPPLY = MAX_SUPPLY - TREASURY_RESERVE - PRESALE_RESERVE - LEGACY_RESERVE; uint256 public constant RECLAIM_WINDOW = 60 days; uint256 public constant MAX_BATCH_SIZE = 20; bytes24 private constant _AGW_LINK_RIGHTS = bytes24(keccak256("AGW_LINK")); bytes32 private constant _MINT_REQUEST_TYPEHASH = keccak256("MintRequest(address account,uint256 quantity)"); uint8 private _flags; uint8 private constant FLAG_TRADING_ENABLED = 1 << 0; uint8 private constant FLAG_PRESALE_CLAIM_ACTIVE = 1 << 1; uint8 private constant FLAG_LEGACY_CLAIM_ACTIVE = 1 << 2; uint8 private constant FLAG_TIME_BASED_REDUCTION = 1 << 3; uint8 private constant FLAG_REVEALED = 1 << 4; uint16 public treasuryMinted; uint16 public presaleClaimed; uint16 public legacyClaimed; uint16 public publicMinted; uint16 public finalBossMinted; uint16 public maxPerWallet; mapping(address => uint256) public presaleAllocation; mapping(address => uint256) public legacyAllocation; mapping(address => uint16) public publicMintCount; uint256 public publicMintPrice; uint256 public publicMintStartTime; uint256 public publicMintEndTime; uint256 public claimEndTime; uint256 public reclaimStartTime; address public treasury; address public delegateResolver; address public signerAddress; string private baseTokenURI; string private hiddenURI; bool private _initialized; /** @dev Ensures function can only be called during active public mint */ modifier onlyDuringPublicMint() { uint256 nowTime = block.timestamp; if (nowTime < publicMintStartTime || nowTime >= publicMintEndTime) { revert SaleNotActive(nowTime, publicMintStartTime, publicMintEndTime); } if (_calculateRemainingPublicSupply() == 0) { revert PublicMintClosed(); } _; } /** @dev Ensures function can only be called during active claim period */ modifier onlyDuringClaim() { if (block.timestamp > claimEndTime) { revert ClaimNotActive(); } _; } /** @dev Validates that msg.sender is properly delegated for the given address */ modifier checkDelegate(address delegated) { if (delegateResolver == address(0)) revert DelegateResolverNotSet(); IExclusiveDelegateResolver instance = IExclusiveDelegateResolver(delegateResolver); if (msg.sender != instance.exclusiveWalletByRights(delegated, _AGW_LINK_RIGHTS)) { revert NotDelegated(); } _; } /** @dev Ensures function can only be called during reclaim period */ modifier onlyDuringReclaim() { uint256 nowTime = block.timestamp; if (nowTime < reclaimStartTime) { revert ReclaimWindowNotOpen(nowTime, reclaimStartTime); } _; } /** @dev Ensures trading is enabled for transfers from non-zero addresses */ modifier onlyWhenTradingEnabled(address from) { _checkTradingEnabled(from); _; } /** @dev Disables initializers for the implementation contract */ constructor() ERC721ACExtendable("Final Bosu", "BOSU") { _initialized = true; } /** * @notice Initializes the contract with required addresses * @param owner Address that will own the contract * @param _treasuryAddress Address receiving treasury funds and royalties * @param _delegateResolver Address resolving delegated rights for claims * @param _signerAddress Address for verifying public mint signatures * @param _hiddenURI URI for unrevealed tokens */ function initialize( address owner, address _treasuryAddress, address _delegateResolver, address _signerAddress, string calldata _hiddenURI ) external { if (_initialized) revert ContractAlreadyInitialized(); _initialized = true; if (owner == address(0) || _treasuryAddress == address(0) || _delegateResolver == address(0) || _signerAddress == address(0)) { revert InvalidAddress(); } _initializeOwner(owner); treasury = _treasuryAddress; delegateResolver = _delegateResolver; signerAddress = _signerAddress; hiddenURI = _hiddenURI; publicMintPrice = 0.14 ether; maxPerWallet = 2; _flags = FLAG_TIME_BASED_REDUCTION; publicMintStartTime = 1744642800; publicMintEndTime = 1744650000; claimEndTime = 1749920400; reclaimStartTime = claimEndTime + RECLAIM_WINDOW; _setDefaultRoyalty(_treasuryAddress, 500); uint256 currentIndex = _startTokenId(); assembly { sstore(0, currentIndex) } emit Initialized(owner); } /** * @notice Public mint function with EIP712 signature-based bot protection * @param quantity Number of tokens to mint * @param signature Signature proving permission to mint */ function publicMint( uint256 quantity, bytes calldata signature ) external payable nonReentrant onlyDuringPublicMint { if (quantity == 0) { revert InvalidQuantity(0, 1); } uint256 totalPrice = publicMintPrice * quantity; if (msg.value != totalPrice) { revert InvalidPrice(msg.value, totalPrice); } if (!_validateSignature(msg.sender, quantity, signature)) { revert InvalidSignature(); } uint256 currentRemainingPublicSupply = _calculateRemainingPublicSupply(); if (quantity > currentRemainingPublicSupply) { revert MaxSupplyReached(quantity, currentRemainingPublicSupply); } uint16 alreadyMinted = publicMintCount[msg.sender]; if (alreadyMinted + quantity > maxPerWallet) { revert MaxPerWalletExceeded(quantity, alreadyMinted, maxPerWallet); } publicMintCount[msg.sender] = alreadyMinted + uint16(quantity); _processMint(msg.sender, quantity, MintType.Public); } /** * @notice Claims presale allocation directly * @param to Recipient address for the tokens * @param quantity Number of tokens to claim */ function claimPresale(address to, uint256 quantity) external nonReentrant onlyDuringClaim { _claimPresale(to, msg.sender, quantity); } /** * @notice Claims presale allocation via delegate * @param to Recipient address for the tokens * @param quantity Number of tokens to claim * @param vault Address with presale allocation rights */ function claimPresaleDelegate(address to, uint256 quantity, address vault) external nonReentrant onlyDuringClaim checkDelegate(vault) { _claimPresale(to, vault, quantity); } /** * @notice Claims legacy allocation directly * @param to Recipient address for the tokens * @param quantity Number of tokens to claim */ function claimLegacy(address to, uint256 quantity) external nonReentrant onlyDuringClaim { _claimLegacy(to, msg.sender, quantity); } /** * @notice Claims legacy allocation via delegate * @param to Recipient address for the tokens * @param quantity Number of tokens to claim * @param vault Address with legacy allocation rights */ function claimLegacyDelegate(address to, uint256 quantity, address vault) external nonReentrant onlyDuringClaim checkDelegate(vault) { _claimLegacy(to, vault, quantity); } /** @dev Verifies caller is contract owner */ function _requireCallerIsContractOwner() internal view override { if (msg.sender != owner()) { revert UnauthorizedCaller(); } } /** * @notice Mints tokens from treasury allocation * @param to Recipient address for the tokens * @param quantity Number of tokens to mint */ function treasuryMint(address to, uint256 quantity) external { _requireCallerIsContractOwner(); uint16 mintedSoFar = treasuryMinted; if (mintedSoFar + quantity > TREASURY_RESERVE) { revert MaxSupplyReached(quantity, TREASURY_RESERVE - mintedSoFar); } _processMint(to, quantity, MintType.Treasury); } /** * @notice Mints tokens from time-reduced public supply * @param to Recipient address for the tokens * @param quantity Number of tokens to mint */ function finalBossMint(address to, uint256 quantity) external { _requireCallerIsContractOwner(); if (block.timestamp <= publicMintEndTime) { revert SaleNotActive(block.timestamp, publicMintEndTime + 1, type(uint256).max); } uint256 available = PUBLIC_SUPPLY - publicMinted; uint256 used = finalBossMinted; if (used + quantity > available) { revert MaxSupplyReached(quantity, available - used); } _processMint(to, quantity, MintType.FinalBoss); } /** * @notice Reclaims unclaimed NFTs after claim period * @param to Recipient address for the tokens * @param quantity Number of tokens to reclaim */ function reclaimUnclaimedNFTs(address to, uint256 quantity) external onlyDuringReclaim { _requireCallerIsContractOwner(); uint16 unclaimedPresale = uint16(PRESALE_RESERVE - presaleClaimed); uint16 unclaimedLegacy = uint16(LEGACY_RESERVE - legacyClaimed); uint16 unclaimedPublic = uint16(PUBLIC_SUPPLY - publicMinted - finalBossMinted); uint256 totalUnclaimed = unclaimedPresale + unclaimedLegacy + unclaimedPublic; if (quantity > totalUnclaimed) { revert MaxSupplyReached(quantity, totalUnclaimed); } _mint(to, quantity); emit ReclaimUnclaimedNFTs(quantity); } /** * @notice Sets presale allocations for multiple addresses * @param addresses Array of addresses to set allocations for * @param amounts Array of allocation amounts */ function setPresaleAllocations(address[] calldata addresses, uint256[] calldata amounts) external { _requireCallerIsContractOwner(); _setBulkAllocations(addresses, amounts, true); } /** * @notice Sets legacy allocations for multiple addresses * @param addresses Array of addresses to set allocations for * @param quantities Array of allocation quantities */ function setLegacyAllocations(address[] calldata addresses, uint256[] calldata quantities) external { _requireCallerIsContractOwner(); _setBulkAllocations(addresses, quantities, false); } /** * @notice Sets the public mint price * @param price New price in wei */ function setPublicMintPrice(uint256 price) external { _requireCallerIsContractOwner(); publicMintPrice = price; emit PublicMintPriceUpdated(price); } /** * @notice Sets maximum tokens per wallet for public mint * @param max New maximum per wallet */ function setMaxPerWallet(uint16 max) external { _requireCallerIsContractOwner(); maxPerWallet = max; emit MaxPerWalletUpdated(max); } /** * @notice Sets the time window for public mint * @param startTime Start timestamp for public mint * @param endTime End timestamp for public mint */ function setPublicMintTimeWindow(uint256 startTime, uint256 endTime) external { _requireCallerIsContractOwner(); if (startTime >= endTime) revert InvalidTime(startTime, endTime); publicMintStartTime = startTime; publicMintEndTime = endTime; emit PublicMintTimeWindowUpdated(startTime, endTime); } /** * @notice Sets presale claim status * @param active Whether presale claims should be active */ function setPresaleClaimActive(bool active) external { _requireCallerIsContractOwner(); if (active) { _flags |= FLAG_PRESALE_CLAIM_ACTIVE; } else { _flags &= ~FLAG_PRESALE_CLAIM_ACTIVE; } } /** * @notice Sets legacy claim status * @param active Whether legacy claims should be active */ function setLegacyClaimActive(bool active) external { _requireCallerIsContractOwner(); if (active) { _flags |= FLAG_LEGACY_CLAIM_ACTIVE; } else { _flags &= ~FLAG_LEGACY_CLAIM_ACTIVE; } } /** * @notice Sets the end time for claims and updates reclaim start time * @param endTime New timestamp for end of claim period */ function setClaimEndTime(uint256 endTime) external { _requireCallerIsContractOwner(); claimEndTime = endTime; reclaimStartTime = endTime + RECLAIM_WINDOW; emit ClaimEndTimeUpdated(endTime, reclaimStartTime); } /** * @notice Sets the base URI for token metadata * @param _baseTokenURI New base URI */ function setBaseURI(string calldata _baseTokenURI) external { _requireCallerIsContractOwner(); baseTokenURI = _baseTokenURI; emit BaseURIUpdated(baseTokenURI); } /** * @notice Sets the hidden URI for unrevealed tokens * @param _hiddenURI New hidden URI */ function setHiddenURI(string calldata _hiddenURI) external { _requireCallerIsContractOwner(); hiddenURI = _hiddenURI; emit HiddenURIUpdated(hiddenURI); } /** * @notice Sets reveal status for token metadata * @param _revealed Whether tokens should be revealed */ function setRevealed(bool _revealed) external { _requireCallerIsContractOwner(); if (_revealed) { _flags |= FLAG_REVEALED; } else { _flags &= ~FLAG_REVEALED; } emit RevealStatusUpdated(_revealed); } /** * @notice Sets trading enabled status */ function setTradingEnabled() external { _requireCallerIsContractOwner(); _flags |= FLAG_TRADING_ENABLED; emit TradingStatusUpdated(true); } /** * @notice Updates the treasury address * @param newTreasury New treasury address */ function setTreasury(address newTreasury) external { _requireCallerIsContractOwner(); if (newTreasury == address(0)) { revert InvalidAddress(); } address oldTreasury = treasury; treasury = newTreasury; emit TreasuryUpdated(oldTreasury, newTreasury); } /** * @notice Updates the signer address for mint validation * @param newSigner New signer address */ function setSignerAddress(address newSigner) external { _requireCallerIsContractOwner(); if (newSigner == address(0)) { revert InvalidAddress(); } address oldSigner = signerAddress; signerAddress = newSigner; emit SignerAddressUpdated(oldSigner, newSigner); } /** * @notice Updates the delegate resolver address * @param newDelegateResolver New delegate resolver address */ function setDelegateResolver(address newDelegateResolver) external { _requireCallerIsContractOwner(); address oldDelegateResolver = delegateResolver; delegateResolver = newDelegateResolver; emit DelegateResolverUpdated(oldDelegateResolver, newDelegateResolver); } /** * @notice Sets the default royalty parameters * @param receiver Address to receive royalties * @param feeNumerator Fee amount in basis points (100 = 1%) */ function setDefaultRoyalty(address receiver, uint96 feeNumerator) external { _requireCallerIsContractOwner(); _setDefaultRoyalty(receiver, feeNumerator); } /** * @notice Sets royalty parameters for a specific token * @param tokenId Token ID to set royalties for * @param receiver Address to receive royalties * @param feeNumerator Fee amount in basis points (100 = 1%) */ function setTokenRoyalty(uint256 tokenId, address receiver, uint96 feeNumerator) external { _requireCallerIsContractOwner(); _setTokenRoyalty(tokenId, receiver, feeNumerator); } /** @notice Withdraws all ETH from contract to treasury */ function withdrawETH() external nonReentrant { _requireCallerIsContractOwner(); SafeTransferLib.safeTransferAllETH(treasury); } /** * @notice Sets the status of time-based supply reduction * @param enabled Whether time-based reduction should be enabled */ function setTimeBasedReductionEnabled(bool enabled) external { _requireCallerIsContractOwner(); if (enabled) { _flags |= FLAG_TIME_BASED_REDUCTION; } else { _flags &= ~FLAG_TIME_BASED_REDUCTION; } emit TimeBasedReductionUpdated(enabled); } /** @notice Checks if token trading is enabled */ function tradingEnabled() public view returns (bool) { return (_flags & FLAG_TRADING_ENABLED) != 0; } /** @notice Checks if presale claiming is active */ function presaleClaimActive() public view returns (bool) { return (_flags & FLAG_PRESALE_CLAIM_ACTIVE) != 0; } /** @notice Checks if legacy claiming is active */ function legacyClaimActive() public view returns (bool) { return (_flags & FLAG_LEGACY_CLAIM_ACTIVE) != 0; } /** @notice Checks if time-based supply reduction is enabled */ function timeBasedReductionEnabled() public view returns (bool) { return (_flags & FLAG_TIME_BASED_REDUCTION) != 0; } /** @notice Checks if tokens are revealed */ function revealed() public view returns (bool) { return (_flags & FLAG_REVEALED) != 0; } /** * @notice Returns the metadata URI for a given token * @param tokenId The token ID * @return Metadata URI string */ function tokenURI(uint256 tokenId) public view override(ERC721A, IERC721A) returns (string memory) { if (!_exists(tokenId)) { revert URIQueryForNonexistentToken(); } if (!revealed()) { return hiddenURI; } return string(abi.encodePacked(baseTokenURI, LibString.toString(tokenId))); } /** @notice Returns the current block timestamp */ function currentTime() external view returns (uint256) { return block.timestamp; } /** @notice Calculates remaining public supply */ function remainingPublicSupply() external view returns (uint256) { return _calculateRemainingPublicSupply(); } function supportsInterface(bytes4 interfaceId) public view override(ERC721ACExtendable, ERC2981) returns (bool) { return ERC721ACExtendable.supportsInterface(interfaceId) || ERC2981.supportsInterface(interfaceId); } /** @notice Returns the domain separator for EIP-712 signatures */ function DOMAIN_SEPARATOR() public view returns (bytes32) { return _domainSeparator(); } /** @dev Required override for EIP712 */ function _domainNameAndVersion() internal pure override returns (string memory name, string memory version) { name = "FinalBosu"; version = "1"; } /** @dev Start tokens at ID=1 */ function _startTokenId() internal pure override returns (uint256) { return 1; } /** * @dev Sets allocation values for multiple addresses * @param addresses Array of addresses * @param amounts Array of allocation amounts * @param isPresale Whether this is for presale (true) or legacy (false) allocations */ function _setBulkAllocations(address[] calldata addresses, uint256[] calldata amounts, bool isPresale) internal { uint256 length = addresses.length; if (length != amounts.length) { revert ArrayLengthMismatch(); } for (uint256 i = 0; i < length; ) { if (isPresale) { presaleAllocation[addresses[i]] = amounts[i]; } else { legacyAllocation[addresses[i]] = amounts[i]; } unchecked { ++i; } } } /** * @dev Process presale claims * @param to Recipient address * @param claimer Address with allocation * @param quantity Number of tokens to claim */ function _claimPresale(address to, address claimer, uint256 quantity) internal { if (!presaleClaimActive()) { revert ClaimNotActive(); } if (quantity == 0) { revert InvalidQuantity(0, 1); } uint256 available = presaleAllocation[claimer]; if (available < quantity) { revert InsufficientAllocation(quantity, available); } uint16 claimedSoFar = presaleClaimed; if (claimedSoFar + quantity > PRESALE_RESERVE) { revert MaxSupplyReached(quantity, PRESALE_RESERVE - claimedSoFar); } presaleAllocation[claimer] = available - quantity; _processMint(to, quantity, MintType.Presale); } /** * @dev Process legacy claims * @param to Recipient address * @param claimer Address with allocation * @param quantity Number of tokens to claim */ function _claimLegacy(address to, address claimer, uint256 quantity) internal { if (!legacyClaimActive()) { revert ClaimNotActive(); } if (quantity == 0) { revert InvalidQuantity(0, 1); } uint256 available = legacyAllocation[claimer]; if (available < quantity) { revert InsufficientAllocation(quantity, available); } uint16 legacyCount = legacyClaimed; if (legacyCount + quantity > LEGACY_RESERVE) { revert MaxSupplyReached(quantity, LEGACY_RESERVE - legacyCount); } legacyAllocation[claimer] = available - quantity; _processMint(to, quantity, MintType.Legacy); } /** * @dev Process minting of tokens * @param to Recipient address * @param quantity Number of tokens to mint * @param mintType Type of mint operation */ function _processMint(address to, uint256 quantity, MintType mintType) internal { if (mintType == MintType.Public) { publicMinted += uint16(quantity); _mint(to, quantity); emit PublicMint(to, quantity); } else if (mintType == MintType.Treasury) { treasuryMinted += uint16(quantity); _mint(to, quantity); emit TreasuryMint(to, quantity); } else if (mintType == MintType.Presale) { presaleClaimed += uint16(quantity); _mint(to, quantity); emit PreSaleClaim(to, quantity); } else if (mintType == MintType.Legacy) { legacyClaimed += uint16(quantity); _mint(to, quantity); emit LegacyClaim(to, quantity); } else if (mintType == MintType.FinalBoss) { finalBossMinted += uint16(quantity); _mint(to, quantity); emit FinalBossMint(to, quantity); } else if (mintType == MintType.Reclaim) { _mint(to, quantity); emit ReclaimUnclaimedNFTs(quantity); } } /** @dev Enforces max supply */ function _mint(address to, uint256 quantity) internal override { if (_totalMinted() + quantity > MAX_SUPPLY) { revert MaxSupplyReached(quantity, MAX_SUPPLY - _totalMinted()); } super._mint(to, quantity); } /** @dev Calculate remaining public supply with optional time-based reduction */ function _calculateRemainingPublicSupply() internal view returns (uint256) { if (publicMinted >= PUBLIC_SUPPLY) { return 0; } uint256 startTime = publicMintStartTime; uint256 endTime = publicMintEndTime; uint16 minted = publicMinted; if (block.timestamp < startTime) { return PUBLIC_SUPPLY - minted; } if (block.timestamp >= endTime) { return 0; } if (!timeBasedReductionEnabled()) { return PUBLIC_SUPPLY - minted; } uint256 totalMintDuration = endTime - startTime; if (totalMintDuration == 0) { return 0; } uint256 timeElapsed = block.timestamp - startTime; if (timeElapsed > totalMintDuration) { timeElapsed = totalMintDuration; } uint256 mintReduction = (PUBLIC_SUPPLY * timeElapsed) / totalMintDuration; uint256 remaining = PUBLIC_SUPPLY - mintReduction; // Account for finalBossMints in the remaining supply remaining = remaining > finalBossMinted ? remaining - finalBossMinted : 0; return remaining > minted ? remaining - minted : 0; } /** * @notice Returns the available supply for finalBossMint * @return amount of public supply available for finalBossMint */ function finalBossAvailableSupply() external view returns (uint256) { if (block.timestamp <= publicMintEndTime) { return 0; } uint256 available = PUBLIC_SUPPLY - publicMinted; return available > finalBossMinted ? available - finalBossMinted : 0; } /** * @dev Validates EIP-712 signature for minting * @param account Address attempting to mint * @param quantity Quantity requested * @param signature Signature bytes */ function _validateSignature( address account, uint256 quantity, bytes calldata signature ) internal view returns (bool) { bytes32 structHash = keccak256(abi.encode(_MINT_REQUEST_TYPEHASH, account, quantity)); bytes32 digest = _hashTypedData(structHash); return SignatureCheckerLib.isValidSignatureNow(signerAddress, digest, signature); } /** @dev Checks if trading is enabled for non-mint transfers */ function _checkTradingEnabled(address from) internal view { if (from != address(0) && !tradingEnabled()) { revert TradeNotEnabled(); } } /** @dev Checks if trading is enabled */ function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal override { _checkTradingEnabled(from); super._validateBeforeTransfer(from, to, tokenId); } /** @dev Only owner can upgrade */ function _authorizeUpgrade(address newImplementation) internal override { _requireCallerIsContractOwner(); } /** * @notice Override approve to ensure trading is enabled * @param to Address to approve for the token * @param tokenId Token ID to approve */ function approve(address to, uint256 tokenId) public payable override(ERC721A, IERC721A) onlyWhenTradingEnabled(msg.sender) { super.approve(to, tokenId); } /** * @notice Override setApprovalForAll to ensure trading is enabled * @param operator Address to approve for all tokens * @param approved Approval status */ function setApprovalForAll(address operator, bool approved) public override(ERC721A, IERC721A) onlyWhenTradingEnabled(msg.sender) { super.setApprovalForAll(operator, approved); } /** * @notice Sets user and expires timestamp for a token * @param tokenId Token ID * @param user Address of user * @param expires UNIX timestamp for expiration */ function setUser( uint256 tokenId, address user, uint64 expires ) public virtual override onlyWhenTradingEnabled(ownerOf(tokenId)) { super.setUser(tokenId, user, expires); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@limitbreak/creator-token-standards/src/utils/AutomaticValidatorTransferApproval.sol"; import "@limitbreak/creator-token-standards/src/utils/CreatorTokenBase.sol"; import {TOKEN_TYPE_ERC721} from "@limitbreak/permit-c/src/Constants.sol"; import {ERC721A, IERC721A} from "../base/ERC721A.sol"; import {ERC721AQueryable} from "./ERC721AQueryable.sol"; import {ERC4907A} from "./ERC4907A.sol"; import {ERC721ABatchTransferable} from "./ERC721ABatchTransferable.sol"; import {ERC721ABatchBurnable} from "./ERC721ABatchBurnable.sol"; /** * @title ERC721ACExtendable * @author @finalbosux * @dev Extends limit break creator token contracts (CreatorTokenBase, AutomaticValidatorTransferApproval) * with Azuki based chiru labs extensions (ERC721AQueryable, ERC4907A, ERC721ABatchTransferable, ERC721ABatchBurnable) */ abstract contract ERC721ACExtendable is ERC721AQueryable, ERC4907A, ERC721ABatchTransferable, ERC721ABatchBurnable, CreatorTokenBase, AutomaticValidatorTransferApproval { constructor(string memory name_, string memory symbol_) CreatorTokenBase() ERC721A(name_, symbol_) {} /** * @notice Overrides behavior of isApprovedFor all such that if an operator is not explicitly approved * for all, the contract owner can optionally auto-approve the 721-C transfer validator for transfers. */ function isApprovedForAll(address owner, address operator) public view virtual override(ERC721A, IERC721A) returns (bool isApproved) { isApproved = super.isApprovedForAll(owner, operator); if (!isApproved) { if (autoApproveTransfersFromValidator) { isApproved = operator == address(getTransferValidator()); } } } /** * @notice Indicates whether the contract implements the specified interface. * @dev Overrides supportsInterface in ERC165. * @param interfaceId The interface id * @return true if the contract implements the specified interface, false otherwise */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, IERC721A, ERC4907A) returns (bool) { return interfaceId == type(ICreatorToken).interfaceId || interfaceId == type(ICreatorTokenLegacy).interfaceId || ERC4907A.supportsInterface(interfaceId) || super.supportsInterface(interfaceId); } /** * @notice Returns the function selector for the transfer validator's validation function to be called * @notice for transaction simulation. */ function getTransferValidationFunction() external pure returns (bytes4 functionSignature, bool isViewFunction) { functionSignature = bytes4(keccak256("validateTransfer(address,address,address,uint256)")); isViewFunction = true; } /// @dev Ties the erc721a _beforeTokenTransfers hook to more granular transfer validation logic function _beforeTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual override { for (uint256 i = 0; i < quantity;) { _validateBeforeTransfer(from, to, startTokenId + i); unchecked { ++i; } } } /// @dev Ties the erc721a _afterTokenTransfer hook to more granular transfer validation logic function _afterTokenTransfers( address from, address to, uint256 startTokenId, uint256 quantity ) internal virtual override { for (uint256 i = 0; i < quantity;) { _validateAfterTransfer(from, to, startTokenId + i); unchecked { ++i; } } } function _msgSenderERC721A() internal view virtual override returns (address) { return _msgSender(); } function _tokenType() internal pure override returns(uint16) { return uint16(TOKEN_TYPE_ERC721); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.28; /// @title Exclusive Delegate Resolver Interface /// @notice Interface for resolving delegates with exclusive rights /// @dev Implemented by contracts that want to handle delegation interface IExclusiveDelegateResolver { /// @notice Returns the exclusive wallet address for a given address and rights /// @param addr The address to check delegation for /// @param rights The rights type to check /// @return The address of the delegated wallet, or address(0) if not delegated function exclusiveWalletByRights(address addr, bytes24 rights) external view returns (address); function DELEGATE_REGISTRY() external view returns (address); function GLOBAL_DELEGATION() external view returns (bytes24); function delegatedWalletsByRights( address wallet, bytes24 rights ) external view returns (address[] memory wallets); function exclusiveOwnerByRights( address contractAddress, uint256 tokenId, bytes24 rights ) external view returns (address owner); function decodeRightsExpiration( bytes32 rights ) external pure returns (bytes24 rightsIdentifier, uint40 expiration); function generateRightsWithExpiration( bytes24 rightsIdentifier, uint40 expiration ) external pure returns (bytes32); }
// 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 pragma solidity ^0.8.4; /// @notice Signature verification helper that supports both ECDSA signatures from EOAs /// and ERC1271 signatures from smart contract wallets like Argent and Gnosis safe. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/SignatureCheckerLib.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/SignatureChecker.sol) /// /// @dev Note: /// - The signature checking functions use the ecrecover precompile (0x1). /// - The `bytes memory signature` variants use the identity precompile (0x4) /// to copy memory internally. /// - Unlike ECDSA signatures, contract signatures are revocable. /// - As of Solady version 0.0.134, all `bytes signature` variants accept both /// regular 65-byte `(r, s, v)` and EIP-2098 `(r, vs)` short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// This is for calldata efficiency on smart accounts prevalent on L2s. /// /// WARNING! Do NOT use signatures as unique identifiers: /// - Use a nonce in the digest to prevent replay attacks on the same contract. /// - Use EIP-712 for the digest to prevent replay attacks across different chains and contracts. /// EIP-712 also enables readable signing of typed data for better user safety. /// This implementation does NOT check if a signature is non-malleable. library SignatureCheckerLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* SIGNATURE CHECKING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer.code.length == 0`, then validate with `ecrecover`, else /// it will validate with ERC1271 on `signer`. function isValidSignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { if (signer == address(0)) return isValid; /// @solidity memory-safe-assembly assembly { let m := mload(0x40) for {} 1 {} { if iszero(extcodesize(signer)) { switch mload(signature) case 64 { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. } default { break } mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n) isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20) isValid := and(eq(mload(d), f), and(isValid, copied)) break } } } /// @dev Returns whether `signature` is valid for `signer` and `hash`. /// If `signer.code.length == 0`, then validate with `ecrecover`, else /// it will validate with ERC1271 on `signer`. function isValidSignatureNowCalldata(address signer, bytes32 hash, bytes calldata signature) internal view returns (bool isValid) { if (signer == address(0)) return isValid; /// @solidity memory-safe-assembly assembly { let m := mload(0x40) for {} 1 {} { if iszero(extcodesize(signer)) { switch signature.length case 64 { let vs := calldataload(add(signature.offset, 0x20)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, calldataload(signature.offset)) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // `r`, `s`. } default { break } mstore(0x00, hash) let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20) isValid := and(eq(mload(d), f), isValid) break } } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `signer` and `hash`. /// If `signer.code.length == 0`, then validate with `ecrecover`, else /// it will validate with ERC1271 on `signer`. function isValidSignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { if (signer == address(0)) return isValid; /// @solidity memory-safe-assembly assembly { let m := mload(0x40) for {} 1 {} { if iszero(extcodesize(signer)) { mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, shr(1, shl(1, vs))) // `s`. let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`. mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`. isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20) isValid := and(eq(mload(d), f), isValid) break } } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `signer` and `hash`. /// If `signer.code.length == 0`, then validate with `ecrecover`, else /// it will validate with ERC1271 on `signer`. function isValidSignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { if (signer == address(0)) return isValid; /// @solidity memory-safe-assembly assembly { let m := mload(0x40) for {} 1 {} { if iszero(extcodesize(signer)) { mstore(0x00, hash) mstore(0x20, and(v, 0xff)) // `v`. mstore(0x40, r) // `r`. mstore(0x60, s) // `s`. let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20) isValid := and(eq(mload(d), f), isValid) break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC1271 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC1271 operations do NOT have an ECDSA fallback. /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes memory signature) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. // Copy the `signature` over. let n := add(0x20, mload(signature)) let copied := staticcall(gas(), 4, signature, n, add(m, 0x44), n) isValid := staticcall(gas(), signer, m, add(returndatasize(), 0x44), d, 0x20) isValid := and(eq(mload(d), f), and(isValid, copied)) } } /// @dev Returns whether `signature` is valid for `hash` for an ERC1271 `signer` contract. function isValidERC1271SignatureNowCalldata( address signer, bytes32 hash, bytes calldata signature ) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), signature.length) // Copy the `signature` over. calldatacopy(add(m, 0x64), signature.offset, signature.length) isValid := staticcall(gas(), signer, m, add(signature.length, 0x64), d, 0x20) isValid := and(eq(mload(d), f), isValid) } } /// @dev Returns whether the signature (`r`, `vs`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, bytes32 r, bytes32 vs) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), shr(1, shl(1, vs))) // `s`. mstore8(add(m, 0xa4), add(shr(255, vs), 27)) // `v`. isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20) isValid := and(eq(mload(d), f), isValid) } } /// @dev Returns whether the signature (`v`, `r`, `s`) is valid for `hash` /// for an ERC1271 `signer` contract. function isValidERC1271SignatureNow(address signer, bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (bool isValid) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) let f := shl(224, 0x1626ba7e) mstore(m, f) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m, 0x04), hash) let d := add(m, 0x24) mstore(d, 0x40) // The offset of the `signature` in the calldata. mstore(add(m, 0x44), 65) // Length of the signature. mstore(add(m, 0x64), r) // `r`. mstore(add(m, 0x84), s) // `s`. mstore8(add(m, 0xa4), v) // `v`. isValid := staticcall(gas(), signer, m, 0xa5, d, 0x20) isValid := and(eq(mload(d), f), isValid) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC6492 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // Note: These ERC6492 operations now include an ECDSA fallback at the very end. // The calldata variants are excluded for brevity. /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt to /// deploy / prepare the `signer` smart account before doing a regular ERC1271 check. /// Note: This function is NOT reentrancy safe. /// The verifier must be deployed. /// Otherwise, the function will return false if `signer` is not yet deployed / prepared. /// See: https://gist.github.com/Vectorized/011d6becff6e0a73e42fe100f8d7ef04 /// With a dedicated verifier, this function is safe to use in contracts /// that have been granted special permissions. function isValidERC6492SignatureNowAllowSideEffects( address signer, bytes32 hash, bytes memory signature ) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_) _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) _isValid := and(eq(mload(d_), f_), and(_isValid, copied_)) } let noCode := iszero(extcodesize(signer)) let n := mload(signature) for {} 1 {} { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) } break } if iszero(noCode) { let o := add(signature, 0x20) // Signature bytes. isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40)))) if isValid { break } } let m := mload(0x40) mstore(m, signer) mstore(add(m, 0x20), hash) pop( call( gas(), // Remaining gas. 0x0000bc370E4DC924F427d84e2f4B9Ec81626ba7E, // Non-reverting verifier. 0, // Send zero ETH. m, // Start of memory. add(returndatasize(), 0x40), // Length of calldata in memory. staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1. 0x00 // Length of returndata to write. ) ) isValid := returndatasize() break } // Do `ecrecover` fallback if `noCode && !isValid`. for {} gt(noCode, isValid) {} { switch n case 64 { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. } default { break } let m := mload(0x40) mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /// @dev Returns whether `signature` is valid for `hash`. /// If the signature is postfixed with the ERC6492 magic number, it will attempt /// to use a reverting verifier to deploy / prepare the `signer` smart account /// and do a `isValidSignature` check via the reverting verifier. /// Note: This function is reentrancy safe. /// The reverting verifier must be deployed. /// Otherwise, the function will return false if `signer` is not yet deployed / prepared. /// See: https://gist.github.com/Vectorized/846a474c855eee9e441506676800a9ad function isValidERC6492SignatureNow(address signer, bytes32 hash, bytes memory signature) internal returns (bool isValid) { /// @solidity memory-safe-assembly assembly { function callIsValidSignature(signer_, hash_, signature_) -> _isValid { let m_ := mload(0x40) let f_ := shl(224, 0x1626ba7e) mstore(m_, f_) // `bytes4(keccak256("isValidSignature(bytes32,bytes)"))`. mstore(add(m_, 0x04), hash_) let d_ := add(m_, 0x24) mstore(d_, 0x40) // The offset of the `signature` in the calldata. let n_ := add(0x20, mload(signature_)) let copied_ := staticcall(gas(), 4, signature_, n_, add(m_, 0x44), n_) _isValid := staticcall(gas(), signer_, m_, add(returndatasize(), 0x44), d_, 0x20) _isValid := and(eq(mload(d_), f_), and(_isValid, copied_)) } let noCode := iszero(extcodesize(signer)) let n := mload(signature) for {} 1 {} { if iszero(eq(mload(add(signature, n)), mul(0x6492, div(not(isValid), 0xffff)))) { if iszero(noCode) { isValid := callIsValidSignature(signer, hash, signature) } break } if iszero(noCode) { let o := add(signature, 0x20) // Signature bytes. isValid := callIsValidSignature(signer, hash, add(o, mload(add(o, 0x40)))) if isValid { break } } let m := mload(0x40) mstore(m, signer) mstore(add(m, 0x20), hash) let willBeZeroIfRevertingVerifierExists := call( gas(), // Remaining gas. 0x00007bd799e4A591FeA53f8A8a3E9f931626Ba7e, // Reverting verifier. 0, // Send zero ETH. m, // Start of memory. add(returndatasize(), 0x40), // Length of calldata in memory. staticcall(gas(), 4, add(signature, 0x20), n, add(m, 0x40), n), // 1. 0x00 // Length of returndata to write. ) isValid := gt(returndatasize(), willBeZeroIfRevertingVerifierExists) break } // Do `ecrecover` fallback if `noCode && !isValid`. for {} gt(noCode, isValid) {} { switch n case 64 { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. } case 65 { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. } default { break } let m := mload(0x40) mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. let recovered := mload(staticcall(gas(), 1, 0x00, 0x80, 0x01, 0x20)) isValid := gt(returndatasize(), shl(96, xor(signer, recovered))) mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. break } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an Ethereum Signed Message, created from a `hash`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. function toEthSignedMessageHash(bytes32 hash) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { mstore(0x20, hash) // Store into scratch space for keccak256. mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 28 bytes. result := keccak256(0x04, 0x3c) // `32 * 2 - (32 - 28) = 60 = 0x3c`. } } /// @dev Returns an Ethereum Signed Message, created from `s`. /// This produces a hash corresponding to the one signed with the /// [`eth_sign`](https://eth.wiki/json-rpc/API#eth_sign) /// JSON-RPC method as part of EIP-191. /// Note: Supports lengths of `s` up to 999999 bytes. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let sLength := mload(s) let o := 0x20 mstore(o, "\x19Ethereum Signed Message:\n") // 26 bytes, zero-right-padded. mstore(0x00, 0x00) // Convert the `s.length` to ASCII decimal representation: `base10(s.length)`. for { let temp := sLength } 1 {} { o := sub(o, 1) mstore8(o, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } let n := sub(0x3a, o) // Header length: `26 + 32 - o`. // Throw an out-of-offset error (consumes all gas) if the header exceeds 32 bytes. returndatacopy(returndatasize(), returndatasize(), gt(n, 0x20)) mstore(s, or(mload(0x00), mload(n))) // Temporarily store the header. result := keccak256(add(s, sub(0x20, n)), add(n, sLength)) mstore(s, sLength) // Restore the length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EMPTY CALLDATA HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns an empty calldata bytes. function emptySignature() internal pure returns (bytes calldata signature) { /// @solidity memory-safe-assembly assembly { signature.length := 0 } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {LibBytes} from "./LibBytes.sol"; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated string storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native string storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct StringStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /// @dev The input string must be a 7-bit ASCII. error StringNot7BitASCII(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant ALPHANUMERIC_7_BIT_ASCII = 0x7fffffe07fffffe03ff000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant LETTERS_7_BIT_ASCII = 0x7fffffe07fffffe0000000000000000; /// @dev Lookup for 'abcdefghijklmnopqrstuvwxyz'. uint128 internal constant LOWERCASE_7_BIT_ASCII = 0x7fffffe000000000000000000000000; /// @dev Lookup for 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'. uint128 internal constant UPPERCASE_7_BIT_ASCII = 0x7fffffe0000000000000000; /// @dev Lookup for '0123456789'. uint128 internal constant DIGITS_7_BIT_ASCII = 0x3ff000000000000; /// @dev Lookup for '0123456789abcdefABCDEF'. uint128 internal constant HEXDIGITS_7_BIT_ASCII = 0x7e0000007e03ff000000000000; /// @dev Lookup for '01234567'. uint128 internal constant OCTDIGITS_7_BIT_ASCII = 0xff000000000000; /// @dev Lookup for '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~ \t\n\r\x0b\x0c'. uint128 internal constant PRINTABLE_7_BIT_ASCII = 0x7fffffffffffffffffffffff00003e00; /// @dev Lookup for '!"#$%&\'()*+,-./:;<=>?@[\\]^_`{|}~'. uint128 internal constant PUNCTUATION_7_BIT_ASCII = 0x78000001f8000001fc00fffe00000000; /// @dev Lookup for ' \t\n\r\x0b\x0c'. uint128 internal constant WHITESPACE_7_BIT_ASCII = 0x100003e00; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRING STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the string storage `$` to `s`. function set(StringStorage storage $, string memory s) internal { LibBytes.set(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to `s`. function setCalldata(StringStorage storage $, string calldata s) internal { LibBytes.setCalldata(bytesStorage($), bytes(s)); } /// @dev Sets the value of the string storage `$` to the empty string. function clear(StringStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty string "". function isEmpty(StringStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(StringStorage storage $) internal view returns (uint256) { return LibBytes.length(bytesStorage($)); } /// @dev Returns the value stored in `$`. function get(StringStorage storage $) internal view returns (string memory) { return string(LibBytes.get(bytesStorage($))); } /// @dev Helper to cast `$` to a `BytesStorage`. function bytesStorage(StringStorage storage $) internal pure returns (LibBytes.BytesStorage storage casted) { /// @solidity memory-safe-assembly assembly { casted.slot := $.slot } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end of the memory to calculate the length later. let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 1)`. // Store the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(result, add(48, mod(temp, 10))) temp := div(temp, 10) // Keep dividing `temp` until zero. if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) // Move the pointer 32 bytes back to make room for the length. mstore(result, n) // Store the length. } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory result) { if (value >= 0) return toString(uint256(value)); unchecked { result = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let n := mload(result) // Load the string length. mstore(result, 0x2d) // Store the '-' character. result := sub(result, 1) // Move back the string pointer by a byte. mstore(result, add(n, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2 + 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 byteCount) internal pure returns (string memory result) { result = toHexStringNoPrefix(value, byteCount); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `byteCount` bytes. /// The output is not prefixed with "0x" and is encoded using 2 hexadecimal digits per byte, /// giving a total length of `byteCount * 2` bytes. /// Reverts if `byteCount` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 byteCount) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `byteCount * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. result := add(mload(0x40), and(add(shl(1, byteCount), 0x42), not(0x1f))) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(result, add(byteCount, byteCount)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(result, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := add(mload(result), 2) // Compute the length. mstore(add(result, o), 0x3078) // Store the "0x" prefix, accounting for leading zero. result := sub(add(result, o), 2) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(result, 0x20))), 0x30) // Whether leading zero is present. let n := mload(result) // Get the length. result := add(result, o) // Move the pointer, accounting for leading zero. mstore(result, sub(n, o)) // Store the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. result := add(mload(0x40), 0x80) mstore(0x40, add(result, 0x20)) // Allocate memory. mstore(result, 0) // Zeroize the slot after the string. let end := result // Cache the end to calculate the length later. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { result := add(result, w) // `sub(result, 2)`. mstore8(add(result, 1), mload(and(temp, 15))) mstore8(result, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } let n := sub(end, result) result := sub(result, 0x20) mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory result) { result = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(result, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory result) { result = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Allocate memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(result, 0x80)) mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. result := add(result, 2) mstore(result, 40) // Store the length. let o := add(result, 0x20) mstore(add(o, 40), 0) // Zeroize the slot after the string. value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory result) { result = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let n := add(mload(result), 2) // Compute the length. mstore(result, 0x3078) // Store the "0x" prefix. result := sub(result, 2) // Move the pointer. mstore(result, n) // Store the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(raw) result := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(result, add(n, n)) // Store the length of the output. mstore(0x0f, 0x30313233343536373839616263646566) // Store the "0123456789abcdef" lookup. let o := add(result, 0x20) let end := add(raw, n) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 let mask := shl(7, div(not(0), 255)) let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /// @dev Returns if this string is a 7-bit ASCII string, /// AND all characters are in the `allowed` lookup. /// Note: If `s` is empty, returns true regardless of `allowed`. function is7BitASCII(string memory s, uint128 allowed) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 if mload(s) { let allowed_ := shr(128, shl(128, allowed)) let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := and(result, shr(byte(0, mload(o)), allowed_)) o := add(o, 1) if iszero(and(result, lt(o, end))) { break } } } } } /// @dev Converts the bytes in the 7-bit ASCII string `s` to /// an allowed lookup for use in `is7BitASCII(s, allowed)`. /// To save runtime gas, you can cache the result in an immutable variable. function to7BitASCIIAllowedLookup(string memory s) internal pure returns (uint128 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { let o := add(s, 0x20) for { let end := add(o, mload(s)) } 1 {} { result := or(result, shl(byte(0, mload(o)), 1)) o := add(o, 1) if iszero(lt(o, end)) { break } } if shr(128, result) { mstore(0x00, 0xc9807e0d) // `StringNot7BitASCII()`. revert(0x1c, 0x04) } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(string memory subject, string memory needle, string memory replacement) internal pure returns (string memory) { return string(LibBytes.replace(bytes(subject), bytes(needle), bytes(replacement))); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.indexOf(bytes(subject), bytes(needle), 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle, uint256 from) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), from); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(string memory subject, string memory needle) internal pure returns (uint256) { return LibBytes.lastIndexOf(bytes(subject), bytes(needle), type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.contains(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` starts with `needle`. function startsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.startsWith(bytes(subject), bytes(needle)); } /// @dev Returns whether `subject` ends with `needle`. function endsWith(string memory subject, string memory needle) internal pure returns (bool) { return LibBytes.endsWith(bytes(subject), bytes(needle)); } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory) { return string(LibBytes.repeat(bytes(subject), times)); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, end)); } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory) { return string(LibBytes.slice(bytes(subject), start, type(uint256).max)); } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory needle) internal pure returns (uint256[] memory) { return LibBytes.indicesOf(bytes(subject), bytes(needle)); } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { bytes[] memory a = LibBytes.split(bytes(subject), bytes(delimiter)); /// @solidity memory-safe-assembly assembly { result := a } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory) { return string(LibBytes.concat(bytes(a), bytes(b))); } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let n := mload(subject) if n { result := mload(0x40) let o := add(result, 0x20) let d := sub(subject, result) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) for { let end := add(o, n) } 1 {} { let b := byte(0, mload(add(d, o))) mstore8(o, xor(and(shr(b, flags), 0x20), b)) o := add(o, 1) if eq(o, end) { break } } mstore(result, n) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) // Store the length. let o := add(result, 0x20) mstore(o, s) // Store the bytes of the string. mstore(add(o, n), 0) // Zeroize the slot after the string. mstore(0x40, add(result, 0x40)) // Allocate memory. } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let end := add(s, mload(s)) let o := add(result, 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(o, c) o := add(o, 1) continue } let t := shr(248, mload(c)) mstore(o, mload(and(t, 0x1f))) o := add(o, shr(5, t)) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(o, c) o := add(o, 1) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), c) o := add(o, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(o, mload(0x19)) // "\\u00XX". o := add(o, 6) continue } mstore8(o, 0x5c) // "\\". mstore8(add(o, 1), mload(add(c, 8))) o := add(o, 2) } if addDoubleQuotes { mstore8(o, 34) o := add(1, o) } mstore(o, 0) // Zeroize the slot after the string. mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Encodes `s` so that it can be safely used in a URI, /// just like `encodeURIComponent` in JavaScript. /// See: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/encodeURIComponent /// See: https://datatracker.ietf.org/doc/html/rfc2396 /// See: https://datatracker.ietf.org/doc/html/rfc3986 function encodeURIComponent(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Store "0123456789ABCDEF" in scratch space. // Uppercased to be consistent with JavaScript's implementation. mstore(0x0f, 0x30313233343536373839414243444546) let o := add(result, 0x20) for { let end := add(s, mload(s)) } iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // If not in `[0-9A-Z-a-z-_.!~*'()]`. if iszero(and(1, shr(c, 0x47fffffe87fffffe03ff678200000000))) { mstore8(o, 0x25) // '%'. mstore8(add(o, 1), mload(and(shr(4, c), 15))) mstore8(add(o, 2), mload(and(c, 15))) o := add(o, 3) continue } mstore8(o, c) o := add(o, 1) } mstore(result, sub(o, add(result, 0x20))) // Store the length. mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. function cmp(string memory a, string memory b) internal pure returns (int256) { return LibBytes.cmp(bytes(a), bytes(b)); } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) // Grab the free memory pointer. mstore(0x40, add(result, 0x40)) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(result, 0) // Zeroize the length slot. mstore(add(result, 0x1f), packed) // Store the length and bytes. mstore(add(add(result, 0x20), mload(result)), 0) // Right pad with zeroes. } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( or( // Load the length and the bytes of `a` and `b`. shl(shl(3, sub(0x1f, aLen)), mload(add(a, aLen))), mload(sub(add(b, 0x1e), aLen))), // `totalLen != 0 && totalLen < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLen, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { resultA := mload(0x40) // Grab the free memory pointer. resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the string. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Contract for EIP-712 typed structured data hashing and signing. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/EIP712.sol) /// @author Modified from Solbase (https://github.com/Sol-DAO/solbase/blob/main/src/utils/EIP712.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/EIP712.sol) /// /// @dev Note, this implementation: /// - Uses `address(this)` for the `verifyingContract` field. /// - Does NOT use the optional EIP-712 salt. /// - Does NOT use any EIP-712 extensions. /// This is for simplicity and to save gas. /// If you need to customize, please fork / modify accordingly. abstract contract EIP712 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS AND IMMUTABLES */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev `keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)")`. bytes32 internal constant _DOMAIN_TYPEHASH = 0x8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f; uint256 private immutable _cachedThis; uint256 private immutable _cachedChainId; bytes32 private immutable _cachedNameHash; bytes32 private immutable _cachedVersionHash; bytes32 private immutable _cachedDomainSeparator; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTRUCTOR */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Cache the hashes for cheaper runtime gas costs. /// In the case of upgradeable contracts (i.e. proxies), /// or if the chain id changes due to a hard fork, /// the domain separator will be seamlessly calculated on-the-fly. constructor() { _cachedThis = uint256(uint160(address(this))); _cachedChainId = block.chainid; string memory name; string memory version; if (!_domainNameAndVersionMayChange()) (name, version) = _domainNameAndVersion(); bytes32 nameHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(name)); bytes32 versionHash = _domainNameAndVersionMayChange() ? bytes32(0) : keccak256(bytes(version)); _cachedNameHash = nameHash; _cachedVersionHash = versionHash; bytes32 separator; if (!_domainNameAndVersionMayChange()) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), nameHash) mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } _cachedDomainSeparator = separator; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* FUNCTIONS TO OVERRIDE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Please override this function to return the domain name and version. /// ``` /// function _domainNameAndVersion() /// internal /// pure /// virtual /// returns (string memory name, string memory version) /// { /// name = "Solady"; /// version = "1"; /// } /// ``` /// /// Note: If the returned result may change after the contract has been deployed, /// you must override `_domainNameAndVersionMayChange()` to return true. function _domainNameAndVersion() internal view virtual returns (string memory name, string memory version); /// @dev Returns if `_domainNameAndVersion()` may change /// after the contract has been deployed (i.e. after the constructor). /// Default: false. function _domainNameAndVersionMayChange() internal pure virtual returns (bool result) {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HASHING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _domainSeparator() internal view virtual returns (bytes32 separator) { if (_domainNameAndVersionMayChange()) { separator = _buildDomainSeparator(); } else { separator = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) separator = _buildDomainSeparator(); } } /// @dev Returns the hash of the fully encoded EIP-712 message for this domain, /// given `structHash`, as defined in /// https://eips.ethereum.org/EIPS/eip-712#definition-of-hashstruct. /// /// The hash can be used together with {ECDSA-recover} to obtain the signer of a message: /// ``` /// bytes32 digest = _hashTypedData(keccak256(abi.encode( /// keccak256("Mail(address to,string contents)"), /// mailTo, /// keccak256(bytes(mailContents)) /// ))); /// address signer = ECDSA.recover(digest, signature); /// ``` function _hashTypedData(bytes32 structHash) internal view virtual returns (bytes32 digest) { // We will use `digest` to store the domain separator to save a bit of gas. if (_domainNameAndVersionMayChange()) { digest = _buildDomainSeparator(); } else { digest = _cachedDomainSeparator; if (_cachedDomainSeparatorInvalidated()) digest = _buildDomainSeparator(); } /// @solidity memory-safe-assembly assembly { // Compute the digest. mstore(0x00, 0x1901000000000000) // Store "\x19\x01". mstore(0x1a, digest) // Store the domain separator. mstore(0x3a, structHash) // Store the struct hash. digest := keccak256(0x18, 0x42) // Restore the part of the free memory slot that was overwritten. mstore(0x3a, 0) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EIP-5267 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev See: https://eips.ethereum.org/EIPS/eip-5267 function eip712Domain() public view virtual returns ( bytes1 fields, string memory name, string memory version, uint256 chainId, address verifyingContract, bytes32 salt, uint256[] memory extensions ) { fields = hex"0f"; // `0b01111`. (name, version) = _domainNameAndVersion(); chainId = block.chainid; verifyingContract = address(this); salt = salt; // `bytes32(0)`. extensions = extensions; // `new uint256[](0)`. } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the EIP-712 domain separator. function _buildDomainSeparator() private view returns (bytes32 separator) { // We will use `separator` to store the name hash to save a bit of gas. bytes32 versionHash; if (_domainNameAndVersionMayChange()) { (string memory name, string memory version) = _domainNameAndVersion(); separator = keccak256(bytes(name)); versionHash = keccak256(bytes(version)); } else { separator = _cachedNameHash; versionHash = _cachedVersionHash; } /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Load the free memory pointer. mstore(m, _DOMAIN_TYPEHASH) mstore(add(m, 0x20), separator) // Name hash. mstore(add(m, 0x40), versionHash) mstore(add(m, 0x60), chainid()) mstore(add(m, 0x80), address()) separator := keccak256(m, 0xa0) } } /// @dev Returns if the cached domain separator has been invalidated. function _cachedDomainSeparatorInvalidated() private view returns (bool result) { uint256 cachedChainId = _cachedChainId; uint256 cachedThis = _cachedThis; /// @solidity memory-safe-assembly assembly { result := iszero(and(eq(chainid(), cachedChainId), eq(address(), cachedThis))) } } }
// 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 Reentrancy guard mixin. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ReentrancyGuard.sol) abstract contract ReentrancyGuard { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unauthorized reentrant call. error Reentrancy(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to: `uint72(bytes9(keccak256("_REENTRANCY_GUARD_SLOT")))`. /// 9 bytes is large enough to avoid collisions with lower slots, /// but not too large to result in excessive bytecode bloat. uint256 private constant _REENTRANCY_GUARD_SLOT = 0x929eee149b4bd21268; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* REENTRANCY GUARD */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Guards a function from reentrancy. modifier nonReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } sstore(_REENTRANCY_GUARD_SLOT, address()) } _; /// @solidity memory-safe-assembly assembly { sstore(_REENTRANCY_GUARD_SLOT, codesize()) } } /// @dev Guards a view function from read-only reentrancy. modifier nonReadReentrant() virtual { /// @solidity memory-safe-assembly assembly { if eq(sload(_REENTRANCY_GUARD_SLOT), address()) { mstore(0x00, 0xab143c06) // `Reentrancy()`. revert(0x1c, 0x04) } } _; } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (proxy/utils/UUPSUpgradeable.sol) pragma solidity ^0.8.0; import "../../interfaces/draft-IERC1822.sol"; import "../ERC1967/ERC1967Upgrade.sol"; /** * @dev An upgradeability mechanism designed for UUPS proxies. The functions included here can perform an upgrade of an * {ERC1967Proxy}, when this contract is set as the implementation behind such a proxy. * * A security mechanism ensures that an upgrade does not turn off upgradeability accidentally, although this risk is * reinstated if the upgrade retains upgradeability but removes the security mechanism, e.g. by replacing * `UUPSUpgradeable` with a custom implementation of upgrades. * * The {_authorizeUpgrade} function must be overridden to include access restriction to the upgrade mechanism. * * _Available since v4.1._ */ abstract contract UUPSUpgradeable is IERC1822Proxiable, ERC1967Upgrade { /// @custom:oz-upgrades-unsafe-allow state-variable-immutable state-variable-assignment address private immutable __self = address(this); /** * @dev Check that the execution is being performed through a delegatecall call and that the execution context is * a proxy contract with an implementation (as defined in ERC1967) pointing to self. This should only be the case * for UUPS and transparent proxies that are using the current contract as their implementation. Execution of a * function through ERC1167 minimal proxies (clones) would not normally pass this test, but is not guaranteed to * fail. */ modifier onlyProxy() { require(address(this) != __self, "Function must be called through delegatecall"); require(_getImplementation() == __self, "Function must be called through active proxy"); _; } /** * @dev Check that the execution is not being performed through a delegate call. This allows a function to be * callable on the implementing contract but not through proxies. */ modifier notDelegated() { require(address(this) == __self, "UUPSUpgradeable: must not be called through delegatecall"); _; } /** * @dev Implementation of the ERC1822 {proxiableUUID} function. This returns the storage slot used by the * implementation. It is used to validate the implementation's compatibility when performing an upgrade. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. This is guaranteed by the `notDelegated` modifier. */ function proxiableUUID() external view virtual override notDelegated returns (bytes32) { return _IMPLEMENTATION_SLOT; } /** * @dev Upgrade the implementation of the proxy to `newImplementation`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeTo(address newImplementation) external virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, new bytes(0), false); } /** * @dev Upgrade the implementation of the proxy to `newImplementation`, and subsequently execute the function call * encoded in `data`. * * Calls {_authorizeUpgrade}. * * Emits an {Upgraded} event. */ function upgradeToAndCall(address newImplementation, bytes memory data) external payable virtual onlyProxy { _authorizeUpgrade(newImplementation); _upgradeToAndCallUUPS(newImplementation, data, true); } /** * @dev Function that should revert when `msg.sender` is not authorized to upgrade the contract. Called by * {upgradeTo} and {upgradeToAndCall}. * * Normally, this function will use an xref:access.adoc[access control] modifier such as {Ownable-onlyOwner}. * * ```solidity * function _authorizeUpgrade(address) internal override onlyOwner {} * ``` */ function _authorizeUpgrade(address newImplementation) internal virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {SingleUseETHVault} from "./SingleUseETHVault.sol"; /// @notice Library for force safe transferring ETH and ERC20s in ZKsync. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SafeTransferLib.sol) library SafeTransferLib { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev A single use ETH vault has been created for `to`, with `amount`. event SingleUseETHVaultCreated(address indexed to, uint256 amount, address vault); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ETH transfer has failed. error ETHTransferFailed(); /// @dev The ERC20 `transferFrom` has failed. error TransferFromFailed(); /// @dev The ERC20 `transfer` has failed. error TransferFailed(); /// @dev The ERC20 `approve` has failed. error ApproveFailed(); /// @dev The ERC20 `totalSupply` query has failed. error TotalSupplyQueryFailed(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Suggested gas stipend for contract receiving ETH to perform a few /// storage reads and writes, but low enough to prevent griefing. uint256 internal constant GAS_STIPEND_NO_GRIEF = 1000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ETH OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // If the ETH transfer MUST succeed with a reasonable gas budget, use the force variants. // // The regular variants: // - Forwards all remaining gas to the target. // - Reverts if the target reverts. // - Reverts if the current contract has insufficient balance. // // The force variants: // - Forwards with an optional gas stipend // (defaults to `GAS_STIPEND_NO_GRIEF`, which is sufficient for most cases). // - If the target reverts, or if the gas stipend is exhausted, // creates a temporary contract to force send the ETH via `SELFDESTRUCT`. // Future compatible with `SENDALL`: https://eips.ethereum.org/EIPS/eip-4758. // - Reverts if the current contract has insufficient balance. // // The try variants: // - Forwards with a mandatory gas stipend. // - Instead of reverting, returns whether the transfer succeeded. /// @dev Sends `amount` (in wei) ETH to `to`. function safeTransferETH(address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { if iszero(call(gas(), to, amount, 0x00, 0x00, 0x00, 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Sends all the ETH in the current contract to `to`. function safeTransferAllETH(address to) internal { /// @solidity memory-safe-assembly assembly { // Transfer all the ETH and check if it succeeded or not. if iszero(call(gas(), to, selfbalance(), 0x00, 0x00, 0x00, 0x00)) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } } } /// @dev Force sends `amount` (in wei) ETH to `to`, with a `gasStipend`. /// If force transfer is used, returns the vault. Else returns `address(0)`. function forceSafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (address vault) { if (amount == uint256(0)) return address(0); // Early return if `amount` is zero. uint256 selfBalanceBefore = address(this).balance; /// @solidity memory-safe-assembly assembly { if lt(selfBalanceBefore, amount) { mstore(0x00, 0xb12d13eb) // `ETHTransferFailed()`. revert(0x1c, 0x04) } pop(call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00)) } if (address(this).balance == selfBalanceBefore) { vault = address(new SingleUseETHVault()); /// @solidity memory-safe-assembly assembly { mstore(0x00, shr(96, shl(96, to))) if iszero(call(gas(), vault, amount, 0x00, 0x20, 0x00, 0x00)) { revert(0x00, 0x00) } } emit SingleUseETHVaultCreated(to, amount, vault); } } /// @dev Force sends all the ETH in the current contract to `to`, with a `gasStipend`. /// If force transfer is used, returns the vault. Else returns `address(0)`. function forceSafeTransferAllETH(address to, uint256 gasStipend) internal returns (address vault) { vault = forceSafeTransferETH(to, address(this).balance, gasStipend); } /// @dev Force sends `amount` (in wei) ETH to `to`, with `GAS_STIPEND_NO_GRIEF`. /// If force transfer is used, returns the vault. Else returns `address(0)`. function forceSafeTransferETH(address to, uint256 amount) internal returns (address vault) { vault = forceSafeTransferETH(to, amount, GAS_STIPEND_NO_GRIEF); } /// @dev Force sends all the ETH in the current contract to `to`, with `GAS_STIPEND_NO_GRIEF`. /// If force transfer is used, returns the vault. Else returns `address(0)`. function forceSafeTransferAllETH(address to) internal returns (address vault) { vault = forceSafeTransferETH(to, address(this).balance, GAS_STIPEND_NO_GRIEF); } /// @dev Sends `amount` (in wei) ETH to `to`, with a `gasStipend`. function trySafeTransferETH(address to, uint256 amount, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, amount, 0x00, 0x00, 0x00, 0x00) } } /// @dev Sends all the ETH in the current contract to `to`, with a `gasStipend`. function trySafeTransferAllETH(address to, uint256 gasStipend) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { success := call(gasStipend, to, selfbalance(), 0x00, 0x00, 0x00, 0x00) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC20 OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have at least `amount` approved for /// the current contract to manage. function safeTransferFrom(address token, address from, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from `from` to `to`. /// /// The `from` account must have at least `amount` approved for the current contract to manage. function trySafeTransferFrom(address token, address from, address to, uint256 amount) internal returns (bool success) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x60, amount) // Store the `amount` argument. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x23b872dd000000000000000000000000) // `transferFrom(address,address,uint256)`. success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { success := lt(or(iszero(extcodesize(token)), returndatasize()), success) } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends all of ERC20 `token` from `from` to `to`. /// Reverts upon failure. /// /// The `from` account must have their entire balance approved for the current contract to manage. function safeTransferAllFrom(address token, address from, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x40, to) // Store the `to` argument. mstore(0x2c, shl(96, from)) // Store the `from` argument. mstore(0x0c, 0x70a08231000000000000000000000000) // `balanceOf(address)`. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x60, 0x20) ) ) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } mstore(0x00, 0x23b872dd) // `transferFrom(address,address,uint256)`. amount := mload(0x60) // The `amount` is already at 0x60. We'll need to return it. // Perform the transfer, reverting upon failure. let success := call(gas(), token, 0, 0x1c, 0x64, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x7939f424) // `TransferFromFailed()`. revert(0x1c, 0x04) } } mstore(0x60, 0) // Restore the zero slot to zero. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Sends `amount` of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransfer(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sends all of ERC20 `token` from the current contract to `to`. /// Reverts upon failure. function safeTransferAll(address token, address to) internal returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x70a08231) // Store the function selector of `balanceOf(address)`. mstore(0x20, address()) // Store the address of the current contract. // Read the balance, reverting upon failure. if iszero( and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x1c, 0x24, 0x34, 0x20) ) ) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } mstore(0x14, to) // Store the `to` argument. amount := mload(0x34) // The `amount` is already at 0x34. We'll need to return it. mstore(0x00, 0xa9059cbb000000000000000000000000) // `transfer(address,uint256)`. // Perform the transfer, reverting upon failure. let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x90b8ec18) // `TransferFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// Reverts upon failure. function safeApprove(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Sets `amount` of ERC20 `token` for `to` to manage on behalf of the current contract. /// If the initial attempt to approve fails, attempts to reset the approved amount to zero, /// then retries the approval again (some tokens, e.g. USDT, requires this). /// Reverts upon failure. function safeApproveWithRetry(address token, address to, uint256 amount) internal { /// @solidity memory-safe-assembly assembly { mstore(0x14, to) // Store the `to` argument. mstore(0x34, amount) // Store the `amount` argument. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. // Perform the approval, retrying upon failure. let success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x34, 0) // Store 0 for the `amount`. mstore(0x00, 0x095ea7b3000000000000000000000000) // `approve(address,uint256)`. pop(call(gas(), token, 0, 0x10, 0x44, 0x00, 0x00)) // Reset the approval. mstore(0x34, amount) // Store back the original `amount`. // Retry the approval, reverting upon failure. success := call(gas(), token, 0, 0x10, 0x44, 0x00, 0x20) if iszero(and(eq(mload(0x00), 1), success)) { // Check the `extcodesize` again just in case the token selfdestructs lol. if iszero(lt(or(iszero(extcodesize(token)), returndatasize()), success)) { mstore(0x00, 0x3e3f8f73) // `ApproveFailed()`. revert(0x1c, 0x04) } } } } mstore(0x34, 0) // Restore the part of the free memory pointer that was overwritten. } } /// @dev Returns the amount of ERC20 `token` owned by `account`. /// Returns zero if the `token` does not exist. function balanceOf(address token, address account) internal view returns (uint256 amount) { /// @solidity memory-safe-assembly assembly { mstore(0x14, account) // Store the `account` argument. mstore(0x00, 0x70a08231000000000000000000000000) // `balanceOf(address)`. amount := mul( // The arguments of `mul` are evaluated from right to left. mload(0x20), and( // The arguments of `and` are evaluated from right to left. gt(returndatasize(), 0x1f), // At least 32 bytes returned. staticcall(gas(), token, 0x10, 0x24, 0x20, 0x20) ) ) } } /// @dev Returns the total supply of the `token`. /// Reverts if the token does not exist or does not implement `totalSupply()`. function totalSupply(address token) internal view returns (uint256 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, 0x18160ddd) // `totalSupply()`. if iszero( and(gt(returndatasize(), 0x1f), staticcall(gas(), token, 0x1c, 0x04, 0x00, 0x20)) ) { mstore(0x00, 0x54cd9435) // `TotalSupplyQueryFailed()`. revert(0x1c, 0x04) } result := mload(0x00) } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import '../base/ERC721A.sol'; import {IERC721ABatchTransferable} from '../interfaces/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.3.0 // Creator: Chiru Labs pragma solidity ^0.8.4; import '../interfaces/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 pragma solidity ^0.8.4; import {ERC721ABurnable} from './ERC721ABurnable.sol'; import {IERC721ABatchBurnable} from '../interfaces/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 {IERC721AQueryable} from '../interfaces/IERC721AQueryable.sol'; import {ERC721A} from '../base/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 pragma solidity ^0.8.4; import {IERC4907A} from '../interfaces/IERC4907A.sol'; import {ERC721A, IERC721A} from '../base/ERC721A.sol'; /** * @title ERC4907A * * @dev [ERC4907](https://eips.ethereum.org/EIPS/eip-4907) compliant * extension of ERC721A, which allows owners and authorized addresses * to add a time-limited role with restricted permissions to ERC721 tokens. */ abstract contract ERC4907A is ERC721A, IERC4907A { // The bit position of `expires` in packed user info. uint256 private constant _BITPOS_EXPIRES = 160; // Mapping from token ID to user info. // // Bits Layout: // - [0..159] `user` // - [160..223] `expires` mapping(uint256 => uint256) private _packedUserInfo; /** * @dev Sets the `user` and `expires` for `tokenId`. * The zero address indicates there is no user. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function setUser( uint256 tokenId, address user, uint64 expires ) public virtual override { // Require the caller to be either the token owner or an approved operator. address owner = ownerOf(tokenId); if (_msgSenderERC721A() != owner) if (!isApprovedForAll(owner, _msgSenderERC721A())) if (getApproved(tokenId) != _msgSenderERC721A()) _revert(SetUserCallerNotOwnerNorApproved.selector); _packedUserInfo[tokenId] = (uint256(expires) << _BITPOS_EXPIRES) | uint256(uint160(user)); emit UpdateUser(tokenId, user, expires); } /** * @dev Returns the user address for `tokenId`. * The zero address indicates that there is no user or if the user is expired. */ function userOf(uint256 tokenId) public view virtual override returns (address) { uint256 packed = _packedUserInfo[tokenId]; assembly { // Branchless `packed *= (block.timestamp <= expires ? 1 : 0)`. // If the `block.timestamp == expires`, the `lt` clause will be true // if there is a non-zero user address in the lower 160 bits of `packed`. packed := mul( packed, // `block.timestamp <= expires ? 1 : 0`. lt(shl(_BITPOS_EXPIRES, timestamp()), packed) ) } return address(uint160(packed)); } /** * @dev Returns the user's expires of `tokenId`. */ function userExpires(uint256 tokenId) public view virtual override returns (uint256) { return _packedUserInfo[tokenId] >> _BITPOS_EXPIRES; } /** * @dev Override of {IERC165-supportsInterface}. */ function supportsInterface(bytes4 interfaceId) public view virtual override(ERC721A, IERC721A) returns (bool) { // The interface ID for ERC4907 is `0xad092b5c`, // as defined in [ERC4907](https://eips.ethereum.org/EIPS/eip-4907). return super.supportsInterface(interfaceId) || interfaceId == 0xad092b5c; } /** * @dev Returns the user address for `tokenId`, ignoring the expiry status. */ function _explicitUserOf(uint256 tokenId) internal view virtual returns (address) { return address(uint160(_packedUserInfo[tokenId])); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @dev Constant bytes32 value of 0x000...000 bytes32 constant ZERO_BYTES32 = bytes32(0); /// @dev Constant value of 0 uint256 constant ZERO = 0; /// @dev Constant value of 1 uint256 constant ONE = 1; /// @dev Constant value representing an open order in storage uint8 constant ORDER_STATE_OPEN = 0; /// @dev Constant value representing a filled order in storage uint8 constant ORDER_STATE_FILLED = 1; /// @dev Constant value representing a cancelled order in storage uint8 constant ORDER_STATE_CANCELLED = 2; /// @dev Constant value representing the ERC721 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC721 = 721; /// @dev Constant value representing the ERC1155 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC1155 = 1155; /// @dev Constant value representing the ERC20 token type for signatures and transfer hooks uint256 constant TOKEN_TYPE_ERC20 = 20; /// @dev Constant value to mask the upper bits of a signature that uses a packed `vs` value to extract `s` bytes32 constant UPPER_BIT_MASK = 0x7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; /// @dev EIP-712 typehash used for validating signature based stored approvals bytes32 constant UPDATE_APPROVAL_TYPEHASH = keccak256("UpdateApprovalBySignature(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 approvalExpiration,uint256 sigDeadline,uint256 masterNonce)"); /// @dev EIP-712 typehash used for validating a single use permit without additional data bytes32 constant SINGLE_USE_PERMIT_TYPEHASH = keccak256("PermitTransferFrom(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce)"); /// @dev EIP-712 typehash used for validating a single use permit with additional data string constant SINGLE_USE_PERMIT_TRANSFER_ADVANCED_TYPEHASH_STUB = "PermitTransferFromWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 nonce,address operator,uint256 expiration,uint256 masterNonce,"; /// @dev EIP-712 typehash used for validating an order permit that updates storage as it fills string constant PERMIT_ORDER_ADVANCED_TYPEHASH_STUB = "PermitOrderWithAdditionalData(uint256 tokenType,address token,uint256 id,uint256 amount,uint256 salt,address operator,uint256 expiration,uint256 masterNonce,"; /// @dev Pausable flag for stored approval transfers of ERC721 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC721 = 1 << 0; /// @dev Pausable flag for stored approval transfers of ERC1155 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC1155 = 1 << 1; /// @dev Pausable flag for stored approval transfers of ERC20 assets uint256 constant PAUSABLE_APPROVAL_TRANSFER_FROM_ERC20 = 1 << 2; /// @dev Pausable flag for single use permit transfers of ERC721 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC721 = 1 << 3; /// @dev Pausable flag for single use permit transfers of ERC1155 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC1155 = 1 << 4; /// @dev Pausable flag for single use permit transfers of ERC20 assets uint256 constant PAUSABLE_PERMITTED_TRANSFER_FROM_ERC20 = 1 << 5; /// @dev Pausable flag for order fill transfers of ERC1155 assets uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC1155 = 1 << 6; /// @dev Pausable flag for order fill transfers of ERC20 assets uint256 constant PAUSABLE_ORDER_TRANSFER_FROM_ERC20 = 1 << 7;
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "../access/OwnablePermissions.sol"; import "../interfaces/ICreatorToken.sol"; import "../interfaces/ICreatorTokenLegacy.sol"; import "../interfaces/ITransferValidator.sol"; import "./TransferValidation.sol"; import "../interfaces/ITransferValidatorSetTokenType.sol"; /** * @title CreatorTokenBase * @author Limit Break, Inc. * @notice CreatorTokenBaseV3 is an abstract contract that provides basic functionality for managing token * transfer policies through an implementation of ICreatorTokenTransferValidator/ICreatorTokenTransferValidatorV2/ICreatorTokenTransferValidatorV3. * This contract is intended to be used as a base for creator-specific token contracts, enabling customizable transfer * restrictions and security policies. * * <h4>Features:</h4> * <ul>Ownable: This contract can have an owner who can set and update the transfer validator.</ul> * <ul>TransferValidation: Implements the basic token transfer validation interface.</ul> * * <h4>Benefits:</h4> * <ul>Provides a flexible and modular way to implement custom token transfer restrictions and security policies.</ul> * <ul>Allows creators to enforce policies such as account and codehash blacklists, whitelists, and graylists.</ul> * <ul>Can be easily integrated into other token contracts as a base contract.</ul> * * <h4>Intended Usage:</h4> * <ul>Use as a base contract for creator token implementations that require advanced transfer restrictions and * security policies.</ul> * <ul>Set and update the ICreatorTokenTransferValidator implementation contract to enforce desired policies for the * creator token.</ul> * * <h4>Compatibility:</h4> * <ul>Backward and Forward Compatible - V1/V2/V3 Creator Token Base will work with V1/V2/V3 Transfer Validators.</ul> */ abstract contract CreatorTokenBase is OwnablePermissions, TransferValidation, ICreatorToken { /// @dev Thrown when setting a transfer validator address that has no deployed code. error CreatorTokenBase__InvalidTransferValidatorContract(); /// @dev The default transfer validator that will be used if no transfer validator has been set by the creator. address public constant DEFAULT_TRANSFER_VALIDATOR = address(0x721C002B0059009a671D00aD1700c9748146cd1B); /// @dev Used to determine if the default transfer validator is applied. /// @dev Set to true when the creator sets a transfer validator address. bool private isValidatorInitialized; /// @dev Address of the transfer validator to apply to transactions. address private transferValidator; constructor() { _emitDefaultTransferValidator(); _registerTokenType(DEFAULT_TRANSFER_VALIDATOR); } /** * @notice Sets the transfer validator for the token contract. * * @dev Throws when provided validator contract is not the zero address and does not have code. * @dev Throws when the caller is not the contract owner. * * @dev <h4>Postconditions:</h4> * 1. The transferValidator address is updated. * 2. The `TransferValidatorUpdated` event is emitted. * * @param transferValidator_ The address of the transfer validator contract. */ function setTransferValidator(address transferValidator_) public { _requireCallerIsContractOwner(); bool isValidTransferValidator = transferValidator_.code.length > 0; if(transferValidator_ != address(0) && !isValidTransferValidator) { revert CreatorTokenBase__InvalidTransferValidatorContract(); } emit TransferValidatorUpdated(address(getTransferValidator()), transferValidator_); isValidatorInitialized = true; transferValidator = transferValidator_; _registerTokenType(transferValidator_); } /** * @notice Returns the transfer validator contract address for this token contract. */ function getTransferValidator() public view override returns (address validator) { validator = transferValidator; if (validator == address(0)) { if (!isValidatorInitialized) { validator = DEFAULT_TRANSFER_VALIDATOR; } } } /** * @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy. * Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent * and calling _validateBeforeTransfer so that checks can be properly applied during token transfers. * * @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the * transfer validator is expected to pre-validate the transfer. * * @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is * set to a non-zero address. * * @param caller The address of the caller. * @param from The address of the sender. * @param to The address of the receiver. * @param tokenId The token id being transferred. */ function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 /*value*/) internal virtual override { address validator = getTransferValidator(); if (validator != address(0)) { if (msg.sender == validator) { return; } ITransferValidator(validator).validateTransfer(caller, from, to, tokenId); } } /** * @dev Pre-validates a token transfer, reverting if the transfer is not allowed by this token's security policy. * Inheriting contracts are responsible for overriding the _beforeTokenTransfer function, or its equivalent * and calling _validateBeforeTransfer so that checks can be properly applied during token transfers. * * @dev Be aware that if the msg.sender is the transfer validator, the transfer is automatically permitted, as the * transfer validator is expected to pre-validate the transfer. * * @dev Used for ERC20 and ERC1155 token transfers which have an amount value to validate in the transfer validator. * @dev The `tokenId` for ERC20 tokens should be set to `0`. * * @dev Throws when the transfer doesn't comply with the collection's transfer policy, if the transferValidator is * set to a non-zero address. * * @param caller The address of the caller. * @param from The address of the sender. * @param to The address of the receiver. * @param tokenId The token id being transferred. * @param amount The amount of token being transferred. */ function _preValidateTransfer( address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 /*value*/) internal virtual override { address validator = getTransferValidator(); if (validator != address(0)) { if (msg.sender == validator) { return; } ITransferValidator(validator).validateTransfer(caller, from, to, tokenId, amount); } } function _tokenType() internal virtual pure returns(uint16); function _registerTokenType(address validator) internal { if (validator != address(0)) { uint256 validatorCodeSize; assembly { validatorCodeSize := extcodesize(validator) } if(validatorCodeSize > 0) { try ITransferValidatorSetTokenType(validator).setTokenTypeOfCollection(address(this), _tokenType()) { } catch { } } } } /** * @dev Used during contract deployment for constructable and cloneable creator tokens * @dev to emit the `TransferValidatorUpdated` event signaling the validator for the contract * @dev is the default transfer validator. */ function _emitDefaultTransferValidator() internal { emit TransferValidatorUpdated(address(0), DEFAULT_TRANSFER_VALIDATOR); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "../access/OwnablePermissions.sol"; /** * @title AutomaticValidatorTransferApproval * @author Limit Break, Inc. * @notice Base contract mix-in that provides boilerplate code giving the contract owner the * option to automatically approve a 721-C transfer validator implementation for transfers. */ abstract contract AutomaticValidatorTransferApproval is OwnablePermissions { /// @dev Emitted when the automatic approval flag is modified by the creator. event AutomaticApprovalOfTransferValidatorSet(bool autoApproved); /// @dev If true, the collection's transfer validator is automatically approved to transfer holder's tokens. bool public autoApproveTransfersFromValidator; /** * @notice Sets if the transfer validator is automatically approved as an operator for all token owners. * * @dev Throws when the caller is not the contract owner. * * @param autoApprove If true, the collection's transfer validator will be automatically approved to * transfer holder's tokens. */ function setAutomaticApprovalOfTransfersFromValidator(bool autoApprove) external { _requireCallerIsContractOwner(); autoApproveTransfersFromValidator = autoApprove; emit AutomaticApprovalOfTransferValidatorSet(autoApprove); } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {IERC721A} from './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 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 pragma solidity ^0.8.4; import {IERC721ABurnable} from '../interfaces/IERC721ABurnable.sol'; import {ERC721A} from '../base/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 pragma solidity ^0.8.4; import {IERC721ABurnable} from './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; import {IERC721A} from './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 pragma solidity ^0.8.4; import {IERC721A} from './IERC721A.sol'; /** * @dev Interface of ERC4907A. */ interface IERC4907A is IERC721A { /** * The caller must own the token or be an approved operator. */ error SetUserCallerNotOwnerNorApproved(); /** * @dev Emitted when the `user` of an NFT or the `expires` of the `user` is changed. * The zero address for user indicates that there is no user address. */ event UpdateUser(uint256 indexed tokenId, address indexed user, uint64 expires); /** * @dev Sets the `user` and `expires` for `tokenId`. * The zero address indicates there is no user. * * Requirements: * * - The caller must own `tokenId` or be an approved operator. */ function setUser( uint256 tokenId, address user, uint64 expires ) external; /** * @dev Returns the user address for `tokenId`. * The zero address indicates that there is no user or if the user is expired. */ function userOf(uint256 tokenId) external view returns (address); /** * @dev Returns the user's expires of `tokenId`. */ function userExpires(uint256 tokenId) external view returns (uint256); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Library for byte related operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibBytes.sol) library LibBytes { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STRUCTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Goated bytes storage struct that totally MOGs, no cap, fr. /// Uses less gas and bytecode than Solidity's native bytes storage. It's meta af. /// Packs length with the first 31 bytes if <255 bytes, so it’s mad tight. struct BytesStorage { bytes32 _spacer; } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the bytes. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STORAGE OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Sets the value of the bytes storage `$` to `s`. function set(BytesStorage storage $, bytes memory s) internal { /// @solidity memory-safe-assembly assembly { let n := mload(s) let packed := or(0xff, shl(8, n)) for { let i := 0 } 1 {} { if iszero(gt(n, 0xfe)) { i := 0x1f packed := or(n, shl(8, mload(add(s, i)))) if iszero(gt(n, i)) { break } } let o := add(s, 0x20) mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), mload(add(o, i))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to `s`. function setCalldata(BytesStorage storage $, bytes calldata s) internal { /// @solidity memory-safe-assembly assembly { let packed := or(0xff, shl(8, s.length)) for { let i := 0 } 1 {} { if iszero(gt(s.length, 0xfe)) { i := 0x1f packed := or(s.length, shl(8, shr(8, calldataload(s.offset)))) if iszero(gt(s.length, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { sstore(add(p, shr(5, i)), calldataload(add(s.offset, i))) i := add(i, 0x20) if iszero(lt(i, s.length)) { break } } break } sstore($.slot, packed) } } /// @dev Sets the value of the bytes storage `$` to the empty bytes. function clear(BytesStorage storage $) internal { delete $._spacer; } /// @dev Returns whether the value stored is `$` is the empty bytes "". function isEmpty(BytesStorage storage $) internal view returns (bool) { return uint256($._spacer) & 0xff == uint256(0); } /// @dev Returns the length of the value stored in `$`. function length(BytesStorage storage $) internal view returns (uint256 result) { result = uint256($._spacer); /// @solidity memory-safe-assembly assembly { let n := and(0xff, result) result := or(mul(shr(8, result), eq(0xff, n)), mul(n, iszero(eq(0xff, n)))) } } /// @dev Returns the value stored in `$`. function get(BytesStorage storage $) internal view returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let o := add(result, 0x20) let packed := sload($.slot) let n := shr(8, packed) for { let i := 0 } 1 {} { if iszero(eq(or(packed, 0xff), packed)) { mstore(o, packed) n := and(0xff, packed) i := 0x1f if iszero(gt(n, i)) { break } } mstore(0x00, $.slot) for { let p := keccak256(0x00, 0x20) } 1 {} { mstore(add(o, i), sload(add(p, shr(5, i)))) i := add(i, 0x20) if iszero(lt(i, n)) { break } } break } mstore(result, n) // Store the length of the memory. mstore(add(o, n), 0) // Zeroize the slot after the bytes. mstore(0x40, add(add(o, n), 0x20)) // Allocate memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTES OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns `subject` all occurrences of `needle` replaced with `replacement`. function replace(bytes memory subject, bytes memory needle, bytes memory replacement) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let needleLen := mload(needle) let replacementLen := mload(replacement) let d := sub(result, subject) // Memory difference. let i := add(subject, 0x20) // Subject bytes pointer. mstore(0x00, add(i, mload(subject))) // End of subject. if iszero(gt(needleLen, mload(subject))) { let subjectSearchEnd := add(sub(mload(0x00), needleLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(needleLen, 0x20)) { h := keccak256(add(needle, 0x20), needleLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(needleLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `needleLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, needleLen), h)) { mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let j := 0 } 1 {} { mstore(add(add(i, d), j), mload(add(add(replacement, 0x20), j))) j := add(j, 0x20) if iszero(lt(j, replacementLen)) { break } } d := sub(add(d, replacementLen), needleLen) if needleLen { i := add(i, needleLen) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(add(i, d), t) i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } } let end := mload(0x00) let n := add(sub(d, add(result, 0x20)), end) // Copy the rest of the bytes one word at a time. for {} lt(i, end) { i := add(i, 0x20) } { mstore(add(i, d), mload(i)) } let o := add(i, d) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { result := not(0) // Initialize to `NOT_FOUND`. for { let subjectLen := mload(subject) } 1 {} { if iszero(mload(needle)) { result := from if iszero(gt(from, subjectLen)) { break } result := subjectLen break } let needleLen := mload(needle) let subjectStart := add(subject, 0x20) subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLen), needleLen), 1) let m := shl(3, sub(0x20, and(needleLen, 0x1f))) let s := mload(add(needle, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLen))) { break } if iszero(lt(needleLen, 0x20)) { for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, needleLen), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function indexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return indexOf(subject, needle, 0); } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let needleLen := mload(needle) if gt(needleLen, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), needleLen) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(needle, 0x20), needleLen) } 1 {} { if eq(keccak256(subject, needleLen), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `needle` in `subject`, /// needleing from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `needle` is not found. function lastIndexOf(bytes memory subject, bytes memory needle) internal pure returns (uint256) { return lastIndexOf(subject, needle, type(uint256).max); } /// @dev Returns true if `needle` is found in `subject`, false otherwise. function contains(bytes memory subject, bytes memory needle) internal pure returns (bool) { return indexOf(subject, needle) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `needle`. function startsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) // Just using keccak256 directly is actually cheaper. let t := eq(keccak256(add(subject, 0x20), n), keccak256(add(needle, 0x20), n)) result := lt(gt(n, mload(subject)), t) } } /// @dev Returns whether `subject` ends with `needle`. function endsWith(bytes memory subject, bytes memory needle) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let n := mload(needle) let notInRange := gt(n, mload(subject)) // `subject + 0x20 + max(subject.length - needle.length, 0)`. let t := add(add(subject, 0x20), mul(iszero(notInRange), sub(mload(subject), n))) // Just using keccak256 directly is actually cheaper. result := gt(eq(keccak256(t, n), keccak256(add(needle, 0x20), n)), notInRange) } } /// @dev Returns `subject` repeated `times`. function repeat(bytes memory subject, uint256 times) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(or(iszero(times), iszero(l))) { result := mload(0x40) subject := add(subject, 0x20) let o := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let j := 0 } 1 {} { mstore(add(o, j), mload(add(subject, j))) j := add(j, 0x20) if iszero(lt(j, l)) { break } } o := add(o, l) times := sub(times, 1) if iszero(times) { break } } mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, sub(o, add(result, 0x20))) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(bytes memory subject, uint256 start, uint256 end) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { let l := mload(subject) // Subject length. if iszero(gt(l, end)) { end := l } if iszero(gt(l, start)) { start := l } if lt(start, end) { result := mload(0x40) let n := sub(end, start) let i := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let j := and(add(n, 0x1f), w) } 1 {} { mstore(add(result, j), mload(add(i, j))) j := add(j, w) // `sub(j, 0x20)`. if iszero(j) { break } } let o := add(add(result, 0x20), n) mstore(o, 0) // Zeroize the slot after the bytes. mstore(0x40, add(o, 0x20)) // Allocate memory. mstore(result, n) // Store the length. } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. function slice(bytes memory subject, uint256 start) internal pure returns (bytes memory result) { result = slice(subject, start, type(uint256).max); } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start, uint256 end) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { end := xor(end, mul(xor(end, subject.length), lt(subject.length, end))) start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, end), sub(end, start)) } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the bytes. /// `start` is a byte offset. Faster than Solidity's native slicing. function sliceCalldata(bytes calldata subject, uint256 start) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { start := xor(start, mul(xor(start, subject.length), lt(subject.length, start))) result.offset := add(subject.offset, start) result.length := mul(lt(start, subject.length), sub(subject.length, start)) } } /// @dev Reduces the size of `subject` to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncate(bytes memory subject, uint256 n) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := subject mstore(mul(lt(n, mload(result)), result), n) } } /// @dev Returns a copy of `subject`, with the length reduced to `n`. /// If `n` is greater than the size of `subject`, this will be a no-op. function truncatedCalldata(bytes calldata subject, uint256 n) internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.offset := subject.offset result.length := xor(n, mul(xor(n, subject.length), lt(subject.length, n))) } } /// @dev Returns all the indices of `needle` in `subject`. /// The indices are byte offsets. function indicesOf(bytes memory subject, bytes memory needle) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let searchLen := mload(needle) if iszero(gt(searchLen, mload(subject))) { result := mload(0x40) let i := add(subject, 0x20) let o := add(result, 0x20) let subjectSearchEnd := add(sub(add(i, mload(subject)), searchLen), 1) let h := 0 // The hash of `needle`. if iszero(lt(searchLen, 0x20)) { h := keccak256(add(needle, 0x20), searchLen) } let s := mload(add(needle, 0x20)) for { let m := shl(3, sub(0x20, and(searchLen, 0x1f))) } 1 {} { let t := mload(i) // Whether the first `searchLen % 32` bytes of `subject` and `needle` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(i, searchLen), h)) { i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } continue } } mstore(o, sub(i, add(subject, 0x20))) // Append to `result`. o := add(o, 0x20) i := add(i, searchLen) // Advance `i` by `searchLen`. if searchLen { if iszero(lt(i, subjectSearchEnd)) { break } continue } } i := add(i, 1) if iszero(lt(i, subjectSearchEnd)) { break } } mstore(result, shr(5, sub(o, add(result, 0x20)))) // Store the length of `result`. // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(o, 0x20)) } } } /// @dev Returns a arrays of bytess based on the `delimiter` inside of the `subject` bytes. function split(bytes memory subject, bytes memory delimiter) internal pure returns (bytes[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) for { let prevIndex := 0 } 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let l := sub(index, prevIndex) mstore(element, l) // Store the length of the element. // Copy the `subject` one word at a time, backwards. for { let o := and(add(l, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } mstore(add(add(element, 0x20), l), 0) // Zeroize the slot after the bytes. // Allocate memory for the length and the bytes, rounded up to a multiple of 32. mstore(0x40, add(element, and(add(l, 0x3f), w))) mstore(indexPtr, element) // Store the `element` into the array. } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated bytes of `a` and `b`. /// Cheaper than `bytes.concat()` and does not de-align the free memory pointer. function concat(bytes memory a, bytes memory b) internal pure returns (bytes memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let w := not(0x1f) let aLen := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLen, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLen := mload(b) let output := add(result, aLen) // Copy `b` one word at a time, backwards. for { let o := and(add(bLen, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLen := add(aLen, bLen) let last := add(add(result, 0x20), totalLen) mstore(last, 0) // Zeroize the slot after the bytes. mstore(result, totalLen) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate memory. } } /// @dev Returns whether `a` equals `b`. function eq(bytes memory a, bytes memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small bytes. function eqs(bytes memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Returns 0 if `a == b`, -1 if `a < b`, +1 if `a > b`. /// If `a` == b[:a.length]`, and `a.length < b.length`, returns -1. function cmp(bytes memory a, bytes memory b) internal pure returns (int256 result) { /// @solidity memory-safe-assembly assembly { let aLen := mload(a) let bLen := mload(b) let n := and(xor(aLen, mul(xor(aLen, bLen), lt(bLen, aLen))), not(0x1f)) if n { for { let i := 0x20 } 1 {} { let x := mload(add(a, i)) let y := mload(add(b, i)) if iszero(or(xor(x, y), eq(i, n))) { i := add(i, 0x20) continue } result := sub(gt(x, y), lt(x, y)) break } } // forgefmt: disable-next-item if iszero(result) { let l := 0x201f1e1d1c1b1a191817161514131211100f0e0d0c0b0a090807060504030201 let x := and(mload(add(add(a, 0x20), n)), shl(shl(3, byte(sub(aLen, n), l)), not(0))) let y := and(mload(add(add(b, 0x20), n)), shl(shl(3, byte(sub(bLen, n), l)), not(0))) result := sub(gt(x, y), lt(x, y)) if iszero(result) { result := sub(gt(aLen, bLen), lt(aLen, bLen)) } } } } /// @dev Directly returns `a` without copying. function directReturn(bytes memory a) internal pure { assembly { // Assumes that the bytes does not start from the scratch space. let retStart := sub(a, 0x20) let retUnpaddedSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the bytes is produced // by a method that doesn't zero right pad. mstore(add(retStart, retUnpaddedSize), 0) mstore(retStart, 0x20) // Store the return offset. // End the transaction, returning the bytes. return(retStart, and(not(0x1f), add(0x1f, retUnpaddedSize))) } } /// @dev Directly returns `a` with minimal copying. function directReturn(bytes[] memory a) internal pure { assembly { let n := mload(a) // `a.length`. let o := add(a, 0x20) // Start of elements in `a`. let u := a // Highest memory slot. let w := not(0x1f) for { let i := 0 } iszero(eq(i, n)) { i := add(i, 1) } { let c := add(o, shl(5, i)) // Location of pointer to `a[i]`. let s := mload(c) // `a[i]`. let l := mload(s) // `a[i].length`. let r := and(l, 0x1f) // `a[i].length % 32`. let z := add(0x20, and(l, w)) // Offset of last word in `a[i]` from `s`. // If `s` comes before `o`, or `s` is not zero right padded. if iszero(lt(lt(s, o), or(iszero(r), iszero(shl(shl(3, r), mload(add(s, z))))))) { let m := mload(0x40) mstore(m, l) // Copy `a[i].length`. for {} 1 {} { mstore(add(m, z), mload(add(s, z))) // Copy `a[i]`, backwards. z := add(z, w) // `sub(z, 0x20)`. if iszero(z) { break } } let e := add(add(m, 0x20), l) mstore(e, 0) // Zeroize the slot after the copied bytes. mstore(0x40, add(e, 0x20)) // Allocate memory. s := m } mstore(c, sub(s, o)) // Convert to calldata offset. let t := add(l, add(s, 0x20)) if iszero(lt(t, u)) { u := t } } let retStart := add(a, w) // Assumes `a` doesn't start from scratch space. mstore(retStart, 0x20) // Store the return offset. return(retStart, add(0x40, sub(u, retStart))) // End the transaction. } } /// @dev Returns the word at `offset`, without any bounds checks. /// To load an address, you can use `address(bytes20(load(a, offset)))`. function load(bytes memory a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(add(add(a, 0x20), offset)) } } /// @dev Returns the word at `offset`, without any bounds checks. /// To load an address, you can use `address(bytes20(loadCalldata(a, offset)))`. function loadCalldata(bytes calldata a, uint256 offset) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := calldataload(add(a.offset, offset)) } } /// @dev Returns empty calldata bytes. For silencing the compiler. function emptyCalldata() internal pure returns (bytes calldata result) { /// @solidity memory-safe-assembly assembly { result.length := 0 } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.5.0) (interfaces/draft-IERC1822.sol) pragma solidity ^0.8.0; /** * @dev ERC1822: Universal Upgradeable Proxy Standard (UUPS) documents a method for upgradeability through a simplified * proxy whose upgrades are fully controlled by the current implementation. */ interface IERC1822Proxiable { /** * @dev Returns the storage slot that the proxiable contract assumes is being used to store the implementation * address. * * IMPORTANT: A proxy pointing at a proxiable contract should not be considered proxiable itself, because this risks * bricking a proxy that upgrades to it, by delegating to itself until out of gas. Thus it is critical that this * function revert if invoked through a proxy. */ function proxiableUUID() external view returns (bytes32); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (proxy/ERC1967/ERC1967Upgrade.sol) pragma solidity ^0.8.2; import "../beacon/IBeacon.sol"; import "../../interfaces/IERC1967.sol"; import "../../interfaces/draft-IERC1822.sol"; import "../../utils/Address.sol"; import "../../utils/StorageSlot.sol"; /** * @dev This abstract contract provides getters and event emitting update functions for * https://eips.ethereum.org/EIPS/eip-1967[EIP1967] slots. * * _Available since v4.1._ * * @custom:oz-upgrades-unsafe-allow delegatecall */ abstract contract ERC1967Upgrade is IERC1967 { // This is the keccak-256 hash of "eip1967.proxy.rollback" subtracted by 1 bytes32 private constant _ROLLBACK_SLOT = 0x4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd9143; /** * @dev Storage slot with the address of the current implementation. * This is the keccak-256 hash of "eip1967.proxy.implementation" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; /** * @dev Returns the current implementation address. */ function _getImplementation() internal view returns (address) { return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; } /** * @dev Stores a new address in the EIP1967 implementation slot. */ function _setImplementation(address newImplementation) private { require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; } /** * @dev Perform implementation upgrade * * Emits an {Upgraded} event. */ function _upgradeTo(address newImplementation) internal { _setImplementation(newImplementation); emit Upgraded(newImplementation); } /** * @dev Perform implementation upgrade with additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCall( address newImplementation, bytes memory data, bool forceCall ) internal { _upgradeTo(newImplementation); if (data.length > 0 || forceCall) { Address.functionDelegateCall(newImplementation, data); } } /** * @dev Perform implementation upgrade with security checks for UUPS proxies, and additional setup call. * * Emits an {Upgraded} event. */ function _upgradeToAndCallUUPS( address newImplementation, bytes memory data, bool forceCall ) internal { // Upgrades from old implementations will perform a rollback test. This test requires the new // implementation to upgrade back to the old, non-ERC1822 compliant, implementation. Removing // this special case will break upgrade paths from old UUPS implementation to new ones. if (StorageSlot.getBooleanSlot(_ROLLBACK_SLOT).value) { _setImplementation(newImplementation); } else { try IERC1822Proxiable(newImplementation).proxiableUUID() returns (bytes32 slot) { require(slot == _IMPLEMENTATION_SLOT, "ERC1967Upgrade: unsupported proxiableUUID"); } catch { revert("ERC1967Upgrade: new implementation is not UUPS"); } _upgradeToAndCall(newImplementation, data, forceCall); } } /** * @dev Storage slot with the admin of the contract. * This is the keccak-256 hash of "eip1967.proxy.admin" subtracted by 1, and is * validated in the constructor. */ bytes32 internal constant _ADMIN_SLOT = 0xb53127684a568b3173ae13b9f8a6016e243e63b6e8ee1178d6a717850b5d6103; /** * @dev Returns the current admin. */ function _getAdmin() internal view returns (address) { return StorageSlot.getAddressSlot(_ADMIN_SLOT).value; } /** * @dev Stores a new address in the EIP1967 admin slot. */ function _setAdmin(address newAdmin) private { require(newAdmin != address(0), "ERC1967: new admin is the zero address"); StorageSlot.getAddressSlot(_ADMIN_SLOT).value = newAdmin; } /** * @dev Changes the admin of the proxy. * * Emits an {AdminChanged} event. */ function _changeAdmin(address newAdmin) internal { emit AdminChanged(_getAdmin(), newAdmin); _setAdmin(newAdmin); } /** * @dev The storage slot of the UpgradeableBeacon contract which defines the implementation for this proxy. * This is bytes32(uint256(keccak256('eip1967.proxy.beacon')) - 1)) and is validated in the constructor. */ bytes32 internal constant _BEACON_SLOT = 0xa3f0ad74e5423aebfd80d3ef4346578335a9a72aeaee59ff6cb3582b35133d50; /** * @dev Returns the current beacon. */ function _getBeacon() internal view returns (address) { return StorageSlot.getAddressSlot(_BEACON_SLOT).value; } /** * @dev Stores a new beacon in the EIP1967 beacon slot. */ function _setBeacon(address newBeacon) private { require(Address.isContract(newBeacon), "ERC1967: new beacon is not a contract"); require( Address.isContract(IBeacon(newBeacon).implementation()), "ERC1967: beacon implementation is not a contract" ); StorageSlot.getAddressSlot(_BEACON_SLOT).value = newBeacon; } /** * @dev Perform beacon upgrade with additional setup call. Note: This upgrades the address of the beacon, it does * not upgrade the implementation contained in the beacon (see {UpgradeableBeacon-_setImplementation} for that). * * Emits a {BeaconUpgraded} event. */ function _upgradeBeaconToAndCall( address newBeacon, bytes memory data, bool forceCall ) internal { _setBeacon(newBeacon); emit BeaconUpgraded(newBeacon); if (data.length > 0 || forceCall) { Address.functionDelegateCall(IBeacon(newBeacon).implementation(), data); } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice A single-use vault that allows a designated caller to withdraw all ETH in it. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ext/zksync/SingleUseETHVault.sol) contract SingleUseETHVault { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Unable to withdraw all. error WithdrawAllFailed(); /// @dev Not authorized. error Unauthorized(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* WITHDRAW ALL */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ fallback() external payable virtual { /// @solidity memory-safe-assembly assembly { mstore(0x40, 0) // Optimization trick to remove free memory pointer initialization. let owner := sload(0) // Initialization. if iszero(owner) { sstore(0, calldataload(0x00)) // Store the owner. return(0x00, 0x00) // Early return. } // Authorization check. if iszero(eq(caller(), owner)) { mstore(0x00, 0x82b42900) // `Unauthorized()`. revert(0x1c, 0x04) } let to := calldataload(0x00) // If the calldata is less than 32 bytes, zero-left-pad it to 32 bytes. // Then use the rightmost 20 bytes of the word as the `to` address. // This allows for the calldata to be `abi.encode(to)` or `abi.encodePacked(to)`. to := shr(mul(lt(calldatasize(), 0x20), shl(3, sub(0x20, calldatasize()))), to) // If `to` is `address(0)`, set it to `msg.sender`. to := xor(mul(xor(to, caller()), iszero(to)), to) // Transfers the whole balance to `to`. if iszero(call(gas(), to, selfbalance(), 0x00, 0x00, 0x00, 0x00)) { mstore(0x00, 0x651aee10) // `WithdrawAllFailed()`. revert(0x1c, 0x04) } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import {IERC721A} from './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; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ICreatorToken { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; function getTransferValidationFunction() external view returns (bytes4 functionSignature, bool isViewFunction); }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/utils/Context.sol"; abstract contract OwnablePermissions is Context { function _requireCallerIsContractOwner() internal view virtual; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidatorSetTokenType { function setTokenTypeOfCollection(address collection, uint16 tokenType) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ITransferValidator { function applyCollectionTransferPolicy(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId) external view; function validateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount) external; function beforeAuthorizedTransfer(address operator, address token, uint256 tokenId) external; function afterAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransfer(address operator, address token) external; function afterAuthorizedTransfer(address token) external; function beforeAuthorizedTransfer(address token, uint256 tokenId) external; function beforeAuthorizedTransferWithAmount(address token, uint256 tokenId, uint256 amount) external; function afterAuthorizedTransferWithAmount(address token, uint256 tokenId) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; interface ICreatorTokenLegacy { event TransferValidatorUpdated(address oldValidator, address newValidator); function getTransferValidator() external view returns (address validator); function setTransferValidator(address validator) external; }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; import "@openzeppelin/contracts/utils/Context.sol"; /** * @title TransferValidation * @author Limit Break, Inc. * @notice A mix-in that can be combined with ERC-721 contracts to provide more granular hooks. * Openzeppelin's ERC721 contract only provides hooks for before and after transfer. This allows * developers to validate or customize transfers within the context of a mint, a burn, or a transfer. */ abstract contract TransferValidation is Context { /// @dev Thrown when the from and to address are both the zero address. error ShouldNotMintToBurnAddress(); /*************************************************************************/ /* Transfers Without Amounts */ /*************************************************************************/ /// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks. function _validateBeforeTransfer(address from, address to, uint256 tokenId) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if(fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if(fromZeroAddress) { _preValidateMint(_msgSender(), to, tokenId, msg.value); } else if(toZeroAddress) { _preValidateBurn(_msgSender(), from, tokenId, msg.value); } else { _preValidateTransfer(_msgSender(), from, to, tokenId, msg.value); } } /// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks. function _validateAfterTransfer(address from, address to, uint256 tokenId) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if(fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if(fromZeroAddress) { _postValidateMint(_msgSender(), to, tokenId, msg.value); } else if(toZeroAddress) { _postValidateBurn(_msgSender(), from, tokenId, msg.value); } else { _postValidateTransfer(_msgSender(), from, to, tokenId, msg.value); } } /// @dev Optional validation hook that fires before a mint function _preValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a mint function _postValidateMint(address caller, address to, uint256 tokenId, uint256 value) internal virtual {} /// @dev Optional validation hook that fires before a burn function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a burn function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 value) internal virtual {} /// @dev Optional validation hook that fires before a transfer function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a transfer function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 value) internal virtual {} /*************************************************************************/ /* Transfers With Amounts */ /*************************************************************************/ /// @dev Inheriting contracts should call this function in the _beforeTokenTransfer function to get more granular hooks. function _validateBeforeTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if(fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if(fromZeroAddress) { _preValidateMint(_msgSender(), to, tokenId, amount, msg.value); } else if(toZeroAddress) { _preValidateBurn(_msgSender(), from, tokenId, amount, msg.value); } else { _preValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value); } } /// @dev Inheriting contracts should call this function in the _afterTokenTransfer function to get more granular hooks. function _validateAfterTransfer(address from, address to, uint256 tokenId, uint256 amount) internal virtual { bool fromZeroAddress = from == address(0); bool toZeroAddress = to == address(0); if(fromZeroAddress && toZeroAddress) { revert ShouldNotMintToBurnAddress(); } else if(fromZeroAddress) { _postValidateMint(_msgSender(), to, tokenId, amount, msg.value); } else if(toZeroAddress) { _postValidateBurn(_msgSender(), from, tokenId, amount, msg.value); } else { _postValidateTransfer(_msgSender(), from, to, tokenId, amount, msg.value); } } /// @dev Optional validation hook that fires before a mint function _preValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a mint function _postValidateMint(address caller, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} /// @dev Optional validation hook that fires before a burn function _preValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a burn function _postValidateBurn(address caller, address from, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} /// @dev Optional validation hook that fires before a transfer function _preValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} /// @dev Optional validation hook that fires after a transfer function _postValidateTransfer(address caller, address from, address to, uint256 tokenId, uint256 amount, uint256 value) internal virtual {} }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.3) (interfaces/IERC1967.sol) pragma solidity ^0.8.0; /** * @dev ERC-1967: Proxy Storage Slots. This interface contains the events defined in the ERC. * * _Available since v4.9._ */ interface IERC1967 { /** * @dev Emitted when the implementation is upgraded. */ event Upgraded(address indexed implementation); /** * @dev Emitted when the admin account has changed. */ event AdminChanged(address previousAdmin, address newAdmin); /** * @dev Emitted when the beacon is changed. */ event BeaconUpgraded(address indexed beacon); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.8.0) (utils/Address.sol) pragma solidity ^0.8.1; /** * @dev Collection of functions related to the address type */ library Address { /** * @dev Returns true if `account` is a contract. * * [IMPORTANT] * ==== * It is unsafe to assume that an address for which this function returns * false is an externally-owned account (EOA) and not a contract. * * Among others, `isContract` will return false for the following * types of addresses: * * - an externally-owned account * - a contract in construction * - an address where a contract will be created * - an address where a contract lived, but was destroyed * ==== * * [IMPORTANT] * ==== * You shouldn't rely on `isContract` to protect against flash loan attacks! * * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract * constructor. * ==== */ function isContract(address account) internal view returns (bool) { // This method relies on extcodesize/address.code.length, which returns 0 // for contracts in construction, since the code is only stored at the end // of the constructor execution. return account.code.length > 0; } /** * @dev Replacement for Solidity's `transfer`: sends `amount` wei to * `recipient`, forwarding all available gas and reverting on errors. * * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost * of certain opcodes, possibly making contracts go over the 2300 gas limit * imposed by `transfer`, making them unable to receive funds via * `transfer`. {sendValue} removes this limitation. * * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more]. * * IMPORTANT: because control is transferred to `recipient`, care must be * taken to not create reentrancy vulnerabilities. Consider using * {ReentrancyGuard} or the * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern]. */ function sendValue(address payable recipient, uint256 amount) internal { require(address(this).balance >= amount, "Address: insufficient balance"); (bool success, ) = recipient.call{value: amount}(""); require(success, "Address: unable to send value, recipient may have reverted"); } /** * @dev Performs a Solidity function call using a low level `call`. A * plain `call` is an unsafe replacement for a function call: use this * function instead. * * If `target` reverts with a revert reason, it is bubbled up by this * function (like regular Solidity function calls). * * Returns the raw returned data. To convert to the expected return value, * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`]. * * Requirements: * * - `target` must be a contract. * - calling `target` with `data` must not revert. * * _Available since v3.1._ */ function functionCall(address target, bytes memory data) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, "Address: low-level call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with * `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { return functionCallWithValue(target, data, 0, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but also transferring `value` wei to `target`. * * Requirements: * * - the calling contract must have an ETH balance of at least `value`. * - the called Solidity function must be `payable`. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value ) internal returns (bytes memory) { return functionCallWithValue(target, data, value, "Address: low-level call with value failed"); } /** * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but * with `errorMessage` as a fallback revert reason when `target` reverts. * * _Available since v3.1._ */ function functionCallWithValue( address target, bytes memory data, uint256 value, string memory errorMessage ) internal returns (bytes memory) { require(address(this).balance >= value, "Address: insufficient balance for call"); (bool success, bytes memory returndata) = target.call{value: value}(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) { return functionStaticCall(target, data, "Address: low-level static call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a static call. * * _Available since v3.3._ */ function functionStaticCall( address target, bytes memory data, string memory errorMessage ) internal view returns (bytes memory) { (bool success, bytes memory returndata) = target.staticcall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) { return functionDelegateCall(target, data, "Address: low-level delegate call failed"); } /** * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`], * but performing a delegate call. * * _Available since v3.4._ */ function functionDelegateCall( address target, bytes memory data, string memory errorMessage ) internal returns (bytes memory) { (bool success, bytes memory returndata) = target.delegatecall(data); return verifyCallResultFromTarget(target, success, returndata, errorMessage); } /** * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract. * * _Available since v4.8._ */ function verifyCallResultFromTarget( address target, bool success, bytes memory returndata, string memory errorMessage ) internal view returns (bytes memory) { if (success) { if (returndata.length == 0) { // only check isContract if the call was successful and the return data is empty // otherwise we already know that it was a contract require(isContract(target), "Address: call to non-contract"); } return returndata; } else { _revert(returndata, errorMessage); } } /** * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the * revert reason or using the provided one. * * _Available since v4.3._ */ function verifyCallResult( bool success, bytes memory returndata, string memory errorMessage ) internal pure returns (bytes memory) { if (success) { return returndata; } else { _revert(returndata, errorMessage); } } function _revert(bytes memory returndata, string memory errorMessage) private pure { // Look for revert reason and bubble it up if present if (returndata.length > 0) { // The easiest way to bubble the revert reason is using memory via assembly /// @solidity memory-safe-assembly assembly { let returndata_size := mload(returndata) revert(add(32, returndata), returndata_size) } } else { revert(errorMessage); } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (proxy/beacon/IBeacon.sol) pragma solidity ^0.8.0; /** * @dev This is the interface that {BeaconProxy} expects of its beacon. */ interface IBeacon { /** * @dev Must return an address that can be used as a delegate call target. * * {BeaconProxy} will check that this address is a contract. */ function implementation() external view returns (address); }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts (last updated v4.7.0) (utils/StorageSlot.sol) pragma solidity ^0.8.0; /** * @dev Library for reading and writing primitive types to specific storage slots. * * Storage slots are often used to avoid storage conflict when dealing with upgradeable contracts. * This library helps with reading and writing to such slots without the need for inline assembly. * * The functions in this library return Slot structs that contain a `value` member that can be used to read or write. * * Example usage to set ERC1967 implementation slot: * ``` * contract ERC1967 { * bytes32 internal constant _IMPLEMENTATION_SLOT = 0x360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc; * * function _getImplementation() internal view returns (address) { * return StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value; * } * * function _setImplementation(address newImplementation) internal { * require(Address.isContract(newImplementation), "ERC1967: new implementation is not a contract"); * StorageSlot.getAddressSlot(_IMPLEMENTATION_SLOT).value = newImplementation; * } * } * ``` * * _Available since v4.1 for `address`, `bool`, `bytes32`, and `uint256`._ */ library StorageSlot { struct AddressSlot { address value; } struct BooleanSlot { bool value; } struct Bytes32Slot { bytes32 value; } struct Uint256Slot { uint256 value; } /** * @dev Returns an `AddressSlot` with member `value` located at `slot`. */ function getAddressSlot(bytes32 slot) internal pure returns (AddressSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `BooleanSlot` with member `value` located at `slot`. */ function getBooleanSlot(bytes32 slot) internal pure returns (BooleanSlot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Bytes32Slot` with member `value` located at `slot`. */ function getBytes32Slot(bytes32 slot) internal pure returns (Bytes32Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } /** * @dev Returns an `Uint256Slot` with member `value` located at `slot`. */ function getUint256Slot(bytes32 slot) internal pure returns (Uint256Slot storage r) { /// @solidity memory-safe-assembly assembly { r.slot := slot } } }
// SPDX-License-Identifier: MIT // OpenZeppelin Contracts v4.4.1 (utils/Context.sol) pragma solidity ^0.8.0; /** * @dev Provides information about the current execution context, including the * sender of the transaction and its data. While these are generally available * via msg.sender and msg.data, they should not be accessed in such a direct * manner, since when dealing with meta-transactions the account sending and * paying for execution may not be the actual sender (as far as an application * is concerned). * * This contract is only required for intermediate, library-like contracts. */ abstract contract Context { function _msgSender() internal view virtual returns (address) { return msg.sender; } function _msgData() internal view virtual returns (bytes calldata) { return msg.data; } }
{ "evmVersion": "cancun", "optimizer": { "enabled": true, "mode": "3", "runs": 10000 }, "outputSelection": { "*": { "*": [ "abi" ] } }, "detectMissingLibraries": false, "forceEVMLA": false, "enableEraVMExtensions": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"ApprovalCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ApprovalQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"ArrayLengthMismatch","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"ClaimNotActive","type":"error"},{"inputs":[],"name":"ContractAlreadyInitialized","type":"error"},{"inputs":[],"name":"CreatorTokenBase__InvalidTransferValidatorContract","type":"error"},{"inputs":[],"name":"DelegateResolverNotSet","type":"error"},{"inputs":[],"name":"EmptyTokenList","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"available","type":"uint256"}],"name":"InsufficientAllocation","type":"error"},{"inputs":[],"name":"InvalidAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"InvalidPrice","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"maxAllowed","type":"uint256"}],"name":"InvalidQuantity","type":"error"},{"inputs":[],"name":"InvalidQueryRange","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"InvalidTime","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"alreadyMinted","type":"uint256"},{"internalType":"uint256","name":"maxAllowed","type":"uint256"}],"name":"MaxPerWalletExceeded","type":"error"},{"inputs":[{"internalType":"uint256","name":"requested","type":"uint256"},{"internalType":"uint256","name":"remaining","type":"uint256"}],"name":"MaxSupplyReached","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":"NotAuthorized","type":"error"},{"inputs":[],"name":"NotCompatibleWithSpotMints","type":"error"},{"inputs":[],"name":"NotDelegated","type":"error"},{"inputs":[],"name":"OwnerQueryForNonexistentToken","type":"error"},{"inputs":[],"name":"OwnershipNotInitializedForExtraData","type":"error"},{"inputs":[],"name":"PublicMintClosed","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"reclaimStartTime","type":"uint256"}],"name":"ReclaimWindowNotOpen","type":"error"},{"inputs":[],"name":"Reentrancy","type":"error"},{"inputs":[],"name":"RoyaltyOverflow","type":"error"},{"inputs":[],"name":"RoyaltyReceiverIsZeroAddress","type":"error"},{"inputs":[{"internalType":"uint256","name":"currentTime","type":"uint256"},{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"SaleNotActive","type":"error"},{"inputs":[],"name":"SequentialMintExceedsLimit","type":"error"},{"inputs":[],"name":"SequentialUpToTooSmall","type":"error"},{"inputs":[],"name":"SetUserCallerNotOwnerNorApproved","type":"error"},{"inputs":[],"name":"ShouldNotMintToBurnAddress","type":"error"},{"inputs":[],"name":"SpotMintTokenIdTooSmall","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenIdsNotStrictlyAscending","type":"error"},{"inputs":[],"name":"TradeNotEnabled","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":"UnauthorizedCaller","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"previousAdmin","type":"address"},{"indexed":false,"internalType":"address","name":"newAdmin","type":"address"}],"name":"AdminChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"approved","type":"address"},{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"operator","type":"address"},{"indexed":false,"internalType":"bool","name":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"autoApproved","type":"bool"}],"name":"AutomaticApprovalOfTransferValidatorSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"baseURI","type":"string"}],"name":"BaseURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"beacon","type":"address"}],"name":"BeaconUpgraded","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"reclaimTime","type":"uint256"}],"name":"ClaimEndTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"fromTokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"toTokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"}],"name":"ConsecutiveTransfer","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldDelegateResolver","type":"address"},{"indexed":false,"internalType":"address","name":"newDelegateResolver","type":"address"}],"name":"DelegateResolverUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"FinalBossMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"hiddenURI","type":"string"}],"name":"HiddenURIUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"owner","type":"address"}],"name":"Initialized","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"LegacyClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint16","name":"newMax","type":"uint16"}],"name":"MaxPerWalletUpdated","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":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"PreSaleClaim","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"PublicMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"newPrice","type":"uint256"}],"name":"PublicMintPriceUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"startTime","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"PublicMintTimeWindowUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"reclaimTime","type":"uint256"}],"name":"ReclaimStartTimeUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ReclaimUnclaimedNFTs","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"revealed","type":"bool"}],"name":"RevealStatusUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerAddressUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"TimeBasedReductionUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bool","name":"enabled","type":"bool"}],"name":"TradingStatusUpdated","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":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"TreasuryMint","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldTreasury","type":"address"},{"indexed":false,"internalType":"address","name":"newTreasury","type":"address"}],"name":"TreasuryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":false,"internalType":"uint64","name":"expires","type":"uint64"}],"name":"UpdateUser","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"implementation","type":"address"}],"name":"Upgraded","type":"event"},{"inputs":[],"name":"DEFAULT_TRANSFER_VALIDATOR","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"LEGACY_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_BATCH_SIZE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"MAX_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PRESALE_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PUBLIC_SUPPLY","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"RECLAIM_WINDOW","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"TREASURY_RESERVE","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"autoApproveTransfersFromValidator","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"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":[],"name":"claimEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"claimLegacy","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"claimLegacyDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"claimPresale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"address","name":"vault","type":"address"}],"name":"claimPresaleDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"currentTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegateResolver","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"eip712Domain","outputs":[{"internalType":"bytes1","name":"fields","type":"bytes1"},{"internalType":"string","name":"name","type":"string"},{"internalType":"string","name":"version","type":"string"},{"internalType":"uint256","name":"chainId","type":"uint256"},{"internalType":"address","name":"verifyingContract","type":"address"},{"internalType":"bytes32","name":"salt","type":"bytes32"},{"internalType":"uint256[]","name":"extensions","type":"uint256[]"}],"stateMutability":"view","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":[],"name":"finalBossAvailableSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"finalBossMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"finalBossMinted","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getTransferValidationFunction","outputs":[{"internalType":"bytes4","name":"functionSignature","type":"bytes4"},{"internalType":"bool","name":"isViewFunction","type":"bool"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTransferValidator","outputs":[{"internalType":"address","name":"validator","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"_treasuryAddress","type":"address"},{"internalType":"address","name":"_delegateResolver","type":"address"},{"internalType":"address","name":"_signerAddress","type":"address"},{"internalType":"string","name":"_hiddenURI","type":"string"}],"name":"initialize","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"isApproved","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"legacyAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legacyClaimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"legacyClaimed","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"maxPerWallet","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","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":[{"internalType":"address","name":"","type":"address"}],"name":"presaleAllocation","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleClaimActive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"presaleClaimed","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxiableUUID","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"publicMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"publicMintCount","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintEndTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMintStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"publicMinted","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"reclaimStartTime","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"reclaimUnclaimedNFTs","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"remainingPublicSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"revealed","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":"_baseTokenURI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"setClaimEndTime","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":"address","name":"newDelegateResolver","type":"address"}],"name":"setDelegateResolver","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"_hiddenURI","type":"string"}],"name":"setHiddenURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint256[]","name":"quantities","type":"uint256[]"}],"name":"setLegacyAllocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"active","type":"bool"}],"name":"setLegacyClaimActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint16","name":"max","type":"uint16"}],"name":"setMaxPerWallet","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address[]","name":"addresses","type":"address[]"},{"internalType":"uint256[]","name":"amounts","type":"uint256[]"}],"name":"setPresaleAllocations","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"active","type":"bool"}],"name":"setPresaleClaimActive","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"setPublicMintPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"startTime","type":"uint256"},{"internalType":"uint256","name":"endTime","type":"uint256"}],"name":"setPublicMintTimeWindow","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"_revealed","type":"bool"}],"name":"setRevealed","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newSigner","type":"address"}],"name":"setSignerAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bool","name":"enabled","type":"bool"}],"name":"setTimeBasedReductionEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"receiver","type":"address"},{"internalType":"uint96","name":"feeNumerator","type":"uint96"}],"name":"setTokenRoyalty","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setTradingEnabled","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"transferValidator_","type":"address"}],"name":"setTransferValidator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newTreasury","type":"address"}],"name":"setTreasury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"address","name":"user","type":"address"},{"internalType":"uint64","name":"expires","type":"uint64"}],"name":"setUser","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","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":[],"name":"timeBasedReductionEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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":[],"name":"tradingEnabled","outputs":[{"internalType":"bool","name":"","type":"bool"}],"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"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"treasuryMint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasuryMinted","outputs":[{"internalType":"uint16","name":"","type":"uint16"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"}],"name":"upgradeTo","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newImplementation","type":"address"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"upgradeToAndCall","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"userExpires","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"userOf","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
9c4d535b000000000000000000000000000000000000000000000000000000000000000001000c55756a7be9a401b8e3b2c1e348a93eb733bb654cccb22cbed51b6212d800000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000000000000000000000000000
Deployed Bytecode
0x00040000000000020012000000000002000000600410027000000ae2034001970003000000310355000200000001035500000ae20040019d0000000100200190000000360000c13d0000008004000039000000400040043f000000040030008c00001e290000413d000000000201043b000000e00220027000000af90020009c0000006d0000a13d00000afa0020009c000001370000a13d00000afb0020009c000001480000a13d00000afc0020009c000001ed0000213d00000b060020009c0000038f0000a13d00000b070020009c000005d60000213d00000b0a0020009c00000cb60000613d00000b0b0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d0000000a01000039000000000201041a00000b9b022001c7000000000021041b0000000103000039000000800030043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d0200003900000b9d0400004100000d9f0000013d0000014001000039000000400010043f0000000001000416000000000001004b00001e290000c13d0000000a01000039000001400010043f00000ae301000041000001600010043f000001c001000039000000400010043f0000000401000039000001800010043f00000ae401000041000001a00010043f0000000201000039000000000201041a000000010320019000000001022002700000007f0220618f0000001f0020008c00000000040000390000000104002039000000000043004b000000670000c13d000000200020008c0000005a0000413d000000000010043f00000ae5030000410000001f02200039000000050220027000000ae60220009a000000000003041b0000000103300039000000000023004b000000560000413d00000ae702000041000000000021041b0000000303000039000000000103041a000000010010019000000001041002700000007f0440618f0000001f0040008c00000000020000390000000102002039000000000121013f0000000100100190000000820000613d00000c2701000041000000000010043f0000002201000039000000040010043f00000c280100004100002b860001043000000b430020009c000001240000213d00000b670020009c000001570000213d00000b790020009c000002270000a13d00000b7a0020009c000003e20000a13d00000b7b0020009c000006160000213d00000b7e0020009c00000ec40000613d00000b7f0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d2b841f9c0000040f000000800010043f00000b8c0100004100002b850001042e000000200040008c0000009b0000413d000b00000004001d000000000030043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ae8011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000b020000290000001f0220003900000005022002700000000002210019000000000021004b00000003030000390000009b0000813d000000000001041b0000000101100039000000000021004b000000970000413d000001a00100043d00000ae90110019700000008011001bf000000000013041b0000000103000039000000000030041b000000400100043d000000200210003900000aea040000410000000000420435000000000001043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000aeb011001c70000800d0200003900000aec040000412b842b750000040f000000010020019000001e290000613d00000aed01000041000000000010044300000aea010000410000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b000005a60000c13d0000000001000410000b00000001001d000000800010043f00000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000401043b000000a00040043f000000400200043d00000af40020009c000018e30000213d0000004001200039000000400010043f0000000901000039000000000112043600000af5030000410000000000310435000000400300043d00000af40030009c000018e30000213d000a00000004001d0000004004300039000000400040043f0000002005300039000900000005001d00000af60400004100000000004504350000000104000039000000000043043500000000020204332b842b420000040f000800000001001d000000090100002900000001020000392b842b420000040f0000000802000029000000c00020043f000000e00010043f000000400400043d000000200340003900000000002304350000004003400039000000000013043500000060014000390000000a02000029000000000021043500000af701000041000000000014043500000080014000390000000b020000290000000000210435000000a00200003900000000010400192b842b420000040f000001000010043f0000000b05000029000001200050043f0000001903000039000000000403041a00000c400240019700000001022001bf000000000023041b000000800200043d000001400000044300000160002004430000002002000039000000a00300043d0000018000200443000001a0003004430000004003000039000000c00400043d000001c000300443000001e0004004430000006003000039000000e00400043d00000200003004430000022000400443000000800300003900000240003004430000026000100443000000a0010000390000028000100443000002a00050044300000100002004430000000601000039000001200010044300000af80100004100002b850001042e00000b440020009c000001ab0000213d00000b560020009c000002410000a13d00000b570020009c000004150000a13d00000b580020009c000006360000213d00000b5b0020009c00000ed80000613d00000b5c0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000b9f001001980000106f0000013d00000b200020009c000001bf0000213d00000b320020009c0000028d0000a13d00000b330020009c000005400000a13d00000b340020009c000006590000213d00000b370020009c000010690000613d00000b380020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d00000b8d0100004100000c930000013d00000b0f0020009c0000020e0000a13d00000b100020009c000003d50000a13d00000b110020009c0000060d0000213d00000b140020009c00000eb00000613d00000b150020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000001001000039000010ed0000013d00000b680020009c0000024e0000a13d00000b690020009c000005080000a13d00000b6a0020009c0000063f0000213d00000b6d0020009c00000ee40000613d00000b6e0020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000002402100370000000000202043b000b00000002001d0000000401100370000000000101043b000000000010043f00000be501000041000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000201041a00000be40020009c0000017d0000213d00000be501000041000000000201041a00000be4012001980000000003000019000000010300c08a000000000313c0d90000000b0030006b0000000003000019000000000301201900000001040000310000000005430019000000000045004b00001e290000213d00000c41053001980000001f0630018f00000003074003670000000003540019000001920000613d000000000807034f000000008908043c0000000004940436000000000034004b0000018e0000c13d0000006002200270000000000006004b000001a00000613d000000000457034f0000000305600210000000000603043300000000065601cf000000000656022f000000000404043b0000010005500089000000000454022f00000000045401cf000000000464019f00000000004304350000000b011000b9000027100110011a000000400300043d00000020043000390000000000140435000000000023043500000ae20030009c00000ae203008041000000400130021000000c10011001c700002b850001042e00000b450020009c0000025d0000a13d00000b460020009c000005350000a13d00000b470020009c0000064a0000213d00000b4a0020009c00000f210000613d00000b4b0020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b2b8427390000040f00000b8a01100197000010c90000013d00000b210020009c0000029c0000a13d00000b220020009c000005990000a13d00000b230020009c0000066f0000213d00000b260020009c000010740000613d00000b270020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000501043b00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d0000000a01000039000000000301041a000000b8023002700000ffff0220018f000000000052001a0000141d0000413d0000000004520019000003790040008c000013000000413d000003780020008c0000141d0000213d00000bc301000041000000000010043f000000040050043f0000037801200089000000240010043f00000af00100004100002b860001043000000afd0020009c000003be0000a13d00000afe0020009c000005fa0000213d00000b010020009c00000cda0000613d00000b020020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000000001004b00000b8e0100004100000000010060190000000a02000039000000000302041a00000b8f03300197000006320000013d00000b190020009c000002b40000213d00000b1d0020009c000006940000613d00000b1e0020009c000008550000613d00000b1f0020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b2b8423b60000040f000000400200043d000b00000002001d2b841f3f0000040f0000000b0100002900000ae20010009c00000ae201008041000000400110021000000bb7011001c700002b850001042e00000b830020009c000002e90000213d00000b870020009c000006ca0000613d00000b880020009c00000a370000613d00000b890020009c00001e290000c13d00000000010300192b841e3d0000040f000b00000001001d000a00000002001d000900000003001d000000400100043d000800000001001d00000020020000392b841e2b0000040f0000000805000029000000000005043500000000010004110000000b020000290000000a0300002900000009040000292b8424490000040f000000000100001900002b850001042e00000b600020009c000002f60000213d00000b640020009c000006d10000613d00000b650020009c00000a4b0000613d00000b660020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000001201000039000010ed0000013d00000b720020009c000003030000213d00000b760020009c0000071b0000613d00000b770020009c00000a6d0000613d00000b780020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d00000fa001000039000000800010043f00000b8c0100004100002b850001042e00000b4f0020009c0000032e0000213d00000b530020009c000007580000613d00000b540020009c00000a720000613d00000b550020009c00001e290000c13d000000640030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b0000002403100370000000000303043b000b00000003001d00000b8a0030009c00001e290000213d0000004401100370000000000101043b000a00000001001d00000be40010009c00001e290000213d00000b8d01000041000000000101041a00000b8a011001970000000003000411000000000013004b000012fc0000c13d0000000a01000029000027100010008c000007870000213d0000000b0000006b000013fd0000613d000000000020043f00000be501000041000000200010043f000000400200003900000000010000192b842b420000040f0000000b0200002900000060022002100000000a022001af000000000021041b000000000100001900002b850001042e00000b3c0020009c000003580000213d00000b400020009c000007ac0000613d00000b410020009c00000c690000613d00000b420020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000b8e001001980000106f0000013d00000b2b0020009c000003650000213d00000b2f0020009c000007c10000613d00000b300020009c00000c700000613d00000b310020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d000000000010043f0000000e01000039000000200010043f000000400200003900000000010000192b842b420000040f000010d40000013d00000b1a0020009c000006ac0000613d00000b1b0020009c000008940000613d00000b1c0020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000401043b00000ba101000041000000000301041a0000000002000410000000000023004b000010b10000613d000900000004001d000000000021041b0000001201000039000000000101041a000a00000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000a0010006c0000133f0000213d00000000020004110000000b0100002900000009030000292b84277a0000040f0000000001000412000d00000001001d0000800201000039000000240300003900000000040004150000000d0440008a000014100000013d00000b840020009c000007710000613d00000b850020009c00000ab10000613d00000b860020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a000000c801100270000010d50000013d00000b610020009c0000078b0000613d00000b620020009c00000ad30000613d00000b630020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000b01000039000000000101041a0000001001100270000010d50000013d00000b730020009c0000079c0000613d00000b740020009c00000bc60000613d00000b750020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000001302000039000000000202041a000b00000002001d0000002401100370000000000101043b000800000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000b03000029000000000031004b000012d40000813d00000c1802000041000000000020043f000000040010043f000000240030043f00000af00100004100002b860001043000000b500020009c000007a70000613d00000b510020009c00000bcd0000613d00000b520020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000000a02000039000000000302041a00000be103300197000000000001004b00000bd2040000410000000004006019000000000343019f000000000032041b000000800010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d02000039000000010300003900000be20400004100000d9f0000013d00000b3d0020009c000007f00000613d00000b3e0020009c00000c8f0000613d00000b3f0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d00000d7501000039000000800010043f00000b8c0100004100002b850001042e00000b2c0020009c000007f70000613d00000b2d0020009c00000c980000613d00000b2e0020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000000a02000039000000000302041a00000bc803300197000000000001004b000000000400001900000bc90400c041000000000343019f000000000032041b000000800010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d02000039000000010300003900000bca0400004100000d9f0000013d00000b0c0020009c000008b40000613d00000b0d0020009c00000da40000613d00000b0e0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d00000ba102000041000000000302041a0000000001000410000000000013004b000010b10000613d000000000012041b00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000001402000039000000000202041a000b00000002001d00000ba20200004100000000002004430000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c70000800a020000392b842b7a0000040f000000010020019000001df00000613d0000000b0200002900000b8a04200197000000000301043b000000000100041400000ae20010009c00000ae201008041000000c001100210000000000003004b000014010000c13d0000000002040019000014040000013d00000b030020009c00000a080000613d00000b040020009c00000e3e0000613d00000b050020009c00001e290000c13d000000240030008c00001e290000413d0000000401100370000000000101043b00000b8a0010009c00001e290000213d00000b8d02000041000000000202041a0000000003000411000000000023004b0000117b0000c13d000000000001004b000014770000c13d00000b9001000041000000000010043f00000b910100004100002b860001043000000b160020009c00000d000000613d00000b170020009c000010ba0000613d00000b180020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000001401000039000000800010043f00000b8c0100004100002b850001042e00000b800020009c00000d230000613d00000b810020009c000010c10000613d00000b820020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000001101000039000000000101041a000b00000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000b0010006c00000000020000190000040e0000a13d0000000a01000039000000000101041a000000e8011002700000ffff0110018f00000d760010008c0000141d0000813d00000d75031000890000000b02000039000000000202041a0000ffff0420018f000000000043004b00000000020000190000040e0000a13d000000000141001900000d7502100089000000000032004b0000141d0000213d000000400100043d000000000021043500000ae20010009c00000ae201008041000000400110021000000b9a011001c700002b850001042e00000b5d0020009c00000d420000613d00000b5e0020009c000010d00000613d00000b5f0020009c00001e290000c13d000000440030008c00001e290000413d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002402100370000000000402043b00000af10040009c00001e290000213d0000002302400039000000000032004b00001e290000813d0000000405400039000000000251034f000000000202043b00000af10020009c000018e30000213d0000001f0720003900000c41077001970000003f0770003900000c410770019700000bad0070009c000018e30000213d00000024044000390000008007700039000000400070043f000000800020043f0000000004420019000000000034004b00001e290000213d0000002003500039000000000331034f00000c41042001980000001f0520018f000000a001400039000004470000613d000000a006000039000000000703034f000000007807043c0000000006860436000000000016004b000004430000c13d000000000005004b000004540000613d000000000343034f0000000304500210000000000501043300000000054501cf000000000545022f000000000303043b0000010004400089000000000343022f00000000034301cf000000000353019f0000000000310435000000a001200039000000000001043500000be901000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b00000b8a011001970000000002000410000000000012004b00000a690000613d00000bef02000041000000000202041a00000b8a02200197000000000012004b000013e70000c13d00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d00000bf001000041000000000101041a000000ff0010019000001a490000c13d000000400200043d000a00000002001d00000bf101000041000000000012043500000ae20020009c00000ae20100004100000000010240190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ba8011001c70000000b020000292b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0640018f00000020074001900000000a0b0000290000000a05700029000004990000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000004950000c13d000000000006004b000004a60000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000100000003001f000300000001035500000001002001900000181f0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000af10010009c000018e30000213d0000000100200190000018e30000c13d000000400010043f000000200030008c00001e290000413d00000000020b043300000bef0020009c00001ad70000c13d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b000016a80000613d00000bef01000041000000000201041a00000b92022001970000000b05000029000000000252019f000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000020300003900000bf4040000412b842b750000040f000000010020019000001e290000613d000000400100043d000a00000001001d00000bf50010009c000018e30000213d0000000a030000290000006001300039000000400010043f000000400130003900000bf6020000410000000000210435000000200130003900000bf702000041000000000021043500000027010000390000000000130435000000800100043d00000ae20010009c00000ae2010080410000006001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000bf8011001c70000000b020000292b842b7f0000040f0003000000010355000000600310027000010ae20030019d00000ae20530019800001c0a0000c13d000000600300003900000080040000390000000001030433000000010020019000001c310000613d000000000001004b00000da20000c13d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400001b990000013d00000b6f0020009c00000d490000613d00000b700020009c000010d90000613d00000b710020009c00001e290000c13d00000b8b010000410000000c0010043f0000000001000411000000000010043f00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000b00000001001d000000000100041400000ae20010009c00000ae201008041000000c00110021000000b95011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000b0200002900000c110220009a000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000020300003900000c12040000410000076f0000013d00000b4c0020009c00000d870000613d00000b4d0020009c000010de0000613d00000b4e0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d000000140100003900000c930000013d00000b390020009c00000e530000613d00000b3a0020009c000010f10000613d00000b3b0020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000404200039000000000441034f000000000404043b000900000004001d00000af10040009c00001e290000213d000800240020003d000000090200002900000005022002100000000802200029000000000032004b00001e290000213d0000002402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000404200039000000000141034f000000000101043b00000af10010009c00001e290000213d000700240020003d00000005021002100000000702200029000000000032004b00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000090010006b000017750000c13d000000090000006b00000da20000613d000000000400001900000005014002100000000702100029000000080110002900000002011003670000000202200367000000000202043b000a00000002001d000000000101043b00000b8a0010009c00001e290000213d000000000010043f0000000c01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c70000801002000039000b00000004001d2b842b7a0000040f0000000b04000029000000010020019000001e290000613d000000000101043b0000000a02000029000000000021041b0000000104400039000000090040006c0000057a0000413d00000da20000013d00000b280020009c00000e670000613d00000b290020009c000011280000613d00000b2a0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a000000e801100270000010d50000013d00000aed01000041000000000010044300000aea010000410000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b00001e290000613d000000400300043d0000002401300039000002d102000039000000000021043500000aef01000041000000000013043500000004013000390000000002000410000000000021043500000ae20030009c000b00000003001d00000ae20100004100000000010340190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000af0011001c700000aea020000412b842b750000040f000000600310027000010ae20030019d00030000000103550000000100200190000000c40000613d0000000b0100002900000af10010009c000018e30000213d000000400010043f000000c40000013d00000b080020009c00000ce60000613d00000b090020009c00001e290000c13d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000002402100370000000000202043b0000000401100370000000000101043b00000b8d03000041000000000303041a00000b8a033001970000000004000411000000000034004b000012fc0000c13d000000000021004b0000119f0000813d0000001003000039000000000013041b0000001103000039000000000023041b000000800010043f000000a00020043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b93011001c70000800d02000039000000010300003900000b990400004100000d9f0000013d00000aff0020009c00000cf90000613d00000b000020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d00000b8b020000410000000c0020043f000000000010043f0000000c010000390000002002000039000010ec0000013d00000b120020009c00000ebd0000613d00000b130020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000000f01000039000010ed0000013d00000b7c0020009c00000f280000613d00000b7d0020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000000001004b00000bd90100004100000000010060190000000a02000039000000000302041a00000c2c03300197000000000113019f000000000012041b000000000100001900002b850001042e00000b590020009c00000f310000613d00000b5a0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d0000001101000039000010ed0000013d00000b6b0020009c00000f510000613d00000b6c0020009c00001e290000c13d0000000001000416000000000001004b00001e290000c13d000022b801000039000000800010043f00000b8c0100004100002b850001042e00000b480020009c00000fe80000613d00000b490020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d2b8421370000040f000010c90000013d00000b350020009c0000109b0000613d00000b360020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000010043f0000000901000039000000200010043f000000400200003900000000010000192b842b420000040f000000000101041a000000a001100270000000800010043f00000b8c0100004100002b850001042e00000b240020009c000010b50000613d00000b250020009c00001e290000c13d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b0000ffff0010008c00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000ffff0210018f000000100110021000000bbb011001970000000b03000039000000000403041a00000bbc04400197000000000114019f000000000013041b000000800020043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d02000039000000010300003900000bbd0400004100000d9f0000013d000000840030008c00001e290000413d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000006402100370000000000202043b00000af10020009c00001e290000213d0000004401100370000000000101043b000900000001001d000000040120003900000000020300192b841ef50000040f0000000004010019000007960000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000010043f0000000901000039000000200010043f000000400200003900000000010000192b842b420000040f000000000101041a000b00000001001d0000800b0100003900000004030000390000000004000415000000120440008a000000050440021000000b96020000412b842b570000040f000000a0011002100000000b0300002900000b8a02300197000000000031004b0000000002008019000000800020043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d00000aea01000041000000800010043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d00000be90100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000b00000001001d00000be9010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000a00000001001d00000be90100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000900000001001d00000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d0000000002000412000000000101043b00000000030004100000000a0030006c000014230000c13d000000090010006c000014230000c13d000000400100043d0000000b020000290000040f0000013d000000440030008c00001e290000413d0000000402100370000000000202043b000b00000002001d0000002402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d000900040020003d0000000901100360000000000101043b000a00000001001d00000af10010009c00001e290000213d0000000a01200029000800240010003d000000080030006b00001e290000213d00000ba101000041000000000201041a0000000003000410000000000032004b000010b10000613d000000000031041b0000001001000039000000000101041a000700000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d0000001102000039000000000202041a000600000002001d000000000101043b000000070010006c000014ef0000413d000000060010006c000014ef0000813d0000000a01000039000000000101041a000000e8011002700000ffff0110018f000700000001001d00000d740010008c000015b10000a13d00000c2a01000041000000000010043f00000ba80100004100002b860001043000000b8b010000410000000c0010043f0000000001000411000000000010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b95011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000001041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000020300003900000be804000041000000000500041100000d9f0000013d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000b8a0020009c00001e290000213d0000002401100370000000000101043b00000be40010009c00001e290000213d00000b8d03000041000000000303041a00000b8a033001970000000004000411000000000034004b000012fc0000c13d00000be401100197000027110010008c000013fb0000413d00000c3701000041000000000010043f00000b910100004100002b860001043000000000010300192b841ee30000040f000b00000001001d000a00000002001d000900000003001d000000400100043d000800000001001d00000020020000392b841e2b0000040f000000080400002900000000000404350000000b010000290000000a0200002900000009030000292b84214f0000040f000000000100001900002b850001042e0000000001000416000000000001004b00001e290000c13d0000000101000039000000000101041a00000c4201100167000000000200041a0000000001120019000000800010043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d000000160100003900000c930000013d00000b8d01000041000000000501041a0000000001000411000000000051004b0000117b0000c13d000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000030300003900000bdc0400004100000000060000192b842b750000040f000000010020019000001e290000613d00000b8d01000041000000000001041b000000000100001900002b850001042e000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000401043b00000ba101000041000000000301041a0000000002000410000000000023004b000010b10000613d000900000004001d000000000021041b0000001201000039000000000101041a000a00000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000a0010006c0000133f0000213d00000000020004110000000b0100002900000009030000292b8428850000040f0000000001000412000e00000001001d0000800201000039000000240300003900000000040004150000000e0440008a000014100000013d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000bd9001001980000106f0000013d000000640030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000700000002001d00000b8a0020009c00001e290000213d0000004402100370000000000202043b0000002401100370000000000301043b000000000023004b000011950000813d000000000100041a000000000012004b0000000002018019000600000002001d000000010030008c000000010300a0390000000701000029000000000001004b0000122a0000613d000a00000003001d000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000400600000003d000000000101043b0000000a03000029000000060230006b00001a000000a13d000000000101041a00000af10110019800001a000000613d000000000012004b0000000002018019000500000002001d0000000501200210000000400200043d000400000002001d00000000012100190000002001100039000000400010043f000900000001001d00000bad0010009c0000000a02000029000018e30000213d00000009030000290000008001300039000000400010043f0000006001300039000000000001043500000040013000390000000000010435000000200130003900000000000104350000000000030435000000000100041a000000000021004b0000000001000019000015cb0000a13d0000000a01000029000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b000018ab0000c13d0000000b01000029000000010110008a000008410000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000406200039000000000461034f000000000404043b00000af10040009c00001e290000213d00000024052000390000000002540019000000000032004b00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000001802000039000000000702041a000000010070019000000001037002700000007f0330618f0000001f0030008c00000000080000390000000108002039000000000787013f0000000100700190000000670000c13d000000200030008c0000088c0000413d000000000020043f0000001f07400039000000050770027000000bb80770009a000000200040008c00000bb4070040410000001f03300039000000050330027000000bb80330009a000000000037004b0000088c0000813d000000000007041b0000000107700039000000000037004b000008880000413d0000001f0040008c000014f80000a13d000000000020043f00000c4106400198000016180000c13d00000bb4030000410000000007000019000016220000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000001502000039000000000302041a00000b9204300197000000000414019f000000000042041b00000b8a02300197000000800020043f000000a00010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b93011001c70000800d02000039000000010300003900000bb60400004100000d9f0000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002305200039000000000035004b00001e290000813d0000000405200039000000000551034f000000000605043b00000af10060009c000018e30000213d00000005056002100000003f0750003900000bac0770019700000bad0070009c000018e30000213d0000008007700039000000400070043f000000800060043f00000024022000390000000005250019000000000035004b00001e290000213d000000000006004b00000da20000613d000000000321034f000000000303043b000000200440003900000000003404350000002002200039000000000052004b000008d30000413d000000800100043d000000000001004b00000da20000613d000000a004000039000000000200041a000300000002001d000000000200041100060b8a0020019b0000000501100210000700a00010003d00000001020000390000000001000019000400000000001d000800000000001d000008ed0000013d000000010150008a000000070040006c000000000200001900001af90000613d000a00000004001d0000000003040433000500000003001d000000000003004b0000119b0000613d0000000504000029000000030040006b0000119b0000a13d0000000504000029000000000014004b0000000001000039000000010100a03900000c4202200167000000000112016f000000010010019000001af50000c13d000b00000004001d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b04000029000000010440008a000000000101043b000000000101041a000000000001004b000008fd0000613d00000ba5001001980000119b0000c13d000100000001001d00000b8a03100197000000040200002900000b8a01200197000000000013004b000900000003001d000009510000613d000000060000006b000800010000003d0000000002030019000009510000613d000000060030006c000800010000003d0000000002030019000009510000613d000000000030043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000602000029000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000800ff0010019400000009030000290000000002030019000009510000c13d0000000a01000039000000000201041a00000ba6002001980000094f0000613d000000080120027000000b8a011001980000094a0000c13d000000ff00200190000000000100001900000aea01006041000000060010006b00000000010000390000000101006039000800000001001d000009500000013d000800000000001d0000000002030019000400000002001d000000050200002900000000010000190000000100100190000b00000002001d000009680000613d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b0000000b020000290000099d0000c13d000000000020043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b07000029000000000101043b0000000905000029000000000005004b000015140000613d0000000a02000039000000000202041a00000b9b0020019800000ed40000613d000000000201041a000000080000006b000009820000c13d000000060020006b000018dc0000c13d000000000002004b000009850000613d000000000001041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000060000192b842b750000040f000000010020019000001e290000613d0000000b0100002900000001031000390000000a010000290000002001100039000000070010006c000a00000001001d0000099e0000613d0000000002010433000000000032004b0000000101000039000009540000613d0000099e0000013d0000000003020019000b00000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000200000001001d0000000501000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000202000029000000a0022002100000000903000029000000000232019f00000ba5022001c7000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b05000029000000050650006a00000bb0026000d1000000000101043b000000000301041a0000000002230019000000000021041b000000030050006c000009f90000613d000200000006001d000000000050043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b0000000b050000290000000206000029000009f90000c13d000000000050043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000102000029000000000021041b0000000b050000290000000206000029000000050050006c0000000a04000029000008e90000613d000000090000006b000015140000613d000000010100008a000000050110014f00000000020000190000000a04000029000000000012004b0000141d0000213d0000000102200039000000000062004b00000a020000413d000008e90000013d000000240030008c00001e290000413d0000000401100370000000000101043b000b00000001001d00000b8a0010009c00001e290000213d00000b8d01000041000000000101041a0000000002000411000000000012004b0000117b0000c13d00000b8b010000410000000c0010043f0000000b01000029000000000010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b95011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000900000001001d000000000101041a000a00000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000a0010006c000014740000a13d00000b9701000041000000000010043f00000b910100004100002b8600010430000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000201043b00000c380020019800001e290000c13d000000010100003900000ae90320019700000c390030009c000011a50000213d00000c3d0030009c000011b10000613d00000c3e0030009c000011b10000613d00000c3f0030009c000011b10000613d000011ab0000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000b00000001001d00000b8a0010009c00001e290000213d00000be901000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b00000b8a011001970000000002000410000000000012004b0000122e0000c13d000000400100043d000000640210003900000c0503000041000013ea0000013d0000000001000416000000000001004b00001e290000c13d2b8426f40000040f000010c90000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000406200039000000000461034f000000000404043b00000af10040009c00001e290000213d00000024052000390000000002540019000000000032004b00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000001702000039000000000702041a000000010070019000000001037002700000007f0330618f0000001f0030008c00000000080000390000000108002039000000000787013f0000000100700190000000670000c13d000000200030008c00000aa90000413d000000000020043f0000001f07400039000000050770027000000be60770009a000000200040008c00000bb3070040410000001f03300039000000050330027000000be60330009a000000000037004b00000aa90000813d000000000007041b0000000107700039000000000037004b00000aa50000413d0000001f0040008c000015050000a13d000000000020043f00000c4106400198000016580000c13d00000bb3030000410000000007000019000016620000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000000001004b00000e4f0000613d0000001602000039000000000302041a00000b9204300197000000000414019f000000000042041b00000b8a02300197000000800020043f000000a00010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b93011001c70000800d02000039000000010300003900000c330400004100000d9f0000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000119b0000613d000a00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000b050000c13d000000000100041a0000000a02000029000000000021004b0000119b0000a13d000b00000002001d0000000b01000029000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000af20000613d000b00000001001d00000ba5001001980000000a010000290000119b0000c13d000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b0200002900000b8a02200197000000000101043b000700000001001d000000000101041a000800000001001d0000000001000411000900000002001d000000000021004b00000b4e0000613d0000000002000411000000080020006c00000b4e0000613d0000000901000029000000000010043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000200041100000b8a02200197000600000002001d000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000ff0010019000000b4e0000c13d0000000a01000039000000000101041a00000ba600100198000018dc0000613d000000080210027000000b8a0220019800000b4c0000c13d000000ff00100190000000000200001900000aea02006041000000060020006b000018dc0000c13d000000090000006b000015140000613d0000000a01000039000000000101041a00000b9b0010019800000ed40000613d000000080000006b00000b580000613d0000000701000029000000000001041b0000000901000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000201041a00000bfc0220009a000000000021041b00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000800000001001d0000000a01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000802000029000000a00220021000000009022001af00000bfd022001c7000000000101043b000000000021041b0000000b0100002900000bc00010019800000bb20000c13d0000000a010000290000000101100039000800000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000bb20000c13d000000000100041a000000080010006b00000bb20000613d0000000801000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000b02000029000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf04000041000000090500002900000000060000190000000a070000292b842b750000040f000000010020019000001e290000613d0000000101000039000000000201041a0000000102200039000000000021041b000000000100001900002b850001042e0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a000000d801100270000010d50000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d000a00040020003d0000000a04100360000000000504043b00000af10050009c00001e290000213d000000050450021000000000024200190000002402200039000000000032004b00001e290000213d000000800050043f000000a002400039000000400020043f000000000005004b00000c0f0000c13d00000020010000390000000001120436000000800300043d00000000003104350000004001200039000000000003004b0000118c0000613d0000008004000039000000000500001900000020044000390000000006040433000000008706043400000b8a077001970000000007710436000000000808043300000af108800197000000000087043500000040076000390000000007070433000000000007004b0000000007000039000000010700c039000000400810003900000000007804350000006006600039000000000606043300000be3066001970000006007100039000000000067043500000080011000390000000105500039000000000035004b00000bf10000413d0000118c0000013d000000200460008c00000080036000390000000000230435000000400200043d00000be80000613d00000000060400190000000a03400029000000000331034f000000000403043b00000bad0020009c000018e30000213d0000008003200039000000400030043f0000006003200039000000000003043500000040032000390000000000030435000000200320003900000000000304350000000000020435000000000004004b00000c0a0000613d000000000300041a000000000043004b00000c0a0000a13d000900000006001d000b00000004001d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000c380000c13d0000000b04000029000000010440008a00000c240000013d000000400100043d00000bad0010009c0000000b03000029000018e30000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000030043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d00000bad0020009c0000000906000029000018e30000213d000000000301034f0000000201000367000000000303043b000000000303041a0000008004200039000000400040043f0000006004200039000000e805300270000000000054043500000ba5003001980000000004000039000000010400c0390000004005200039000000000045043500000b8a043001970000000004420436000000a00330027000000af103300197000000000034043500000c0a0000013d0000000001000416000000000001004b00001e290000c13d00000bda01000041000000800010043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d0000000303000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000552013f0000000100500190000000670000c13d000000800010043f000000000004004b0000117f0000613d000000000030043f000000000001004b0000000002000019000011840000613d00000bce030000410000000002000019000000000403041a000000a005200039000000000045043500000001033000390000002002200039000000000012004b00000c870000413d000011840000013d0000000001000416000000000001004b00001e290000c13d0000001501000039000000000101041a00000b8a01100197000000800010043f00000b8c0100004100002b850001042e000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000001202000039000000000012041b00000bcc0210009c0000141d0000813d0000001303000039000000000023041b000000800010043f000000a00020043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b93011001c70000800d02000039000000010300003900000bcd0400004100000d9f0000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000000000001004b0000000002000039000000010200c039000000000021004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000000a02000039000000000302041a00000b9e03300197000000000001004b00000b9f040000410000000004006019000000000343019f000000000032041b000000800010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d02000039000000010300003900000ba00400004100000d9f0000013d00000000010300192b841e3d0000040f00000000040100190000000005020019000000000603001900000000010004110000000002040019000000000305001900000000040600192b84297a0000040f000000000100001900002b850001042e000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000302043b00000b8a0030009c00001e290000213d0000002401100370000000000201043b00000b8a0020009c00001e290000213d00000000010300192b8424140000040f000000000001004b0000000001000039000000010100c039000010c90000013d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a000000b801100270000010d50000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000201043b000000000002004b000013ce0000613d000000000100041a000000000021004b000013ce0000a13d000a00000002001d000b00000002001d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b000013ab0000c13d0000000b02000029000000000002004b000000010220008a00000d0d0000c13d0000141d0000013d0000000001000416000000000001004b00001e290000c13d0000000203000039000000000203041a000000010420019000000001012002700000007f0110618f0000001f0010008c00000000050000390000000105002039000000000552013f0000000100500190000000670000c13d000000800010043f000000000004004b0000117f0000613d000000000030043f000000000001004b0000000002000019000011840000613d00000ae5030000410000000002000019000000000403041a000000a005200039000000000045043500000001033000390000002002200039000000000012004b00000d3a0000413d000011840000013d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000b9b001001980000106f0000013d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000301043b00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d000800000003001d0000001101000039000000000101041a000b00000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000b02000029000000000021004b0000141b0000a13d0000000a01000039000000000101041a000000e8011002700000ffff0410018f00000d750040008c00000008050000290000141d0000213d0000000b01000039000000000201041a0000ffff0320018f000000000053001a0000141d0000413d00000d75044000890000000005530019000000000045004b000015180000a13d000000000134004b00000008030000290000141d0000413d00000bc302000041000000000020043f000000040030043f000000240010043f00000af00100004100002b8600010430000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d0000000401100370000000000101043b0000000f02000039000000000012041b000000800010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b9c011001c70000800d02000039000000010300003900000be0040000412b842b750000040f000000010020019000001e290000613d000000000100001900002b850001042e000000640030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000a00000002001d0000002402100370000000000202043b000900000002001d00000b8a0020009c00001e290000213d0000004401100370000000000101043b000800000001001d00000af10010009c00001e290000213d0000000a01000029000000000001004b0000119b0000613d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000de10000c13d000000000100041a0000000a02000029000000000021004b0000119b0000a13d000b00000002001d0000000b01000029000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000dce0000613d00000ba5001001980000119b0000c13d00000b8a0010019800000de90000613d0000000a01000039000000000101041a00000b9b0010019800000ed40000613d0000000a01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000e120000c13d000000000100041a0000000a02000029000000000021004b0000119b0000a13d000b00000002001d0000000b01000029000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00000dff0000613d00000ba5001001980000119b0000c13d00000b8a011001970000000002000411000000000012004b00001a040000c13d0000000a01000029000000000010043f0000000901000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000090200002900000b8a062001970000000803000029000000a00230021000000baa02200197000000000262019f000000000101043b000000000021041b00000af101300197000000400200043d000000000012043500000ae20020009c00000ae2020080410000004001200210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000030300003900000bab040000410000000a0500002900000d9f0000013d000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000000001004b0000131b0000c13d00000c3401000041000000000010043f00000ba80100004100002b8600010430000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000600000001001d00000b8a0010009c00001e290000213d000000000100041a000000000001004b000011950000613d0005000100100094000012260000c13d00000080010000390000006002000039000b00000001001d2b841f520000040f0000118b0000013d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000201043b000000000002004b0000000001000039000000010100c039000a00000002001d000000000012004b00001e290000c13d000000000200041100000b8a0020019800000e800000613d0000000a01000039000000000101041a00000b9b0010019800000ed40000613d000000000020043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000b02000029000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000201041a00000c40022001970000000a03000029000000000232019f000000000021041b000000400100043d000000000031043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000030300003900000bc70400004100000000050004110000000b0600002900000d9f0000013d0000000001000416000000000001004b00001e290000c13d0000800b0100003900000004030000390000000004000415000000120440008a000000050440021000000b96020000412b842b570000040f000000800010043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d0000022b01000039000000800010043f00000b8c0100004100002b850001042e000000440030008c00001e290000413d0000000402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000201043b000000000100041100000b8a03100198000011990000613d0000000a01000039000000000101041a00000b9b00100198000011990000c13d00000c2f01000041000000000010043f00000ba80100004100002b8600010430000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d000000000010043f0000000d01000039000010e90000013d000000840030008c00001e290000413d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000004402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000404200039000000000441034f000000000504043b00000af10050009c000018e30000213d00000005045002100000003f0640003900000bac0660019700000bad0060009c000018e30000213d0000008006600039000000400060043f000000800050043f00000024022000390000000004240019000000000034004b00001e290000213d000000000005004b00000f120000613d0000008005000039000000000621034f000000000606043b000000200550003900000000006504350000002002200039000000000042004b00000f0b0000413d0000006401100370000000000101043b00000af10010009c00001e290000213d000000040110003900000000020300192b841ef50000040f0000000005010019000000000100041100000080040000390000000b020000290000000a030000292b8424490000040f000000000100001900002b850001042e0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000ba6001001980000106f0000013d0000000001000416000000000001004b00001e290000c13d00000c2d01000041000000800010043f0000000101000039000000a00010043f00000c2e0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d00000be901000041000000000010044300000000010004120000000400100443000000a0010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000400300043d00000ae20030009c00000ae20200004100000000020340190000004002200210000000000101043b00000b8a011001970000000004000410000000000014004b000011b50000c13d00000bef01000041000000000013043500000b9a012001c700002b850001042e000000a40030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000002402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000004402100370000000000202043b000900000002001d00000b8a0020009c00001e290000213d0000006402100370000000000202043b000800000002001d00000b8a0020009c00001e290000213d0000008402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d000600040020003d0000000601100360000000000101043b000700000001001d00000af10010009c00001e290000213d0000002402200039000500000002001d0000000701200029000000000031004b00001e290000213d0000001901000039000000000201041a000000ff002001900000182f0000c13d00000c400220019700000001022001bf000000000021041b0000000b0000006b00000e4f0000613d0000000a0000006b00000e4f0000613d000000090000006b00000e4f0000613d000000080000006b00000e4f0000613d00000b8d010000410000000b06000029000000000061041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000030300003900000bdc0400004100000000050000192b842b750000040f000000010020019000001e290000613d0000001401000039000000000201041a00000b92022001970000000a022001af000000000021041b0000001501000039000000000201041a00000b920220019700000009022001af000000000021041b0000001601000039000000000201041a00000b920220019700000008022001af000000000021041b0000001801000039000000000101041a000000010010019000000001021002700000007f0220618f000900000002001d0000001f0020008c00000000020000390000000102002039000000000121013f0000000100100190000000670000c13d0000000901000029000000200010008c00000fd40000413d0000001801000039000000000010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ae8011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d00000007030000290000001f023000390000000502200270000000200030008c0000000002004019000000000301043b00000009010000290000001f01100039000000050110027000000000011300190000000002230019000000000012004b00000fd40000813d000000000002041b0000000102200039000000000012004b00000fd00000413d0000000701000029000000200010008c00001ae60000413d0000001801000039000000000010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ae8011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000200200008a0000000702200180000000000101043b00001b000000c13d000000000300001900001b0b0000013d000000640030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000004402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000401043b00000ba101000041000000000301041a0000000002000410000000000023004b000010b10000613d000800000004001d000000000021041b0000001201000039000000000101041a000900000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000090010006c0000133f0000213d0000001501000039000000000101041a00000b8a021001980000148d0000613d000000400400043d000900000004001d000000240140003900000bcf03000041000000000031043500000bd001000041000000000014043500000004014000390000000a03000029000000000031043500000ae20040009c00000ae20100004100000000010440190000004001100210000000000300041400000ae20030009c00000ae203008041000000c003300210000000000113019f00000af0011001c72b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000090b00002900000009057000290000103a0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000010360000c13d000000000006004b000010470000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000100000003001f00030000000103550000000100200190000016d80000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000af10010009c000018e30000213d0000000100200190000018e30000c13d000000400010043f000000200030008c00001e290000413d00000000010b043300000b8a0010009c00001e290000213d0000000002000411000000000012004b00001acf0000c13d0000000b010000290000000a0200002900000008030000292b84277a0000040f0000000001000412001000000001001d000080020100003900000024030000390000000004000415000000100440008a000014100000013d0000000001000416000000000001004b00001e290000c13d0000000a01000039000000000101041a00000bd2001001980000000001000039000000010100c039000000800010043f00000b8c0100004100002b850001042e000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b000b00000001001d00000b8a0010009c00001e290000213d00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d0000000b04000029000000000004004b000013430000613d000000000101043b000000000001004b000013430000c13d00000bc401000041000000000010043f00000ba80100004100002b8600010430000000640030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b000b00000002001d00000b8a0020009c00001e290000213d0000004402100370000000000202043b000a00000002001d00000b8a0020009c00001e290000213d0000002401100370000000000401043b00000ba101000041000000000301041a0000000002000410000000000023004b0000132c0000c13d00000c2b01000041000000000010043f00000b910100004100002b86000104300000000001000416000000000001004b00001e290000c13d0000001301000039000010ed0000013d0000000001000416000000000001004b00001e290000c13d0000037801000039000000800010043f00000b8c0100004100002b850001042e000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b2b841f610000040f000000400200043d000000000012043500000ae20020009c00000ae202008041000000400120021000000b9a011001c700002b850001042e0000000001000416000000000001004b00001e290000c13d0000000b01000039000000000101041a0000ffff0110018f000000800010043f00000b8c0100004100002b850001042e00000000010300192b841ee30000040f2b841fa60000040f000000000100001900002b850001042e000000240030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000401100370000000000101043b00000b8a0010009c00001e290000213d000000000010043f0000000c01000039000000200010043f000000400200003900000000010000192b842b420000040f000000000101041a000000800010043f00000b8c0100004100002b850001042e0000000001000416000000000001004b00001e290000c13d0000000901000039000000800010043f00000af502000041000000a00020043f0000010002000039000000400020043f0000000102000039000000c00020043f00000af603000041000000e00030043f00000bd403000041000001000030043f000000e003000039000001200030043f000001e00010043f000002000100043d00000bd50110019700000af5011001c7000002000010043f000002090000043f0000012001000039000001400010043f000002200020043f000002400100043d00000bb10110019700000af6011001c7000002400010043f000002410000043f00000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000001600010043f0000000001000410000001800010043f000001a00000043f0000016001000039000001c00010043f000000600100043d000002600010043f000000000001004b000011c50000c13d0000018001000039000011cf0000013d000000440030008c00001e290000413d0000000002000416000000000002004b00001e290000c13d0000000402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000404200039000000000441034f000000000404043b000900000004001d00000af10040009c00001e290000213d000800240020003d000000090200002900000005022002100000000802200029000000000032004b00001e290000213d0000002402100370000000000202043b00000af10020009c00001e290000213d0000002304200039000000000034004b00001e290000813d0000000404200039000000000141034f000000000101043b00000af10010009c00001e290000213d000700240020003d00000005021002100000000702200029000000000032004b00001e290000213d00000b8d02000041000000000202041a00000b8a022001970000000003000411000000000023004b000012fc0000c13d000000090010006b000017750000c13d000000090000006b00000da20000613d000000000400001900000005014002100000000702100029000000080110002900000002011003670000000202200367000000000202043b000a00000002001d000000000101043b00000b8a0010009c00001e290000213d000000000010043f0000000d01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c70000801002000039000b00000004001d2b842b7a0000040f0000000b04000029000000010020019000001e290000613d000000000101043b0000000a02000029000000000021041b0000000104400039000000090040006c0000115c0000413d00000da20000013d00000bdb01000041000000000010043f00000b910100004100002b860001043000000c4002200197000000a00020043f000000000001004b00000020020000390000000002006039000000200220003900000080010000392b841e2b0000040f000000400100043d000b00000001001d00000080020000392b841eae0000040f0000000b02000029000000000121004900000ae20010009c00000ae201008041000000600110021000000ae20020009c00000ae2020080410000004002200210000000000121019f00002b850001042e00000bd701000041000000000010043f00000ba80100004100002b8600010430000000000002004b000011d40000c13d00000c3201000041000000000010043f00000ba80100004100002b860001043000000b9803000041000000000030043f000000040010043f000000240020043f00000af00100004100002b860001043000000c3a0030009c000011b10000613d00000c3b0030009c000011b10000613d00000c3c0030009c000011b10000613d000000e00220027000000b6e0020009c0000000001000039000000010100603900000b880020009c00000001011061bf000000010110018f000000800010043f00000b8c0100004100002b850001042e000000640130003900000beb040000410000000000410435000000440130003900000bec04000041000000000041043500000024013000390000003804000039000000000041043500000bed01000041000000000013043500000004013000390000002003000039000000000031043500000bee012001c700002b86000104300000008002000039000002800300003900000000040000190000000005030019000000002302043400000000033504360000000104400039000000000014004b000011c80000413d000000e00150008a00000ae20010009c00000ae201008041000000600110021000000bd6011001c700002b850001042e000800000003001d000900000002001d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b000011fe0000c13d000000000100041a0000000902000029000000000021004b0000119b0000a13d000b00000002001d0000000b01000029000000010110008a000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b000011eb0000613d00000ba50010019800000000020004110000119b0000c13d000b0b8a0010019b0000000b0020006c000015830000c13d0000000901000029000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000a0200002900000b8a06200197000000000101043b000000000201041a00000b9202200197000000000262019f000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000c31040000410000000b0500002900000009070000292b842b750000040f000000010020019000001e290000613d00000da20000013d000400000001001d0000000601000029000000000001004b000013d20000c13d00000bd801000041000000000010043f00000ba80100004100002b860001043000000bef02000041000000000202041a00000b8a02200197000000000012004b000013e70000c13d00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d000000400100043d000a00000001001d00000c000010009c000018e30000213d0000000a010000290000002002100039000900000002001d000000400020043f000000000001043500000bf001000041000000000101041a000000ff00100190000016980000c13d000000400200043d000800000002001d00000bf101000041000000000012043500000ae20020009c00000ae20100004100000000010240190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ba8011001c70000000b020000292b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000080b0000290000000805700029000012660000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000012620000c13d000000000006004b000012730000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000100000003001f000300000001035500000001002001900000181f0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000af10010009c000018e30000213d0000000100200190000018e30000c13d000000400010043f000000200030008c00001e290000413d00000000020b043300000bef0020009c00001ad70000c13d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b000016a80000613d00000bef01000041000000000201041a00000b92022001970000000b05000029000000000252019f000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000020300003900000bf4040000412b842b750000040f000000010020019000001e290000613d0000000a010000290000000001010433000000000001004b00000da20000613d000000400100043d000800000001001d00000bf50010009c000018e30000213d00000008030000290000006001300039000000400010043f000000400130003900000bf6020000410000000000210435000000200130003900000bf702000041000000000021043500000027010000390000000000130435000000090100002900000ae20010009c00000ae20100804100000040011002100000000a02000029000000000202043300000ae20020009c00000ae2020080410000006002200210000000000112019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f0000000b020000292b842b7f0000040f0003000000010355000000600310027000010ae20030019d00000ae20530019800001b690000c13d0000006003000039000000800400003900001b8f0000013d00000b8d01000041000000000101041a00000b8a011001970000000002000411000000000012004b000012fc0000c13d0000000a01000039000000000301041a000000c8013002700000ffff0110018f00000fa00010008c00000008060000290000141d0000213d000000d8023002700000ffff0220018f0000022b0020008c0000141d0000213d000000e8033002700000ffff0330018f00000d750030008c0000141d0000213d00000d75033000890000000b04000039000000000404041a0000ffff0540018f000000000035004b0000141d0000213d000000000112001900000000024300490000ffff0220018f0000000001120049000011cb011000390000ffff0010008c0000141d0000213d000000000016004b00001a4f0000a13d00000bc302000041000000000020043f000000080200002900001ae20000013d00000c3501000041000000000010043f00000ba80100004100002b86000104300000ffff0450018f00000000024200190000ffff0020008c0000141d0000213d00000bbe03300197000000b80220021000000bbf02200197000000000232019f000000000021041b000000000100041a000b00000001001d000000010110008a000000000051001a0000141d0000413d0000000002510019000022b90020008c000014820000413d000022b80010008c0000141d0000213d00000bc301000041000000000010043f000000040050043f0000000b01000029000022b901100089000000240010043f00000af00100004100002b86000104300000001402000039000000000302041a00000b9204300197000000000414019f000000000042041b00000b8a02300197000000800020043f000000a00010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000b93011001c70000800d02000039000000010300003900000b940400004100000d9f0000013d000800000004001d000000000021041b0000001201000039000000000101041a000900000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000090010006c000014890000a13d00000bdf01000041000000000010043f00000ba80100004100002b86000104300000000a01000039000000000201041a000000080120027000000b8a011001980000134b0000c13d000000ff00200190000000000100001900000aea01006041000000400200043d00000020032000390000000000430435000000000012043500000ae20020009c00000ae2020080410000004001200210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000aeb011001c70000800d02000039000000010300003900000aec040000412b842b750000040f000000010020019000001e290000613d0000000a04000039000000000104041a00000bc5011001970000000b03000029000000080230021000000bc602200197000000000112019f00000001011001bf000000000014041b000000000003004b00000da20000613d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b00000da20000613d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b00001e290000613d000000400300043d0000002401300039000002d102000039000000000021043500000aef01000041000000000013043500000004013000390000000002000410000000000021043500000ae20030009c000a00000003001d00000ae20100004100000000010340190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000af0011001c70000000b020000292b842b750000040f000000600310027000010ae20030019d0003000000010355000000010020019000000da20000613d0000000a0100002900000af10010009c000018e30000213d0000000a01000029000000400010043f000000000100001900002b850001042e00000ba500100198000013ce0000c13d000000400100043d0000000a02000039000000000202041a00000b9f00200198000014910000c13d0000001805000039000000000405041a000000010640019000000001024002700000007f0220618f0000001f0020008c00000000030000390000000103002039000000000334013f0000000100300190000000670000c13d0000000003210436000000000006004b000017790000613d000000000050043f000000000002004b00000000040000190000177e0000613d00000bb40500004100000000040000190000000006340019000000000705041a000000000076043500000001055000390000002004400039000000000024004b000013c60000413d0000177e0000013d00000bb501000041000000000010043f00000ba80100004100002b8600010430000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d000900000002001d000000000101043b000000000101041a00000af101100198000014c10000c13d0000000901000029000000600200003900000e640000013d000000400100043d000000640210003900000bfe030000410000000000320435000000440210003900000bff03000041000000000032043500000024021000390000002c03000039000000000032043500000bed02000041000000000021043500000004021000390000002003000039000000000032043500000ae20010009c00000ae201008041000000400110021000000bee011001c700002b8600010430000000000002004b0000146e0000c13d00000c3601000041000000000010043f00000b910100004100002b860001043000000ba3011001c7000080090200003900000000050000192b842b750000040f0003000000010355000000600110027000010ae20010019d0000000100200190000014170000613d0000000001000412000c00000001001d0000800201000039000000240300003900000000040004150000000c0440008a000000050440021000000aed020000412b842b570000040f00000ba102000041000000000012041b000000000100001900002b850001042e00000ba401000041000000000010043f00000b910100004100002b8600010430000000010220003a0000147a0000c13d00000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b8600010430000000400300043d00000af701000041000a00000003001d0000000001130436000b00000001001d00000be9010000410000000000100443000000040020044300000040010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000b02000029000000000012043500000be90100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000a020000290000004002200039000000000012043500000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000a040000290000008002400039000000000300041000000000003204350000006002400039000000000012043500000ae20040009c00000ae2040080410000004001400210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f00000c06011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000b00000001001d000007180000013d0000006002200210000000000121019f00000be502000041000000000012041b000000000100001900002b850001042e0000000901000029000000000001041b0000000b010000292b84286f0000040f000000000100001900002b850001042e00000c1303000041000000000030043f000000040010043f000000240020043f000000010100008a000000440010043f00000c020100004100002b8600010430000800000005001d000000000005004b000015120000c13d00000c1701000041000000000010043f00000ba80100004100002b86000104300000001501000039000000000101041a00000b8a021001980000152f0000c13d00000bde01000041000000000010043f00000ba80100004100002b8600010430000000a002100039000000400020043f000000800210003900000000000204350000000a060000290000000003020019000000090060008c0000000a2660011a000000f804200210000000010230008a000000000502043300000bb105500197000000000445019f00000bb2044001c70000000000420435000014960000213d00000000013100490000008101100039000000210330008a00000000001304350000001707000039000000000607041a000000010860019000000001046002700000007f0440618f0000001f0040008c00000000010000390000000101002039000000000116013f0000000100100190000000670000c13d000000400100043d0000002005100039000000000008004b000017810000613d000000000070043f000000000004004b000017830000613d00000bb30600004100000000070000190000000008570019000000000906041a000000000098043500000001066000390000002007700039000000000047004b000014b90000413d000017830000013d000000050010006b00000000020100190000000502004029000500000002001d000000050120021000000009011000290000002001100039000000400010043f000800000001001d00000bad0010009c000018e30000213d00000008020000290000008001200039000000400010043f0000006001200039000000000001043500000040012000390000000000010435000000200120003900000000000104350000000000020435000000000100041a000000020010008c0000000001000019000017cf0000413d0000000101000039000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b000018e00000c13d0000000b01000029000000010110008a000014db0000013d00000c1302000041000000000020043f000000040010043f0000000701000029000000240010043f0000000601000029000000440010043f00000c020100004100002b8600010430000000000004004b0000000003000019000014fe0000613d0000002003600039000000000131034f000000000301043b000000030140021000000c420110027f00000c4201100167000000000113016f0000000103400210000000000131019f0000162f0000013d000000000004004b00000000030000190000150b0000613d0000002003600039000000000131034f000000000301043b000000030140021000000c420110027f00000c4201100167000000000113016f0000000103400210000000000131019f0000166f0000013d0000000a0000006b000016e40000c13d00000c2401000041000000000010043f00000ba80100004100002b860001043000000008050000290000ffff0450018f00000000034300190000ffff0030008c0000141d0000213d00000c1402200197000000000223019f000000000021041b000000000100041a000b00000001001d000000010110008a000000000051001a0000141d0000413d0000000002510019000022b90020008c000018330000413d000022b80010008c00000008020000290000141d0000213d00000bc301000041000000000010043f000000040020043f000013160000013d000000400400043d000900000004001d000000240140003900000bcf03000041000000000031043500000bd001000041000000000014043500000004014000390000000a03000029000000000031043500000ae20040009c00000ae20100004100000000010440190000004001100210000000000300041400000ae20030009c00000ae203008041000000c003300210000000000113019f00000af0011001c72b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0640018f0000002007400190000000090b0000290000000905700029000015540000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b000015500000c13d000000000006004b000015610000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000100000003001f00030000000103550000000100200190000017570000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000af10010009c000018e30000213d0000000100200190000018e30000c13d000000400010043f000000200030008c00001e290000413d00000000010b043300000b8a0010009c00001e290000213d0000000002000411000000000012004b00001acf0000c13d0000000b010000290000000a0200002900000008030000292b8428850000040f0000000001000412000f00000001001d0000800201000039000000240300003900000000040004150000000f0440008a000014100000013d0000000b01000029000000000010043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000802000029000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000ff00100190000012040000c13d0000000a01000039000000000101041a00000ba600100198000015ad0000613d000000080210027000000b8a02200198000015ab0000c13d000000ff00100190000000000200001900000aea02006041000000080020006b000012040000613d00000c3001000041000000000010043f00000ba80100004100002b86000104300000001001000039000000000101041a000500000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000201043b000000050120006c000018f00000813d0000000b0000006b000019380000c13d00000c2901000041000000000010043f000000040000043f0000000101000039000000240010043f00000af00100004100002b8600010430000b00000001001d000800000000001d00000000010000190000000a05000029000015d50000013d000b00000000001d0000000901000029000000400010043f000000010550003900000001010000390000000100100190000015dc0000613d000000060050006c000019fd0000613d0000000802000029000000050020006c000019fd0000613d000000400100043d00000bad0010009c000018e30000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000a00000005001d000000000050043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d00000bad0020009c0000000a05000029000018e30000213d000000000101043b000000000101041a0000006003200039000000e8041002700000000000430435000000400320003900000ba5001001980000000004000039000000010400c0390000000000430435000000a00310027000000af1033001970000002004200039000000000034043500000b8a011001970000000000120435000015d00000c13d000000000001004b00000000020100190000000b02006029000b00000002001d000000070120014f00000b8a00100198000015d10000c13d00000008010000290000000101100039000800000001001d000000050110021000000004011000290000000000510435000015d10000013d00000bb40300004100000000070000190000000008570019000000000881034f000000000808043b000000000083041b00000001033000390000002007700039000000000067004b0000161a0000413d000000000046004b0000162d0000813d0000000306400210000000f80660018f00000c420660027f00000c42066001670000000005570019000000000151034f000000000101043b000000000161016f000000000013041b000000010140021000000001011001bf000000000012041b0000002003000039000000800030043f000000010310019000000001041002700000007f0440618f000b00000004001d0000001f0040008c00000000040000390000000104002039000000000441013f0000000100400190000000670000c13d0000000b04000029000000a00040043f000000000003004b000016b20000613d000000000020043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ae8011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b05000029000000000005004b0000000002000019000016b70000613d000000000101043b0000000002000019000000000301041a000000c004200039000000000034043500000001011000390000002002200039000000000052004b000016500000413d000016b70000013d00000bb30300004100000000070000190000000008570019000000000881034f000000000808043b000000000083041b00000001033000390000002007700039000000000067004b0000165a0000413d000000000046004b0000166d0000813d0000000306400210000000f80660018f00000c420660027f00000c42066001670000000005570019000000000151034f000000000101043b000000000161016f000000000013041b000000010140021000000001011001bf000000000012041b0000002003000039000000800030043f000000010310019000000001041002700000007f0440618f000b00000004001d0000001f0040008c00000000040000390000000104002039000000000441013f0000000100400190000000670000c13d0000000b04000029000000a00040043f000000000003004b000016c50000613d000000000020043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ae8011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000b05000029000000000005004b0000000002000019000016ca0000613d000000000101043b0000000002000019000000000301041a000000c004200039000000000034043500000001011000390000002002200039000000000052004b000016900000413d000016ca0000013d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b000018e90000c13d000000400100043d000000640210003900000c03030000410000000000320435000000440210003900000c0403000041000000000032043500000024021000390000002d03000039000013f00000013d00000c4001100197000000c00010043f0000000b0000006b00000020020000390000000002006039000000000100041400000ae20010009c00000ae201008041000000c001100210000000400220003900000ae20020009c00000ae2020080410000006002200210000000000112019f00000bb9011001c70000800d02000039000000010300003900000bba0400004100000d9f0000013d00000c4001100197000000c00010043f0000000b0000006b00000020020000390000000002006039000000000100041400000ae20010009c00000ae201008041000000c001100210000000400220003900000ae20020009c00000ae2020080410000006002200210000000000112019f00000bb9011001c70000800d02000039000000010300003900000be70400004100000d9f0000013d0000001f0530018f00000bd106300198000000400200043d0000000004620019000017620000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b000016df0000c13d000017620000013d000000010100008a0000000b0310014f00000000010000190000000802000029000000000031004b0000141d0000213d0000000101100039000000000021004b000016e80000413d000700000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000900000001001d0000000b01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000902000029000000a0022002100000000803000029000000010030008c000000000300001900000bc003006041000000000223019f0000000a03000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000080400002900000bc1024000d1000000000301041a0000000002230019000000000021041b0009000b0040002d0000000001000019000017380000013d0000000b07000029000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000050000190000000a06000029000b00000007001d2b842b750000040f0000000100200190000000010100003900001e290000613d0000000100100190000017280000613d0000000b070000290000000107700039000000090070006c000017290000c13d0000000901000029000000000010041b000000000100001900000008020000290000000703000029000000000031004b0000141d0000213d0000000101100039000000000021004b000017430000413d000000400100043d000000000021043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000020300003900000bc20400004100000e3c0000013d0000001f0530018f00000bd106300198000000400200043d0000000004620019000017620000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000175e0000c13d000000000005004b0000176f0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000ae20020009c00000ae2020080410000004002200210000000000112019f00002b860001043000000bd301000041000000000010043f00000ba80100004100002b860001043000000c40044001970000000000430435000000000002004b000000200400003900000000040060390000003f02400039000000200300008a000017b60000013d00000c4006600197000000000065043500000000045400190000000005030433000000200300008a000000000735016f0000001f0650018f000000000042004b0000179a0000813d000000000007004b000017960000613d00000000096200190000000008640019000000200880008a000000200990008a000000000a780019000000000b790019000000000b0b04330000000000ba0435000000200770008c000017900000c13d000000000006004b000017b00000613d0000000008040019000017a60000013d0000000008740019000000000007004b000017a30000613d0000000009020019000000000a040019000000009b090434000000000aba043600000000008a004b0000179f0000c13d000000000006004b000017b00000613d00000000027200190000000306600210000000000708043300000000076701cf000000000767022f00000000020204330000010006600089000000000262022f00000000026201cf000000000272019f0000000000280435000000000245001900000000000204350000000002120049000000200420008a00000000004104350000001f02200039000000000232016f0000000004120019000000000024004b0000000002000039000000010200403900000af10040009c000018e30000213d00000000030400190000000100200190000018e30000c13d000b00000003001d000000400030043f000000200200003900000000022304362b841e7c0000040f0000000b02000029000000000121004900000ae20010009c00000ae20100804100000ae20020009c00000ae20200804100000060011002100000004002200210000000000121019f00002b850001042e000a00000001001d0000000105000039000700000000001d00000000010000190000000902000029000017db0000013d000a00000000001d00000009020000290000000801000029000000400010043f000000010550003900000001010000390000000100100190000017e20000613d000000040050006c00001ad30000613d0000000703000029000000050030006c00001ad30000613d000000400100043d00000bad0010009c000018e30000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000b00000005001d000000000050043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d00000bad0020009c0000000b05000029000018e30000213d000000000101043b000000000101041a0000006003200039000000e8041002700000000000430435000000400320003900000ba5001001980000000004000039000000010400c0390000000000430435000000a00310027000000af1033001970000002004200039000000000034043500000b8a011001970000000000120435000017d50000c13d000000000001004b00000000020100190000000a02006029000a00000002001d000000060120014f00000b8a001001980000000902000029000017d70000c13d00000007010000290000000101100039000700000001001d000000050110021000000000012100190000000000510435000017d70000013d000000400200043d000b00000002001d00000bed01000041000000000012043500000004012000392b84276d0000040f0000000b02000029000000000121004900000ae20010009c00000ae201008041000000600110021000000ae20020009c00000ae2020080410000004002200210000000000121019f00002b860001043000000c0701000041000000000010043f00000ba80100004100002b8600010430000000080000006b000014850000613d0000000a0000006b000015140000613d000000010100008a0000000b0310014f00000000010000190000000802000029000000000031004b0000141d0000213d0000000101100039000000000021004b0000183b0000413d000700000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000900000001001d0000000b01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000902000029000000a0022002100000000803000029000000010030008c000000000300001900000bc003006041000000000223019f0000000a03000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000080400002900000bc1024000d1000000000301041a0000000002230019000000000021041b0009000b0040002d00000000010000190000188b0000013d0000000b07000029000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000050000190000000a06000029000b00000007001d2b842b750000040f0000000100200190000000010100003900001e290000613d00000001001001900000187b0000613d0000000b070000290000000107700039000000090070006c0000187c0000c13d0000000901000029000000000010041b000000000100001900000008020000290000000703000029000000000031004b0000141d0000213d0000000101100039000000000021004b000018960000413d000000400100043d000000000021043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000020300003900000c15040000410000000a0500002900000d9f0000013d000000400100043d00000bad0010009c000018e30000213d0000008002100039000000400020043f00000060021000390000000000020435000000400210003900000000000204350000002002100039000000000002043500000000000104350000000b01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d00000bad0020009c000018e30000213d000000000101043b000000000101041a0000008003200039000000400030043f0000006003200039000000e8041002700000000000430435000000400320003900000ba5001001980000000004000039000000010400c0390000000000430435000000a00310027000000af1033001970000002004200039000000000034043500000b8a011001970000000000120435000b00000000001d000b00000001601d000015cc0000013d00000bfb01000041000000000010043f00000ba80100004100002b8600010430000000400100043d00000bad0010009c0000190a0000a13d00000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b860001043000000bef01000041000000000201041a00000b92022001970000000b022001af000000000021041b000000000100001900002b850001042e000000060020006c000007540000813d0000000a02000039000000000202041a00000bd200200198000015c20000613d00000005030000290000000602300069000000000021004b000000000102801900000d75031000c900000d750430011a000000000014004b0000141d0000c13d00000000012300d900000d750010008c0000141d0000213d00000d75011000890000000b02000039000000000202041a0000ffff0220018f000000000121004b000007540000a13d000000070010006c000015c20000213d000007540000013d0000008002100039000000400020043f00000060021000390000000000020435000000400210003900000000000204350000002002100039000000000002043500000000000104350000000b01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000400200043d00000bad0020009c000018e30000213d000000000101043b000000000101041a0000008003200039000000400030043f0000006003200039000000e8041002700000000000430435000000400320003900000ba5001001980000000004000039000000010400c0390000000000430435000000a00310027000000af1033001970000002004200039000000000034043500000b8a011001970000000000120435000a00000000001d000a00000001601d000017d00000013d0000000f01000039000000000201041a0000000b012000b9000000000002004b000019400000613d00000000022100d90000000b0020006c0000141d0000c13d0000000002000416000000000012004b00001ae00000c13d000000400100043d00000060021000390000000b03000029000000000032043500000060020000390000000002210436000000000300041100000b8a043001970000004003100039000700000004001d000000000043043500000c1a03000041000000000032043500000bad0010009c000018e30000213d0000008003100039000000400030043f00000ae20020009c00000ae2020080410000004002200210000000000101043300000ae20010009c00000ae2010080410000006001100210000000000121019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ba3011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000600000001001d00000be90100004100000000001004430000000001000412000000040010044300000080010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000500000001001d00000be9010000410000000000100443000000000100041200000004001004430000002400000443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000400000001001d00000be90100004100000000001004430000000001000412000000040010044300000020010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000300000001001d00000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000002000410000000040020006c00001bbe0000c13d000000030010006c00001bbe0000c13d00000c1b01000041000000000010043f00000005010000290000001a0010043f00000006010000290000003a0010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000c1c011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000a020000290000001f0320003900000c41033001970000003f0330003900000c4103300197000000000101043b000400000001001d0000003a0000043f000000400400043d0000000001340019000600000004001d000000000041004b0000000003000039000000010300403900000af10010009c000018e30000213d0000000100300190000018e30000c13d0000001603000039000000000303041a000300000003001d000000400010043f0000000a0100002900000006040000290000000001140436000500000001001d0000000801000029000000000010007c00001e290000213d0000000a0100002900000c41021001980000001f0310018f0000000501200029000000090400002900000020044000390000000204400367000019e50000613d000000000504034f0000000506000029000000005705043c0000000006760436000000000016004b000019e10000c13d000000030500002900090b8a0050019b000000000003004b000019f40000613d000000000224034f0000000303300210000000000401043300000000043401cf000000000434022f000000000202043b0000010003300089000000000232022f00000000023201cf000000000242019f000000000021043500000005020000290000000a012000290000000000010435000000090000006b00001c430000c13d00000c2601000041000000000010043f00000ba80100004100002b8600010430000000040100002900000008020000290000000000210435000000400100043d000b00000001001d000000040200002900000e650000013d000000000010043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000200041100000b8a02200197000b00000002001d000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000ff0010019000000e180000c13d0000000a01000039000000000101041a00000ba60010019800001a2f0000613d000000080210027000000b8a0220019800001a2d0000c13d000000ff00100190000000000200001900000aea020060410000000b0020006b00000e180000613d000000000100041a0000000a0010006c00001b650000a13d0000000a01000029000b00000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a000000000001004b00001b4c0000c13d0000000b01000029000000000001004b000000010110008a00001a330000c13d0000141d0000013d00000aed0100004100000000001004430000000b01000029000000040010044300000000010004140000169d0000013d000000000100041a000b00000001001d000000010110008a0000000802000029000000000021001a0000141d0000413d0000000002210019000022b90020008c000015280000813d000000080000006b000014850000613d0000000a0000006b000015140000613d000000010100008a0000000b0310014f00000000010000190000000802000029000000000031004b0000141d0000213d0000000101100039000000000021004b00001a600000413d000700000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000900000001001d0000000b01000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000902000029000000a0022002100000000803000029000000010030008c000000000300001900000bc003006041000000000223019f0000000a03000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000080400002900000bc1024000d1000000000301041a0000000002230019000000000021041b0009000b0040002d000000000100001900001ab00000013d0000000b07000029000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000050000190000000a06000029000b00000007001d2b842b750000040f0000000100200190000000010100003900001e290000613d000000010010019000001aa00000613d0000000b070000290000000107700039000000090070006c00001aa10000c13d0000000901000029000000000010041b000000000100001900000008020000290000000703000029000000000031004b0000141d0000213d0000000101100039000000000021004b00001abb0000413d000000400100043d000000000021043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000010300003900000c160400004100000d9f0000013d00000bdd01000041000000000010043f00000ba80100004100002b860001043000000007010000290000000000120435000000400100043d00000e640000013d000000640210003900000bf2030000410000000000320435000000440210003900000bf303000041000000000032043500000024021000390000002903000039000013f00000013d00000c1903000041000000000030043f000000040020043f000000240010043f00000af00100004100002b8600010430000000070000006b000000000100001900001b1a0000613d0000000703000029000000030130021000000c420110027f00000c4201100167000000060200002900000020022000390000000202200367000000000202043b000000000112016f0000000102300210000000000121019f00001b1a0000013d00000bae01000041000000000010043f00000ba80100004100002b86000104300000000101000039000000000201041a000000800300043d0000000002320019000000000021041b000000000100001900002b850001042e0000000204000367000000000300001900000005060000290000000005630019000000000554034f000000000505043b000000000051041b00000001011000390000002003300039000000000023004b00001b030000413d000000070020006c00001b170000813d00000007020000290000000302200210000000f80220018f00000c420220027f00000c420220016700000005033000290000000203300367000000000303043b000000000223016f000000000021041b0000000701000029000000010110021000000001011001bf0000001802000039000000000012041b00000c08010000410000000f02000039000000000012041b0000000b01000039000000000201041a00000bbc0220019700000c09022001c7000000000021041b0000000a01000039000000000201041a00000c0a0220019700000bd2022001c7000000000021041b00000c0b010000410000001002000039000000000012041b00000c0c010000410000001102000039000000000012041b00000c0d010000410000001202000039000000000012041b00000c0e010000410000001302000039000000000012041b0000000a010000290000006001100212000013fd0000613d000001f4011001bf00000be502000041000000000012041b0000000103000039000000000030041b000000400100043d0000000b02000029000000000021043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d0200003900000c0f0400004100000d9f0000013d00000ba50010019800001b650000c13d0000000a01000029000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a00000b8a011001970000000002000411000000000021004b00000e180000613d00000ba901000041000000000010043f00000ba80100004100002b860001043000000ba701000041000000000010043f00000ba80100004100002b86000104300000001f0350003900000bf9033001970000003f0330003900000bfa04300197000000400300043d0000000004430019000000000034004b0000000006000039000000010600403900000af10040009c000018e30000213d0000000100600190000018e30000c13d000000400040043f0000001f0650018f000000000453043600000bd107500198000000000574001900001b820000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b00001b7e0000c13d000000000006004b00001b8f0000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f00000000001504350000000001030433000000010020019000001bb50000613d000000000001004b00000da20000c13d00000aed0100004100000000001004430000000b010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b00000da20000c13d000000400100043d000000440210003900000c0103000041000000000032043500000024021000390000001d03000039000000000032043500000bed02000041000000000021043500000004021000390000002003000039000000000032043500000ae20010009c00000ae201008041000000400110021000000c02011001c700002b8600010430000000000001004b00001c3b0000c13d000000400200043d000b00000002001d00000bed0100004100000000001204350000000401200039000000080200002900001c390000013d000000400200043d00000af701000041000400000002001d0000000001120436000500000001001d00000be90100004100000000001004430000000001000412000000040010044300000040010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b0000000502000029000000000012043500000be90100004100000000001004430000000001000412000000040010044300000060010000390000002400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000bea011001c700008005020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b00000004020000290000004002200039000000000012043500000af2010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b00000004040000290000008002400039000000000300041000000000003204350000006002400039000000000012043500000ae20040009c00000ae2040080410000004001400210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f00000c06011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000500000001001d000019ab0000013d0000001f0350003900000bf9033001970000003f0330003900000bfa04300197000000400300043d0000000004430019000000000034004b0000000006000039000000010600403900000af10040009c000018e30000213d0000000100600190000018e30000c13d000000400040043f0000001f0650018f000000000453043600000bd107500198000000000574001900001c230000613d000000000801034f0000000009040019000000008a08043c0000000009a90436000000000059004b00001c1f0000c13d000000000006004b000004fd0000613d000000000171034f0000000306600210000000000705043300000000076701cf000000000767022f000000000101043b0000010006600089000000000161022f00000000016101cf000000000171019f0000000000150435000004fd0000013d000000000001004b00001c3b0000c13d000000400200043d000b00000002001d00000bed01000041000000000012043500000004012000390000000a020000292b841eae0000040f000018250000013d00000ae20040009c00000ae204008041000000400240021000000ae20010009c00000ae2010080410000006001100210000000000121019f00002b8600010430000000400100043d000800000001001d00000aed01000041000000000010044300000009010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000000000001004b00001c630000c13d00000006010000290000000001010433000000400010008c00001cd70000613d000000410010008c000019f90000c13d000000060200002900000060012000390000000001010433000000f801100270000000200010043f0000004001200039000000000101043300001cde0000013d0000000803000029000500440030003d0000002404300039000000040130003900000c1d020000410000000000230435000000040200002900000000002104350000004001000039000a00000004001d0000000000140435000000060200002900000ae20020009c00000ae2010000410000000001024019000000400110021000000000020204330000002002200039000400000002001d00000ae20020009c00000ae2020080410000006002200210000000000112019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f00000004020000392b842b7a0000040f000600000002001d000000600210027000000ae202200197000000040020006c000000040300002900000000030240190000001f0430018f00000bd1053001980000000508000029000000050350002900001c920000613d000000000601034f000000006706043c00000000097804360000000008090019000000000039004b00001c8d0000c13d000000000004004b00001c9f0000613d000000000551034f0000000304400210000000000603043300000000064601cf000000000646022f000000000505043b0000010004400089000000000545022f00000000044501cf000000000464019f00000000004304350003000000010355000100000002001f000000080100002900000ae20010009c00000ae201008041000000400110021000000c1e0020009c00000c1e020080410000006002200210000000000112019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f00000c1f0110009a00000009020000292b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0540018f00000020064001900000000a0460002900001cc00000613d000000000701034f0000000a08000029000000007907043c0000000008980436000000000048004b00001cbc0000c13d000000000005004b00001ccd0000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f0000000000540435000100000003001f0003000000010355000000060120017f0000000100100190000019f90000613d0000000a01000029000000000101043300000c1d0010009c00001d140000613d000019f90000013d000000060100002900000040011000390000000001010433000000ff021002700000001b02200039000000200020043f00000c2001100197000000600010043f0000000401000029000000000010043f00000005010000290000000001010433000000400010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000bb7011001c70000000102000039000a00000002001d2b842b7a0000040f000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0540018f000000200640019000000001046001bf00001cfc0000613d000000000701034f000000007807043c0000000a090000290000000009890436000a00000009001d000000000049004b00001cf60000c13d000000010220018f000000000005004b00001d0a0000613d000000000661034f0000000305500210000000000704043300000000075701cf000000000757022f000000000606043b0000010005500089000000000656022f00000000055601cf000000000575019f00000000005404350003000000010355000100000003001f0000000001020433000000600000043f0000000802000029000000400020043f000000030110014f0000006001100210000000000013004b000019f90000a13d0000000a01000039000000000101041a000000e8011002700000ffff0110018f000a00000001001d00000d740010008c000000000300001900001d200000a13d00000bc301000041000000000010043f0000000b010000290000032a0000013d0000001101000039000000000101041a000800000001001d0000001001000039000000000101041a000900000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d00000d7502000039000000000301043b000000090130006c00001d3c0000413d000000080030006c000000000300001900001d1c0000813d0000000a03000039000000000303041a00000bd20030019800001d600000c13d0000000a0320006a0000000b0030006b00001d1c0000213d0000000701000029000000000010043f0000000e01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000101041a0000ffff0110018f0000000b0010002a0000141d0000413d0000000b031000290000000b02000039000000000202041a00000010022002700000ffff0220018f000000000023004b00001d750000a13d00000c2503000041000000000030043f0000000b03000029000000040030043f000000240010043f000000440020043f00000c020100004100002b860001043000000009030000290000000802300069000000000021004b000000000102801900000d75031000c900000d750430011a000000000014004b0000141d0000c13d00000000012300d900000d750010008c0000141d0000213d00000d75011000890000000b02000039000000000202041a0000ffff0220018f000000000221004b00001daa0000a13d0000000a0020006c000000000300001900001d3c0000213d00001d1c0000013d0000000b02000029000affff002001930000000a01100029000900000001001d0000ffff0010008c0000141d0000213d0000000701000029000000000010043f0000000e01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b000000000201041a00000c140220019700000009022001af000000000021041b0000000a01000039000000000101041a000000e8021002700000ffff0220018f0000000a022000290000ffff0020008c0000141d0000213d00000c2101100197000000e80220021000000c2202200197000000000112019f0000000a02000039000000000012041b000000000100041a000900000001001d000000010110008a0000000b0010002a0000141d0000413d0000000b02100029000022b90020008c00001dac0000413d000022b80010008c0000141d0000213d00000bc301000041000000000010043f0000000b01000029000000040010043f0000000901000029000013170000013d000000000300001900001d1c0000013d000000070000006b000015140000613d000000010100008a000a00090010015300000000010000190000000a0010006c0000141d0000213d00000001011000390000000b0010006c00001db10000413d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000001df00000613d000000000101043b000800000001001d0000000901000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d0000000802000029000000a0022002100000000b03000029000000010030008c000000000300001900000bc003006041000000000223019f0000000703000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001e290000613d000000000101043b0000000b0400002900000bc1024000d1000000000301041a0000000002230019000000000021041b000800090040002d000000000100001900001e000000013d000000000001042f000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf040000410000000005000019000000070600002900000009070000292b842b750000040f0000000100200190000000010100003900001e290000613d000000010010019000001df10000613d00000009010000290000000101100039000900000001001d000000080010006c00001df10000c13d0000000801000029000000000010041b00000000010000190000000a0010006c0000141d0000213d00000001011000390000000b0010006c00001e0a0000413d000000400100043d0000000b02000029000000000021043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000020300003900000c230400004100000007050000292b842b750000040f000000010020019000001e290000613d0000000001000412001100000001001d000080020100003900000024030000390000000004000415000000110440008a000014100000013d000000000100001900002b86000104300000001f0220003900000c41022001970000000001120019000000000021004b0000000002000039000000010200403900000af10010009c00001e370000213d000000010020019000001e370000c13d000000400010043f000000000001042d00000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b860001043000000c200010009c00001e740000213d0000000004010019000000630010008c00001e740000a13d00000002050003670000000401500370000000000101043b00000b8a0010009c00001e740000213d0000002402500370000000000202043b00000b8a0020009c00001e740000213d0000004403500370000000000603043b00000af10060009c00001e740000213d0000002303600039000000000043004b00001e740000813d0000000403600039000000000335034f000000000703043b00000c430070009c00001e760000813d00000005087002100000003f0380003900000bac09300197000000400300043d0000000009930019000000000039004b000000000a000039000000010a00403900000af10090009c00001e760000213d0000000100a0019000001e760000c13d000000400090043f000000000073043500000024066000390000000008680019000000000048004b00001e740000213d000000000007004b00001e730000613d0000000004030019000000000765034f000000000707043b000000200440003900000000007404350000002006600039000000000086004b00001e6c0000413d000000000001042d000000000100001900002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b86000104300000000043010434000000000132043600000c41063001970000001f0530018f000000000014004b00001e920000813d000000000006004b00001e8e0000613d00000000085400190000000007510019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c00001e880000c13d000000000005004b00001ea80000613d000000000701001900001e9e0000013d0000000007610019000000000006004b00001e9b0000613d00000000080400190000000009010019000000008a0804340000000009a90436000000000079004b00001e970000c13d000000000005004b00001ea80000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f0000000000470435000000000431001900000000000404350000001f0330003900000c41023001970000000001210019000000000001042d000000200300003900000000033104360000000042020434000000000023043500000c41062001970000001f0520018f0000004001100039000000000014004b00001ec70000813d000000000006004b00001ec30000613d00000000085400190000000007510019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c00001ebd0000c13d000000000005004b00001edd0000613d000000000701001900001ed30000013d0000000007610019000000000006004b00001ed00000613d00000000080400190000000009010019000000008a0804340000000009a90436000000000079004b00001ecc0000c13d000000000005004b00001edd0000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f0000000000470435000000000412001900000000000404350000001f0220003900000c41022001970000000001120019000000000001042d00000c200010009c00001ef30000213d000000630010008c00001ef30000a13d00000002030003670000000401300370000000000101043b00000b8a0010009c00001ef30000213d0000002402300370000000000202043b00000b8a0020009c00001ef30000213d0000004403300370000000000303043b000000000001042d000000000100001900002b860001043000000000030100190000001f01100039000000000021004b000000000400001900000c440400404100000c440520019700000c4401100197000000000651013f000000000051004b000000000100001900000c440100204100000c440060009c000000000104c019000000000001004b00001f3d0000613d0000000205000367000000000135034f000000000401043b00000c430040009c00001f370000813d0000001f0140003900000c41011001970000003f0110003900000c4107100197000000400100043d0000000007710019000000000017004b0000000008000039000000010800403900000af10070009c00001f370000213d000000010080019000001f370000c13d0000002008300039000000400070043f00000000034104360000000007840019000000000027004b00001f3d0000213d000000000585034f00000c41064001980000001f0740018f000000000263001900001f270000613d000000000805034f0000000009030019000000008a08043c0000000009a90436000000000029004b00001f230000c13d000000000007004b00001f340000613d000000000565034f0000000306700210000000000702043300000000076701cf000000000767022f000000000505043b0000010006600089000000000565022f00000000056501cf000000000575019f000000000052043500000000024300190000000000020435000000000001042d00000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b8600010430000000000100001900002b8600010430000000004301043400000b8a033001970000000003320436000000000404043300000af104400197000000000043043500000040031000390000000003030433000000000003004b0000000003000039000000010300c0390000004004200039000000000034043500000060022000390000006001100039000000000101043300000be3011001970000000000120435000000000001042d00000020030000390000000004310436000000000302043300000000003404350000004001100039000000000003004b00001f600000613d00000000040000190000002002200039000000000502043300000000015104360000000104400039000000000034004b00001f5a0000413d000000000001042d0002000000000002000000000001004b00001f980000613d000000000200041a000000000012004b00001f980000a13d000100000001001d000200000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001f960000613d000000000101043b000000000101041a000000000001004b00001f830000c13d0000000201000029000000000001004b000000010110008a00001f680000c13d00000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b860001043000000ba500100198000000010100002900001f980000c13d000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000001f960000613d000000000101043b000000000101041a00000b8a01100197000000000001042d000000000100001900002b860001043000000ba701000041000000000010043f00000ba80100004100002b86000104300000000a01000039000000000201041a000000080120027000000b8a0110019800001fa20000613d000000000001042d000000ff00200190000000000100001900000aea01006041000000000001042d0008000000000002000500000002001d000600000001001d000700000003001d000000000003004b000020f90000613d0000000701000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b000000000101041a000000000001004b00001fd40000c13d000000000100041a000000070010006c000020f90000a13d0000000702000029000000010220008a000800000002001d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b000000000101041a000000000001004b000000080200002900001fc10000613d00000ba500100198000020f90000c13d000000060200002900000b8a02200197000400000001001d00000b8a01100197000600000002001d000000000021004b000020fe0000c13d0000000701000029000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000401043b000000000504041a00000000060004110000000603000029000000000036004b000020230000613d000000000056004b000020230000613d000300000005001d000800000004001d000000000030043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000000030004110000000100200190000020f70000613d000000000101043b00000b8a02300197000200000002001d000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000000060004110000000100200190000020f70000613d000000000101043b000000000101041a000000ff00100190000000060300002900000008040000290000000305000029000020230000c13d0000000a01000039000000000101041a00000ba6001001980000210a0000613d000000080210027000000b8a02200198000020210000c13d000000ff00100190000000000200001900000aea02006041000000020020006b0000210a0000c13d000000000003004b0000206e0000613d0000000a01000039000000000101041a00000b9b00100198000021060000613d000000050200002900000b8a07200198000020710000613d000000080210027000000b8a02200198000020f10000613d000000000026004b000020710000613d000200000007001d000300000005001d000800000004001d00000aed010000410000000000100443000100000002001d0000000400200443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f0000000100200190000020fd0000613d000000000101043b000000000001004b00000000030004110000000204000029000020f70000613d000000400500043d0000006401500039000000070200002900000000002104350000004401500039000000000041043500000024015000390000000602000029000000000021043500000c2d01000041000000000015043500000b8a013001970000000402500039000000000012043500000ae20050009c000200000005001d00000ae20100004100000000010540190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000bee011001c700000001020000292b842b7a0000040f000000600310027000010ae20030019d00030000000103550000000100200190000021120000613d000000020100002900000c430010009c00000008040000290000000305000029000021310000813d000000400010043f0000000603000029000020710000013d000000050100002900000b8a001001980000210e0000613d000000000005004b000020740000613d000000000004041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b000000000201041a000000010220008a000000000021041b000000050100002900000b8a01100197000800000001001d000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b000000000201041a0000000102200039000000000021041b00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000020fd0000613d000000000101043b000500000001001d0000000701000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d0000000502000029000000a00220021000000008022001af00000bc0022001c7000000000101043b000000000021041b000000040100002900000bc000100198000020e00000c13d00000007010000290000000101100039000500000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b000000000101041a000000000001004b000020e00000c13d000000000100041a000000050010006b000020e00000613d0000000501000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000020f70000613d000000000101043b0000000402000029000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf040000410000000605000029000000080600002900000007070000292b842b750000040f0000000100200190000020f70000613d000000080000006b000021020000613d000000000001042d000000ff00100190000020710000c13d00000aea02000041000000000026004b000020310000c13d000020710000013d000000000100001900002b860001043000000c3201000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000c4501000041000000000010043f00000ba80100004100002b860001043000000c4601000041000000000010043f00000ba80100004100002b860001043000000c2f01000041000000000010043f00000ba80100004100002b860001043000000bfb01000041000000000010043f00000ba80100004100002b860001043000000c2401000041000000000010043f00000ba80100004100002b860001043000000ae2033001970000001f0530018f00000bd106300198000000400200043d00000000046200190000211e0000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000211a0000c13d000000000005004b0000212b0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000ae20020009c00000ae2020080410000004002200210000000000112019f00002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b860001043000000b8a01100198000021490000613d000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000214d0000613d000000000101043b000000000101041a00000af101100197000000000001042d00000bd801000041000000000010043f00000ba80100004100002b8600010430000000000100001900002b86000104300009000000000002000300000004001d000600000002001d000700000001001d000800000003001d000000000003004b0000233d0000613d0000000801000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000101041a000000000001004b0000217e0000c13d000000000100041a000000080010006c0000233d0000a13d0000000802000029000000010220008a000900000002001d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000101041a000000000001004b00000009020000290000216b0000613d00000ba5001001980000233d0000c13d000000070200002900000b8a02200197000500000001001d00000b8a01100197000900000002001d000000000021004b000023420000c13d0000000801000029000000000010043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000301043b000000000403041a0000000002000411000000090020006c000021cc0000613d0000000001000411000000000041004b000021cc0000613d000700000004001d000400000003001d0000000901000029000000000010043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000200041100000b8a02200197000200000002001d000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000101041a000000ff0010019000000004030000290000000704000029000021cc0000c13d0000000a01000039000000000101041a00000ba600100198000023520000613d000000080210027000000b8a02200198000021ca0000c13d000000ff00100190000000000200001900000aea02006041000000020020006b000023520000c13d000000090000006b000022170000613d0000000a01000039000000000101041a00000b9b001001980000234a0000613d000000060200002900000b8a052001980000221a0000613d000000080210027000000b8a02200198000023340000613d0000000001000411000000000021004b0000221a0000613d000200000005001d000700000004001d000400000003001d00000aed010000410000000000100443000100000002001d0000000400200443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f0000000100200190000023410000613d000000000101043b000000000001004b00000002030000290000233b0000613d000000400400043d0000006401400039000000080200002900000000002104350000004401400039000000000031043500000024014000390000000902000029000000000021043500000c2d010000410000000000140435000000000100041100000b8a011001970000000402400039000000000012043500000ae20040009c000200000004001d00000ae20100004100000000010440190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000bee011001c700000001020000292b842b7a0000040f000000600310027000010ae20030019d00030000000103550000000100200190000023970000613d000000020100002900000c430010009c0000000704000029000023880000813d000000400010043f00000004030000290000221a0000013d000000060100002900000b8a00100198000023560000613d000000000004004b0000221d0000613d000000000003041b0000000901000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000201041a000000010220008a000000000021041b000000060100002900000b8a01100197000700000001001d000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000201041a0000000102200039000000000021041b00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000023410000613d000000000101043b000400000001001d0000000801000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d0000000402000029000000a00220021000000007022001af00000bc0022001c7000000000101043b000000000021041b000000050100002900000bc0001001980000228a0000c13d00000008010000290000000101100039000400000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b000000000101041a000000000001004b0000228a0000c13d000000000100041a000000040010006b0000228a0000613d0000000401000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000233b0000613d000000000101043b0000000502000029000000000021041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf040000410000000905000029000000070600002900000008070000292b842b750000040f00000001002001900000233b0000613d000000070000006b000023460000613d00000aed01000041000000000010044300000006010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f0000000100200190000023410000613d000000000101043b000000000001004b000023330000613d000000400b00043d0000006401b000390000008002000039000600000002001d00000000002104350000004401b00039000000080200002900000000002104350000002401b000390000000902000029000000000021043500000c470100004100000000001b0435000000000100041100000b8a011001970000000402b0003900000000001204350000008402b0003900000003010000290000000041010434000000000012043500000c41061001970000001f0510018f000000a403b00039000000000034004b000022d40000813d000000000006004b000022d00000613d00000000085400190000000007530019000000200770008a000000200880008a0000000009670019000000000a680019000000000a0a04330000000000a90435000000200660008c000022ca0000c13d000000000005004b000022ea0000613d0000000007030019000022e00000013d0000000007630019000000000006004b000022dd0000613d00000000080400190000000009030019000000008a0804340000000009a90436000000000079004b000022d90000c13d000000000005004b000022ea0000613d00000000046400190000000305500210000000000607043300000000065601cf000000000656022f00000000040404330000010005500089000000000454022f00000000045401cf000000000464019f00000000004704350000001f0410003900000c410240019700000000013100190000000000010435000000a40120003900000ae20010009c00000ae201008041000000600110021000000ae200b0009c00000ae20200004100000000020b40190000004002200210000000000121019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f000000070200002900090000000b001d2b842b750000040f000000090b000029000000600310027000000ae203300197000000200030008c000000200400003900000000040340190000001f0640018f000000200740019000000000057b00190000230f0000613d000000000801034f00000000090b0019000000008a08043c0000000009a90436000000000059004b0000230b0000c13d000000000006004b0000231c0000613d000000000771034f0000000306600210000000000805043300000000086801cf000000000868022f000000000707043b0000010006600089000000000767022f00000000066701cf000000000686019f0000000000650435000100000003001f000300000001035500000001002001900000234e0000613d0000001f01400039000000600210018f0000000001b20019000000000021004b0000000002000039000000010200403900000af10010009c000023880000213d0000000100200190000023880000c13d000000400010043f000000200030008c0000233b0000413d00000000010b043300000c38001001980000233b0000c13d00000ae90110019700000c470010009c000023840000c13d000000000001042d000000ff001001900000221a0000c13d00000aea020000410000000001000411000000000021004b000021db0000c13d0000221a0000013d000000000100001900002b860001043000000c3201000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000c4501000041000000000010043f00000ba80100004100002b860001043000000c4601000041000000000010043f00000ba80100004100002b860001043000000c2f01000041000000000010043f00000ba80100004100002b8600010430000000000003004b0000235a0000c13d0000006002000039000023810000013d00000bfb01000041000000000010043f00000ba80100004100002b860001043000000c2401000041000000000010043f00000ba80100004100002b86000104300000001f0230003900000bf9022001970000003f0220003900000bfa04200197000000400200043d0000000004420019000000000024004b0000000005000039000000010500403900000af10040009c000023880000213d0000000100500190000023880000c13d000000400040043f0000001f0430018f000000000632043600000bd105300198000600000006001d0000000003560019000023740000613d000000000601034f0000000607000029000000006806043c0000000007870436000000000037004b000023700000c13d000000000004004b000023810000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000001020433000000000001004b0000238e0000c13d00000c4801000041000000000010043f00000ba80100004100002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b8600010430000000060200002900000ae20020009c00000ae202008041000000400220021000000ae20010009c00000ae2010080410000006001100210000000000121019f00002b860001043000000ae2033001970000001f0530018f00000bd106300198000000400200043d0000000004620019000023a30000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000239f0000c13d000000000005004b000023b00000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000ae20020009c00000ae2020080410000004002200210000000000112019f00002b860001043000010000000000020000000003010019000000400100043d00000c490010009c0000240e0000813d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000003004b0000240b0000613d000000000200041a000000000032004b0000240b0000a13d000100000003001d000000000030043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000240c0000613d000000000101043b000000000101041a000000000001004b000023dd0000c13d0000000103000029000000010330008a000023c90000013d000000400100043d00000bad0010009c00000001030000290000240e0000213d0000008002100039000000400020043f0000006002100039000000000002043500000040021000390000000000020435000000200210003900000000000204350000000000010435000000000030043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000240c0000613d000000000301034f000000400100043d00000bad0010009c0000240e0000213d000000000203043b000000000202041a0000008003100039000000400030043f0000006003100039000000e804200270000000000043043500000ba5002001980000000003000039000000010300c0390000004004100039000000000034043500000b8a032001970000000003310436000000a00220027000000af1022001970000000000230435000000000001042d000000000100001900002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b86000104300001000000000002000100000002001d00000b8a01100197000000000010043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000024470000613d000000000101043b000000010200002900000b8a02200197000100000002001d000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000024470000613d000000000101043b000000000101041a000000ff01100190000024370000613d000000000001042d0000000a01000039000000000201041a00000ba600200198000024450000613d000000080120027000000b8a01100198000024410000c13d000000ff00200190000000000100001900000aea01006041000000010010006b00000000010000390000000101006039000000000001042d0000000001000019000000000001042d000000000100001900002b86000104300013000000000002000300000005001d000200000004001d000100000003001d00100b8a0030019c000026f00000613d00000b8a0220019700000b8a01100198000e00010000003d001100000002001d000d00000001001d000024850000613d000000000021004b000024850000613d000000000020043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b0000000d02000029000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b000000000101041a000e00ff001001940000000d03000029000024850000c13d0000000a01000039000000000201041a00000ba600200198000024840000613d000000080120027000000b8a011001980000247f0000c13d000000ff00200190000000000100001900000aea01006041000000000013004b00000000010000390000000101006039000e00000001001d000024850000013d000e00000000001d00000002010000290000000012010434000600000001001d000000000002004b000025c90000613d001300000002001d000000000100041a000700000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000026830000613d000000130200002900000005022002100000000603000029000f00000032001d000000000101043b000000a00110021000040010001001b300000001020000390000000001000019000024a60000013d000000010140008a0000000f0030006c0000000002000019000025c90000613d001200000003001d0000000004030433000000000004004b000026a30000613d000000070040006b000026a30000a13d000000000014004b0000000001000039000000010100a03900000c4202200167000000000112016f0000000100100190000800000004001d000026a70000c13d001300000004001d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d0000001304000029000000010440008a000000000101043b000000000101041a000000000001004b000024b40000613d00000ba5001001980000000803000029000026a30000c13d000500000001001d00000b8a01100197000000110010006c000026ab0000c13d00000000010000190000000100100190001300000003001d000024e30000613d000000000030043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b000000000101041a000000000001004b0000001303000029000025600000c13d000000000030043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000301043b000000000403041a0000001105000029000000000005004b000025400000613d0000000a01000039000000000101041a00000b9b001001980000267f0000613d000000080210027000000b8a022001980000253a0000613d0000000001000411000000000021004b000025400000613d000b00000004001d000a00000003001d00000aed010000410000000000100443000c00000002001d0000000400200443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f0000000100200190000026830000613d000000000101043b000000000001004b0000001302000029000026730000613d000000400300043d0000006401300039000000000021043500000044013000390000001002000029000000000021043500000024013000390000001102000029000000000021043500000c2d010000410000000000130435000000000100041100000b8a011001970000000402300039000000000012043500000ae20030009c000900000003001d00000ae20100004100000000010340190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000bee011001c70000000c020000292b842b7a0000040f000000600310027000010ae20030019d00030000000103550000000100200190000026840000613d000000090100002900000c430010009c0000000b04000029000026e10000813d000000400010043f00000011050000290000000a03000029000025400000013d000000ff00100190000025400000c13d00000aea020000410000000001000411000000000021004b000024fe0000c13d0000000e0000006b000025440000c13d0000000d0040006b000026750000c13d000000000004004b000025470000613d000000000003041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf04000041000000100600002900000013070000292b842b750000040f0000000100200190000026730000613d00000013010000290000000104100039000000120200002900000020022000390000000003020433000000000043004b001200000002001d000025610000c13d0000000f0020006c0000000101000039000024cf0000c13d000025610000013d0000000004030019001300000004001d0000000801000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b0000000402000029000000000021041b0000001101000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d0000001303000029000c000800300072000000000101043b000000000201041a0000000c0220006a000000000021041b0000001001000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b000000000201041a0000000c050000290000000002520019000000000021041b0000001304000029000000070040006c000025bd0000613d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b000000000101041a000000000001004b00000013040000290000000c05000029000025bd0000c13d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000026730000613d000000000101043b0000000502000029000000000021041b00000013040000290000000c050000290000000802000029000000000024004b0000001203000029000024a20000613d00000c42012001670000000002000019000000000012004b000026790000213d0000000102200039000000000052004b000025c30000413d000024a20000013d00000aed01000041000000000010044300000001010000290000000400100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f0000000100200190000026830000613d000000000101043b000000000001004b00000011030000290000000602000029000026720000613d000000020100002900000000010104330000000501100212000026720000613d000e00000021001d000000400a00043d0000000301000029001200200010003d0000000001000411000f0b8a0010019b000d00800000003d000000200900008a0000000021020434000600000002001d0000006402a00039000000800400003900000000004204350000004402a0003900000000001204350000002401a00039000000000031043500000c470100004100000000001a04350000000401a000390000000f020000290000000000210435000000030100002900000000010104330000008402a000390000000000120435000000000491016f0000001f0310018f000000a402a00039000000120020006b0000260e0000813d000000000004004b000026090000613d00000003053000290000000006320019000000200660008a0000000007460019000000000845001900000000080804330000000000870435000000200440008c000026030000c13d000000000003004b000026240000613d000000120400002900000000050200190000261a0000013d0000000005420019000000000004004b000026170000613d0000001206000029000000000702001900000000680604340000000007870436000000000057004b000026130000c13d000000000003004b000026240000613d00000012044000290000000303300210000000000605043300000000063601cf000000000636022f00000000040404330000010003300089000000000434022f00000000033401cf000000000363019f00000000003504350000001f03100039000000000393016f00000000012100190000000000010435000000a40130003900000ae20010009c00000ae201008041000000600110021000000ae200a0009c00000ae20200004100000000020a40190000004002200210000000000121019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000121019f000000100200002900130000000a001d2b842b750000040f000000130a000029000000600310027000000ae203300197000000200030008c00000020040000390000000004034019000000200640019000000000056a0019000026480000613d000000000701034f00000000080a0019000000007907043c0000000008980436000000000058004b000026440000c13d0000001f07400190000026550000613d000000000661034f0000000307700210000000000805043300000000087801cf000000000878022f000000000606043b0000010007700089000000000676022f00000000067601cf000000000686019f0000000000650435000100000003001f00030000000103550000000100200190000000200900008a000026af0000613d0000001f01400039000000600210018f0000000001a20019000000000021004b0000000002000039000000010200403900000af10010009c000026e10000213d0000000100200190000026e10000c13d000000400010043f000000200030008c000026730000413d00000000020a043300000c3800200198000026730000c13d00000ae90220019700000c470020009c000026dd0000c13d00000006020000290000000e0020006c000000000a0100190000001103000029000025e70000c13d000000000001042d000000000100001900002b860001043000000bfb01000041000000000010043f00000ba80100004100002b860001043000000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b860001043000000c2f01000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000ae2033001970000001f0530018f00000bd106300198000000400200043d0000000004620019000026900000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b0000268c0000c13d000000000005004b0000269d0000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000ae20020009c00000ae2020080410000004002200210000000000112019f00002b860001043000000c3201000041000000000010043f00000ba80100004100002b860001043000000bae01000041000000000010043f00000ba80100004100002b860001043000000c4501000041000000000010043f00000ba80100004100002b8600010430000000000003004b000026b30000c13d0000006002000039000026da0000013d0000001f0230003900000bf9022001970000003f0220003900000bfa04200197000000400200043d0000000004420019000000000024004b0000000005000039000000010500403900000af10040009c000026e10000213d0000000100500190000026e10000c13d000000400040043f0000001f0430018f000000000632043600000bd105300198000d00000006001d0000000003560019000026cd0000613d000000000601034f0000000d07000029000000006806043c0000000007870436000000000037004b000026c90000c13d000000000004004b000026da0000613d000000000151034f0000000304400210000000000503043300000000054501cf000000000545022f000000000101043b0000010004400089000000000141022f00000000014101cf000000000151019f00000000001304350000000001020433000000000001004b000026e70000c13d00000c4801000041000000000010043f00000ba80100004100002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b86000104300000000d0200002900000ae20020009c00000ae202008041000000400220021000000ae20010009c00000ae2010080410000006001100210000000000121019f00002b860001043000000c4601000041000000000010043f00000ba80100004100002b860001043000030000000000020000000a01000039000000000101041a000000e8011002700000ffff0210018f00000d750020008c0000000001000019000026fd0000413d000000000001042d000300000002001d0000001101000039000000000101041a000100000001001d0000001001000039000000000101041a000200000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000027320000613d000000000101043b0000000204000029000000000241004b0000000305000029000027160000813d00000d7501500089000000000001042d000000010010006c00000000010000190000000a03000039000026fc0000813d000000000103041a00000bd200100198000027140000613d0000000101400069000000000012004b000000000201801900000d75032000c900000d750430011a000000000024004b000027330000c13d00000000011300d900000d750010008c000027330000213d00000d75011000890000000b02000039000000000202041a0000ffff0220018f000000000221004b0000000001000019000026fc0000a13d000000000252004b00000000010000190000000001022019000000000001042d000000000001042f00000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b86000104300001000000000002000000000001004b000027690000613d000100000001001d000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000027670000613d000000000101043b000000000101041a000000000001004b000027640000c13d000000000100041a0000000102000029000000000021004b000027690000a13d000000010220008a000100000002001d000000000020043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f0000000100200190000027670000613d000000000101043b000000000101041a000000000001004b0000000102000029000027510000613d00000ba500100198000027690000c13d000000000001042d000000000100001900002b860001043000000c3201000041000000000010043f00000ba80100004100002b8600010430000000600210003900000c4a030000410000000000320435000000400210003900000c4b03000041000000000032043500000020021000390000002e030000390000000000320435000000200200003900000000002104350000008001100039000000000001042d00050000000000020000000a04000039000000000404041a00000bd900400198000028400000613d000300000001001d000400000003001d000000000003004b000028440000613d00000b8a01200197000500000001001d000000000010043f0000000c01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000000004030000290000283e0000613d000000000101043b000000000101041a000000000431004b0000000a020000390000284b0000413d000000000102041a000000c8011002700000ffff0110018f000000000031001a0000285d0000413d000200000004001d000000000231001900000fa00020008c000028510000213d0000000501000029000000000010043f0000000c01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000000004040000290000283e0000613d000000000101043b0000000202000029000000000021041b0000ffff0240018f0000000a05000039000000000105041a000000c8031002700000ffff0330018f00000000022300190000ffff0020008c0000285d0000213d00000c4c01100197000000c80220021000000c4d02200197000000000112019f000000000015041b000000000300041a000000010130008a000000000041001a0000285d0000413d0000000002410019000022b90020008c0000285b0000813d000000030100002900030b8a0010019c000028630000613d00000c42023001670000000001000019000000000021004b0000285d0000213d0000000101100039000000000041004b000027ca0000413d000100000002001d000500000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000028670000613d000000000101043b000200000001001d0000000501000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000000004030000290000283e0000613d0000000202000029000000a002200210000000010030008c000000000300001900000bc003006041000000000223019f0000000303000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000040400002900000001002001900000283e0000613d000000000101043b00000bc1024000d1000000000301041a0000000002230019000000000021041b000200050040002d00000000010000190000281c0000013d0000000507000029000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000050000190000000306000029000500000007001d2b842b750000040f0000000404000029000000010020019000000001010000390000283e0000613d00000001001001900000280b0000613d00000005070000290000000107700039000000020070006c0000280c0000c13d0000000201000029000000000010041b00000000010000190000000102000029000000000021004b0000285d0000213d0000000101100039000000000041004b000028260000413d000000400100043d000000000041043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000020300003900000c4e0400004100000003050000292b842b750000040f00000001002001900000283e0000613d000000000001042d000000000100001900002b860001043000000bdf01000041000000000010043f00000ba80100004100002b860001043000000c2901000041000000000010043f000000040000043f0000000101000039000000240010043f00000af00100004100002b860001043000000c4f02000041000000000020043f000000040030043f000000240010043f00000af00100004100002b860001043000000fa00010008c00000004030000290000285d0000213d00000bc302000041000000000020043f000000040030043f00000fa001100089000000240010043f00000af00100004100002b8600010430000022b80010008c000028680000a13d00000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b860001043000000c2401000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000bc301000041000000000010043f000000040040043f000022b901300089000000240010043f00000af00100004100002b8600010430000100000000000200000b8d02000041000000000502041a000000000200041400000b8a0610019700000ae20020009c00000ae202008041000000c00120021000000ba3011001c70000800d02000039000000030300003900000bdc04000041000100000006001d2b842b750000040f0000000100200190000028830000613d00000b8d010000410000000102000029000000000021041b000000000001042d000000000100001900002b860001043000050000000000020000000a04000039000000000404041a00000b8e004001980000294b0000613d000300000001001d000400000003001d000000000003004b0000294f0000613d00000b8a01200197000500000001001d000000000010043f0000000d01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000000403000029000029490000613d000000000101043b000000000101041a000000000431004b0000000a02000039000029560000413d000000000102041a000000d8011002700000ffff0110018f000000000031001a000029680000413d000200000004001d00000000023100190000022b0020008c0000295c0000213d0000000501000029000000000010043f0000000d01000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000000404000029000029490000613d000000000101043b0000000202000029000000000021041b0000ffff0240018f0000000a05000039000000000105041a000000d8031002700000ffff0330018f00000000022300190000ffff0020008c000029680000213d00000c5001100197000000d80220021000000c5102200197000000000112019f000000000015041b000000000300041a000000010130008a000000000041001a000029680000413d0000000002410019000022b90020008c000029660000813d000000030100002900030b8a0010019c0000296e0000613d00000c42023001670000000001000019000000000021004b000029680000213d0000000101100039000000000041004b000028d50000413d000100000002001d000500000003001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f0000000100200190000029720000613d000000000101043b000200000001001d0000000501000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000001002001900000000403000029000029490000613d0000000202000029000000a002200210000000010030008c000000000300001900000bc003006041000000000223019f0000000303000029000000000232019f000000000101043b000000000021041b000000000030043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f00000004040000290000000100200190000029490000613d000000000101043b00000bc1024000d1000000000301041a0000000002230019000000000021041b000200050040002d0000000001000019000029270000013d0000000507000029000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf0400004100000000050000190000000306000029000500000007001d2b842b750000040f000000040400002900000001002001900000000101000039000029490000613d0000000100100190000029160000613d00000005070000290000000107700039000000020070006c000029170000c13d0000000201000029000000000010041b00000000010000190000000102000029000000000021004b000029680000213d0000000101100039000000000041004b000029310000413d000000400100043d000000000041043500000ae20010009c00000ae2010080410000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ae8011001c70000800d02000039000000020300003900000c520400004100000003050000292b842b750000040f0000000100200190000029490000613d000000000001042d000000000100001900002b860001043000000bdf01000041000000000010043f00000ba80100004100002b860001043000000c2901000041000000000010043f000000040000043f0000000101000039000000240010043f00000af00100004100002b860001043000000c4f02000041000000000020043f000000040030043f000000240010043f00000af00100004100002b86000104300000022b0010008c0000000403000029000029680000213d00000bc302000041000000000020043f000000040030043f0000022b01100089000000240010043f00000af00100004100002b8600010430000022b80010008c000029730000a13d00000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b860001043000000c2401000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000bc301000041000000000010043f000000040040043f000022b901300089000000240010043f00000af00100004100002b8600010430000f000000000002000c0b8a0030019c00002b3d0000613d00000b8a0220019700000b8a01100198000a00010000003d000d00000002001d000900000001001d000029b30000613d000000000021004b000029b30000613d000f00000004001d000000000020043f0000000701000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b0000000902000029000000000020043f000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b000000000101041a000a00ff0010019400000009030000290000000f04000029000029b30000c13d0000000a01000039000000000201041a00000ba60020019800002af60000613d000000080120027000000b8a01100198000029af0000c13d000000ff00200190000000000100001900000aea01006041000000000013004b00000000010000390000000101006039000a00000001001d0000000012040434000000000002004b00002afa0000613d000f00000002001d000e00000001001d000000000100041a000300000001001d00000b96010000410000000000100443000000000100041400000ae20010009c00000ae201008041000000c00110021000000af3011001c70000800b020000392b842b7a0000040f000000010020019000002b0b0000613d0000000f0200002900000005022002100000000e03000029000b00000032001d000000000101043b000000a0011002100001000c001001b300000001020000390000000001000019000029d30000013d000000010140008a0000000b0030006c000000000200001900002afa0000613d000e00000003001d0000000004030433000000000004004b00002b310000613d000000030040006b00002b310000a13d000000000014004b0000000001000039000000010100a03900000c4202200167000000000112016f0000000100100190000400000004001d00002b350000c13d000f00000004001d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d0000000f04000029000000010440008a000000000101043b000000000101041a000000000001004b000029e10000613d00000ba500100198000000040300002900002b310000c13d000200000001001d00000b8a011001970000000d0010006c00002b390000c13d00000000010000190000000100100190000f00000003001d00002a100000613d000000000030043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b000000000101041a000000000001004b0000000f0300002900002a8d0000c13d000000000030043f0000000601000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000301043b000000000403041a0000000d05000029000000000005004b00002a6d0000613d0000000a01000039000000000101041a00000b9b0010019800002b070000613d000000080210027000000b8a0220019800002a670000613d0000000001000411000000000021004b00002a6d0000613d000700000004001d000600000003001d00000aed010000410000000000100443000800000002001d0000000400200443000000000100041400000ae20010009c00000ae201008041000000c00110021000000aee011001c700008002020000392b842b7a0000040f000000010020019000002b0b0000613d000000000101043b000000000001004b0000000f0200002900002afb0000613d000000400300043d0000006401300039000000000021043500000044013000390000000c02000029000000000021043500000024013000390000000d02000029000000000021043500000c2d010000410000000000130435000000000100041100000b8a011001970000000402300039000000000012043500000ae20030009c000500000003001d00000ae20100004100000000010340190000004001100210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000bee011001c700000008020000292b842b7a0000040f000000600310027000010ae20030019d0003000000010355000000010020019000002b0c0000613d000000050100002900000c430010009c000000070400002900002b2b0000813d000000400010043f0000000d05000029000000060300002900002a6d0000013d000000ff0010019000002a6d0000c13d00000aea020000410000000001000411000000000021004b00002a2b0000c13d0000000a0000006b00002a710000c13d000000090040006b00002afd0000c13d000000000004004b00002a740000613d000000000003041b000000000100041400000ae20010009c00000ae201008041000000c00110021000000ba3011001c70000800d02000039000000040300003900000baf040000410000000c060000290000000f070000292b842b750000040f000000010020019000002afb0000613d0000000f0100002900000001041000390000000e0100002900000020011000390000000003010433000000000043004b000e00000001001d00002a8e0000c13d0000000b0010006c0000000101000039000029fc0000c13d00002a8e0000013d0000000004030019000f00000004001d0000000401000029000000000010043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b0000000102000029000000000021041b0000000d01000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d0000000f030000290008000400300072000000000101043b000000000201041a000000080220006a000000000021041b0000000c01000029000000000010043f0000000501000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b000000000201041a00000008050000290000000002520019000000000021041b0000000f04000029000000030040006c00002aea0000613d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b000000000101041a000000000001004b0000000f04000029000000080500002900002aea0000c13d000000000040043f0000000401000039000000200010043f000000000100041400000ae20010009c00000ae201008041000000c00110021000000aeb011001c700008010020000392b842b7a0000040f000000010020019000002afb0000613d000000000101043b0000000202000029000000000021041b0000000f0400002900000008050000290000000402000029000000000024004b0000000e03000029000029cf0000613d00000c42012001670000000002000019000000000012004b00002b010000213d0000000102200039000000000052004b00002af00000413d000029cf0000013d000a00000000001d0000000012040434000000000002004b000029b60000c13d000000000001042d000000000100001900002b860001043000000bfb01000041000000000010043f00000ba80100004100002b860001043000000c2701000041000000000010043f0000001101000039000000040010043f00000c280100004100002b860001043000000c2f01000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000ae2033001970000001f0530018f00000bd106300198000000400200043d000000000462001900002b180000613d000000000701034f0000000008020019000000007907043c0000000008980436000000000048004b00002b140000c13d000000000005004b00002b250000613d000000000161034f0000000305500210000000000604043300000000065601cf000000000656022f000000000101043b0000010005500089000000000151022f00000000015101cf000000000161019f0000000000140435000000600130021000000ae20020009c00000ae2020080410000004002200210000000000112019f00002b860001043000000c2701000041000000000010043f0000004101000039000000040010043f00000c280100004100002b860001043000000c3201000041000000000010043f00000ba80100004100002b860001043000000bae01000041000000000010043f00000ba80100004100002b860001043000000c4501000041000000000010043f00000ba80100004100002b860001043000000c4601000041000000000010043f00000ba80100004100002b8600010430000000000001042f00000ae20010009c00000ae201008041000000400110021000000ae20020009c00000ae2020080410000006002200210000000000112019f000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000ba3011001c700008010020000392b842b7a0000040f000000010020019000002b550000613d000000000101043b000000000001042d000000000100001900002b860001043000000000050100190000000000200443000000050030008c00002b650000413d000000040100003900000000020000190000000506200210000000000664001900000005066002700000000006060031000000000161043a0000000102200039000000000031004b00002b5d0000413d00000ae20030009c00000ae2030080410000006001300210000000000200041400000ae20020009c00000ae202008041000000c002200210000000000112019f00000c53011001c700000000020500192b842b7a0000040f000000010020019000002b740000613d000000000101043b000000000001042d000000000001042f00002b78002104210000000102000039000000000001042d0000000002000019000000000001042d00002b7d002104230000000102000039000000000001042d0000000002000019000000000001042d00002b82002104250000000102000039000000000001042d0000000002000019000000000001042d00002b840000043200002b850001042e00002b8600010430000000000000000000000000000000000000000000000000000000000000000000000000ffffffff46696e616c20426f737500000000000000000000000000000000000000000000424f535500000000000000000000000000000000000000000000000000000000405787fa12a823e0f2b7631cc41b3ba8828b3321ca811111fa75cd3aa3bb5acebfa87805ed57dc1f0d489ce33be4c4577d74ccde357eeeee058a32c55c44a53246696e616c20426f7375000000000000000000000000000000000000000000140200000000000000000000000000000000000020000000000000000000000000ffffffff00000000000000000000000000000000000000000000000000000000000000000000000000000000721c002b0059009a671d00ad1700c9748146cd1b0200000000000000000000000000000000000040000000000000000000000000cc5dc080ff977b3c3a211fa63ab74f90f658f5ba9d3236e92c8f59570f442aac1806aa1896bbf26568e884a7374b41e002500962caba6a15023a8d90e8508b830200000200000000000000000000000000000024000000000000000000000000fb2de5d7000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000044000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff9a8a0592ac89c5ad3bc6df8224c17b485976f597df104ee20d0df415241f670b0200000200000000000000000000000000000004000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffbf46696e616c426f7375000000000000000000000000000000000000000000000031000000000000000000000000000000000000000000000000000000000000008b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f00000002000000000000000000000000000001c000000100000000000000000000000000000000000000000000000000000000000000000000000000715018a500000000000000000000000000000000000000000000000000000000b88d4fdd00000000000000000000000000000000000000000000000000000000dc8e92e900000000000000000000000000000000000000000000000000000000f04e283d00000000000000000000000000000000000000000000000000000000f3993d1000000000000000000000000000000000000000000000000000000000fdd0f3c900000000000000000000000000000000000000000000000000000000fdd0f3ca00000000000000000000000000000000000000000000000000000000fee81cf400000000000000000000000000000000000000000000000000000000f3993d1100000000000000000000000000000000000000000000000000000000fc4db93500000000000000000000000000000000000000000000000000000000f04e283e00000000000000000000000000000000000000000000000000000000f0f4426000000000000000000000000000000000000000000000000000000000f2fde38b00000000000000000000000000000000000000000000000000000000e0a8085200000000000000000000000000000000000000000000000000000000e985e9c400000000000000000000000000000000000000000000000000000000e985e9c500000000000000000000000000000000000000000000000000000000ec1cad2400000000000000000000000000000000000000000000000000000000e0a8085300000000000000000000000000000000000000000000000000000000e156afd500000000000000000000000000000000000000000000000000000000dc8e92ea00000000000000000000000000000000000000000000000000000000e030565e00000000000000000000000000000000000000000000000000000000e086e5ec00000000000000000000000000000000000000000000000000000000c87b56dc00000000000000000000000000000000000000000000000000000000d18e81b200000000000000000000000000000000000000000000000000000000daad289d00000000000000000000000000000000000000000000000000000000daad289e00000000000000000000000000000000000000000000000000000000dc53fd9200000000000000000000000000000000000000000000000000000000d18e81b300000000000000000000000000000000000000000000000000000000d3cf00a300000000000000000000000000000000000000000000000000000000c87b56dd00000000000000000000000000000000000000000000000000000000ccc1b80a00000000000000000000000000000000000000000000000000000000cfdbf25400000000000000000000000000000000000000000000000000000000c2f1f14900000000000000000000000000000000000000000000000000000000c2f1f14a00000000000000000000000000000000000000000000000000000000c571de5f00000000000000000000000000000000000000000000000000000000c87a90bb00000000000000000000000000000000000000000000000000000000b88d4fde00000000000000000000000000000000000000000000000000000000bbaac02f00000000000000000000000000000000000000000000000000000000c23dc68f0000000000000000000000000000000000000000000000000000000091f76d0f00000000000000000000000000000000000000000000000000000000a22cb46400000000000000000000000000000000000000000000000000000000a9fc664d00000000000000000000000000000000000000000000000000000000ad581ef600000000000000000000000000000000000000000000000000000000ad581ef700000000000000000000000000000000000000000000000000000000af23ee3300000000000000000000000000000000000000000000000000000000a9fc664e00000000000000000000000000000000000000000000000000000000aa35cca300000000000000000000000000000000000000000000000000000000a22cb46500000000000000000000000000000000000000000000000000000000a2b751a700000000000000000000000000000000000000000000000000000000a4f4f8af0000000000000000000000000000000000000000000000000000000099a255790000000000000000000000000000000000000000000000000000000099a2557a000000000000000000000000000000000000000000000000000000009a3aa766000000000000000000000000000000000000000000000000000000009e05d2400000000000000000000000000000000000000000000000000000000091f76d100000000000000000000000000000000000000000000000000000000095d89b410000000000000000000000000000000000000000000000000000000096330b5f000000000000000000000000000000000000000000000000000000008462151b000000000000000000000000000000000000000000000000000000008bba1e7f000000000000000000000000000000000000000000000000000000008f3f383c000000000000000000000000000000000000000000000000000000008f3f383d000000000000000000000000000000000000000000000000000000008fc88c48000000000000000000000000000000000000000000000000000000008bba1e80000000000000000000000000000000000000000000000000000000008da5cb5b000000000000000000000000000000000000000000000000000000008462151c0000000000000000000000000000000000000000000000000000000084b0196e0000000000000000000000000000000000000000000000000000000087f936750000000000000000000000000000000000000000000000000000000079af02720000000000000000000000000000000000000000000000000000000079af0273000000000000000000000000000000000000000000000000000000007a8b39a1000000000000000000000000000000000000000000000000000000008342083a00000000000000000000000000000000000000000000000000000000715018a6000000000000000000000000000000000000000000000000000000007234074a0000000000000000000000000000000000000000000000000000000076c888f1000000000000000000000000000000000000000000000000000000003644e5140000000000000000000000000000000000000000000000000000000054d1f13c000000000000000000000000000000000000000000000000000000005d82cf6d000000000000000000000000000000000000000000000000000000006221d13b0000000000000000000000000000000000000000000000000000000066a7d1200000000000000000000000000000000000000000000000000000000066a7d1210000000000000000000000000000000000000000000000000000000070a08231000000000000000000000000000000000000000000000000000000006221d13c000000000000000000000000000000000000000000000000000000006352211e000000000000000000000000000000000000000000000000000000005d82cf6e000000000000000000000000000000000000000000000000000000005dab6e140000000000000000000000000000000000000000000000000000000061d027b3000000000000000000000000000000000000000000000000000000005b7633cf000000000000000000000000000000000000000000000000000000005b7633d0000000000000000000000000000000000000000000000000000000005bbb2177000000000000000000000000000000000000000000000000000000005d4be6080000000000000000000000000000000000000000000000000000000054d1f13d0000000000000000000000000000000000000000000000000000000055f804b3000000000000000000000000000000000000000000000000000000005944c753000000000000000000000000000000000000000000000000000000004ada218a00000000000000000000000000000000000000000000000000000000507d22920000000000000000000000000000000000000000000000000000000052d1902c0000000000000000000000000000000000000000000000000000000052d1902d0000000000000000000000000000000000000000000000000000000054be0a7d00000000000000000000000000000000000000000000000000000000507d22930000000000000000000000000000000000000000000000000000000051830227000000000000000000000000000000000000000000000000000000004ada218b000000000000000000000000000000000000000000000000000000004e45abdb000000000000000000000000000000000000000000000000000000004f1ef2860000000000000000000000000000000000000000000000000000000042842e0d0000000000000000000000000000000000000000000000000000000042842e0e0000000000000000000000000000000000000000000000000000000042966c6800000000000000000000000000000000000000000000000000000000453c2310000000000000000000000000000000000000000000000000000000003644e515000000000000000000000000000000000000000000000000000000003659cfe60000000000000000000000000000000000000000000000000000000040d1d255000000000000000000000000000000000000000000000000000000000ed89c0000000000000000000000000000000000000000000000000000000000221a63f60000000000000000000000000000000000000000000000000000000028cfbd45000000000000000000000000000000000000000000000000000000002fb3b360000000000000000000000000000000000000000000000000000000002fb3b3610000000000000000000000000000000000000000000000000000000032cb6b0c0000000000000000000000000000000000000000000000000000000028cfbd46000000000000000000000000000000000000000000000000000000002a55205a00000000000000000000000000000000000000000000000000000000221a63f70000000000000000000000000000000000000000000000000000000023b872dd00000000000000000000000000000000000000000000000000000000256929620000000000000000000000000000000000000000000000000000000018160ddc0000000000000000000000000000000000000000000000000000000018160ddd000000000000000000000000000000000000000000000000000000001c0f069d000000000000000000000000000000000000000000000000000000001f88182b000000000000000000000000000000000000000000000000000000000ed89c010000000000000000000000000000000000000000000000000000000010042e1000000000000000000000000000000000000000000000000000000000134981100000000000000000000000000000000000000000000000000000000006fdde0200000000000000000000000000000000000000000000000000000000095ea7b2000000000000000000000000000000000000000000000000000000000d705df5000000000000000000000000000000000000000000000000000000000d705df6000000000000000000000000000000000000000000000000000000000d853e6900000000000000000000000000000000000000000000000000000000095ea7b300000000000000000000000000000000000000000000000000000000098144d40000000000000000000000000000000000000000000000000000000006fdde0300000000000000000000000000000000000000000000000000000000081812fc00000000000000000000000000000000000000000000000000000000095ca0700000000000000000000000000000000000000000000000000000000004634d8c0000000000000000000000000000000000000000000000000000000004634d8d00000000000000000000000000000000000000000000000000000000046dc1660000000000000000000000000000000000000000000000000000000004ea870300000000000000000000000000000000000000000000000000000000014635460000000000000000000000000000000000000000000000000000000001ffc9a700000000000000000000000000000000000000000000000000000000034601ec000000000000000000000000ffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000000000000389a75e10000000000000000000000000000000000000020000000800000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739270000000000000000000400000000000000000000000000000000000000000000fffffffffffffffffffbffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000000000000007448fbae00000000000000000000000000000000000000040000001c0000000000000000ffffffffffffffffffffffff000000000000000000000000000000000000000002000000000000000000000000000000000000400000008000000000000000004ab5be82436d353e61ca18726e984e561f5c1cc7c6d38b29d2553c790434705a02000000000000000000000000000000000000200000000c0000000000000000796b89b91644bc98cd93958e4c9038275d622183e25ac5af08cc6b5d95539132000000000000000000000000000000000000000000000000000000006f5e881821ccfeb700000000000000000000000000000000000000000000000000000000c426eca5c30f0cac8b78a045ee4f49272d04f2ea1e96876045beb9083728305a00000000000000000000000000000000000000200000000000000000000000000000000000000000000100000000000000000000000000000000000000000000020000000000000000000000000000000000002000000080000000000000000044025b4c6266facf728a25ba1ed858c89e2215e03094486152577b87636ea7abffffffffffffffffffefffffffffffffffffffffffffffffffffffffffffffff00000000000000000010000000000000000000000000000000000000000000008a5de882a70ee0f5ae6ea16870cd6a35453e6bc38ee192f5c835a4b27b6d9a000000000000000000000000000000000000000000000000929eee149b4bd212689cc7f708afc65944829bd487b90b72536b1951864fbfc14e125fc972a6507f39020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b12d13eb000000010000000000000000000000000000000000000000000000000000000000000000000000000000ff000000000000000000000000000000000000000000cf4700e40000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000000000000000000004f1dd8e80000000000000000000000000000000000000000000000000000000000000000ffffffffffffffff00000000000000000000000000000000000000004e06b4e7000e659094299b3533b47b6aa8ad048e95e872d23d1f4ee55af89cfe7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0000000000000000000000000000000000000000000000000ffffffffffffff7f9fc3da3700000000000000000000000000000000000000000000000000000000ddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef00000000000000000000000000000000ffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3000000000000000000000000000000000000000000000000000000000000000c624b66cc0138b8fabc209247f72d758e1cf3343756d543badbf24212bed8c15b13d2d76d1f4b7be834882e410b3e3a8afaf69f83600ae24db354391d2378d2ea14c4b50000000000000000000000000000000000000000000000000000000006bd49f851db94c5cff00fe6b38b30fd9780af25a09273beee2c884eba927b67600000000000000000000000000000000000000800000000000000000000000004ec2d2892e0b48417cb77d1bef4c1c5750509607c9ff51db24cabc6e2dc872d2020000000000000000000000000000000000000000000080000000000000000045369159047c5499b1c9b077b5525862bc88be82363efdd09aaed1cb93f1de1100000000000000000000000000000000000000000000000000000000ffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffff6690e6d222cc5eb6749096863ace6f49c5ddb0c3f93cb2b68c37a092c7adc425ffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffff00000000000000ffff0000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000100000000000000014a9f0bc4fa7e0e0d70aba96482e6e4dadf15298daff23a34b937566acd51b393bc9c6d520000000000000000000000000000000000000000000000000000000032483afb00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffff0017307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31ffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffff00000000000000000000010000000000000000000000000000000000000000006787c7f9a80aa0f5ceddab2c54f1f5169c0b88e75dd5e19d5e858a64144c7dbcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0e5ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffb0e600ca0004b7ec3c16ac2be6e2bb91bec2b9f20558847eb99c693359b043ef30bbeec2575a0e9e593c00f959f8c92f12db2869c3395a3b0502d05e2516446f71f85bc10dcfe266c1f71ef476efbd3223555750dc271e4115626b0000000000000000598926570000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffe00000000000000000000800000000000000000000000000000000000000000000a24a13a6000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffff000000000000000000000000000000000000000000000100000000000000000032c1995a000000000000000000000000000000000000000000000000000000008f4eb60400000000000000000000000000000000000000000000000000000000000000000000000000020000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000004f1a000000000000000000000000000000000000000000000000000000000082b429008be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09ccd6d760000000000000000000000000000000000000000000000000000000035a66b2c0000000000000000000000000000000000000000000000000000000024fbaa90000000000000000000000000000000000000000000000000000000006267c2c470a7940d276500728ecd2ad64aed9043ea1a307826e7613adff1f20ffffffffffffffffffff7ffffffffffffffffffffffffffffffffffffffffffff09569cfdd92178c5809aae45d654cd4cd7b98420995e6117395835ee4caedb660000000000000000000000000000000000000000000000000000000000ffffff0000000000000000000000000000000000000000ffffffffffffffffffffffff0000000000000000000000000000000000000000000000aa4ec00224afccfdb739db49933fec7470543df6db808d28a71e30ccbc8a92abc45240dbded41273eb6741b2fc379fad678116fe3d4d4b9a1a184ab53ba36b86ad0fa66340b1ab41adfa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92310ab089e4439a4c15d089f94afb7896ff553aecb10793d0ab882de59d99a32e02000002000000000000000000000000000000440000000000000000000000006c6564207468726f7567682064656c656761746563616c6c0000000000000000555550535570677261646561626c653a206d757374206e6f742062652063616c08c379a0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000084000000000000000000000000360894a13ba1a3210667c828492db98dca3e2076cc3735a920a3ca505d382bbc4910fdfa16fed3260ed0e7147f7cc6da11a60208b5b9406d12a635614ffd914352d1902d000000000000000000000000000000000000000000000000000000006961626c6555554944000000000000000000000000000000000000000000000045524331393637557067726164653a20756e737570706f727465642070726f78bc7cd75a20ee27fd9adebab32041f755214dbc6bffa90cc0225b39da2e5c2d3b000000000000000000000000000000000000000000000000ffffffffffffff9f206661696c656400000000000000000000000000000000000000000000000000416464726573733a206c6f772d6c6576656c2064656c65676174652063616c6c0000000000000000000000000000000000000000000000a0000000000000000000000000000000000000000000000000000000000000000000000001ffffffe000000000000000000000000000000000000000000000000000000003ffffffe059c896be00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffff0000000000000000000000000000000100000003000000000000000000000000000000000000000000000000000000006163746976652070726f7879000000000000000000000000000000000000000046756e6374696f6e206d7573742062652063616c6c6564207468726f75676820000000000000000000000000000000000000000000000000ffffffffffffffdf416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000000000000000000000000000000000000000000640000000000000000000000006f74206120636f6e747261637400000000000000000000000000000000000000455243313936373a206e657720696d706c656d656e746174696f6e206973206e64656c656761746563616c6c000000000000000000000000000000000000000002000000000000000000000000000000000000a00000000000000000000000007b878c0c0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f161421c8e00000000000000000000000000000000000000000000000000000000000000020000ffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffff0000000000000000000000000000000000000000000000000000000067fd22f00000000000000000000000000000000000000000000000000000000067fd3f1000000000000000000000000000000000000000000000000000000000684daa9000000000000000000000000000000000000000000000000000000000689cc490908408e307fc569b417f6cbec5d5a06f44a0a505ac0479b47d421a4b2fd6a1e60000000000000000000000000000000000000040000000000000000000000000fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffd5d00dbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1ddec3425c00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00009396981071dffa551b70bcfb27a0921b9ed53b367314b2eeec06ad128f6c9a34ccd677413877af997f8a9646dc5ed841e076eea2d336731b923925e083f577efb562e8dd000000000000000000000000000000000000000000000000000000004432414600000000000000000000000000000000000000000000000000000000af608abb00000000000000000000000000000000000000000000000000000000719486fd24600db3957f404ec8bc83d3bf786056c4cb8485d27783a43dc5f739000000000000000000000000000000000000000000000000190100000000000002000000000000000000000000000000000000420000001800000000000000001626ba7e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffbbffffffffffffffffffffffffffffffffffffffbc0000000000000000000000007fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffff0000000000000000000000000000000000000000000000000000000000748a2986091c2034d6e93b6f44f771a79f0e1d6acd8a60c68c17d4e1e2feaed25cbd944100000000000000000000000000000000000000000000000000000000cdc53013000000000000000000000000000000000000000000000000000000008baa579f000000000000000000000000000000000000000000000000000000004e487b710000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000240000000000000000000000004f174b29000000000000000000000000000000000000000000000000000000002d0a3f8e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ab143c06fffffffffffffffffffdffffffffffffffffffffffffffffffffffffffffffffcaee23ea000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000040000000800000000000000000c4b24d5e00000000000000000000000000000000000000000000000000000000cfb3b942000000000000000000000000000000000000000000000000000000008c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925df2d9b4200000000000000000000000000000000000000000000000000000000161a11d78e4c8a98c15b73ea9fd62ecc47a26992a28ca57d3307f1568dd637dee6c4247b000000000000000000000000000000000000000000000000000000005c427cd90000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000b4457eaa00000000000000000000000000000000000000000000000000000000350a88b300000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa07d2299ffffffffffffffffffffffffffffffffffffffffffffffffffffffffa07d229a00000000000000000000000000000000000000000000000000000000ad092b5c00000000000000000000000000000000000000000000000000000000ad0d7f6c0000000000000000000000000000000000000000000000000000000001ffc9a7000000000000000000000000000000000000000000000000000000005b5e139f0000000000000000000000000000000000000000000000000000000080ac58cd00000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00000000000000000000000000000000000000000000000100000000000000008000000000000000000000000000000000000000000000000000000000000000a114810000000000000000000000000000000000000000000000000000000000ea553b3400000000000000000000000000000000000000000000000000000000150b7a0200000000000000000000000000000000000000000000000000000000d1a57ed600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffff806f6e206973206e6f74205555505300000000000000000000000000000000000045524331393637557067726164653a206e657720696d706c656d656e74617469ffffffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffff0000000000ffff0000000000000000000000000000000000000000000000000002a728011dd3c4e0670c0062df24430abab41f1ff23507c373ab8101f8987633af4956d000000000000000000000000000000000000000000000000000000000ffffff0000ffffffffffffffffffffffffffffffffffffffffffffffffffffff000000ffff0000000000000000000000000000000000000000000000000000005bd159af1fc35b1160812318aa9d165c928b27e9e98ac77f29205a4d22b70f430200000200000000000000000000000000000000000000000000000000000000ebf5e61d9198335dd92e02339e980a997f0cbf919c5f2f19b0f016ea22d2b2b2
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.