More Info
Private Name Tags
ContractCreator
TokenTracker
Latest 25 from a total of 4,719 transactions
Transaction Hash |
Method
|
Block
|
From
|
To
|
|||||
---|---|---|---|---|---|---|---|---|---|
Set Approval For... | 14807411 | 80 days ago | IN | 0 ETH | 0.00000003 | ||||
Redeem Pupnik | 14726269 | 82 days ago | IN | 0 ETH | 0.00009637 | ||||
Redeem Pupnik | 14726254 | 82 days ago | IN | 0 ETH | 0.00005946 | ||||
Redeem Pupnik | 14726251 | 82 days ago | IN | 0 ETH | 0.00009637 | ||||
Redeem Pupnik | 12574134 | 132 days ago | IN | 0 ETH | 0.00008672 | ||||
Redeem Pupnik | 12574123 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12574104 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12574087 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12574070 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12574052 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12574027 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12573860 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12573818 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 12573793 | 132 days ago | IN | 0 ETH | 0.00009639 | ||||
Redeem Pupnik | 10639678 | 176 days ago | IN | 0 ETH | 0.00000007 | ||||
Withdraw All Gas | 10639589 | 176 days ago | IN | 0 ETH | 0.00000013 | ||||
Withdraw Yield | 10639543 | 176 days ago | IN | 0 ETH | 0.00000035 | ||||
Redeem Pupnik | 10512712 | 179 days ago | IN | 0 ETH | 0.00000008 | ||||
Redeem Pupnik | 7327417 | 253 days ago | IN | 0 ETH | 0.0000868 | ||||
Redeem Pupnik | 7327404 | 253 days ago | IN | 0 ETH | 0.00009645 | ||||
Redeem Pupnik Ba... | 7160822 | 257 days ago | IN | 0 ETH | 0.00000007 | ||||
Redeem Pupnik Ba... | 7160813 | 257 days ago | IN | 0 ETH | 0.00000007 | ||||
Redeem Pupnik Ba... | 7160799 | 257 days ago | IN | 0 ETH | 0.00000008 | ||||
Redeem Pupnik Ba... | 7160789 | 257 days ago | IN | 0 ETH | 0.00000007 | ||||
Redeem Pupnik Ba... | 7160774 | 257 days ago | IN | 0 ETH | 0.00000007 |
Latest 25 internal transactions (View All)
Parent Transaction Hash | Block | From | To | |||
---|---|---|---|---|---|---|
14726269 | 82 days ago | 0.5 ETH | ||||
14726251 | 82 days ago | 0.5 ETH | ||||
12574134 | 132 days ago | 0.5 ETH | ||||
12574123 | 132 days ago | 0.5 ETH | ||||
12574104 | 132 days ago | 0.5 ETH | ||||
12574087 | 132 days ago | 0.5 ETH | ||||
12574070 | 132 days ago | 0.5 ETH | ||||
12574052 | 132 days ago | 0.5 ETH | ||||
12574027 | 132 days ago | 0.5 ETH | ||||
12573860 | 132 days ago | 0.5 ETH | ||||
12573818 | 132 days ago | 0.5 ETH | ||||
12573793 | 132 days ago | 0.5 ETH | ||||
10639678 | 176 days ago | 0.5 ETH | ||||
10512712 | 179 days ago | 0.5 ETH | ||||
7327417 | 253 days ago | 0.5 ETH | ||||
7327404 | 253 days ago | 0.5 ETH | ||||
7160822 | 257 days ago | 0.5 ETH | ||||
7160813 | 257 days ago | 0.5 ETH | ||||
7160799 | 257 days ago | 0.5 ETH | ||||
7160789 | 257 days ago | 0.5 ETH | ||||
7160774 | 257 days ago | 0.5 ETH | ||||
4710911 | 314 days ago | 0.5 ETH | ||||
4695727 | 314 days ago | 0.5 ETH | ||||
3729505 | 336 days ago | 0.5 ETH | ||||
3729487 | 336 days ago | 0.5 ETH |
Loading...
Loading
Contract Name:
Pupniks
Compiler Version
v0.8.19+commit.7dd6d404
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; import "@solady/tokens/ERC721.sol"; import "@solady/auth/Ownable.sol"; import "@solady/utils/ECDSA.sol"; import "@solady/utils/LibString.sol"; import "src/interfaces/IBlast.sol"; error InvalidSignature(); error InvalidHash(); error SaleClosed(); error ContractMetadataLocked(); error OutOfStock(); error IncorrectAmountSent(); error NotApprovedOrOwner(); error TokenNotFound(); error NonceAlreadyUsed(); error CannotMintMoreThanMax(); error RedemptionTransferFailed(); error CannotMintSpecificIdsUntilAllMinted(); error InvalidTokenId(); error SetSignerBeforeTogglingSale(); contract Pupniks is ERC721, Ownable { using LibString for uint256; using ECDSA for bytes32; event BaseURISet(string URI); event ContractURIUpdated(); event MetadataLocked(); event SaleStatusToggled(bool live); event SignerAddressSet(address oldSigner, address newSigner); uint256 private constant TOTAL_SUPPLY = 3000; uint256 private constant PRICE = 0.5 ether; uint256 private constant MAX_MINTING_PER_TX = 1; IBlast private constant BLAST = IBlast(0x4300000000000000000000000000000000000002); /// @dev Map of an address to a bitmap (slot => status) mapping(address => mapping(uint256 => uint256)) private _usedNonces; /// @dev Base token uri string public baseTokenURI; /// @dev Contract URI - ERC7572 compliance string public contractURI; uint256 public amountMinted; bool public saleLive; bool public metadataLocked; address public signerAddress; constructor() { _initializeOwner(msg.sender); BLAST.configureClaimableGas(); } /** * @notice Mint function for Pupniks. This function is payable and requires a valid signature from the signer. * @dev The signature is generated by signing the hash of the message that includes the sender's address, the quantity of Pupniks to mint, and the nonce. * @dev The nonce is used to prevent replay attacks. There is a maximum amount of 3000 pupniks that can be minted. * * @param hash The hash of the message that was signed. * @param signature The signature of the message. * @param nonce The nonce used to sign the message. * @param quantity The quantity of Pupniks to mint. */ function mintPupnik(bytes32 hash, bytes calldata signature, uint256 nonce, uint256 quantity) external payable { _requireSaleOpen(); _requireValidSignature(hash, signature, nonce, quantity); _useNonce(msg.sender, nonce); uint256 currentAmount = amountMinted; if (currentAmount + quantity > TOTAL_SUPPLY) { revert OutOfStock(); } if (PRICE * quantity != msg.value) { revert IncorrectAmountSent(); } if (quantity > MAX_MINTING_PER_TX) { revert CannotMintMoreThanMax(); } unchecked { amountMinted += quantity; for (uint256 i = 1; i <= quantity;) { _mint(msg.sender, currentAmount + i); ++i; } } } /** * @notice Mint function for Pupniks. This function is payable and requires a valid signature from the signer. * @dev The signature is generated by signing the hash of the message that includes the sender's address, the quantity of Pupniks to mint, and the nonce. * @dev The nonce is used to prevent replay attacks. There is a maximum amout of * * @param hash The hash of the message that was signed. * @param signature The signature of the message. * @param nonce The nonce used to sign the message. * @param ids The array of tokenIds to mint. */ function mintSpecificPupniks(bytes32 hash, bytes calldata signature, uint256 nonce, uint256[] calldata ids) external payable { _requireSaleOpen(); _requireValidSignature(hash, signature, nonce, ids.length); _useNonce(msg.sender, nonce); uint256 currentAmount = amountMinted; if (currentAmount < TOTAL_SUPPLY) { revert CannotMintSpecificIdsUntilAllMinted(); } uint256 quantity = ids.length; if (PRICE * quantity != msg.value) { revert IncorrectAmountSent(); } if (quantity > MAX_MINTING_PER_TX) { revert CannotMintMoreThanMax(); } unchecked { for (uint256 i = 0; i < quantity;) { if (ids[i] > TOTAL_SUPPLY) { revert InvalidTokenId(); } _mint(msg.sender, ids[i]); ++i; } } } /** * @notice Redeem function for Pupniks. This function allows the owner to redeem a batch of Pupniks. * @notice Redemption sends back the original funding of the Pupniks. * * @param tokenIds The array of tokenIds to redeem. */ function redeemPupnikBatch(uint256[] calldata tokenIds) external { unchecked { for (uint256 i = 0; i < tokenIds.length;) { _redeemPupnik(tokenIds[i]); ++i; } } } /** * @notice Redeem function for Pupniks. This function allows the owner to redeem a single Pupnik. * @notice Redemption sends back the original funding of the Pupnik. * @dev This function is slightly more gas efficient and preferred if the user only has one Pupnik to redeem. * * @param tokenId The tokenId to redeem. */ function redeemPupnik(uint256 tokenId) external { _redeemPupnik(tokenId); } function _redeemPupnik(uint256 tokenId) private { if (!_isApprovedOrOwner(msg.sender, tokenId)) { revert NotApprovedOrOwner(); } _burn(tokenId); (bool success, ) = msg.sender.call{value: PRICE, gas: 30_000}(""); if (!success) { revert RedemptionTransferFailed(); } } /** * @notice Owner mint for pupniks allowing team to mint before opening. * * @param quantity Number of pupniks to mint */ function ownerMint(uint256 quantity) external payable onlyOwner { uint256 currentAmount = amountMinted; if (currentAmount + quantity > TOTAL_SUPPLY) { revert OutOfStock(); } if (PRICE * quantity != msg.value) { revert IncorrectAmountSent(); } unchecked { amountMinted += quantity; for (uint256 i = 1; i <= quantity;) { _mint(msg.sender, currentAmount + i); ++i; } } } /** * @notice Turns on claimable yield for the contract. */ function configureClaimableYield() external onlyOwner { BLAST.configureClaimableYield(); } /** * @notice Updates the governor of the contract. */ function configureGovernor(address newGov) external onlyOwner { BLAST.configureGovernor(newGov); } /** * @notice Locks metadata from being changed. Only the owner can call this function. */ function lockMetadata() external onlyOwner { metadataLocked = true; emit MetadataLocked(); } /** * @notice Toggles the sale status. Only the owner can call this function. */ function toggleSaleStatus() external onlyOwner { if (signerAddress == address(0)) { revert SetSignerBeforeTogglingSale(); } saleLive = !saleLive; emit SaleStatusToggled(saleLive); } /** * @notice Sets the signer address. Only the owner can call this function. */ function setSignerAddress(address addr) external onlyOwner { address oldSigner = signerAddress; signerAddress = addr; emit SignerAddressSet(oldSigner, addr); } /** * @notice Sets the contract URI. Only the owner can call this function. * @dev This function will revert if the contract is locked. */ function setContractURI(string calldata URI) external onlyOwner { _requireMetadataNotLocked(); contractURI = URI; emit ContractURIUpdated(); } /** * @notice Sets the base token URI. Only the owner can call this function. * @dev This function will revert if the contract is locked. */ function setBaseURI(string calldata URI) external onlyOwner { _requireMetadataNotLocked(); baseTokenURI = URI; emit BaseURISet(URI); } /** * @notice Withdraws any claimable yield from the contract. Only the owner can call this function. */ function withdrawYield() external onlyOwner { if (BLAST.readClaimableYield(address(this)) > 0) { BLAST.claimAllYield(address(this), owner()); } } /** * @notice Withdraws any claimable gas from the contract. Only the owner can call this function. * @dev NOTE: if gas is not all fully claimable, calling this will result in a loss of unvested gas fees. */ function withdrawAllGas() external onlyOwner { BLAST.claimAllGas(address(this), owner()); } /** * @notice Withdraws gas from the contract at the minimum claim rate. Only the owner can call this function. * @dev Claim rate is in BIPs, so an 80% claim rate would be 8000. */ function withdrawGasAtMinClaimrate(uint256 minClaimRateBips) external onlyOwner { BLAST.claimGasAtMinClaimRate(address(this), owner(), minClaimRateBips); } /** * @notice Returns the amount of claimable yield for the contract. */ function claimableYield() external view returns (uint256 yield) { yield = BLAST.readClaimableYield(address(this)); } /** * @notice Returns the amount of claimable gas for the contract. */ function claimableGas() external view returns (uint256 etherBalance) { (, etherBalance,,) = BLAST.readGasParams(address(this)); } /** * @notice Returns the token URI for a given tokenId. * @dev This function will revert if the token does not exist. * * @param tokenId The tokenId to get the URI for. * @return uri The token URI. */ function tokenURI(uint256 tokenId) public view override(ERC721) returns (string memory uri) { if (!_exists(tokenId)) { revert TokenNotFound(); } uri = string(abi.encodePacked(baseTokenURI, tokenId.toString())); } /** * @notice Returns the amount of Pupniks that are currently minted * @return amount The amount of Pupniks that are currently minted. */ function getAmountMinted() external view returns (uint256 amount) { amount = amountMinted; } /** * @notice Returns the name of the contract * @return name_ The contract name. */ function name() public pure override returns (string memory name_) { name_ = "Pupniks"; } /** * @notice Returns the symbol of the contract * @return symbol_ The contract symbol. */ function symbol() public pure override returns (string memory symbol_) { symbol_ = "PUPNIK"; } /** * @notice Returns the price of a single Pupnik. * @return price The price of a single Pupnik. */ function getPrice() external pure returns (uint256 price) { price = PRICE; } /** * @notice Returns the total supply of Pupniks. * @return supply The total supply of Pupniks. */ function getTotalSupply() external pure returns (uint256 supply) { supply = TOTAL_SUPPLY; } /** * @notice Returns if a nonce is valid for a given address. * * @param tokenOwner The address to check the nonce for. * @param nonce The nonce to check. * * @return isValid True if the nonce is valid, false otherwise. */ function isValidNonce(address tokenOwner, uint256 nonce) external view returns (bool isValid) { isValid = ((_usedNonces[tokenOwner][uint248(nonce >> 8)] >> uint8(nonce)) & 1) == 0; } function _requireValidSignature(bytes32 hash, bytes calldata signature, uint256 nonce, uint256 quantity) private view { if (signerAddress != hash.recover(signature)) { revert InvalidSignature(); } bytes32 localHash = keccak256( abi.encodePacked( "\x19Ethereum Signed Message:\n32", keccak256(abi.encodePacked(msg.sender, nonce, quantity)) ) ); if (localHash != hash) { revert InvalidHash(); } } function _requireSaleOpen() private view { if (!saleLive) { revert SaleClosed(); } } function _requireMetadataNotLocked() private view { if (metadataLocked) { revert ContractMetadataLocked(); } } function _useNonce(address account, uint256 nonce) internal { unchecked { if ( uint256(_usedNonces[account][uint248(nonce >> 8)] ^= (1 << uint8(nonce))) & (1 << uint8(nonce)) == 0 ) { revert NonceAlreadyUsed(); } } } }
// SPDX-License-Identifier: MIT pragma solidity ^0.8.4; /// @notice Simple ERC721 implementation with storage hitchhiking. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/tokens/ERC721.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/tree/master/contracts/token/ERC721/ERC721.sol) /// /// @dev Note: /// - The ERC721 standard allows for self-approvals. /// For performance, this implementation WILL NOT revert for such actions. /// Please add any checks with overrides if desired. /// - For performance, methods are made payable where permitted by the ERC721 standard. /// - The `safeTransfer` functions use the identity precompile (0x4) /// to copy memory internally. /// /// If you are overriding: /// - NEVER violate the ERC721 invariant: /// the balance of an owner MUST always be equal to their number of ownership slots. /// The transfer functions do not have an underflow guard for user token balances. /// - Make sure all variables written to storage are properly cleaned // (e.g. the bool value for `isApprovedForAll` MUST be either 1 or 0 under the hood). /// - Check that the overridden function is actually used in the function you want to /// change the behavior of. Much of the code has been manually inlined for performance. abstract contract ERC721 { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev An account can hold up to 4294967295 tokens. uint256 internal constant _MAX_ACCOUNT_BALANCE = 0xffffffff; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Only the token owner or an approved account can manage the token. error NotOwnerNorApproved(); /// @dev The token does not exist. error TokenDoesNotExist(); /// @dev The token already exists. error TokenAlreadyExists(); /// @dev Cannot query the balance for the zero address. error BalanceQueryForZeroAddress(); /// @dev Cannot mint or transfer to the zero address. error TransferToZeroAddress(); /// @dev The token must be owned by `from`. error TransferFromIncorrectOwner(); /// @dev The recipient's balance has overflowed. error AccountBalanceOverflow(); /// @dev Cannot safely transfer to a contract that does not implement /// the ERC721Receiver interface. error TransferToNonERC721ReceiverImplementer(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* EVENTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Emitted when token `id` is transferred from `from` to `to`. event Transfer(address indexed from, address indexed to, uint256 indexed id); /// @dev Emitted when `owner` enables `account` to manage the `id` token. event Approval(address indexed owner, address indexed account, uint256 indexed id); /// @dev Emitted when `owner` enables or disables `operator` to manage all of their tokens. event ApprovalForAll(address indexed owner, address indexed operator, bool isApproved); /// @dev `keccak256(bytes("Transfer(address,address,uint256)"))`. uint256 private constant _TRANSFER_EVENT_SIGNATURE = 0xddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef; /// @dev `keccak256(bytes("Approval(address,address,uint256)"))`. uint256 private constant _APPROVAL_EVENT_SIGNATURE = 0x8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925; /// @dev `keccak256(bytes("ApprovalForAll(address,address,bool)"))`. uint256 private constant _APPROVAL_FOR_ALL_EVENT_SIGNATURE = 0x17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* STORAGE */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The ownership data slot of `id` is given by: /// ``` /// mstore(0x00, id) /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) /// ``` /// Bits Layout: /// - [0..159] `addr` /// - [160..255] `extraData` /// /// The approved address slot is given by: `add(1, ownershipSlot)`. /// /// See: https://notes.ethereum.org/%40vbuterin/verkle_tree_eip /// /// The balance slot of `owner` is given by: /// ``` /// mstore(0x1c, _ERC721_MASTER_SLOT_SEED) /// mstore(0x00, owner) /// let balanceSlot := keccak256(0x0c, 0x1c) /// ``` /// Bits Layout: /// - [0..31] `balance` /// - [32..255] `aux` /// /// The `operator` approval slot of `owner` is given by: /// ``` /// mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) /// mstore(0x00, owner) /// let operatorApprovalSlot := keccak256(0x0c, 0x30) /// ``` uint256 private constant _ERC721_MASTER_SLOT_SEED = 0x7d8825530a5a2e7a << 192; /// @dev Pre-shifted and pre-masked constant. uint256 private constant _ERC721_MASTER_SLOT_SEED_MASKED = 0x0a5a2e7a00000000; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 METADATA */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the token collection name. function name() public view virtual returns (string memory); /// @dev Returns the token collection symbol. function symbol() public view virtual returns (string memory); /// @dev Returns the Uniform Resource Identifier (URI) for token `id`. function tokenURI(uint256 id) public view virtual returns (string memory); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* ERC721 */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the owner of token `id`. /// /// Requirements: /// - Token `id` must exist. function ownerOf(uint256 id) public view virtual returns (address result) { result = _ownerOf(id); /// @solidity memory-safe-assembly assembly { if iszero(result) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } } } /// @dev Returns the number of tokens owned by `owner`. /// /// Requirements: /// - `owner` must not be the zero address. function balanceOf(address owner) public view virtual returns (uint256 result) { /// @solidity memory-safe-assembly assembly { // Revert if the `owner` is the zero address. if iszero(owner) { mstore(0x00, 0x8f4eb604) // `BalanceQueryForZeroAddress()`. revert(0x1c, 0x04) } mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := and(sload(keccak256(0x0c, 0x1c)), _MAX_ACCOUNT_BALANCE) } } /// @dev Returns the account approved to manage token `id`. /// /// Requirements: /// - Token `id` must exist. function getApproved(uint256 id) public view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) if iszero(shl(96, sload(ownershipSlot))) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } result := sload(add(1, ownershipSlot)) } } /// @dev Sets `account` as the approved account to manage token `id`. /// /// Requirements: /// - Token `id` must exist. /// - The caller must be the owner of the token, /// or an approved operator for the token owner. /// /// Emits an {Approval} event. function approve(address account, uint256 id) public payable virtual { _approve(msg.sender, account, id); } /// @dev Returns whether `operator` is approved to manage the tokens of `owner`. function isApprovedForAll(address owner, address operator) public view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, owner) result := sload(keccak256(0x0c, 0x30)) } } /// @dev Sets whether `operator` is approved to manage the tokens of the caller. /// /// Emits an {ApprovalForAll} event. function setApprovalForAll(address operator, bool isApproved) public virtual { /// @solidity memory-safe-assembly assembly { // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`msg.sender`, `operator`). mstore(0x1c, operator) mstore(0x08, _ERC721_MASTER_SLOT_SEED_MASKED) mstore(0x00, caller()) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) // forgefmt: disable-next-item log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, caller(), shr(96, shl(96, operator))) } } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function transferFrom(address from, address to, uint256 id) public payable virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, caller())) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if the token does not exist, or if `from` is not the owner. if iszero(mul(owner, eq(owner, from))) { // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`. mstore(shl(2, iszero(owner)), 0xceea21b6a1148100) revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // Revert if the caller is not the owner, nor approved. if iszero(or(eq(caller(), from), eq(caller(), approvedAddress))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `safeTransferFrom(from, to, id, "")`. function safeTransferFrom(address from, address to, uint256 id) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - 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 id, bytes calldata data) public payable virtual { transferFrom(from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @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, ERC721: 0x80ac58cd, ERC721Metadata: 0x5b5e139f. result := or(or(eq(s, 0x01ffc9a7), eq(s, 0x80ac58cd)), eq(s, 0x5b5e139f)) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL QUERY FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if token `id` exists. function _exists(uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := iszero(iszero(shl(96, sload(add(id, add(id, keccak256(0x00, 0x20))))))) } } /// @dev Returns the owner of token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _ownerOf(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(96, shl(96, sload(add(id, add(id, keccak256(0x00, 0x20)))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL DATA HITCHHIKING FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance, no events are emitted for the hitchhiking setters. // Please emit your own events if required. /// @dev Returns the auxiliary data for `owner`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _getAux(address owner) internal view virtual returns (uint224 result) { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) result := shr(32, sload(keccak256(0x0c, 0x1c))) } } /// @dev Set the auxiliary data for `owner` to `value`. /// Minting, transferring, burning the tokens of `owner` will not change the auxiliary data. /// Auxiliary data can be set for any address, even if it does not have any tokens. function _setAux(address owner, uint224 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x1c, _ERC721_MASTER_SLOT_SEED) mstore(0x00, owner) let balanceSlot := keccak256(0x0c, 0x1c) let packed := sload(balanceSlot) sstore(balanceSlot, xor(packed, shl(32, xor(value, shr(32, packed))))) } } /// @dev Returns the extra data for token `id`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _getExtraData(uint256 id) internal view virtual returns (uint96 result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := shr(160, sload(add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Sets the extra data for token `id` to `value`. /// Minting, transferring, burning a token will not change the extra data. /// The extra data can be set on a non-existent token. function _setExtraData(uint256 id, uint96 value) internal virtual { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let packed := sload(ownershipSlot) sstore(ownershipSlot, xor(packed, shl(160, xor(value, shr(160, packed))))) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL MINT FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mint(address to, uint256 id) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Revert if the token already exists. if shl(96, ownershipPacked) { mstore(0x00, 0xc991cbb1) // `TokenAlreadyExists()`. revert(0x1c, 0x04) } // Update with the owner. sstore(ownershipSlot, or(ownershipPacked, to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Mints token `id` to `to`, and updates the extra data for token `id` to `value`. /// Does NOT check if token `id` already exists (assumes `id` is auto-incrementing). /// /// Requirements: /// /// - `to` cannot be the zero address. /// /// Emits a {Transfer} event. function _mintAndSetExtraDataUnchecked(address to, uint256 id, uint96 value) internal virtual { _beforeTokenTransfer(address(0), to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. to := shr(96, shl(96, to)) // Update with the owner and extra data. mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) sstore(add(id, add(id, keccak256(0x00, 0x20))), or(shl(160, value), to)) // Increment the balance of the owner. { mstore(0x00, to) let balanceSlot := keccak256(0x0c, 0x1c) let balanceSlotPacked := add(sload(balanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(balanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(balanceSlot, balanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, 0, to, id) } _afterTokenTransfer(address(0), to, id); } /// @dev Equivalent to `_safeMint(to, id, "")`. function _safeMint(address to, uint256 id) internal virtual { _safeMint(to, id, ""); } /// @dev Mints token `id` to `to`. /// /// Requirements: /// /// - Token `id` must not exist. /// - `to` cannot be the zero address. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeMint(address to, uint256 id, bytes memory data) internal virtual { _mint(to, id); if (_hasCode(to)) _checkOnERC721Received(address(0), to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL BURN FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_burn(address(0), id)`. function _burn(uint256 id) internal virtual { _burn(address(0), id); } /// @dev Destroys token `id`, using `by`. /// /// Requirements: /// /// - Token `id` must exist. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _burn(address by, uint256 id) internal virtual { address owner = ownerOf(id); _beforeTokenTransfer(owner, address(0), id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) // Reload the owner in case it is changed in `_beforeTokenTransfer`. owner := shr(96, shl(96, ownershipPacked)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Load and check the token approval. { mstore(0x00, owner) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, owner), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Clear the owner. sstore(ownershipSlot, xor(ownershipPacked, owner)) // Decrement the balance of `owner`. { let balanceSlot := keccak256(0x0c, 0x1c) sstore(balanceSlot, sub(sload(balanceSlot), 1)) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, owner, 0, id) } _afterTokenTransfer(owner, address(0), id); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL APPROVAL FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns whether `account` is the owner of token `id`, or is approved to manage it. /// /// Requirements: /// - Token `id` must exist. function _isApprovedOrOwner(address account, uint256 id) internal view virtual returns (bool result) { /// @solidity memory-safe-assembly assembly { result := 1 // Clear the upper 96 bits. account := shr(96, shl(96, account)) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, account)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := shr(96, shl(96, sload(ownershipSlot))) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // Check if `account` is the `owner`. if iszero(eq(account, owner)) { mstore(0x00, owner) // Check if `account` is approved to manage the token. if iszero(sload(keccak256(0x0c, 0x30))) { result := eq(account, sload(add(1, ownershipSlot))) } } } } /// @dev Returns the account approved to manage token `id`. /// Returns the zero address instead of reverting if the token does not exist. function _getApproved(uint256 id) internal view virtual returns (address result) { /// @solidity memory-safe-assembly assembly { mstore(0x00, id) mstore(0x1c, _ERC721_MASTER_SLOT_SEED) result := sload(add(1, add(id, add(id, keccak256(0x00, 0x20))))) } } /// @dev Equivalent to `_approve(address(0), account, id)`. function _approve(address account, uint256 id) internal virtual { _approve(address(0), account, id); } /// @dev Sets `account` as the approved account to manage token `id`, using `by`. /// /// Requirements: /// - Token `id` must exist. /// - If `by` is not the zero address, `by` must be the owner /// or an approved operator for the token owner. /// /// Emits a {Transfer} event. function _approve(address by, address account, uint256 id) internal virtual { assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) account := and(bitmaskAddress, account) by := and(bitmaskAddress, by) // Load the owner of the token. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let owner := and(bitmaskAddress, sload(ownershipSlot)) // Revert if the token does not exist. if iszero(owner) { mstore(0x00, 0xceea21b6) // `TokenDoesNotExist()`. revert(0x1c, 0x04) } // If `by` is not the zero address, do the authorization check. // Revert if `by` is not the owner, nor approved. if iszero(or(iszero(by), eq(by, owner))) { mstore(0x00, owner) if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Sets `account` as the approved account to manage `id`. sstore(add(1, ownershipSlot), account) // Emit the {Approval} event. log4(codesize(), 0x00, _APPROVAL_EVENT_SIGNATURE, owner, account, id) } } /// @dev Approve or remove the `operator` as an operator for `by`, /// without authorization checks. /// /// Emits an {ApprovalForAll} event. function _setApprovalForAll(address by, address operator, bool isApproved) internal virtual { /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. by := shr(96, shl(96, by)) operator := shr(96, shl(96, operator)) // Convert to 0 or 1. isApproved := iszero(iszero(isApproved)) // Update the `isApproved` for (`by`, `operator`). mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, operator)) mstore(0x00, by) sstore(keccak256(0x0c, 0x30), isApproved) // Emit the {ApprovalForAll} event. mstore(0x00, isApproved) log3(0x00, 0x20, _APPROVAL_FOR_ALL_EVENT_SIGNATURE, by, operator) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* INTERNAL TRANSFER FUNCTIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Equivalent to `_transfer(address(0), from, to, id)`. function _transfer(address from, address to, uint256 id) internal virtual { _transfer(address(0), from, to, id); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// /// Emits a {Transfer} event. function _transfer(address by, address from, address to, uint256 id) internal virtual { _beforeTokenTransfer(from, to, id); /// @solidity memory-safe-assembly assembly { // Clear the upper 96 bits. let bitmaskAddress := shr(96, not(0)) from := and(bitmaskAddress, from) to := and(bitmaskAddress, to) by := and(bitmaskAddress, by) // Load the ownership data. mstore(0x00, id) mstore(0x1c, or(_ERC721_MASTER_SLOT_SEED, by)) let ownershipSlot := add(id, add(id, keccak256(0x00, 0x20))) let ownershipPacked := sload(ownershipSlot) let owner := and(bitmaskAddress, ownershipPacked) // Revert if the token does not exist, or if `from` is not the owner. if iszero(mul(owner, eq(owner, from))) { // `TokenDoesNotExist()`, `TransferFromIncorrectOwner()`. mstore(shl(2, iszero(owner)), 0xceea21b6a1148100) revert(0x1c, 0x04) } // Load, check, and update the token approval. { mstore(0x00, from) let approvedAddress := sload(add(1, ownershipSlot)) // If `by` is not the zero address, do the authorization check. // Revert if the `by` is not the owner, nor approved. if iszero(or(iszero(by), or(eq(by, from), eq(by, approvedAddress)))) { if iszero(sload(keccak256(0x0c, 0x30))) { mstore(0x00, 0x4b6e7f18) // `NotOwnerNorApproved()`. revert(0x1c, 0x04) } } // Delete the approved address if any. if approvedAddress { sstore(add(1, ownershipSlot), 0) } } // Update with the new owner. sstore(ownershipSlot, xor(ownershipPacked, xor(from, to))) // Decrement the balance of `from`. { let fromBalanceSlot := keccak256(0x0c, 0x1c) sstore(fromBalanceSlot, sub(sload(fromBalanceSlot), 1)) } // Increment the balance of `to`. { mstore(0x00, to) let toBalanceSlot := keccak256(0x0c, 0x1c) let toBalanceSlotPacked := add(sload(toBalanceSlot), 1) // Revert if `to` is the zero address, or if the account balance overflows. if iszero(mul(to, and(toBalanceSlotPacked, _MAX_ACCOUNT_BALANCE))) { // `TransferToZeroAddress()`, `AccountBalanceOverflow()`. mstore(shl(2, iszero(to)), 0xea553b3401336cea) revert(0x1c, 0x04) } sstore(toBalanceSlot, toBalanceSlotPacked) } // Emit the {Transfer} event. log4(codesize(), 0x00, _TRANSFER_EVENT_SIGNATURE, from, to, id) } _afterTokenTransfer(from, to, id); } /// @dev Equivalent to `_safeTransfer(from, to, id, "")`. function _safeTransfer(address from, address to, uint256 id) internal virtual { _safeTransfer(from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - The caller must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(address(0), from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /// @dev Equivalent to `_safeTransfer(by, from, to, id, "")`. function _safeTransfer(address by, address from, address to, uint256 id) internal virtual { _safeTransfer(by, from, to, id, ""); } /// @dev Transfers token `id` from `from` to `to`. /// /// Requirements: /// /// - Token `id` must exist. /// - `from` must be the owner of the token. /// - `to` cannot be the zero address. /// - If `by` is not the zero address, /// it must be the owner of the token, or be approved to manage the token. /// - If `to` refers to a smart contract, it must implement /// {IERC721Receiver-onERC721Received}, which is called upon a safe transfer. /// /// Emits a {Transfer} event. function _safeTransfer(address by, address from, address to, uint256 id, bytes memory data) internal virtual { _transfer(by, from, to, id); if (_hasCode(to)) _checkOnERC721Received(from, to, id, data); } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HOOKS FOR OVERRIDING */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Hook that is called before any token transfers, including minting and burning. function _beforeTokenTransfer(address from, address to, uint256 id) internal virtual {} /// @dev Hook that is called after any token transfers, including minting and burning. function _afterTokenTransfer(address from, address to, uint256 id) internal virtual {} /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* PRIVATE HELPERS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns if `a` has bytecode of non-zero length. function _hasCode(address a) private view returns (bool result) { /// @solidity memory-safe-assembly assembly { result := extcodesize(a) // Can handle dirty upper bits. } } /// @dev Perform a call to invoke {IERC721Receiver-onERC721Received} on `to`. /// Reverts if the target does not support the function correctly. function _checkOnERC721Received(address from, address to, uint256 id, bytes memory data) private { /// @solidity memory-safe-assembly assembly { // Prepare the calldata. let m := mload(0x40) let onERC721ReceivedSelector := 0x150b7a02 mstore(m, onERC721ReceivedSelector) mstore(add(m, 0x20), caller()) // The `operator`, which is always `msg.sender`. mstore(add(m, 0x40), shr(96, shl(96, from))) mstore(add(m, 0x60), id) mstore(add(m, 0x80), 0x80) let n := mload(data) mstore(add(m, 0xa0), n) if n { pop(staticcall(gas(), 4, add(data, 0x20), n, add(m, 0xc0), n)) } // Revert if the call reverts. if iszero(call(gas(), to, 0, add(m, 0x1c), add(n, 0xa4), m, 0x20)) { if returndatasize() { // Bubble up the revert if the call reverts. returndatacopy(m, 0x00, returndatasize()) revert(m, returndatasize()) } } // Load the returndata and compare it. if iszero(eq(mload(m), shl(224, onERC721ReceivedSelector))) { mstore(0x00, 0xd1a57ed6) // `TransferToNonERC721ReceiverImplementer()`. revert(0x1c, 0x04) } } } }
// 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 Gas optimized ECDSA wrapper. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/ECDSA.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/ECDSA.sol) /// @author Modified from OpenZeppelin (https://github.com/OpenZeppelin/openzeppelin-contracts/blob/master/contracts/utils/cryptography/ECDSA.sol) /// /// @dev Note: /// - The recovery functions use the ecrecover precompile (0x1). /// - As of Solady version 0.0.68, the `recover` variants will revert upon recovery failure. /// This is for more safety by default. /// Use the `tryRecover` variants if you need to get the zero address back /// upon recovery failure instead. /// - 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 ECDSA { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The signature is invalid. error InvalidSignature(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RECOVERY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function recover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. for {} 1 {} { mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. break } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. break } result := 0 break } result := mload( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function recoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) for {} 1 {} { if eq(signature.length, 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`. break } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. break } result := 0 break } result := mload( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. result := mload( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) result := mload( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x01, // Start of output. 0x20 // Size of output. ) ) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. if iszero(returndatasize()) { mstore(0x00, 0x8baa579f) // `InvalidSignature()`. revert(0x1c, 0x04) } mstore(0x60, 0) // Restore the zero slot. mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* TRY-RECOVER OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // WARNING! // These functions will NOT revert upon recovery failure. // Instead, they will return the zero address upon recovery failure. // It is critical that the returned address is NEVER compared against // a zero address (e.g. an uninitialized address variable). /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function tryRecover(bytes32 hash, bytes memory signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. for {} 1 {} { mstore(0x00, hash) mstore(0x40, mload(add(signature, 0x20))) // `r`. if eq(mload(signature), 64) { let vs := mload(add(signature, 0x40)) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x60, shr(1, shl(1, vs))) // `s`. break } if eq(mload(signature), 65) { mstore(0x20, byte(0, mload(add(signature, 0x60)))) // `v`. mstore(0x60, mload(add(signature, 0x40))) // `s`. break } result := 0 break } pop( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, and the `signature`. function tryRecoverCalldata(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { result := 1 let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) for {} 1 {} { if eq(signature.length, 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`. break } if eq(signature.length, 65) { mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) // `v`. calldatacopy(0x40, signature.offset, 0x40) // Copy `r` and `s`. break } result := 0 break } pop( staticcall( gas(), // Amount of gas left for the transaction. result, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. function tryRecover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, add(shr(255, vs), 27)) // `v`. mstore(0x40, r) mstore(0x60, shr(1, shl(1, vs))) // `s`. pop( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. function tryRecover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { let m := mload(0x40) // Cache the free memory pointer. mstore(0x00, hash) mstore(0x20, and(v, 0xff)) mstore(0x40, r) mstore(0x60, s) pop( staticcall( gas(), // Amount of gas left for the transaction. 1, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) mstore(0x60, 0) // Restore the zero slot. // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(xor(0x60, returndatasize())) mstore(0x40, m) // Restore the free memory pointer. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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; /// @notice Library for converting numbers into strings and other string operations. /// @author Solady (https://github.com/vectorized/solady/blob/main/src/utils/LibString.sol) /// @author Modified from Solmate (https://github.com/transmissions11/solmate/blob/main/src/utils/LibString.sol) /// /// @dev Note: /// For performance and bytecode compactness, most of the string operations are restricted to /// byte strings (7-bit ASCII), except where otherwise specified. /// Usage of byte string operations on charsets with runes spanning two or more bytes /// can lead to undefined behavior. library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The length of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /// @dev The length of the string is more than 32 bytes. error TooBigForSmallString(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The constant returned when the `search` is not found in the string. uint256 internal constant NOT_FOUND = type(uint256).max; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* DECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the base 10 decimal representation of `value`. function toString(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // The maximum value of a uint256 contains 78 digits (1 byte per digit), but // we allocate 0xa0 bytes to keep the free memory pointer 32-byte word aligned. // We will need 1 word for the trailing zeros padding, 1 word for the length, // and 3 words for a maximum of 78 digits. str := add(mload(0x40), 0x80) // Update the free memory pointer to allocate. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str let w := not(0) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 1)`. // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) if iszero(temp) { break } } let length := sub(end, str) // Move the pointer 32 bytes leftwards to make room for the length. str := sub(str, 0x20) // Store the length. mstore(str, length) } } /// @dev Returns the base 10 decimal representation of `value`. function toString(int256 value) internal pure returns (string memory str) { if (value >= 0) { return toString(uint256(value)); } unchecked { str = toString(~uint256(value) + 1); } /// @solidity memory-safe-assembly assembly { // We still have some spare memory space on the left, // as we have allocated 3 words (96 bytes) for up to 78 digits. let length := mload(str) // Load the string length. mstore(str, 0x2d) // Store the '-' character. str := sub(str, 1) // Move back the string pointer by a byte. mstore(str, add(length, 1)) // Update the string length. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* HEXADECIMAL OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2 + 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexString(uint256 value, uint256 length) internal pure returns (string memory str) { str = toHexStringNoPrefix(value, length); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`, /// left-padded to an input length of `length` bytes. /// The output is prefixed with "0x" encoded using 2 hexadecimal digits per byte, /// giving a total length of `length * 2` bytes. /// Reverts if `length` is too small for the output to contain all the digits. function toHexStringNoPrefix(uint256 value, uint256 length) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, `length * 2` bytes // for the digits, 0x02 bytes for the prefix, and 0x20 bytes for the length. // We add 0x20 to the total and round down to a multiple of 0x20. // (0x20 + 0x20 + 0x02 + 0x20) = 0x62. str := add(mload(0x40), and(add(shl(1, length), 0x42), not(0x1f))) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let start := sub(str, add(length, length)) let w := not(1) // Tsk. let temp := value // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for {} 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(xor(str, start)) { break } } if temp { mstore(0x00, 0x2194895a) // `HexLengthInsufficient()`. revert(0x1c, 0x04) } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2 + 2` bytes. function toHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x". /// The output excludes leading "0" from the `toHexString` output. /// `0x00: "0x0", 0x01: "0x1", 0x12: "0x12", 0x123: "0x123"`. function toMinimalHexString(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := add(mload(str), 2) // Compute the length. mstore(add(str, o), 0x3078) // Write the "0x" prefix, accounting for leading zero. str := sub(add(str, o), 2) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output excludes leading "0" from the `toHexStringNoPrefix` output. /// `0x00: "0", 0x01: "1", 0x12: "12", 0x123: "123"`. function toMinimalHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let o := eq(byte(0, mload(add(str, 0x20))), 0x30) // Whether leading zero is present. let strLength := mload(str) // Get the length. str := add(str, o) // Move the pointer, accounting for leading zero. mstore(str, sub(strLength, o)) // Write the length, accounting for leading zero. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. /// As address are 20 bytes long, the output will left-padded to have /// a length of `20 * 2` bytes. function toHexStringNoPrefix(uint256 value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x40 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x40) is 0xa0. str := add(mload(0x40), 0x80) // Allocate the memory. mstore(0x40, add(str, 0x20)) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let w := not(1) // Tsk. // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := add(str, w) // `sub(str, 2)`. mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) if iszero(temp) { break } } // Compute the string's length. let strLength := sub(end, str) // Move the pointer and write the length. str := sub(str, 0x20) mstore(str, strLength) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x", encoded using 2 hexadecimal digits per byte, /// and the alphabets are capitalized conditionally according to /// https://eips.ethereum.org/EIPS/eip-55 function toHexStringChecksummed(address value) internal pure returns (string memory str) { str = toHexString(value); /// @solidity memory-safe-assembly assembly { let mask := shl(6, div(not(0), 255)) // `0b010000000100000000 ...` let o := add(str, 0x22) let hashed := and(keccak256(o, 40), mul(34, mask)) // `0b10001000 ... ` let t := shl(240, 136) // `0b10001000 << 240` for { let i := 0 } 1 {} { mstore(add(i, i), mul(t, byte(i, hashed))) i := add(i, 1) if eq(i, 20) { break } } mstore(o, xor(mload(o), shr(1, and(mload(0x00), and(mload(o), mask))))) o := add(o, 0x20) mstore(o, xor(mload(o), shr(1, and(mload(0x20), and(mload(o), mask))))) } } /// @dev Returns the hexadecimal representation of `value`. /// The output is prefixed with "0x" and encoded using 2 hexadecimal digits per byte. function toHexString(address value) internal pure returns (string memory str) { str = toHexStringNoPrefix(value); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hexadecimal representation of `value`. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(address value) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { str := mload(0x40) // Allocate the memory. // We need 0x20 bytes for the trailing zeros padding, 0x20 bytes for the length, // 0x02 bytes for the prefix, and 0x28 bytes for the digits. // The next multiple of 0x20 above (0x20 + 0x20 + 0x02 + 0x28) is 0x80. mstore(0x40, add(str, 0x80)) // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) str := add(str, 2) mstore(str, 40) let o := add(str, 0x20) mstore(add(o, 40), 0) value := shl(96, value) // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let i := 0 } 1 {} { let p := add(o, add(i, i)) let temp := byte(i, value) mstore8(add(p, 1), mload(and(temp, 15))) mstore8(p, mload(shr(4, temp))) i := add(i, 1) if eq(i, 20) { break } } } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexString(bytes memory raw) internal pure returns (string memory str) { str = toHexStringNoPrefix(raw); /// @solidity memory-safe-assembly assembly { let strLength := add(mload(str), 2) // Compute the length. mstore(str, 0x3078) // Write the "0x" prefix. str := sub(str, 2) // Move the pointer. mstore(str, strLength) // Write the length. } } /// @dev Returns the hex encoded string from the raw bytes. /// The output is encoded using 2 hexadecimal digits per byte. function toHexStringNoPrefix(bytes memory raw) internal pure returns (string memory str) { /// @solidity memory-safe-assembly assembly { let length := mload(raw) str := add(mload(0x40), 2) // Skip 2 bytes for the optional prefix. mstore(str, add(length, length)) // Store the length of the output. // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) let o := add(str, 0x20) let end := add(raw, length) for {} iszero(eq(raw, end)) {} { raw := add(raw, 1) mstore8(add(o, 1), mload(and(mload(raw), 15))) mstore8(o, mload(and(shr(4, mload(raw)), 15))) o := add(o, 2) } mstore(o, 0) // Zeroize the slot after the string. mstore(0x40, add(o, 0x20)) // Allocate the memory. } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RUNE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Returns the number of UTF characters in the string. function runeCount(string memory s) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { if mload(s) { mstore(0x00, div(not(0), 255)) mstore(0x20, 0x0202020202020202020202020202020202020202020202020303030304040506) let o := add(s, 0x20) let end := add(o, mload(s)) for { result := 1 } 1 { result := add(result, 1) } { o := add(o, byte(0, mload(shr(250, mload(o))))) if iszero(lt(o, end)) { break } } } } } /// @dev Returns if this string is a 7-bit ASCII string. /// (i.e. all characters codes are in [0..127]) function is7BitASCII(string memory s) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let mask := shl(7, div(not(0), 255)) result := 1 let n := mload(s) if n { let o := add(s, 0x20) let end := add(o, n) let last := mload(end) mstore(end, 0) for {} 1 {} { if and(mask, mload(o)) { result := 0 break } o := add(o, 0x20) if iszero(lt(o, end)) { break } } mstore(end, last) } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, byte string operations are restricted // to 7-bit ASCII strings. All offsets are byte offsets, not UTF character offsets. // Usage of byte string operations on charsets with runes spanning two or more bytes // can lead to undefined behavior. /// @dev Returns `subject` all occurrences of `search` replaced with `replacement`. function replace(string memory subject, string memory search, string memory replacement) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) let replacementLength := mload(replacement) subject := add(subject, 0x20) search := add(search, 0x20) replacement := add(replacement, 0x20) result := add(mload(0x40), 0x20) let subjectEnd := add(subject, subjectLength) if iszero(gt(searchLength, subjectLength)) { let subjectSearchEnd := add(sub(subjectEnd, searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Copy the `replacement` one word at a time. for { let o := 0 } 1 {} { mstore(add(result, o), mload(add(replacement, o))) o := add(o, 0x20) if iszero(lt(o, replacementLength)) { break } } result := add(result, replacementLength) subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } mstore(result, t) result := add(result, 1) subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } } let resultRemainder := result result := add(mload(0x40), 0x20) let k := add(sub(resultRemainder, result), sub(subjectEnd, subject)) // Copy the rest of the string one word at a time. for {} lt(subject, subjectEnd) {} { mstore(resultRemainder, mload(subject)) resultRemainder := add(resultRemainder, 0x20) subject := add(subject, 0x20) } result := sub(result, 0x20) let last := add(add(result, 0x20), k) // Zeroize the slot after the string. mstore(last, 0) mstore(0x40, add(last, 0x20)) // Allocate the memory. mstore(result, k) // Store the length. } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for { let subjectLength := mload(subject) } 1 {} { if iszero(mload(search)) { if iszero(gt(from, subjectLength)) { result := from break } result := subjectLength break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let end := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(add(search, 0x20)) if iszero(and(lt(subject, end), lt(from, subjectLength))) { break } if iszero(lt(searchLength, 0x20)) { for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if iszero(shr(m, xor(mload(subject), s))) { if eq(keccak256(subject, searchLength), h) { result := sub(subject, subjectStart) break } } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } for {} 1 {} { if iszero(shr(m, xor(mload(subject), s))) { result := sub(subject, subjectStart) break } subject := add(subject, 1) if iszero(lt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from left to right. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function indexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = indexOf(subject, search, 0); } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left, starting from `from`. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search, uint256 from) internal pure returns (uint256 result) { /// @solidity memory-safe-assembly assembly { for {} 1 {} { result := not(0) // Initialize to `NOT_FOUND`. let searchLength := mload(search) if gt(searchLength, mload(subject)) { break } let w := result let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } let end := add(add(subject, 0x20), w) subject := add(add(subject, 0x20), from) if iszero(gt(subject, end)) { break } // As this function is not too often used, // we shall simply use keccak256 for smaller bytecode size. for { let h := keccak256(add(search, 0x20), searchLength) } 1 {} { if eq(keccak256(subject, searchLength), h) { result := sub(subject, add(end, 1)) break } subject := add(subject, w) // `sub(subject, 1)`. if iszero(gt(subject, end)) { break } } break } } } /// @dev Returns the byte index of the first location of `search` in `subject`, /// searching from right to left. /// Returns `NOT_FOUND` (i.e. `type(uint256).max`) if the `search` is not found. function lastIndexOf(string memory subject, string memory search) internal pure returns (uint256 result) { result = lastIndexOf(subject, search, uint256(int256(-1))); } /// @dev Returns true if `search` is found in `subject`, false otherwise. function contains(string memory subject, string memory search) internal pure returns (bool) { return indexOf(subject, search) != NOT_FOUND; } /// @dev Returns whether `subject` starts with `search`. function startsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( iszero(gt(searchLength, mload(subject))), eq( keccak256(add(subject, 0x20), searchLength), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns whether `subject` ends with `search`. function endsWith(string memory subject, string memory search) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { let searchLength := mload(search) let subjectLength := mload(subject) // Whether `search` is not longer than `subject`. let withinRange := iszero(gt(searchLength, subjectLength)) // Just using keccak256 directly is actually cheaper. // forgefmt: disable-next-item result := and( withinRange, eq( keccak256( // `subject + 0x20 + max(subjectLength - searchLength, 0)`. add(add(subject, 0x20), mul(withinRange, sub(subjectLength, searchLength))), searchLength ), keccak256(add(search, 0x20), searchLength) ) ) } } /// @dev Returns `subject` repeated `times`. function repeat(string memory subject, uint256 times) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(or(iszero(times), iszero(subjectLength))) { subject := add(subject, 0x20) result := mload(0x40) let output := add(result, 0x20) for {} 1 {} { // Copy the `subject` one word at a time. for { let o := 0 } 1 {} { mstore(add(output, o), mload(add(subject, o))) o := add(o, 0x20) if iszero(lt(o, subjectLength)) { break } } output := add(output, subjectLength) times := sub(times, 1) if iszero(times) { break } } mstore(output, 0) // Zeroize the slot after the string. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Store the length. // Allocate the memory. mstore(0x40, add(result, add(resultLength, 0x20))) } } } /// @dev Returns a copy of `subject` sliced from `start` to `end` (exclusive). /// `start` and `end` are byte offsets. function slice(string memory subject, uint256 start, uint256 end) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) if iszero(gt(subjectLength, end)) { end := subjectLength } if iszero(gt(subjectLength, start)) { start := subjectLength } if lt(start, end) { result := mload(0x40) let resultLength := sub(end, start) mstore(result, resultLength) subject := add(subject, start) let w := not(0x1f) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 0x1f), w) } 1 {} { mstore(add(result, o), mload(add(subject, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(result, 0x20), resultLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 0x3f), w))) } } } /// @dev Returns a copy of `subject` sliced from `start` to the end of the string. /// `start` is a byte offset. function slice(string memory subject, uint256 start) internal pure returns (string memory result) { result = slice(subject, start, uint256(int256(-1))); } /// @dev Returns all the indices of `search` in `subject`. /// The indices are byte offsets. function indicesOf(string memory subject, string memory search) internal pure returns (uint256[] memory result) { /// @solidity memory-safe-assembly assembly { let subjectLength := mload(subject) let searchLength := mload(search) if iszero(gt(searchLength, subjectLength)) { subject := add(subject, 0x20) search := add(search, 0x20) result := add(mload(0x40), 0x20) let subjectStart := subject let subjectSearchEnd := add(sub(add(subject, subjectLength), searchLength), 1) let h := 0 if iszero(lt(searchLength, 0x20)) { h := keccak256(search, searchLength) } let m := shl(3, sub(0x20, and(searchLength, 0x1f))) let s := mload(search) for {} 1 {} { let t := mload(subject) // Whether the first `searchLength % 32` bytes of // `subject` and `search` matches. if iszero(shr(m, xor(t, s))) { if h { if iszero(eq(keccak256(subject, searchLength), h)) { subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } continue } } // Append to `result`. mstore(result, sub(subject, subjectStart)) result := add(result, 0x20) // Advance `subject` by `searchLength`. subject := add(subject, searchLength) if searchLength { if iszero(lt(subject, subjectSearchEnd)) { break } continue } } subject := add(subject, 1) if iszero(lt(subject, subjectSearchEnd)) { break } } let resultEnd := result // Assign `result` to the free memory pointer. result := mload(0x40) // Store the length of `result`. mstore(result, shr(5, sub(resultEnd, add(result, 0x20)))) // Allocate memory for result. // We allocate one more word, so this array can be recycled for {split}. mstore(0x40, add(resultEnd, 0x20)) } } } /// @dev Returns a arrays of strings based on the `delimiter` inside of the `subject` string. function split(string memory subject, string memory delimiter) internal pure returns (string[] memory result) { uint256[] memory indices = indicesOf(subject, delimiter); /// @solidity memory-safe-assembly assembly { let w := not(0x1f) let indexPtr := add(indices, 0x20) let indicesEnd := add(indexPtr, shl(5, add(mload(indices), 1))) mstore(add(indicesEnd, w), mload(subject)) mstore(indices, add(mload(indices), 1)) let prevIndex := 0 for {} 1 {} { let index := mload(indexPtr) mstore(indexPtr, 0x60) if iszero(eq(index, prevIndex)) { let element := mload(0x40) let elementLength := sub(index, prevIndex) mstore(element, elementLength) // Copy the `subject` one word at a time, backwards. for { let o := and(add(elementLength, 0x1f), w) } 1 {} { mstore(add(element, o), mload(add(add(subject, prevIndex), o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } // Zeroize the slot after the string. mstore(add(add(element, 0x20), elementLength), 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(element, and(add(elementLength, 0x3f), w))) // Store the `element` into the array. mstore(indexPtr, element) } prevIndex := add(index, mload(delimiter)) indexPtr := add(indexPtr, 0x20) if iszero(lt(indexPtr, indicesEnd)) { break } } result := indices if iszero(mload(delimiter)) { result := add(indices, 0x20) mstore(result, sub(mload(indices), 2)) } } } /// @dev Returns a concatenated string of `a` and `b`. /// Cheaper than `string.concat()` and does not de-align the free memory pointer. function concat(string memory a, string memory b) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let w := not(0x1f) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(aLength, 0x20), w) } 1 {} { mstore(add(result, o), mload(add(a, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let bLength := mload(b) let output := add(result, aLength) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 0x20), w) } 1 {} { mstore(add(output, o), mload(add(b, o))) o := add(o, w) // `sub(o, 0x20)`. if iszero(o) { break } } let totalLength := add(aLength, bLength) let last := add(add(result, 0x20), totalLength) // Zeroize the slot after the string. mstore(last, 0) // Stores the length. mstore(result, totalLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 0x1f), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. /// WARNING! This function is only compatible with 7-bit ASCII strings. function toCase(string memory subject, bool toUpper) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let length := mload(subject) if length { result := add(mload(0x40), 0x20) subject := add(subject, 1) let flags := shl(add(70, shl(5, toUpper)), 0x3ffffff) let w := not(0) for { let o := length } 1 {} { o := add(o, w) let b := and(0xff, mload(add(subject, o))) mstore8(add(result, o), xor(b, and(shr(b, flags), 0x20))) if iszero(o) { break } } result := mload(0x40) mstore(result, length) // Store the length. let last := add(add(result, 0x20), length) mstore(last, 0) // Zeroize the slot after the string. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } } /// @dev Returns a string from a small bytes32 string. /// `s` must be null-terminated, or behavior will be undefined. function fromSmallString(bytes32 s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { result := mload(0x40) let n := 0 for {} byte(n, s) { n := add(n, 1) } {} // Scan for '\0'. mstore(result, n) let o := add(result, 0x20) mstore(o, s) mstore(add(o, n), 0) mstore(0x40, add(result, 0x40)) } } /// @dev Returns the small string, with all bytes after the first null byte zeroized. function normalizeSmallString(bytes32 s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { for {} byte(result, s) { result := add(result, 1) } {} // Scan for '\0'. mstore(0x00, s) mstore(result, 0x00) result := mload(0x00) } } /// @dev Returns the string as a normalized null-terminated small string. function toSmallString(string memory s) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { result := mload(s) if iszero(lt(result, 33)) { mstore(0x00, 0xec92f9a3) // `TooBigForSmallString()`. revert(0x1c, 0x04) } result := shl(shl(3, sub(32, result)), mload(add(s, result))) } } /// @dev Returns a lowercased copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. /// WARNING! This function is only compatible with 7-bit ASCII strings. function upper(string memory subject) internal pure returns (string memory result) { result = toCase(subject, true); } /// @dev Escapes the string to be used within HTML tags. function escapeHTML(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // Store the bytes of the packed offsets and strides into the scratch space. // `packed = (stride << 5) | offset`. Max offset is 20. Max stride is 6. mstore(0x1f, 0x900094) mstore(0x08, 0xc0000000a6ab) // Store ""&'<>" into the scratch space. mstore(0x00, shl(64, 0x2671756f743b26616d703b262333393b266c743b2667743b)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) // Not in `["\"","'","&","<",">"]`. if iszero(and(shl(c, 1), 0x500000c400000000)) { mstore8(result, c) result := add(result, 1) continue } let t := shr(248, mload(c)) mstore(result, mload(and(t, 0x1f))) result := add(result, shr(5, t)) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. /// If `addDoubleQuotes` is true, the result will be enclosed in double-quotes. function escapeJSON(string memory s, bool addDoubleQuotes) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } // Store "\\u0000" in scratch space. // Store "0123456789abcdef" in scratch space. // Also, store `{0x08:"b", 0x09:"t", 0x0a:"n", 0x0c:"f", 0x0d:"r"}`. // into the scratch space. mstore(0x15, 0x5c75303030303031323334353637383961626364656662746e006672) // Bitmask for detecting `["\"","\\"]`. let e := or(shl(0x22, 1), shl(0x5c, 1)) for {} iszero(eq(s, end)) {} { s := add(s, 1) let c := and(mload(s), 0xff) if iszero(lt(c, 0x20)) { if iszero(and(shl(c, 1), e)) { // Not in `["\"","\\"]`. mstore8(result, c) result := add(result, 1) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), c) result := add(result, 2) continue } if iszero(and(shl(c, 1), 0x3700)) { // Not in `["\b","\t","\n","\f","\d"]`. mstore8(0x1d, mload(shr(4, c))) // Hex value. mstore8(0x1e, mload(and(c, 15))) // Hex value. mstore(result, mload(0x19)) // "\\u00XX". result := add(result, 6) continue } mstore8(result, 0x5c) // "\\". mstore8(add(result, 1), mload(add(c, 8))) result := add(result, 2) } if addDoubleQuotes { mstore8(result, 34) result := add(1, result) } let last := result mstore(last, 0) // Zeroize the slot after the string. result := mload(0x40) mstore(result, sub(last, add(result, 0x20))) // Store the length. mstore(0x40, add(last, 0x20)) // Allocate the memory. } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { result = escapeJSON(s, false); } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Returns whether `a` equals `b`, where `b` is a null-terminated small string. function eqs(string memory a, bytes32 b) internal pure returns (bool result) { /// @solidity memory-safe-assembly assembly { // These should be evaluated on compile time, as far as possible. let m := not(shl(7, div(not(iszero(b)), 255))) // `0x7f7f ...`. let x := not(or(m, or(b, add(m, and(b, m))))) let r := shl(7, iszero(iszero(shr(128, x)))) r := or(r, shl(6, iszero(iszero(shr(64, shr(r, x)))))) r := or(r, shl(5, lt(0xffffffff, shr(r, x)))) r := or(r, shl(4, lt(0xffff, shr(r, x)))) r := or(r, shl(3, lt(0xff, shr(r, x)))) // forgefmt: disable-next-item result := gt(eq(mload(a), add(iszero(x), xor(31, shr(3, r)))), xor(shr(add(8, r), b), shr(add(8, r), mload(add(a, 0x20))))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behavior is undefined. function unpackOne(bytes32 packed) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. result := mload(0x40) // Allocate 2 words (1 for the length, 1 for the bytes). mstore(0x40, add(result, 0x40)) // Zeroize the length slot. mstore(result, 0) // Store the length and bytes. mstore(add(result, 0x1f), packed) // Right pad with zeroes. mstore(add(add(result, 0x20), mload(result)), 0) } } /// @dev Packs two strings with their lengths into a single word. /// Returns `bytes32(0)` if combined length is zero or greater than 30. function packTwo(string memory a, string memory b) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { let aLength := mload(a) // We don't need to zero right pad the strings, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes of `a` and `b`. or( shl(shl(3, sub(0x1f, aLength)), mload(add(a, aLength))), mload(sub(add(b, 0x1e), aLength)) ), // `totalLength != 0 && totalLength < 31`. Abuses underflow. // Assumes that the lengths are valid and within the block gas limit. lt(sub(add(aLength, mload(b)), 1), 0x1e) ) } } /// @dev Unpacks strings packed using {packTwo}. /// Returns the empty strings if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packTwo}, the output behavior is undefined. function unpackTwo(bytes32 packed) internal pure returns (string memory resultA, string memory resultB) { /// @solidity memory-safe-assembly assembly { // Grab the free memory pointer. resultA := mload(0x40) resultB := add(resultA, 0x40) // Allocate 2 words for each string (1 for the length, 1 for the byte). Total 4 words. mstore(0x40, add(resultB, 0x40)) // Zeroize the length slots. mstore(resultA, 0) mstore(resultB, 0) // Store the lengths and bytes. mstore(add(resultA, 0x1f), packed) mstore(add(resultB, 0x1f), mload(add(add(resultA, 0x20), mload(resultA)))) // Right pad with zeroes. mstore(add(add(resultA, 0x20), mload(resultA)), 0) mstore(add(add(resultB, 0x20), mload(resultB)), 0) } } /// @dev Directly returns `a` without copying. function directReturn(string memory a) internal pure { assembly { // Assumes that the string does not start from the scratch space. let retStart := sub(a, 0x20) let retSize := add(mload(a), 0x40) // Right pad with zeroes. Just in case the string is produced // by a method that doesn't zero right pad. mstore(add(retStart, retSize), 0) // Store the return offset. mstore(retStart, 0x20) // End the transaction, returning the string. return(retStart, retSize) } } }
// SPDX-License-Identifier: MIT pragma solidity 0.8.19; enum YieldMode { AUTOMATIC, VOID, CLAIMABLE } enum GasMode { VOID, CLAIMABLE } interface IBlast { // configure function configureContract(address contractAddress, YieldMode _yield, GasMode gasMode, address governor) external; function configure(YieldMode _yield, GasMode gasMode, address governor) external; // base configuration options function configureClaimableYield() external; function configureClaimableYieldOnBehalf(address contractAddress) external; function configureAutomaticYield() external; function configureAutomaticYieldOnBehalf(address contractAddress) external; function configureVoidYield() external; function configureVoidYieldOnBehalf(address contractAddress) external; function configureClaimableGas() external; function configureClaimableGasOnBehalf(address contractAddress) external; function configureVoidGas() external; function configureVoidGasOnBehalf(address contractAddress) external; function configureGovernor(address _governor) external; function configureGovernorOnBehalf(address _newGovernor, address contractAddress) external; // claim yield function claimYield(address contractAddress, address recipientOfYield, uint256 amount) external returns (uint256); function claimAllYield(address contractAddress, address recipientOfYield) external returns (uint256); // claim gas function claimAllGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGasAtMinClaimRate(address contractAddress, address recipientOfGas, uint256 minClaimRateBips) external returns (uint256); function claimMaxGas(address contractAddress, address recipientOfGas) external returns (uint256); function claimGas(address contractAddress, address recipientOfGas, uint256 gasToClaim, uint256 gasSecondsToConsume) external returns (uint256); // read functions function readClaimableYield(address contractAddress) external view returns (uint256); function readYieldConfiguration(address contractAddress) external view returns (uint8); function readGasParams(address contractAddress) external view returns (uint256 etherSeconds, uint256 etherBalance, uint256 lastUpdated, GasMode); }
{ "remappings": [ "@solady/=lib/solady/src/", "ds-test/=lib/forge-std/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solady/=lib/solady/src/" ], "optimizer": { "enabled": true, "runs": 40000 }, "metadata": { "useLiteralContent": false, "bytecodeHash": "ipfs", "appendCBOR": true }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "abi" ] } }, "evmVersion": "paris", "viaIR": false, "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
Contract ABI
API[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AccountBalanceOverflow","type":"error"},{"inputs":[],"name":"AlreadyInitialized","type":"error"},{"inputs":[],"name":"BalanceQueryForZeroAddress","type":"error"},{"inputs":[],"name":"CannotMintMoreThanMax","type":"error"},{"inputs":[],"name":"CannotMintSpecificIdsUntilAllMinted","type":"error"},{"inputs":[],"name":"ContractMetadataLocked","type":"error"},{"inputs":[],"name":"IncorrectAmountSent","type":"error"},{"inputs":[],"name":"InvalidHash","type":"error"},{"inputs":[],"name":"InvalidSignature","type":"error"},{"inputs":[],"name":"InvalidTokenId","type":"error"},{"inputs":[],"name":"NewOwnerIsZeroAddress","type":"error"},{"inputs":[],"name":"NoHandoverRequest","type":"error"},{"inputs":[],"name":"NonceAlreadyUsed","type":"error"},{"inputs":[],"name":"NotApprovedOrOwner","type":"error"},{"inputs":[],"name":"NotOwnerNorApproved","type":"error"},{"inputs":[],"name":"OutOfStock","type":"error"},{"inputs":[],"name":"RedemptionTransferFailed","type":"error"},{"inputs":[],"name":"SaleClosed","type":"error"},{"inputs":[],"name":"SetSignerBeforeTogglingSale","type":"error"},{"inputs":[],"name":"TokenAlreadyExists","type":"error"},{"inputs":[],"name":"TokenDoesNotExist","type":"error"},{"inputs":[],"name":"TokenNotFound","type":"error"},{"inputs":[],"name":"TransferFromIncorrectOwner","type":"error"},{"inputs":[],"name":"TransferToNonERC721ReceiverImplementer","type":"error"},{"inputs":[],"name":"TransferToZeroAddress","type":"error"},{"inputs":[],"name":"Unauthorized","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"account","type":"address"},{"indexed":true,"internalType":"uint256","name":"id","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":"isApproved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"string","name":"URI","type":"string"}],"name":"BaseURISet","type":"event"},{"anonymous":false,"inputs":[],"name":"ContractURIUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"MetadataLocked","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":false,"internalType":"bool","name":"live","type":"bool"}],"name":"SaleStatusToggled","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"oldSigner","type":"address"},{"indexed":false,"internalType":"address","name":"newSigner","type":"address"}],"name":"SignerAddressSet","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":"id","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"amountMinted","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"result","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseTokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"cancelOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"claimableGas","outputs":[{"internalType":"uint256","name":"etherBalance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"claimableYield","outputs":[{"internalType":"uint256","name":"yield","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"pendingOwner","type":"address"}],"name":"completeOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"configureClaimableYield","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newGov","type":"address"}],"name":"configureGovernor","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"contractURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getAmountMinted","outputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getPrice","outputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"getTotalSupply","outputs":[{"internalType":"uint256","name":"supply","type":"uint256"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"operator","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenOwner","type":"address"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"isValidNonce","outputs":[{"internalType":"bool","name":"isValid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockMetadata","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"metadataLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"mintPupnik","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"hash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"},{"internalType":"uint256","name":"nonce","type":"uint256"},{"internalType":"uint256[]","name":"ids","type":"uint256[]"}],"name":"mintSpecificPupniks","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"name_","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"result","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"quantity","type":"uint256"}],"name":"ownerMint","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"result","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":"uint256","name":"tokenId","type":"uint256"}],"name":"redeemPupnik","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256[]","name":"tokenIds","type":"uint256[]"}],"name":"redeemPupnikBatch","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"requestOwnershipHandover","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","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":"id","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"saleLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"isApproved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"URI","type":"string"}],"name":"setBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"URI","type":"string"}],"name":"setContractURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"addr","type":"address"}],"name":"setSignerAddress","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":"result","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"symbol_","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"toggleSaleStatus","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenId","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"uri","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","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":"withdrawAllGas","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"minClaimRateBips","type":"uint256"}],"name":"withdrawGasAtMinClaimrate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdrawYield","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040523480156200001157600080fd5b506200001d336200008c565b7343000000000000000000000000000000000000026001600160a01b0316634e606c476040518163ffffffff1660e01b8152600401600060405180830381600087803b1580156200006d57600080fd5b505af115801562000082573d6000803e3d6000fd5b50505050620000c8565b6001600160a01b0316638b78c6d8198190558060007f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e08180a350565b612a1880620000d86000396000f3fe6080604052600436106103085760003560e01c80638da5cb5b1161019a578063e081b781116100e1578063eea3ca1b1161008a578063f19e75d411610064578063f19e75d414610890578063f2fde38b146108a3578063fee81cf4146108b657600080fd5b8063eea3ca1b14610848578063f04e283e14610868578063f098767a1461087b57600080fd5b8063e8a3d485116100bb578063e8a3d485146107dd578063e985e9c5146107f2578063eb8646981461082857600080fd5b8063e081b78114610799578063e507a8a4146107b3578063e777df20146107c857600080fd5b8063a263a9eb11610143578063c4e41b221161011d578063c4e41b221461074f578063c87b56dd14610764578063d547cfb71461078457600080fd5b8063a263a9eb14610712578063ac59d30214610727578063b88d4fde1461073c57600080fd5b8063989bdbb611610174578063989bdbb6146106c257806398d5fdca146106d7578063a22cb465146106f257600080fd5b80638da5cb5b14610628578063938e3d7b1461065c57806395d89b411461067c57600080fd5b806343155dea1161025e57806369d2ceb111610207578063758ec591116101e1578063758ec591146105d25780637af284d5146105f25780638c84cde71461060857600080fd5b806369d2ceb11461057d57806370a082311461059c578063715018a6146105ca57600080fd5b806355f804b31161023857806355f804b31461050a5780635b7633d01461052a5780636352211e1461055d57600080fd5b806343155dea146104dc57806344bddb5a146104ef57806354d1f13d1461050257600080fd5b8063081812fc116102c057806323b872dd1161029a57806323b872dd146104ae57806325692962146104c157806342842e0e146104c957600080fd5b8063081812fc14610441578063095ea7b3146104865780630a94f22c1461049957600080fd5b8063049c5c49116102f1578063049c5c49146103815780630647ee201461039657806306fdde03146103f257600080fd5b806301ffc9a71461030d578063046dc1661461035f575b600080fd5b34801561031957600080fd5b5061034a6103283660046121e1565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561036b57600080fd5b5061037f61037a36600461224e565b6108e9565b005b34801561038d57600080fd5b5061037f610982565b3480156103a257600080fd5b5061034a6103b1366004612269565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260208181526040808320600885901c8452909152902054600160ff9092161c161590565b3480156103fe57600080fd5b5060408051808201909152600781527f5075706e696b730000000000000000000000000000000000000000000000000060208201525b60405161035691906122b7565b34801561044d57600080fd5b5061046161045c366004612308565b610a4a565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610356565b61037f610494366004612269565b610a9e565b3480156104a557600080fd5b5061037f610aad565b61037f6104bc366004612321565b610b91565b61037f610cd2565b61037f6104d7366004612321565b610d22565b61037f6104ea3660046123a6565b610d4f565b61037f6104fd366004612449565b610e6a565b61037f610fe2565b34801561051657600080fd5b5061037f6105253660046124cc565b61101e565b34801561053657600080fd5b506004546104619062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056957600080fd5b50610461610578366004612308565b61106d565b34801561058957600080fd5b5060045461034a90610100900460ff1681565b3480156105a857600080fd5b506105bc6105b736600461224e565b6110cd565b604051908152602001610356565b61037f61111d565b3480156105de57600080fd5b5061037f6105ed366004612308565b611131565b3480156105fe57600080fd5b506105bc60035481565b34801561061457600080fd5b5061037f61062336600461250e565b61113a565b34801561063457600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610461565b34801561066857600080fd5b5061037f6106773660046124cc565b61116e565b34801561068857600080fd5b5060408051808201909152600681527f5055504e494b00000000000000000000000000000000000000000000000000006020820152610434565b3480156106ce57600080fd5b5061037f6111b9565b3480156106e357600080fd5b506706f05b59d3b200006105bc565b3480156106fe57600080fd5b5061037f61070d366004612544565b611218565b34801561071e57600080fd5b506105bc61126e565b34801561073357600080fd5b506105bc611302565b61037f61074a366004612580565b61139a565b34801561075b57600080fd5b50610bb86105bc565b34801561077057600080fd5b5061043461077f366004612308565b6113f5565b34801561079057600080fd5b5061043461149c565b3480156107a557600080fd5b5060045461034a9060ff1681565b3480156107bf57600080fd5b5061037f61152a565b3480156107d457600080fd5b506003546105bc565b3480156107e957600080fd5b5061043461160a565b3480156107fe57600080fd5b5061034a61080d3660046125ef565b601c52670a5a2e7a000000006008526000526030600c205490565b34801561083457600080fd5b5061037f61084336600461224e565b611617565b34801561085457600080fd5b5061037f610863366004612308565b6116ae565b61037f61087636600461224e565b611796565b34801561088757600080fd5b5061037f6117d3565b61037f61089e366004612308565b611851565b61037f6108b136600461224e565b611911565b3480156108c257600080fd5b506105bc6108d136600461224e565b63389a75e1600c908152600091909152602090205490565b6108f1611938565b6004805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051949093049091168084526020840191909152917fce121e8f958f05b311c92392aa0e029015915f88f62b6df252f493a4d347aa4991015b60405180910390a15050565b61098a611938565b60045462010000900473ffffffffffffffffffffffffffffffffffffffff166109df576040517f65885dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805460ff808216157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921682179092556040519116151581527f8b0b8ee2290145ec29b97ef725c6f6a27db2f256e5bc132e70c5eede8238bb579060200160405180910390a1565b6000816000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602060002082018201805460601b610a945763ceea21b66000526004601cfd5b6001015492915050565b610aa933838361196e565b5050565b610ab5611938565b73430000000000000000000000000000000000000263954fa5ee30610af87fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303816000875af1158015610b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8e9190612622565b50565b60008181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610c055767ceea21b6a1148100831560021b526004601cfd5b856000528160010154925082331486331417610c33576030600c2054610c3357634b6e7f186000526004601cfd5b8215610c4157600082600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055600084905220805460010163ffffffff81168402610ca25767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610d2d838383610b91565b813b15610ccd57610ccd83838360405180602001604052806000815250611a24565b610d57611ab0565b610d648585858585611aec565b610d6e3383611c82565b600354610bb8610d7e838361266a565b1115610db6576040517fade1cb4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34610dc9836706f05b59d3b20000612683565b14610e00576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001821115610e3b576040517f4804729500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548301905560015b828111610e6157610e5933828401611cfd565b600101610e46565b50505050505050565b610e72611ab0565b610e7f8686868685611aec565b610e893384611c82565b600354610bb8811015610ec8576040517f92a8928a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8134610edc826706f05b59d3b20000612683565b14610f13576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811115610f4e576040517f4804729500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610fd757610bb8858583818110610f6e57610f6e61269a565b905060200201351115610fad576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fcf33868684818110610fc357610fc361269a565b90506020020135611cfd565b600101610f51565b505050505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611026611938565b61102e611db3565b600161103b828483612791565b507ff9c7803e94e0d3c02900d8a90893a6d5e90dd04d32a4cfe825520f82bf9f32f682826040516109769291906128ab565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806110c85763ceea21b66000526004601cfd5b919050565b6000816110e257638f4eb6046000526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c528160005263ffffffff601c600c2054169050919050565b611125611938565b61112f6000611df5565b565b610b8e81611e5b565b60005b81811015610ccd5761116683838381811061115a5761115a61269a565b90506020020135611e5b565b60010161113d565b611176611938565b61117e611db3565b600261118b828483612791565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad96290600090a15050565b6111c1611938565b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556040517f27de4862bfc92b76e402ed305829f40e9e5fcd597ab2206b4e6294cd24ed45c490600090a1565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b6040517fec3278e80000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063ec3278e890602401602060405180830381865afa1580156112d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fd9190612622565b905090565b6040517fdde798a40000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063dde798a490602401608060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139191906128f8565b50909392505050565b6113a5858585610b91565b833b156113ee576113ee85858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611a2492505050565b5050505050565b60606114348260008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b61146a576040517fcbdb7b3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600161147583611f33565b60405160200161148692919061293d565b6040516020818303038152906040529050919050565b600180546114a9906126f8565b80601f01602080910402602001604051908101604052809291908181526020018280546114d5906126f8565b80156115225780601f106114f757610100808354040283529160200191611522565b820191906000526020600020905b81548152906001019060200180831161150557829003601f168201915b505050505081565b611532611938565b6040517fec3278e80000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063ec3278e890602401602060405180830381865afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612622565b111561112f5773430000000000000000000000000000000000000263860043b630610af87fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b600280546114a9906126f8565b61161f611938565b6040517feb86469800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201527343000000000000000000000000000000000000029063eb86469890602401600060405180830381600087803b15801561169a57600080fd5b505af11580156113ee573d6000803e3d6000fd5b6116b6611938565b734300000000000000000000000000000000000002630951888f306116f97fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604481018490526064016020604051808303816000875af1158015611772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa99190612622565b61179e611938565b63389a75e1600c52806000526020600c2080544211156117c657636f5e88186000526004601cfd5b60009055610b8e81611df5565b6117db611938565b73430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561183757600080fd5b505af115801561184b573d6000803e3d6000fd5b50505050565b611859611938565b600354610bb8611869838361266a565b11156118a1576040517fade1cb4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b346118b4836706f05b59d3b20000612683565b146118eb576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548301905560015b828111610ccd5761190933828401611cfd565b6001016118f6565b611919611938565b8060601b61192f57637448fbae6000526004601cfd5b610b8e81611df5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754331461112f576382b429006000526004601cfd5b60001960601c8281169250838116935081600052837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c52602060002082018201805482169150816119ca5763ceea21b66000526004601cfd5b8185148515176119f057816000526030600c20546119f057634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611a6b578060c08401826020870160045afa505b60208360a48301601c860160008a5af1611a8e573d15611a8e573d6000843e3d83fd5b508060e01b825114611aa85763d1a57ed66000526004601cfd5b505050505050565b60045460ff1661112f576040517f4c013bd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b2e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508993925050611f959050565b60045462010000900473ffffffffffffffffffffffffffffffffffffffff908116911614611b88576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810183905260548101829052600090607401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c01604051602081830303815290604052805190602001209050858114611aa8576040517f0af806e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208181526040808320600885901c845290915281208054600160ff85161b90811891829055169003610aa9576040517f1fb09b8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160601b60601c9150806000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260206000208101810180548060601b15611d505763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff81168402611d855767ea553b3401336cea841560021b526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b600454610100900460ff161561112f576040517f6d2e892c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b611e65338261203f565b611e9b576040517fe433766c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ea4816120cd565b6040516000903390617530906706f05b59d3b200009084818181858888f193505050503d8060008114611ef3576040519150601f19603f3d011682016040523d82523d6000602084013e611ef8565b606091505b5050905080610aa9576040517f5af3e29f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611f4e5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6040516001908360005260208301516040526040835103611fea57604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16606052612010565b604183510361200b57606083015160001a6020526040830151606052612010565b600091505b6020600160806000855afa5191503d61203157638baa579f6000526004601cfd5b600060605260405292915050565b600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c526020909120820182018054919360019216806120a65763ceea21b66000526004601cfd5b8085146120c557806000526030600c20546120c5578160010154851492505b505092915050565b610b8e60008260006120de8261106d565b905050600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826121475763ceea21b66000526004601cfd5b82600052816001015480861484871417861517612176576030600c205461217657634b6e7f186000526004601cfd5b801561218457600083600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b6000602082840312156121f357600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461222357600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c857600080fd5b60006020828403121561226057600080fd5b6122238261222a565b6000806040838503121561227c57600080fd5b6122858361222a565b946020939093013593505050565b60005b838110156122ae578181015183820152602001612296565b50506000910152565b60208152600082518060208401526122d6816040850160208701612293565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561231a57600080fd5b5035919050565b60008060006060848603121561233657600080fd5b61233f8461222a565b925061234d6020850161222a565b9150604084013590509250925092565b60008083601f84011261236f57600080fd5b50813567ffffffffffffffff81111561238757600080fd5b60208301915083602082850101111561239f57600080fd5b9250929050565b6000806000806000608086880312156123be57600080fd5b85359450602086013567ffffffffffffffff8111156123dc57600080fd5b6123e88882890161235d565b9699909850959660408101359660609091013595509350505050565b60008083601f84011261241657600080fd5b50813567ffffffffffffffff81111561242e57600080fd5b6020830191508360208260051b850101111561239f57600080fd5b6000806000806000806080878903121561246257600080fd5b86359550602087013567ffffffffffffffff8082111561248157600080fd5b61248d8a838b0161235d565b90975095506040890135945060608901359150808211156124ad57600080fd5b506124ba89828a01612404565b979a9699509497509295939492505050565b600080602083850312156124df57600080fd5b823567ffffffffffffffff8111156124f657600080fd5b6125028582860161235d565b90969095509350505050565b6000806020838503121561252157600080fd5b823567ffffffffffffffff81111561253857600080fd5b61250285828601612404565b6000806040838503121561255757600080fd5b6125608361222a565b91506020830135801515811461257557600080fd5b809150509250929050565b60008060008060006080868803121561259857600080fd5b6125a18661222a565b94506125af6020870161222a565b935060408601359250606086013567ffffffffffffffff8111156125d257600080fd5b6125de8882890161235d565b969995985093965092949392505050565b6000806040838503121561260257600080fd5b61260b8361222a565b91506126196020840161222a565b90509250929050565b60006020828403121561263457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561267d5761267d61263b565b92915050565b808202811582820484141761267d5761267d61263b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600181811c9082168061270c57607f821691505b602082108103612745577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610ccd57600081815260208120601f850160051c810160208610156127725750805b601f850160051c820191505b81811015611aa85782815560010161277e565b67ffffffffffffffff8311156127a9576127a96126c9565b6127bd836127b783546126f8565b8361274b565b6000601f84116001811461280f57600085156127d95750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556113ee565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101561285e578685013582556020948501946001909201910161283e565b5086821015612899577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000806000806080858703121561290e57600080fd5b84519350602085015192506040850151915060608501516002811061293257600080fd5b939692955090935050565b600080845461294b816126f8565b600182811680156129635760018114612996576129c5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506129c5565b8860005260208060002060005b858110156129bc5781548a8201529084019082016129a3565b50505082870194505b5050505083516129d9818360208801612293565b0194935050505056fea2646970667358221220cfec19ccb38c11d67180c18fbc9c84382e0d3a4ea515877a0e32b145cc4ea24564736f6c63430008130033
Deployed Bytecode
0x6080604052600436106103085760003560e01c80638da5cb5b1161019a578063e081b781116100e1578063eea3ca1b1161008a578063f19e75d411610064578063f19e75d414610890578063f2fde38b146108a3578063fee81cf4146108b657600080fd5b8063eea3ca1b14610848578063f04e283e14610868578063f098767a1461087b57600080fd5b8063e8a3d485116100bb578063e8a3d485146107dd578063e985e9c5146107f2578063eb8646981461082857600080fd5b8063e081b78114610799578063e507a8a4146107b3578063e777df20146107c857600080fd5b8063a263a9eb11610143578063c4e41b221161011d578063c4e41b221461074f578063c87b56dd14610764578063d547cfb71461078457600080fd5b8063a263a9eb14610712578063ac59d30214610727578063b88d4fde1461073c57600080fd5b8063989bdbb611610174578063989bdbb6146106c257806398d5fdca146106d7578063a22cb465146106f257600080fd5b80638da5cb5b14610628578063938e3d7b1461065c57806395d89b411461067c57600080fd5b806343155dea1161025e57806369d2ceb111610207578063758ec591116101e1578063758ec591146105d25780637af284d5146105f25780638c84cde71461060857600080fd5b806369d2ceb11461057d57806370a082311461059c578063715018a6146105ca57600080fd5b806355f804b31161023857806355f804b31461050a5780635b7633d01461052a5780636352211e1461055d57600080fd5b806343155dea146104dc57806344bddb5a146104ef57806354d1f13d1461050257600080fd5b8063081812fc116102c057806323b872dd1161029a57806323b872dd146104ae57806325692962146104c157806342842e0e146104c957600080fd5b8063081812fc14610441578063095ea7b3146104865780630a94f22c1461049957600080fd5b8063049c5c49116102f1578063049c5c49146103815780630647ee201461039657806306fdde03146103f257600080fd5b806301ffc9a71461030d578063046dc1661461035f575b600080fd5b34801561031957600080fd5b5061034a6103283660046121e1565b6301ffc9a760e09190911c9081146380ac58cd821417635b5e139f9091141790565b60405190151581526020015b60405180910390f35b34801561036b57600080fd5b5061037f61037a36600461224e565b6108e9565b005b34801561038d57600080fd5b5061037f610982565b3480156103a257600080fd5b5061034a6103b1366004612269565b73ffffffffffffffffffffffffffffffffffffffff909116600090815260208181526040808320600885901c8452909152902054600160ff9092161c161590565b3480156103fe57600080fd5b5060408051808201909152600781527f5075706e696b730000000000000000000000000000000000000000000000000060208201525b60405161035691906122b7565b34801561044d57600080fd5b5061046161045c366004612308565b610a4a565b60405173ffffffffffffffffffffffffffffffffffffffff9091168152602001610356565b61037f610494366004612269565b610a9e565b3480156104a557600080fd5b5061037f610aad565b61037f6104bc366004612321565b610b91565b61037f610cd2565b61037f6104d7366004612321565b610d22565b61037f6104ea3660046123a6565b610d4f565b61037f6104fd366004612449565b610e6a565b61037f610fe2565b34801561051657600080fd5b5061037f6105253660046124cc565b61101e565b34801561053657600080fd5b506004546104619062010000900473ffffffffffffffffffffffffffffffffffffffff1681565b34801561056957600080fd5b50610461610578366004612308565b61106d565b34801561058957600080fd5b5060045461034a90610100900460ff1681565b3480156105a857600080fd5b506105bc6105b736600461224e565b6110cd565b604051908152602001610356565b61037f61111d565b3480156105de57600080fd5b5061037f6105ed366004612308565b611131565b3480156105fe57600080fd5b506105bc60035481565b34801561061457600080fd5b5061037f61062336600461250e565b61113a565b34801561063457600080fd5b507fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754610461565b34801561066857600080fd5b5061037f6106773660046124cc565b61116e565b34801561068857600080fd5b5060408051808201909152600681527f5055504e494b00000000000000000000000000000000000000000000000000006020820152610434565b3480156106ce57600080fd5b5061037f6111b9565b3480156106e357600080fd5b506706f05b59d3b200006105bc565b3480156106fe57600080fd5b5061037f61070d366004612544565b611218565b34801561071e57600080fd5b506105bc61126e565b34801561073357600080fd5b506105bc611302565b61037f61074a366004612580565b61139a565b34801561075b57600080fd5b50610bb86105bc565b34801561077057600080fd5b5061043461077f366004612308565b6113f5565b34801561079057600080fd5b5061043461149c565b3480156107a557600080fd5b5060045461034a9060ff1681565b3480156107bf57600080fd5b5061037f61152a565b3480156107d457600080fd5b506003546105bc565b3480156107e957600080fd5b5061043461160a565b3480156107fe57600080fd5b5061034a61080d3660046125ef565b601c52670a5a2e7a000000006008526000526030600c205490565b34801561083457600080fd5b5061037f61084336600461224e565b611617565b34801561085457600080fd5b5061037f610863366004612308565b6116ae565b61037f61087636600461224e565b611796565b34801561088757600080fd5b5061037f6117d3565b61037f61089e366004612308565b611851565b61037f6108b136600461224e565b611911565b3480156108c257600080fd5b506105bc6108d136600461224e565b63389a75e1600c908152600091909152602090205490565b6108f1611938565b6004805473ffffffffffffffffffffffffffffffffffffffff838116620100008181027fffffffffffffffffffff0000000000000000000000000000000000000000ffff85161790945560408051949093049091168084526020840191909152917fce121e8f958f05b311c92392aa0e029015915f88f62b6df252f493a4d347aa4991015b60405180910390a15050565b61098a611938565b60045462010000900473ffffffffffffffffffffffffffffffffffffffff166109df576040517f65885dcf00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6004805460ff808216157fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff0090921682179092556040519116151581527f8b0b8ee2290145ec29b97ef725c6f6a27db2f256e5bc132e70c5eede8238bb579060200160405180910390a1565b6000816000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602060002082018201805460601b610a945763ceea21b66000526004601cfd5b6001015492915050565b610aa933838361196e565b5050565b610ab5611938565b73430000000000000000000000000000000000000263954fa5ee30610af87fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff9283166004820152911660248201526044016020604051808303816000875af1158015610b6a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610b8e9190612622565b50565b60008181527f7d8825530a5a2e7a0000000000000000000000000000000000000000000000003317601c526020902081018101805473ffffffffffffffffffffffffffffffffffffffff9485169493841693811691908286148302610c055767ceea21b6a1148100831560021b526004601cfd5b856000528160010154925082331486331417610c33576030600c2054610c3357634b6e7f186000526004601cfd5b8215610c4157600082600101555b85851818905550601c600c81812080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055600084905220805460010163ffffffff81168402610ca25767ea553b3401336cea841560021b526004601cfd5b90558082847fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef600038a45b505050565b60006202a30067ffffffffffffffff164201905063389a75e1600c5233600052806020600c2055337fdbf36a107da19e49527a7176a1babf963b4b0ff8cde35ee35d6cd8f1f9ac7e1d600080a250565b610d2d838383610b91565b813b15610ccd57610ccd83838360405180602001604052806000815250611a24565b610d57611ab0565b610d648585858585611aec565b610d6e3383611c82565b600354610bb8610d7e838361266a565b1115610db6576040517fade1cb4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b34610dc9836706f05b59d3b20000612683565b14610e00576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001821115610e3b576040517f4804729500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548301905560015b828111610e6157610e5933828401611cfd565b600101610e46565b50505050505050565b610e72611ab0565b610e7f8686868685611aec565b610e893384611c82565b600354610bb8811015610ec8576040517f92a8928a00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8134610edc826706f05b59d3b20000612683565b14610f13576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6001811115610f4e576040517f4804729500000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60005b81811015610fd757610bb8858583818110610f6e57610f6e61269a565b905060200201351115610fad576040517f3f6cc76800000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b610fcf33868684818110610fc357610fc361269a565b90506020020135611cfd565b600101610f51565b505050505050505050565b63389a75e1600c523360005260006020600c2055337ffa7b8eab7da67f412cc9575ed43464468f9bfbae89d1675917346ca6d8fe3c92600080a2565b611026611938565b61102e611db3565b600161103b828483612791565b507ff9c7803e94e0d3c02900d8a90893a6d5e90dd04d32a4cfe825520f82bf9f32f682826040516109769291906128ab565b60008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260209020810181015473ffffffffffffffffffffffffffffffffffffffff16806110c85763ceea21b66000526004601cfd5b919050565b6000816110e257638f4eb6046000526004601cfd5b7f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c528160005263ffffffff601c600c2054169050919050565b611125611938565b61112f6000611df5565b565b610b8e81611e5b565b60005b81811015610ccd5761116683838381811061115a5761115a61269a565b90506020020135611e5b565b60010161113d565b611176611938565b61117e611db3565b600261118b828483612791565b506040517fa5d4097edda6d87cb9329af83fb3712ef77eeb13738ffe43cc35a4ce305ad96290600090a15050565b6111c1611938565b600480547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00ff166101001790556040517f27de4862bfc92b76e402ed305829f40e9e5fcd597ab2206b4e6294cd24ed45c490600090a1565b801515905081601c52670a5a2e7a0000000060085233600052806030600c2055806000528160601b60601c337f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c3160206000a35050565b6040517fec3278e80000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063ec3278e890602401602060405180830381865afa1580156112d9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112fd9190612622565b905090565b6040517fdde798a40000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063dde798a490602401608060405180830381865afa15801561136d573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061139191906128f8565b50909392505050565b6113a5858585610b91565b833b156113ee576113ee85858585858080601f016020809104026020016040519081016040528093929190818152602001838380828437600092019190915250611a2492505050565b5050505050565b60606114348260008181527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c52602090208101015460601b151590565b61146a576040517fcbdb7b3000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600161147583611f33565b60405160200161148692919061293d565b6040516020818303038152906040529050919050565b600180546114a9906126f8565b80601f01602080910402602001604051908101604052809291908181526020018280546114d5906126f8565b80156115225780601f106114f757610100808354040283529160200191611522565b820191906000526020600020905b81548152906001019060200180831161150557829003601f168201915b505050505081565b611532611938565b6040517fec3278e80000000000000000000000000000000000000000000000000000000081523060048201526000907343000000000000000000000000000000000000029063ec3278e890602401602060405180830381865afa15801561159d573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906115c19190612622565b111561112f5773430000000000000000000000000000000000000263860043b630610af87fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b600280546114a9906126f8565b61161f611938565b6040517feb86469800000000000000000000000000000000000000000000000000000000815273ffffffffffffffffffffffffffffffffffffffff821660048201527343000000000000000000000000000000000000029063eb86469890602401600060405180830381600087803b15801561169a57600080fd5b505af11580156113ee573d6000803e3d6000fd5b6116b6611938565b734300000000000000000000000000000000000002630951888f306116f97fffffffffffffffffffffffffffffffffffffffffffffffffffffffff748739275490565b6040517fffffffff0000000000000000000000000000000000000000000000000000000060e085901b16815273ffffffffffffffffffffffffffffffffffffffff928316600482015291166024820152604481018490526064016020604051808303816000875af1158015611772573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610aa99190612622565b61179e611938565b63389a75e1600c52806000526020600c2080544211156117c657636f5e88186000526004601cfd5b60009055610b8e81611df5565b6117db611938565b73430000000000000000000000000000000000000273ffffffffffffffffffffffffffffffffffffffff1663f098767a6040518163ffffffff1660e01b8152600401600060405180830381600087803b15801561183757600080fd5b505af115801561184b573d6000803e3d6000fd5b50505050565b611859611938565b600354610bb8611869838361266a565b11156118a1576040517fade1cb4100000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b346118b4836706f05b59d3b20000612683565b146118eb576040517f19a6bd0f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b600380548301905560015b828111610ccd5761190933828401611cfd565b6001016118f6565b611919611938565b8060601b61192f57637448fbae6000526004601cfd5b610b8e81611df5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff7487392754331461112f576382b429006000526004601cfd5b60001960601c8281169250838116935081600052837f7d8825530a5a2e7a00000000000000000000000000000000000000000000000017601c52602060002082018201805482169150816119ca5763ceea21b66000526004601cfd5b8185148515176119f057816000526030600c20546119f057634b6e7f186000526004601cfd5b6001018390558183827f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925600038a450505050565b60405163150b7a028082523360208301528560601b60601c604083015283606083015260808083015282518060a08401528015611a6b578060c08401826020870160045afa505b60208360a48301601c860160008a5af1611a8e573d15611a8e573d6000843e3d83fd5b508060e01b825114611aa85763d1a57ed66000526004601cfd5b505050505050565b60045460ff1661112f576040517f4c013bd700000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611b2e84848080601f0160208091040260200160405190810160405280939291908181526020018383808284376000920191909152508993925050611f959050565b60045462010000900473ffffffffffffffffffffffffffffffffffffffff908116911614611b88576040517f8baa579f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b6040517fffffffffffffffffffffffffffffffffffffffff0000000000000000000000003360601b1660208201526034810183905260548101829052600090607401604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020918201207f19457468657265756d205369676e6564204d6573736167653a0a33320000000091830191909152603c820152605c01604051602081830303815290604052805190602001209050858114611aa8576040517f0af806e000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b73ffffffffffffffffffffffffffffffffffffffff8216600090815260208181526040808320600885901c845290915281208054600160ff85161b90811891829055169003610aa9576040517f1fb09b8000000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b8160601b60601c9150806000527f7d8825530a5a2e7a000000000000000000000000000000000000000000000000601c5260206000208101810180548060601b15611d505763c991cbb16000526004601cfd5b831790556000829052601c600c20805460010163ffffffff81168402611d855767ea553b3401336cea841560021b526004601cfd5b9055808260007fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8138a45050565b600454610100900460ff161561112f576040517f6d2e892c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffff74873927805473ffffffffffffffffffffffffffffffffffffffff9092169182907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0600080a355565b611e65338261203f565b611e9b576040517fe433766c00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b611ea4816120cd565b6040516000903390617530906706f05b59d3b200009084818181858888f193505050503d8060008114611ef3576040519150601f19603f3d011682016040523d82523d6000602084013e611ef8565b606091505b5050905080610aa9576040517f5af3e29f00000000000000000000000000000000000000000000000000000000815260040160405180910390fd5b60606080604051019050602081016040526000815280600019835b928101926030600a8206018453600a900480611f4e5750508190037fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0909101908152919050565b6040516001908360005260208301516040526040835103611fea57604083015160ff81901c601b016020527f7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff16606052612010565b604183510361200b57606083015160001a6020526040830151606052612010565b600091505b6020600160806000855afa5191503d61203157638baa579f6000526004601cfd5b600060605260405292915050565b600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c526020909120820182018054919360019216806120a65763ceea21b66000526004601cfd5b8085146120c557806000526030600c20546120c5578160010154851492505b505092915050565b610b8e60008260006120de8261106d565b905050600081815273ffffffffffffffffffffffffffffffffffffffff9283167f7d8825530a5a2e7a0000000000000000000000000000000000000000000000008117601c5260209091208201820180549193821691826121475763ceea21b66000526004601cfd5b82600052816001015480861484871417861517612176576030600c205461217657634b6e7f186000526004601cfd5b801561218457600083600101555b5082189055601c600c2080547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff019055816000827fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef8238a4505050565b6000602082840312156121f357600080fd5b81357fffffffff000000000000000000000000000000000000000000000000000000008116811461222357600080fd5b9392505050565b803573ffffffffffffffffffffffffffffffffffffffff811681146110c857600080fd5b60006020828403121561226057600080fd5b6122238261222a565b6000806040838503121561227c57600080fd5b6122858361222a565b946020939093013593505050565b60005b838110156122ae578181015183820152602001612296565b50506000910152565b60208152600082518060208401526122d6816040850160208701612293565b601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169190910160400192915050565b60006020828403121561231a57600080fd5b5035919050565b60008060006060848603121561233657600080fd5b61233f8461222a565b925061234d6020850161222a565b9150604084013590509250925092565b60008083601f84011261236f57600080fd5b50813567ffffffffffffffff81111561238757600080fd5b60208301915083602082850101111561239f57600080fd5b9250929050565b6000806000806000608086880312156123be57600080fd5b85359450602086013567ffffffffffffffff8111156123dc57600080fd5b6123e88882890161235d565b9699909850959660408101359660609091013595509350505050565b60008083601f84011261241657600080fd5b50813567ffffffffffffffff81111561242e57600080fd5b6020830191508360208260051b850101111561239f57600080fd5b6000806000806000806080878903121561246257600080fd5b86359550602087013567ffffffffffffffff8082111561248157600080fd5b61248d8a838b0161235d565b90975095506040890135945060608901359150808211156124ad57600080fd5b506124ba89828a01612404565b979a9699509497509295939492505050565b600080602083850312156124df57600080fd5b823567ffffffffffffffff8111156124f657600080fd5b6125028582860161235d565b90969095509350505050565b6000806020838503121561252157600080fd5b823567ffffffffffffffff81111561253857600080fd5b61250285828601612404565b6000806040838503121561255757600080fd5b6125608361222a565b91506020830135801515811461257557600080fd5b809150509250929050565b60008060008060006080868803121561259857600080fd5b6125a18661222a565b94506125af6020870161222a565b935060408601359250606086013567ffffffffffffffff8111156125d257600080fd5b6125de8882890161235d565b969995985093965092949392505050565b6000806040838503121561260257600080fd5b61260b8361222a565b91506126196020840161222a565b90509250929050565b60006020828403121561263457600080fd5b5051919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b8082018082111561267d5761267d61263b565b92915050565b808202811582820484141761267d5761267d61263b565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052604160045260246000fd5b600181811c9082168061270c57607f821691505b602082108103612745577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b601f821115610ccd57600081815260208120601f850160051c810160208610156127725750805b601f850160051c820191505b81811015611aa85782815560010161277e565b67ffffffffffffffff8311156127a9576127a96126c9565b6127bd836127b783546126f8565b8361274b565b6000601f84116001811461280f57600085156127d95750838201355b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff600387901b1c1916600186901b1783556113ee565b6000838152602090207fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0861690835b8281101561285e578685013582556020948501946001909201910161283e565b5086821015612899577fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff60f88860031b161c19848701351681555b505060018560011b0183555050505050565b60208152816020820152818360408301376000818301604090810191909152601f9092017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0160101919050565b6000806000806080858703121561290e57600080fd5b84519350602085015192506040850151915060608501516002811061293257600080fd5b939692955090935050565b600080845461294b816126f8565b600182811680156129635760018114612996576129c5565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00841687528215158302870194506129c5565b8860005260208060002060005b858110156129bc5781548a8201529084019082016129a3565b50505082870194505b5050505083516129d9818360208801612293565b0194935050505056fea2646970667358221220cfec19ccb38c11d67180c18fbc9c84382e0d3a4ea515877a0e32b145cc4ea24564736f6c63430008130033
Deployed Bytecode Sourcemap
635:12595:4:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;14864:380:1;;;;;;;;;;-1:-1:-1;14864:380:1;;;;;:::i;:::-;15177:10;15042:3;15038:21;;;;15171:17;;;15196:10;15190:17;;15168:40;15216:10;15210:17;;;15165:63;;14864:380;;;;516:14:6;;509:22;491:41;;479:2;464:18;14864:380:1;;;;;;;;7671:188:4;;;;;;;;;;-1:-1:-1;7671:188:4;;;;;:::i;:::-;;:::i;:::-;;7340:230;;;;;;;;;;;;;:::i;11896:194::-;;;;;;;;;;-1:-1:-1;11896:194:4;;;;;:::i;:::-;12012:23;;;;11976:12;12012:23;;;;;;;;;;;12053:1;12044:10;;;12012:44;;;;;;;;12076:1;12012:60;;;;;12011:66;12010:73;;11896:194;10862:101;;;;;;;;;;-1:-1:-1;10939:17:4;;;;;;;;;;;;;;;;;10862:101;;;;;;;:::i;8099:532:1:-;;;;;;;;;;-1:-1:-1;8099:532:1;;;;;:::i;:::-;;:::i;:::-;;;2270:42:6;2258:55;;;2240:74;;2228:2;2213:18;8099:532:1;2094:226:6;8925:119:1;;;;;;:::i;:::-;;:::i;9058:103:4:-;;;;;;;;;;;;;:::i;10748:2886:1:-;;;;;;:::i;:::-;;:::i;9021:617:0:-;;;:::i;13705:198:1:-;;;;;;:::i;:::-;;:::i;2328:800:4:-;;;;;;:::i;:::-;;:::i;3736:928::-;;;;;;:::i;:::-;;:::i;9720:456:0:-;;;:::i;8360:163:4:-;;;;;;;;;;-1:-1:-1;8360:163:4;;;;;:::i;:::-;;:::i;1547:28::-;;;;;;;;;;-1:-1:-1;1547:28:4;;;;;;;;;;;6957:332:1;;;;;;;;;;-1:-1:-1;6957:332:1;;;;;:::i;:::-;;:::i;1514:26:4:-;;;;;;;;;;-1:-1:-1;1514:26:4;;;;;;;;;;;7433:533:1;;;;;;;;;;-1:-1:-1;7433:533:1;;;;;:::i;:::-;;:::i;:::-;;;5449:25:6;;;5437:2;5422:18;7433:533:1;5303:177:6;8762:100:0;;;:::i;5528:87:4:-;;;;;;;;;;-1:-1:-1;5528:87:4;;;;;:::i;:::-;;:::i;1455:27::-;;;;;;;;;;;;;;;;4928:237;;;;;;;;;;-1:-1:-1;4928:237:4;;;;;:::i;:::-;;:::i;11408:182:0:-;;;;;;;;;;-1:-1:-1;11562:11:0;11556:18;11408:182;;8023:171:4;;;;;;;;;;-1:-1:-1;8023:171:4;;;;;:::i;:::-;;:::i;11079:106::-;;;;;;;;;;-1:-1:-1;11160:18:4;;;;;;;;;;;;;;;;;11079:106;;7126:113;;;;;;;;;;;;;:::i;11311:88::-;;;;;;;;;;-1:-1:-1;1024:9:4;11311:88;;9667:726:1;;;;;;;;;;-1:-1:-1;9667:726:1;;;;;:::i;:::-;;:::i;9627:128:4:-;;;;;;;;;;;;;:::i;9846:141::-;;;;;;;;;;;;;:::i;14406:249:1:-;;;;;;:::i;:::-;;:::i;11524:103:4:-;;;;;;;;;;-1:-1:-1;981:4:4;11524:103;;10232:252;;;;;;;;;;-1:-1:-1;10232:252:4;;;;;:::i;:::-;;:::i;1343:26::-;;;;;;;;;;;;;:::i;1488:20::-;;;;;;;;;;-1:-1:-1;1488:20:4;;;;;;;;8648:177;;;;;;;;;;;;;:::i;10648:104::-;;;;;;;;;;-1:-1:-1;10733:12:4;;10648:104;;1423:25;;;;;;;;;;;;;:::i;9135:392:1:-;;;;;;;;;;-1:-1:-1;9135:392:1;;;;;:::i;:::-;9355:4;9348:22;9396:31;9390:4;9383:45;9255:11;9441:19;9505:4;9499;9489:21;9483:28;;9135:392;6905:110:4;;;;;;;;;;-1:-1:-1;6905:110:4;;;;;:::i;:::-;;:::i;9367:167::-;;;;;;;;;;-1:-1:-1;9367:167:4;;;;;:::i;:::-;;:::i;10363:708:0:-;;;;;;:::i;:::-;;:::i;6728:102:4:-;;;;;;;;;;;;;:::i;6126:522::-;;;;;;:::i;:::-;;:::i;8348:349:0:-;;;;;;:::i;:::-;;:::i;11693:435::-;;;;;;;;;;-1:-1:-1;11693:435:0;;;;;:::i;:::-;11963:19;11957:4;11950:33;;;11812:14;11996:26;;;;12106:4;12090:21;;12084:28;;11693:435;7671:188:4;12517:13:0;:11;:13::i;:::-;7760::4::1;::::0;;::::1;7783:20:::0;;::::1;7760:13:::0;7783:20;;::::1;::::0;;::::1;;::::0;;;7819:33:::1;::::0;;7760:13;;;::::1;::::0;;::::1;7410:34:6::0;;;7475:2;7460:18;;7453:43;;;;7760:13:4;7819:33:::1;::::0;7322:18:6;7819:33:4::1;;;;;;;;7730:129;7671:188:::0;:::o;7340:230::-;12517:13:0;:11;:13::i;:::-;7401::4::1;::::0;;;::::1;:27;:13;7397:94;;7451:29;;;;;;;;;;;;;;7397:94;7512:8;::::0;;::::1;::::0;;::::1;7511:9;7500:20:::0;;;::::1;::::0;::::1;::::0;;;7536:27:::1;::::0;7554:8;;516:14:6;509:22;491:41;;7536:27:4::1;::::0;479:2:6;464:18;7536:27:4::1;;;;;;;7340:230::o:0;8099:532:1:-;8161:14;8266:2;8260:4;8253:16;8295:24;8289:4;8282:38;8386:4;8380;8370:21;8366:2;8362:30;8358:2;8354:39;8430:13;8424:20;8420:2;8416:29;8406:158;;8478:10;8472:4;8465:24;8545:4;8539;8532:18;8406:158;8597:1;8593:21;8587:28;;8099:532;-1:-1:-1;;8099:532:1:o;8925:119::-;9004:33;9013:10;9025:7;9034:2;9004:8;:33::i;:::-;8925:119;;:::o;9058:103:4:-;12517:13:0;:11;:13::i;:::-;1131:42:4::1;9113:17;9139:4;9146:7;11562:11:0::0;11556:18;;11408:182;9146:7:4::1;9113:41;::::0;;::::1;::::0;;;;;;7359:42:6;7428:15;;;9113:41:4::1;::::0;::::1;7410:34:6::0;7480:15;;7460:18;;;7453:43;7322:18;;9113:41:4::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;9058:103::o:0;10748:2886:1:-;11025:1;11169:16;;;11214:24;11240:8;11211:38;11205:4;11198:52;11316:4;11300:21;;11292:30;;11284:39;;11359:20;;11013:15;11049:25;;;;11093:23;;;;11405:36;;;11284:39;11557:15;;;11546:27;;11536:229;;11697:18;11688:5;11681:13;11678:1;11674:21;11667:49;11746:4;11740;11733:18;11536:229;11868:4;11862;11855:18;11926:13;11923:1;11919:21;11913:28;11890:51;;12076:15;12066:8;12063:29;12056:4;12046:8;12043:18;12040:53;12030:288;;12149:4;12143;12133:21;12127:28;12117:183;;12196:10;12190:4;12183:24;12273:4;12267;12260:18;12117:183;12393:15;12390:55;;;12441:1;12425:13;12422:1;12418:21;12411:32;12390:55;12557:13;;;12536:35;12514:58;;-1:-1:-1;12690:4:1;12684;12674:21;;;12740:22;;12736:30;;12712:55;;-1:-1:-1;12858:16:1;;;12912:21;12981:20;;12764:1;12977:28;13157:20;13132:46;;13124:55;;13114:270;;13308:18;13302:2;13295:10;13292:1;13288:18;13281:46;13361:4;13355;13348:18;13114:270;13401:42;;13572:2;13568;13562:4;13535:25;13529:4;13517:10;13512:63;13594:33;10748:2886;;;:::o;9021:617:0:-;9114:15;7972:9;9132:46;;:15;:46;9114:64;;9346:19;9340:4;9333:33;9396:8;9390:4;9383:22;9452:7;9445:4;9439;9429:21;9422:38;9599:8;9552:45;9549:1;9546;9541:67;9248:374;9021:617::o;13705:198:1:-;13802:26;13815:4;13821:2;13825;13802:12;:26::i;:::-;38367:14;;13838:58;;;13856:40;13879:4;13885:2;13889;13856:40;;;;;;;;;;;;:22;:40::i;2328:800:4:-;2448:18;:16;:18::i;:::-;2476:56;2499:4;2505:9;;2516:5;2523:8;2476:22;:56::i;:::-;2542:28;2552:10;2564:5;2542:9;:28::i;:::-;2605:12;;981:4;2632:24;2648:8;2605:12;2632:24;:::i;:::-;:39;2628:89;;;2694:12;;;;;;;;;;;;;;2628:89;2750:9;2730:16;2738:8;1024:9;2730:16;:::i;:::-;:29;2726:88;;2782:21;;;;;;;;;;;;;;2726:88;1085:1;2827:8;:29;2823:90;;;2879:23;;;;;;;;;;;;;;2823:90;2947:12;:24;;;;;;-1:-1:-1;2986:126:4;3011:8;3006:1;:13;2986:126;;3040:36;3046:10;3074:1;3058:13;:17;3040:5;:36::i;:::-;3094:3;;2986:126;;;;2438:690;2328:800;;;;;:::o;3736:928::-;3871:18;:16;:18::i;:::-;3899:58;3922:4;3928:9;;3939:5;3946:3;3899:22;:58::i;:::-;3967:28;3977:10;3989:5;3967:9;:28::i;:::-;4030:12;;981:4;4056:28;;4052:103;;;4107:37;;;;;;;;;;;;;;4052:103;4183:3;4228:9;4208:16;4183:3;1024:9;4208:16;:::i;:::-;:29;4204:88;;4260:21;;;;;;;;;;;;;;4204:88;1085:1;4305:8;:29;4301:90;;;4357:23;;;;;;;;;;;;;;4301:90;4430:9;4425:222;4449:8;4445:1;:12;4425:222;;;981:4;4482:3;;4486:1;4482:6;;;;;;;:::i;:::-;;;;;;;:21;4478:91;;;4534:16;;;;;;;;;;;;;;4478:91;4586:25;4592:10;4604:3;;4608:1;4604:6;;;;;;;:::i;:::-;;;;;;;4586:5;:25::i;:::-;4629:3;;4425:222;;;;3861:803;;3736:928;;;;;;:::o;9720:456:0:-;9922:19;9916:4;9909:33;9968:8;9962:4;9955:22;10020:1;10013:4;10007;9997:21;9990:32;10151:8;10105:44;10102:1;10099;10094:66;9720:456::o;8360:163:4:-;12517:13:0;:11;:13::i;:::-;8430:27:4::1;:25;:27::i;:::-;8467:12;:18;8482:3:::0;;8467:12;:18:::1;:::i;:::-;;8501:15;8512:3;;8501:15;;;;;;;:::i;6957:332:1:-:0;7015:14;16190:16;;;16232:24;16226:4;16219:38;16334:4;16318:21;;16310:30;;16302:39;;16296:46;16280:64;;;7138:135;;7187:10;7181:4;7174:24;7254:4;7248;7241:18;7138:135;6957:332;;;:::o;7433:533::-;7496:14;7656:5;7646:143;;7694:10;7688:4;7681:24;7770:4;7764;7757:18;7646:143;7815:24;7809:4;7802:38;7866:5;7860:4;7853:19;7929:20;7921:4;7915;7905:21;7899:28;7895:55;7885:65;;7433:533;;;:::o;8762:100:0:-;12517:13;:11;:13::i;:::-;8834:21:::1;8852:1;8834:9;:21::i;:::-;8762:100::o:0;5528:87:4:-;5586:22;5600:7;5586:13;:22::i;4928:237::-;5032:9;5027:122;5047:19;;;5027:122;;;5087:26;5101:8;;5110:1;5101:11;;;;;;;:::i;:::-;;;;;;;5087:13;:26::i;:::-;5131:3;;5027:122;;8023:171;12517:13:0;:11;:13::i;:::-;8097:27:4::1;:25;:27::i;:::-;8134:11;:17;8148:3:::0;;8134:11;:17:::1;:::i;:::-;-1:-1:-1::0;8167:20:4::1;::::0;::::1;::::0;;;::::1;8023:171:::0;;:::o;7126:113::-;12517:13:0;:11;:13::i;:::-;7179:14:4::1;:21:::0;;;::::1;;;::::0;;7216:16:::1;::::0;::::1;::::0;7179:21;;7216:16:::1;7126:113::o:0;9667:726:1:-;9882:10;9875:18;9868:26;9854:40;;9991:8;9985:4;9978:22;10026:31;10020:4;10013:45;10084:8;10078:4;10071:22;10136:10;10129:4;10123;10113:21;10106:41;10221:10;10215:4;10208:24;10366:8;10362:2;10358:17;10354:2;10350:26;10340:8;10305:33;10299:4;10293;10288:89;9667:726;;:::o;9627:128:4:-;9709:39;;;;;9742:4;9709:39;;;2240:74:6;9676:13:4;;1131:42;;9709:24;;2213:18:6;;9709:39:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;9701:47;;9627:128;:::o;9846:141::-;9946:34;;;;;9974:4;9946:34;;;2240:74:6;9893:20:4;;1131:42;;9946:19;;2213:18:6;;9946:34:4;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;-1:-1:-1;9925:55:4;;9846:141;-1:-1:-1;;;9846:141:4:o;14406:249:1:-;14552:26;14565:4;14571:2;14575;14552:12;:26::i;:::-;38367:14;;14588:60;;;14606:42;14629:4;14635:2;14639;14643:4;;14606:42;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;14606:22:1;;-1:-1:-1;;;14606:42:1:i;:::-;14406:249;;;;;:::o;10232:252:4:-;10305:17;10339:16;10347:7;15636:11:1;15725:16;;;15767:24;15761:4;15754:38;15875:4;15859:21;;15851:30;;15843:39;15837:46;15833:2;15829:55;15822:63;15815:71;;15576:326;10339:16:4;10334:70;;10378:15;;;;;;;;;;;;;;10334:70;10443:12;10457:18;:7;:16;:18::i;:::-;10426:50;;;;;;;;;:::i;:::-;;;;;;;;;;;;;10413:64;;10232:252;;;:::o;1343:26::-;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;8648:177::-;12517:13:0;:11;:13::i;:::-;8706:39:4::1;::::0;;;;8739:4:::1;8706:39;::::0;::::1;2240:74:6::0;8748:1:4::1;::::0;1131:42:::1;::::0;8706:24:::1;::::0;2213:18:6;;8706:39:4::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;:::-;:43;8702:117;;;1131:42;8765:19;8793:4;8800:7;11562:11:0::0;11556:18;;11408:182;1423:25:4;;;;;;;:::i;6905:110::-;12517:13:0;:11;:13::i;:::-;6977:31:4::1;::::0;;;;2270:42:6;2258:55;;6977:31:4::1;::::0;::::1;2240:74:6::0;1131:42:4::1;::::0;6977:23:::1;::::0;2213:18:6;;6977:31:4::1;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;9367:167:::0;12517:13:0;:11;:13::i;:::-;1131:42:4::1;9457:28;9494:4;9501:7;11562:11:0::0;11556:18;;11408:182;9501:7:4::1;9457:70;::::0;;::::1;::::0;;;;;;13455:42:6;13524:15;;;9457:70:4::1;::::0;::::1;13506:34:6::0;13576:15;;13556:18;;;13549:43;13608:18;;;13601:34;;;13418:18;;9457:70:4::1;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;10363:708:0:-:0;12517:13;:11;:13::i;:::-;10597:19:::1;10591:4;10584:33;10643:12;10637:4;10630:26;10705:4;10699;10689:21;10811:12;10805:19;10792:11;10789:36;10786:157;;;10857:10;10851:4;10844:24;10924:4;10918;10911:18;10786:157;11020:1;10999:23:::0;;11041::::1;11051:12:::0;11041:9:::1;:23::i;6728:102:4:-:0;12517:13:0;:11;:13::i;:::-;1131:42:4::1;6792:29;;;:31;;;;;;;;;;;;;;;;;;;;;;;;;;;;::::0;::::1;;;;;;;;;;;;::::0;::::1;;;;;;;;;6728:102::o:0;6126:522::-;12517:13:0;:11;:13::i;:::-;6224:12:4::1;::::0;981:4:::1;6251:24;6267:8:::0;6224:12;6251:24:::1;:::i;:::-;:39;6247:89;;;6313:12;;;;;;;;;;;;;;6247:89;6369:9;6349:16;6357:8:::0;1024:9:::1;6349:16;:::i;:::-;:29;6345:88;;6401:21;;;;;;;;;;;;;;6345:88;6467:12;:24:::0;;;::::1;::::0;;-1:-1:-1;6506:126:4::1;6531:8;6526:1;:13;6506:126;;6560:36;6566:10;6594:1;6578:13;:17;6560:5;:36::i;:::-;6614:3;;6506:126;;8348:349:0::0;12517:13;:11;:13::i;:::-;8520:8:::1;8516:2;8512:17;8502:150;;8562:10;8556:4;8549:24;8633:4;8627;8620:18;8502:150;8671:19;8681:8;8671:9;:19::i;7292:355::-:0;7504:11;7498:18;7488:8;7485:32;7475:156;;7550:10;7544:4;7537:24;7612:4;7606;7599:18;29039:1442:1;29222:1;29218:6;29214:2;29210:15;29269:7;29253:14;29249:28;29238:39;;29316:2;29300:14;29296:23;29290:29;;29389:2;29383:4;29376:16;29447:2;29421:24;29418:32;29412:4;29405:46;29517:4;29511;29501:21;29497:2;29493:30;29489:2;29485:39;29576:13;29570:20;29554:14;29550:41;29537:54;;29665:5;29655:134;;29703:10;29697:4;29690:24;29770:4;29764;29757:18;29655:134;29972:5;29968:2;29965:13;29960:2;29953:10;29950:29;29940:280;;30012:5;30006:4;29999:19;30067:4;30061;30051:21;30045:28;30035:171;;30110:10;30104:4;30097:24;30183:4;30177;30170:18;30035:171;30314:1;30310:21;30303:38;;;30462:2;30333:7;30446:5;30419:25;30413:4;30401:10;30396:69;;29039:1442;;;:::o;38588:1370::-;38825:4;38819:11;38875:10;38908:24;38905:1;38898:35;38967:8;38960:4;38957:1;38953:12;38946:30;39075:4;39071:2;39067:13;39063:2;39059:22;39052:4;39049:1;39045:12;39038:44;39116:2;39109:4;39106:1;39102:12;39095:24;39153:4;39146;39143:1;39139:12;39132:26;39186:4;39180:11;39225:1;39218:4;39215:1;39211:12;39204:23;39243:1;39240:71;;;39306:1;39299:4;39296:1;39292:12;39289:1;39282:4;39276;39272:15;39269:1;39262:5;39251:57;39247:62;39240:71;39427:4;39424:1;39417:4;39414:1;39410:12;39403:4;39400:1;39396:12;39393:1;39389:2;39382:5;39377:55;39367:313;;39455:16;39452:214;;;39583:16;39577:4;39574:1;39559:41;39631:16;39628:1;39621:27;39452:214;39367:313;39776:24;39771:3;39767:34;39763:1;39757:8;39754:48;39744:198;;39835:10;39829:4;39822:24;39923:4;39917;39910:18;39744:198;;;38588:1370;;;;:::o;12634:116:4:-;12690:8;;;;12685:59;;12721:12;;;;;;;;;;;;;;12096:532;12265:23;12278:9;;12265:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;12265:4:4;;:23;-1:-1:-1;;12265:12:4;:23;-1:-1:-1;12265:23:4:i;:::-;12248:13;;;;;:40;:13;;;:40;;;12244:96;;12311:18;;;;;;;;;;;;;;12244:96;12473:45;;13864:66:6;12490:10:4;13851:2:6;13847:15;13843:88;12473:45:4;;;13831:101:6;13948:12;;;13941:28;;;13985:12;;;13978:28;;;12350:17:4;;14022:12:6;;12473:45:4;;;;;;;;;;;;;;12463:56;;12473:45;12463:56;;;;14287:66:6;12393:140:4;;;14275:79:6;;;;14370:12;;;14363:28;14407:12;;12393:140:4;;;;;;;;;;;;12370:173;;;;;;12350:193;;12571:4;12558:9;:17;12554:68;;12598:13;;;;;;;;;;;;;;12904:324;13027:20;;;:11;:20;;;;;;;;;;;13065:1;13056:10;;;13027:41;;;;;;;:64;;13096:1;:17;;;;13027:64;;;;;;;13019:95;:120;;12998:214;;13179:18;;;;;;;;;;;;;;19609:1653:1;19853:2;19849;19845:11;19841:2;19837:20;19831:26;;19923:2;19917:4;19910:16;19952:24;19946:4;19939:38;20043:4;20037;20027:21;20023:2;20019:30;20015:2;20011:39;20092:13;20086:20;20181:15;20177:2;20173:24;20170:146;;;20229:10;20223:4;20216:24;20297:4;20291;20284:18;20170:146;20389:23;;20367:46;;20502:4;20495:16;;;20563:4;20557;20547:21;20614:18;;20634:1;20610:26;20786:20;20763:44;;20755:53;;20745:268;;20937:18;20931:2;20924:10;20921:1;20917:18;20910:46;20990:4;20984;20977:18;20745:268;21030:38;;21194:2;21190;21187:1;21160:25;21187:1;21142:10;21137:60;8925:119;;:::o;12756:142:4:-;12820:14;;;;;;;12816:76;;;12857:24;;;;;;;;;;;;;;6145:1089:0;6857:11;7093:16;;6941:26;;;;;;;7053:38;7050:1;;7042:78;7177:27;6145:1089::o;5621:351:4:-;5684:39;5703:10;5715:7;5684:18;:39::i;:::-;5679:98;;5746:20;;;;;;;;;;;;;;5679:98;5786:14;5792:7;5786:5;:14::i;:::-;5838:46;;5820:12;;5838:10;;5873:6;;1024:9;;5820:12;5838:46;5820:12;5838:46;1024:9;5838:10;5873:6;5838:46;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5819:65;;;5899:7;5894:72;;5929:26;;;;;;;;;;;;;;1946:1641:3;2002:17;2447:4;2440;2434:11;2430:22;2423:29;;2546:4;2541:3;2537:14;2531:4;2524:28;2627:1;2622:3;2615:14;2728:3;2758:1;2754:6;2967:5;2949:402;3005:11;;;;3186:2;3200;3190:13;;3182:22;3005:11;3169:36;3292:2;3282:13;;3312:25;2949:402;3312:25;-1:-1:-1;;3379:13:3;;;3492:14;;;;3552:19;;;3492:14;1946:1641;-1:-1:-1;1946:1641:3:o;2203:1772:2:-;2412:4;2406:11;2383:1;;2507:4;2501;2494:18;2563:4;2552:9;2548:20;2542:27;2536:4;2529:41;2619:2;2607:9;2601:16;2598:24;2595:256;;2676:4;2661:20;;2655:27;2724:3;2720:12;;;2734:2;2716:21;2710:4;2703:35;2780:18;;2774:4;2767:32;2828:5;;2595:256;2892:2;2880:9;2874:16;2871:24;2868:222;;2960:4;2949:9;2945:20;2939:27;2936:1;2931:36;2925:4;2918:50;3031:4;3020:9;3016:20;3010:27;3004:4;2997:41;3067:5;;2868:222;3117:1;3107:11;;2464:690;3536:4;3486;3438;3389;3330:6;3256:5;3220:361;3193:406;3167:432;;3707:16;3697:144;;3756:10;3750:4;3743:24;3822:4;3816;3809:18;3697:144;3867:1;3861:4;3854:15;3915:4;3908:15;2203:1772;;-1:-1:-1;;2203:1772:2:o;26907:1160:1:-;27027:11;27273:16;;;27195:25;;;;27318:24;27315:37;;27309:4;27302:51;27419:4;27403:21;;;27395:30;;27387:39;;27468:20;;27195:25;;27130:1;;27452:38;;27554:134;;27602:10;27596:4;27589:24;27669:4;27663;27656:18;27554:134;27773:5;27764:7;27761:18;27751:300;;27812:5;27806:4;27799:19;27938:4;27932;27922:21;27916:28;27906:131;;28003:13;28000:1;27996:21;27990:28;27981:7;27978:41;27968:51;;27906:131;27751:300;;26907:1160;;;;:::o;23961:82::-;24015:21;24029:1;24033:2;24398:13;24414:11;24422:2;24414:7;:11::i;:::-;24398:27;;-1:-1:-1;24680:4:1;24673:16;;;24600:20;;;;24718:24;24715:32;;24709:4;24702:46;24814:4;24798:21;;;24790:30;;24782:39;;24857:20;;24600;;24980:33;;;;25077:134;;25125:10;25119:4;25112:24;25192:4;25186;25179:18;25077:134;25305:5;25299:4;25292:19;25364:13;25361:1;25357:21;25351:28;25596:15;25592:2;25589:23;25581:5;25577:2;25574:13;25571:42;25566:2;25559:10;25556:58;25546:293;;25670:4;25664;25654:21;25648:28;25638:183;;25717:10;25711:4;25704:24;25794:4;25788;25781:18;25638:183;25914:15;25911:55;;;25962:1;25946:13;25943:1;25939:21;25932:32;25911:55;-1:-1:-1;26047:27:1;;26025:50;;26190:4;26184;26174:21;26236:18;;26232:26;;26212:47;;26388:2;-1:-1:-1;26068:5:1;26351:25;-1:-1:-1;26333:10:1;26328:63;10748:2886;;;:::o;14:332:6:-;72:6;125:2;113:9;104:7;100:23;96:32;93:52;;;141:1;138;131:12;93:52;180:9;167:23;230:66;223:5;219:78;212:5;209:89;199:117;;312:1;309;302:12;199:117;335:5;14:332;-1:-1:-1;;;14:332:6:o;543:196::-;611:20;;671:42;660:54;;650:65;;640:93;;729:1;726;719:12;744:186;803:6;856:2;844:9;835:7;831:23;827:32;824:52;;;872:1;869;862:12;824:52;895:29;914:9;895:29;:::i;935:254::-;1003:6;1011;1064:2;1052:9;1043:7;1039:23;1035:32;1032:52;;;1080:1;1077;1070:12;1032:52;1103:29;1122:9;1103:29;:::i;:::-;1093:39;1179:2;1164:18;;;;1151:32;;-1:-1:-1;;;935:254:6:o;1194:250::-;1279:1;1289:113;1303:6;1300:1;1297:13;1289:113;;;1379:11;;;1373:18;1360:11;;;1353:39;1325:2;1318:10;1289:113;;;-1:-1:-1;;1436:1:6;1418:16;;1411:27;1194:250::o;1449:455::-;1598:2;1587:9;1580:21;1561:4;1630:6;1624:13;1673:6;1668:2;1657:9;1653:18;1646:34;1689:79;1761:6;1756:2;1745:9;1741:18;1736:2;1728:6;1724:15;1689:79;:::i;:::-;1820:2;1808:15;1825:66;1804:88;1789:104;;;;1895:2;1785:113;;1449:455;-1:-1:-1;;1449:455:6:o;1909:180::-;1968:6;2021:2;2009:9;2000:7;1996:23;1992:32;1989:52;;;2037:1;2034;2027:12;1989:52;-1:-1:-1;2060:23:6;;1909:180;-1:-1:-1;1909:180:6:o;2325:328::-;2402:6;2410;2418;2471:2;2459:9;2450:7;2446:23;2442:32;2439:52;;;2487:1;2484;2477:12;2439:52;2510:29;2529:9;2510:29;:::i;:::-;2500:39;;2558:38;2592:2;2581:9;2577:18;2558:38;:::i;:::-;2548:48;;2643:2;2632:9;2628:18;2615:32;2605:42;;2325:328;;;;;:::o;2658:347::-;2709:8;2719:6;2773:3;2766:4;2758:6;2754:17;2750:27;2740:55;;2791:1;2788;2781:12;2740:55;-1:-1:-1;2814:20:6;;2857:18;2846:30;;2843:50;;;2889:1;2886;2879:12;2843:50;2926:4;2918:6;2914:17;2902:29;;2978:3;2971:4;2962:6;2954;2950:19;2946:30;2943:39;2940:59;;;2995:1;2992;2985:12;2940:59;2658:347;;;;;:::o;3010:614::-;3107:6;3115;3123;3131;3139;3192:3;3180:9;3171:7;3167:23;3163:33;3160:53;;;3209:1;3206;3199:12;3160:53;3245:9;3232:23;3222:33;;3306:2;3295:9;3291:18;3278:32;3333:18;3325:6;3322:30;3319:50;;;3365:1;3362;3355:12;3319:50;3404:58;3454:7;3445:6;3434:9;3430:22;3404:58;:::i;:::-;3010:614;;3481:8;;-1:-1:-1;3378:84:6;;3563:2;3548:18;;3535:32;;3614:2;3599:18;;;3586:32;;-1:-1:-1;3010:614:6;-1:-1:-1;;;;3010:614:6:o;3629:367::-;3692:8;3702:6;3756:3;3749:4;3741:6;3737:17;3733:27;3723:55;;3774:1;3771;3764:12;3723:55;-1:-1:-1;3797:20:6;;3840:18;3829:30;;3826:50;;;3872:1;3869;3862:12;3826:50;3909:4;3901:6;3897:17;3885:29;;3969:3;3962:4;3952:6;3949:1;3945:14;3937:6;3933:27;3929:38;3926:47;3923:67;;;3986:1;3983;3976:12;4001:882;4125:6;4133;4141;4149;4157;4165;4218:3;4206:9;4197:7;4193:23;4189:33;4186:53;;;4235:1;4232;4225:12;4186:53;4271:9;4258:23;4248:33;;4332:2;4321:9;4317:18;4304:32;4355:18;4396:2;4388:6;4385:14;4382:34;;;4412:1;4409;4402:12;4382:34;4451:58;4501:7;4492:6;4481:9;4477:22;4451:58;:::i;:::-;4528:8;;-1:-1:-1;4425:84:6;-1:-1:-1;4610:2:6;4595:18;;4582:32;;-1:-1:-1;4667:2:6;4652:18;;4639:32;;-1:-1:-1;4683:16:6;;;4680:36;;;4712:1;4709;4702:12;4680:36;;4751:72;4815:7;4804:8;4793:9;4789:24;4751:72;:::i;:::-;4001:882;;;;-1:-1:-1;4001:882:6;;-1:-1:-1;4001:882:6;;4842:8;;4001:882;-1:-1:-1;;;4001:882:6:o;4888:410::-;4959:6;4967;5020:2;5008:9;4999:7;4995:23;4991:32;4988:52;;;5036:1;5033;5026:12;4988:52;5076:9;5063:23;5109:18;5101:6;5098:30;5095:50;;;5141:1;5138;5131:12;5095:50;5180:58;5230:7;5221:6;5210:9;5206:22;5180:58;:::i;:::-;5257:8;;5154:84;;-1:-1:-1;4888:410:6;-1:-1:-1;;;;4888:410:6:o;5485:437::-;5571:6;5579;5632:2;5620:9;5611:7;5607:23;5603:32;5600:52;;;5648:1;5645;5638:12;5600:52;5688:9;5675:23;5721:18;5713:6;5710:30;5707:50;;;5753:1;5750;5743:12;5707:50;5792:70;5854:7;5845:6;5834:9;5830:22;5792:70;:::i;5927:347::-;5992:6;6000;6053:2;6041:9;6032:7;6028:23;6024:32;6021:52;;;6069:1;6066;6059:12;6021:52;6092:29;6111:9;6092:29;:::i;:::-;6082:39;;6171:2;6160:9;6156:18;6143:32;6218:5;6211:13;6204:21;6197:5;6194:32;6184:60;;6240:1;6237;6230:12;6184:60;6263:5;6253:15;;;5927:347;;;;;:::o;6279:626::-;6376:6;6384;6392;6400;6408;6461:3;6449:9;6440:7;6436:23;6432:33;6429:53;;;6478:1;6475;6468:12;6429:53;6501:29;6520:9;6501:29;:::i;:::-;6491:39;;6549:38;6583:2;6572:9;6568:18;6549:38;:::i;:::-;6539:48;;6634:2;6623:9;6619:18;6606:32;6596:42;;6689:2;6678:9;6674:18;6661:32;6716:18;6708:6;6705:30;6702:50;;;6748:1;6745;6738:12;6702:50;6787:58;6837:7;6828:6;6817:9;6813:22;6787:58;:::i;:::-;6279:626;;;;-1:-1:-1;6279:626:6;;-1:-1:-1;6864:8:6;;6761:84;6279:626;-1:-1:-1;;;6279:626:6:o;6910:260::-;6978:6;6986;7039:2;7027:9;7018:7;7014:23;7010:32;7007:52;;;7055:1;7052;7045:12;7007:52;7078:29;7097:9;7078:29;:::i;:::-;7068:39;;7126:38;7160:2;7149:9;7145:18;7126:38;:::i;:::-;7116:48;;6910:260;;;;;:::o;7507:184::-;7577:6;7630:2;7618:9;7609:7;7605:23;7601:32;7598:52;;;7646:1;7643;7636:12;7598:52;-1:-1:-1;7669:16:6;;7507:184;-1:-1:-1;7507:184:6:o;7696:::-;7748:77;7745:1;7738:88;7845:4;7842:1;7835:15;7869:4;7866:1;7859:15;7885:125;7950:9;;;7971:10;;;7968:36;;;7984:18;;:::i;:::-;7885:125;;;;:::o;8015:168::-;8088:9;;;8119;;8136:15;;;8130:22;;8116:37;8106:71;;8157:18;;:::i;8188:184::-;8240:77;8237:1;8230:88;8337:4;8334:1;8327:15;8361:4;8358:1;8351:15;8377:184;8429:77;8426:1;8419:88;8526:4;8523:1;8516:15;8550:4;8547:1;8540:15;8566:437;8645:1;8641:12;;;;8688;;;8709:61;;8763:4;8755:6;8751:17;8741:27;;8709:61;8816:2;8808:6;8805:14;8785:18;8782:38;8779:218;;8853:77;8850:1;8843:88;8954:4;8951:1;8944:15;8982:4;8979:1;8972:15;8779:218;;8566:437;;;:::o;9134:545::-;9236:2;9231:3;9228:11;9225:448;;;9272:1;9297:5;9293:2;9286:17;9342:4;9338:2;9328:19;9412:2;9400:10;9396:19;9393:1;9389:27;9383:4;9379:38;9448:4;9436:10;9433:20;9430:47;;;-1:-1:-1;9471:4:6;9430:47;9526:2;9521:3;9517:12;9514:1;9510:20;9504:4;9500:31;9490:41;;9581:82;9599:2;9592:5;9589:13;9581:82;;;9644:17;;;9625:1;9614:13;9581:82;;9915:1325;10039:18;10034:3;10031:27;10028:53;;;10061:18;;:::i;:::-;10090:94;10180:3;10140:38;10172:4;10166:11;10140:38;:::i;:::-;10134:4;10090:94;:::i;:::-;10210:1;10235:2;10230:3;10227:11;10252:1;10247:735;;;;11026:1;11043:3;11040:93;;;-1:-1:-1;11099:19:6;;;11086:33;11040:93;9821:66;9812:1;9808:11;;;9804:84;9800:89;9790:100;9896:1;9892:11;;;9787:117;11146:78;;10220:1014;;10247:735;9081:1;9074:14;;;9118:4;9105:18;;10292:66;10283:76;;;10443:9;10465:229;10479:7;10476:1;10473:14;10465:229;;;10568:19;;;10555:33;10540:49;;10675:4;10660:20;;;;10628:1;10616:14;;;;10495:12;10465:229;;;10469:3;10722;10713:7;10710:16;10707:219;;;10842:66;10836:3;10830;10827:1;10823:11;10819:21;10815:94;10811:99;10798:9;10793:3;10789:19;10776:33;10772:139;10764:6;10757:155;10707:219;;;10969:1;10963:3;10960:1;10956:11;10952:19;10946:4;10939:33;10220:1014;;9915:1325;;;:::o;11245:449::-;11404:2;11393:9;11386:21;11443:6;11438:2;11427:9;11423:18;11416:34;11500:6;11492;11487:2;11476:9;11472:18;11459:48;11556:1;11527:22;;;11551:2;11523:31;;;11516:42;;;;11610:2;11598:15;;;11615:66;11594:88;11579:104;11575:113;;11245:449;-1:-1:-1;11245:449:6:o;11699:456::-;11808:6;11816;11824;11832;11885:3;11873:9;11864:7;11860:23;11856:33;11853:53;;;11902:1;11899;11892:12;11853:53;11931:9;11925:16;11915:26;;11981:2;11970:9;11966:18;11960:25;11950:35;;12025:2;12014:9;12010:18;12004:25;11994:35;;12072:2;12061:9;12057:18;12051:25;12105:1;12098:5;12095:12;12085:40;;12121:1;12118;12111:12;12085:40;11699:456;;;;-1:-1:-1;11699:456:6;;-1:-1:-1;;11699:456:6:o;12160:1078::-;12336:3;12365:1;12398:6;12392:13;12428:36;12454:9;12428:36;:::i;:::-;12483:1;12500:18;;;12527:191;;;;12732:1;12727:356;;;;12493:590;;12527:191;12575:66;12564:9;12560:82;12555:3;12548:95;12698:6;12691:14;12684:22;12676:6;12672:35;12667:3;12663:45;12656:52;;12527:191;;12727:356;12758:6;12755:1;12748:17;12788:4;12833:2;12830:1;12820:16;12858:1;12872:165;12886:6;12883:1;12880:13;12872:165;;;12964:14;;12951:11;;;12944:35;13007:16;;;;12901:10;;12872:165;;;12876:3;;;13066:6;13061:3;13057:16;13050:23;;12493:590;;;;;13114:6;13108:13;13130:68;13189:8;13184:3;13177:4;13169:6;13165:17;13130:68;:::i;:::-;13214:18;;12160:1078;-1:-1:-1;;;;12160:1078:6:o
Swarm Source
ipfs://cfec19ccb38c11d67180c18fbc9c84382e0d3a4ea515877a0e32b145cc4ea245
Loading...
Loading
Loading...
Loading
Multichain Portfolio | 34 Chains
Chain | Token | Portfolio % | Price | Amount | Value |
---|---|---|---|---|---|
BLAST | 100.00% | $1,789.45 | 21.001 | $37,580.15 |
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
[ Download: CSV Export ]
A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.