Feature Tip: Add private address tag to any address under My Name Tag !
NFT
Overview
TokenID
2284
Total Transfers
-
Market
Onchain Market Cap
$0.00
Circulating Supply Market Cap
-
Other Info
Token Contract
Loading...
Loading
Loading...
Loading
Loading...
Loading
# | Exchange | Pair | Price | 24H Volume | % Volume |
---|
Contract Name:
ETHGobblers
Compiler Version
v0.8.15+commit.e14f2714
Optimization Enabled:
Yes with 200 runs
Other Settings:
default evmVersion
Contract Source Code (Solidity Standard Json-Input format)
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; import "solady/utils/ECDSA.sol"; import "solady/utils/LibString.sol"; import "solmate/auth/Owned.sol"; import "solmate/tokens/ERC721.sol"; import "./GobDrops.sol"; /// @title ETH Gobblers /// @author EtDu /// @notice Gobble... Gobble... Gobble... contract ETHGobblers is ERC721, Owned { using ECDSA for bytes32; using LibString for uint256; /*------------------------------------------------------*/ /* VARIABLES / CONSTANTS /*------------------------------------------------------*/ uint256 public totalSupply = 0; // Genesis max supply, newer generations can be minted via mitosis uint256 constant genesisMaxSupply = 2000; // Supply of new ETH Gobblers from mitosis uint256 public mitosisSupply = 0; // Current Gobbler Gobbler token ID. Has the power to gobble one ETH Gobbler before declaring another Gobbler Gobbler. uint256 public currentGobblerGobbler; // ETH Gobbler action pricing uint256 public feedPrice = 0.001 ether; uint256 public groomPrice = 0.01 ether; uint256 public sleepPrice = 0.1 ether; uint256 public gobbleGobblerPrice = 1 ether; string public baseURI; bool public paused; GobDrops public gobDrops; // ETHGobblers signer of naughty/nice list verifications address public signerAddress; address constant burnAddress = 0x000000000000000000000000000000000000dEaD; // Gobbler ID to equipped traits // Traits can be swapped/updated, separate from base artistic traits // Base traits are kept track of off-chain // Each trait type value represents a trait tokenID from GobDrops // 7 trait IDs (uint32) are packed into a single uint256 variable to save on storage costs // Value of 2^32 - 1 means no traits mapping(uint256 => uint256) public equippedTraits; // Total amount of ETH Gobbled per Gobbler ID (in wei) mapping(uint256 => uint256) public ETHGobbled; // Current nonce per signer, prevents signature replay attacks // Backend should query it for creating signatures mapping(address => uint256) public signatureNonce; enum Action { Feed, Groom, Sleep } /*------------------------------------------------------*/ /* EVENTS /*------------------------------------------------------*/ // All actions are event based, the backend handles health logic based on emitted events event Feed( uint256 indexed tokenID, uint8 indexed amount, address indexed owner ); event Groom( uint256 indexed tokenID, uint8 indexed amount, address indexed owner ); event Sleep( uint256 indexed tokenID, address indexed owner ); event Bury( uint256 indexed tokenID, address indexed owner ); event Mitosis( uint256 indexed parentTokenID, uint256 indexed newTokenID, address indexed owner ); event ConfigureTraits( uint256 indexed tokenID, uint256 indexed traitIDs ); event TraitUnlocked( uint256 indexed parentGobblerID, uint256 indexed newTraitTokenID, address indexed owner ); event GobblerGobbled( uint256 indexed gobblerGobblerID, uint256 indexed victimID, uint256 indexed newGobblerGobblerID ); /*------------------------------------------------------*/ /* CONSTRUCTOR /*------------------------------------------------------*/ constructor(address signer) ERC721("ETH GOBBLERS", "GOOEY") Owned(msg.sender){ signerAddress = signer; gobDrops = new GobDrops(msg.sender); } modifier onlyTokenOwner(uint256 tokenID, address holder) { require(ownerOf(tokenID) == holder, "Must be token owner"); _; } /*------------------------------------------------------*/ /* USER ACTIONS /*------------------------------------------------------*/ /// @notice Mint a gobbler. Must be on the Omakasea Naughty or Nice list to participate /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function mint( bytes32 messageHash, bytes calldata signature ) external { // Free mint require(totalSupply + 1 <= genesisMaxSupply, "Genesis max supply reached"); // must not be paused require(!paused, "Must not be paused"); // Naughty/nice list checks // The message should contain the msg sender, this contract address, function name sig and sig nonce require( hashMessage( msg.sender, address(this), bytes4(abi.encodePacked("mint")), signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); _mint(msg.sender, totalSupply); unchecked { totalSupply++; signatureNonce[msg.sender]++; } } /// @notice Feed, Groom or Sleep - any action invoked while the gobbler is alive /// @param action The action to invoke /// @param tokenID The Gobbler tokenID to use /// @param amount The of times the action should be invoked /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function actionAlive( Action action, uint256 tokenID, uint8 amount, bytes32 messageHash, bytes calldata signature ) external payable onlyTokenOwner(tokenID, msg.sender) { // Checks required, valid message hash and signature only produced if health is above 0% // This smart contract has no notion of health, which is entirely managed off chain // The message should contain the msg sender, this contract address, function name sig and sig nonce require( hashMessage( msg.sender, address(this), bytes4(abi.encodePacked("actionAlive")), signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); if (action == Action.Feed) { require(msg.value == feedPrice * amount, "Not enough ETH Sent"); emit Feed(tokenID, amount, msg.sender); } else if (action == Action.Groom) { require(msg.value == groomPrice * amount, "Not enough ETH Sent"); emit Groom(tokenID, amount, msg.sender); } else if (action == Action.Sleep) { require(msg.value == sleepPrice, "Not enough ETH Sent"); emit Sleep(tokenID, msg.sender); } unchecked { ETHGobbled[tokenID] += msg.value; signatureNonce[msg.sender]++; } } /// @notice Bury a gobbler, sending it to the burn address, eliminating it from supply permanently. Only possible if health is at 0 /// @param tokenID The Gobbler tokenID to use /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function bury( uint256 tokenID, bytes32 messageHash, bytes calldata signature ) external { // Checks required, valid message hash and signature only produced if health is 0% // This smart contract has no notion of health, which is entirely managed off chain // The message should contain the msg sender, this contract address, function name sig, the tokenID and sig nonce require( hashMessageBury( msg.sender, address(this), bytes4(abi.encodePacked("bury")), tokenID, signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); address currentOwner = ownerOf(tokenID); /*-----------ERC721-----------*/ // custom burn logic, sends to DEAD address require(currentOwner != address(0), "NOT_MINTED"); unchecked { _balanceOf[currentOwner]--; _balanceOf[burnAddress]++; } _ownerOf[tokenID] = burnAddress; delete getApproved[tokenID]; emit Transfer(currentOwner, burnAddress, tokenID); /*-----------ERC721-----------*/ emit Bury(tokenID, msg.sender); unchecked { signatureNonce[msg.sender]++; } } /// @notice Current gobbler divides into another one /// @param tokenID The Gobbler tokenID to use /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address /// @dev should not be invoked until all 2000 genesis are minted function mitosis( uint256 tokenID, bytes32 messageHash, bytes calldata signature ) external onlyTokenOwner(tokenID, msg.sender) { // Checks required, valid message hash and signature only produced if certain actions have been called a number of times // Action counts are tracked by emitted events // The message should contain the msg sender, this contract address, function name and sig nonce require( hashMessage( msg.sender, address(this), bytes4(abi.encodePacked("mitosis")), signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); // token IDs for mitosis gobblers start at ID 2000 uint newTokenID = genesisMaxSupply + mitosisSupply; _mint(msg.sender, newTokenID); emit Mitosis( tokenID, newTokenID, msg.sender ); unchecked { mitosisSupply++; totalSupply++; signatureNonce[msg.sender]++; } } /// @notice Configure NFT traits for the gobbler /// @param tokenID The Gobbler tokenID to use /// @param traitIDs The token IDs of traits to equip (packed into one uint256) /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function configureTraits( uint256 tokenID, uint256 traitIDs, bytes32 messageHash, bytes calldata signature ) external onlyTokenOwner(tokenID, msg.sender) { // checks required, cannot casually call this function from etherscan // The message should contain the msg sender, this contract address, function name, trait IDs and sig nonce require( hashMessageConfigureTraits( msg.sender, address(this), bytes4(abi.encodePacked("configureTraits")), traitIDs, signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); equippedTraits[tokenID] = traitIDs; emit ConfigureTraits( tokenID, traitIDs ); unchecked { signatureNonce[msg.sender]++; } } /// @notice Unlock a new NFT trait /// @param tokenID The Gobbler tokenID to use /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function unlockTrait( uint256 tokenID, bytes32 messageHash, bytes calldata signature ) external onlyTokenOwner(tokenID, msg.sender) { // checks required, valid signature and message hash only produced if certain actions have been called a number of times // The message should contain the msg sender, this contract address, function name sig, and sig nonce require( hashMessage( msg.sender, address(this), bytes4(abi.encodePacked("unlockTrait")), signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); uint newTraitTokenID = gobDrops.totalSupply(); gobDrops.mint(msg.sender); emit TraitUnlocked( tokenID, newTraitTokenID, msg.sender ); unchecked { signatureNonce[msg.sender]++; } } /// @notice Gobble (steal) another gobbler. Must be the Gobbler Gobbler /// @param gobblerGobblerTokenID The token ID of the current Gobbler Gobbler /// @param victimTokenID The token ID of the Gobbler to be gobbled /// @param newGobblerGobbler The token ID of the new Gobbler Gobbler /// @param messageHash Hash of message created by the backend /// @param signature Signature of message hash signed by the ETH Gobblers admin address function gobbleGobbler( uint256 gobblerGobblerTokenID, uint256 victimTokenID, uint256 newGobblerGobbler, bytes32 messageHash, bytes calldata signature ) external payable onlyTokenOwner(gobblerGobblerTokenID, msg.sender) { require(currentGobblerGobbler == gobblerGobblerTokenID, "Must be the Gobbler Gobbler!"); require(msg.value == gobbleGobblerPrice, "Not enough ETH sent!"); require( hashMessageGobbleGobbler( msg.sender, address(this), bytes4(abi.encodePacked("gobbleGobbler")), newGobblerGobbler, signatureNonce[msg.sender] ) == messageHash, "Wrong message hash!" ); require(verifyAddressSigner(messageHash, signature), "Invalid address signer"); address currentOwnerOfVictim = ownerOf(victimTokenID); /*-----------ERC721-----------*/ unchecked { _balanceOf[currentOwnerOfVictim]--; _balanceOf[msg.sender]++; } _ownerOf[victimTokenID] = msg.sender; delete getApproved[victimTokenID]; emit Transfer(currentOwnerOfVictim, msg.sender, victimTokenID); /*-----------ERC721-----------*/ emit GobblerGobbled( gobblerGobblerTokenID, victimTokenID, newGobblerGobbler ); currentGobblerGobbler = newGobblerGobbler; unchecked { signatureNonce[msg.sender]++; } } /*------------------------------------------------------*/ /* ADMIN /*------------------------------------------------------*/ function changeFeedPrice(uint256 price) external onlyOwner { feedPrice = price; } function changeGroomPrice(uint256 price) external onlyOwner { groomPrice = price; } function changeSleepPrice(uint256 price) external onlyOwner { sleepPrice = price; } function changeGobbleGobblerPrice(uint256 price) external onlyOwner { gobbleGobblerPrice = price; } function setGobblerGobbler(uint256 tokenID) external onlyOwner { currentGobblerGobbler = tokenID; } function changeBaseURI(string calldata newBaseURI) external onlyOwner { baseURI = newBaseURI; } function changeSigner(address signer) external onlyOwner { signerAddress = signer; } function flipPaused() external onlyOwner { paused = !paused; } /*------------------------------------------------------*/ /* READ ONLY /*------------------------------------------------------*/ function getTraitConfiguration(uint256 tokenID) external view returns ( uint32 wings, uint32 sidekick, uint32 food, uint32 accessory, uint32 weather, uint32 cushion, uint32 inflight, uint32 freeSlot ) { uint256 currentTraits = equippedTraits[tokenID]; assembly { wings := and(shr(0xE0, currentTraits), 0xffffffff) sidekick := and(shr(0xC0, currentTraits), 0xffffffff) food := and(shr(0xA0, currentTraits), 0xffffffff) accessory := and(shr(0x80, currentTraits), 0xffffffff) weather := and(shr(0x60, currentTraits), 0xffffffff) cushion := and(shr(0x40, currentTraits), 0xffffffff) inflight := and(shr(0x20, currentTraits), 0xffffffff) freeSlot := and(currentTraits, 0xffffffff) } } function tokenURI(uint tokenID) public view override returns (string memory) { require(tokenID < totalSupply, "This token does not exist"); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenID.toString())) : ""; } function verifyAddressSigner(bytes32 messageHash, bytes calldata signature) private view returns (bool) { address recovery = messageHash.toEthSignedMessageHash().recover(signature); return signerAddress == recovery; } function hashMessage(address sender, address thisContract, bytes4 functionNameSig, uint256 nonce) public pure returns (bytes32) { return keccak256(abi.encodePacked(sender, thisContract, functionNameSig, nonce)); } // special hash message for trait configuration function function hashMessageConfigureTraits(address sender, address thisContract, bytes4 functionNameSig, uint256 traitIDs, uint256 nonce) public pure returns (bytes32) { return keccak256(abi.encodePacked(sender, thisContract, functionNameSig, traitIDs, nonce)); } // special hash message for bury function function hashMessageBury(address sender, address thisContract, bytes4 functionNameSig, uint256 tokenID, uint256 nonce) public pure returns (bytes32) { return keccak256(abi.encodePacked(sender, thisContract, functionNameSig, tokenID, nonce)); } // special hash message for gobble gobbler function function hashMessageGobbleGobbler(address sender, address thisContract, bytes4 functionNameSig, uint256 newGobblerGobbler, uint256 nonce) public pure returns (bytes32) { return keccak256(abi.encodePacked(sender, thisContract, functionNameSig, newGobblerGobbler, nonce)); } /*------------------------------------------------------*/ /* WITHDRAW /*------------------------------------------------------*/ function withdraw() external onlyOwner { assembly { let result := call(0, caller(), selfbalance(), 0, 0, 0, 0) switch result case 0 { revert(0, 0) } default { return(0, 0) } } } }
// 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) library ECDSA { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CONSTANTS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The number which `s` must not exceed in order for /// the signature to be non-malleable. bytes32 private constant _MALLEABILITY_THRESHOLD = 0x7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0; /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* RECOVERY OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev Recovers the signer's address from a message digest `hash`, /// and the `signature`. /// /// This function does NOT accept EIP-2098 short form signatures. /// Use `recover(bytes32 hash, bytes32 r, bytes32 vs)` for EIP-2098 /// short form signatures instead. /// /// WARNING! /// The `result` will be the zero address upon recovery failure. /// As such, it is extremely important to ensure that the address which /// the `result` is compared against is never zero. function recover(bytes32 hash, bytes calldata signature) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { if eq(signature.length, 65) { // Copy the free memory pointer so that we can restore it later. let m := mload(0x40) // Directly copy `r` and `s` from the calldata. calldatacopy(0x40, signature.offset, 0x40) // If `s` in lower half order, such that the signature is not malleable. if iszero(gt(mload(0x60), _MALLEABILITY_THRESHOLD)) { mstore(0x00, hash) // Compute `v` and store it in the scratch space. mstore(0x20, byte(0, calldataload(add(signature.offset, 0x40)))) pop( staticcall( gas(), // Amount of gas left for the transaction. 0x01, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) // Restore the zero slot. mstore(0x60, 0) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(sub(0x60, returndatasize())) } // Restore the free memory pointer. mstore(0x40, m) } } } /// @dev Recovers the signer's address from a message digest `hash`, /// and the EIP-2098 short form signature defined by `r` and `vs`. /// /// This function only accepts EIP-2098 short form signatures. /// See: https://eips.ethereum.org/EIPS/eip-2098 /// /// To be honest, I do not recommend using EIP-2098 signatures /// for simplicity, performance, and security reasons. Most if not /// all clients support traditional non EIP-2098 signatures by default. /// As such, this method is intentionally not fully inlined. /// It is merely included for completeness. /// /// WARNING! /// The `result` will be the zero address upon recovery failure. /// As such, it is extremely important to ensure that the address which /// the `result` is compared against is never zero. function recover(bytes32 hash, bytes32 r, bytes32 vs) internal view returns (address result) { uint8 v; bytes32 s; /// @solidity memory-safe-assembly assembly { s := shr(1, shl(1, vs)) v := add(shr(255, vs), 27) } result = recover(hash, v, r, s); } /// @dev Recovers the signer's address from a message digest `hash`, /// and the signature defined by `v`, `r`, `s`. /// /// WARNING! /// The `result` will be the zero address upon recovery failure. /// As such, it is extremely important to ensure that the address which /// the `result` is compared against is never zero. function recover(bytes32 hash, uint8 v, bytes32 r, bytes32 s) internal view returns (address result) { /// @solidity memory-safe-assembly assembly { // Copy the free memory pointer so that we can restore it later. let m := mload(0x40) // If `s` in lower half order, such that the signature is not malleable. if iszero(gt(s, _MALLEABILITY_THRESHOLD)) { mstore(0x00, hash) mstore(0x20, v) mstore(0x40, r) mstore(0x60, s) pop( staticcall( gas(), // Amount of gas left for the transaction. 0x01, // Address of `ecrecover`. 0x00, // Start of input. 0x80, // Size of input. 0x40, // Start of output. 0x20 // Size of output. ) ) // Restore the zero slot. mstore(0x60, 0) // `returndatasize()` will be `0x20` upon success, and `0x00` otherwise. result := mload(sub(0x60, returndatasize())) } // Restore the free memory pointer. mstore(0x40, m) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 { // Store into scratch space for keccak256. mstore(0x20, hash) mstore(0x00, "\x00\x00\x00\x00\x19Ethereum Signed Message:\n32") // 0x40 - 0x04 = 0x3c result := keccak256(0x04, 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. function toEthSignedMessageHash(bytes memory s) internal pure returns (bytes32 result) { assembly { // We need at most 128 bytes for Ethereum signed message header. // The max length of the ASCII reprenstation of a uint256 is 78 bytes. // The length of "\x19Ethereum Signed Message:\n" is 26 bytes (i.e. 0x1a). // The next multiple of 32 above 78 + 26 is 128 (i.e. 0x80). // Instead of allocating, we temporarily copy the 128 bytes before the // start of `s` data to some variables. let m3 := mload(sub(s, 0x60)) let m2 := mload(sub(s, 0x40)) let m1 := mload(sub(s, 0x20)) // The length of `s` is in bytes. let sLength := mload(s) let ptr := add(s, 0x20) // `end` marks the end of the memory which we will compute the keccak256 of. let end := add(ptr, sLength) // Convert the length of the bytes to ASCII decimal representation // and store it into the memory. for { let temp := sLength } 1 {} { ptr := sub(ptr, 1) mstore8(ptr, add(48, mod(temp, 10))) temp := div(temp, 10) if iszero(temp) { break } } // Copy the header over to the memory. mstore(sub(ptr, 0x20), "\x00\x00\x00\x00\x00\x00\x19Ethereum Signed Message:\n") // Compute the keccak256 of the memory. result := keccak256(sub(ptr, 0x1a), sub(end, sub(ptr, 0x1a))) // Restore the previous memory. mstore(s, sLength) mstore(sub(s, 0x20), m1) mstore(sub(s, 0x40), m2) mstore(sub(s, 0x60), m3) } } }
// 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) library LibString { /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* CUSTOM ERRORS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ /// @dev The `length` of the output is too small to contain all the hex digits. error HexLengthInsufficient(); /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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. Total: 5 * 0x20 = 0xa0. let m := add(mload(0x40), 0xa0) // Update the free memory pointer to allocate. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end of the memory to calculate the length later. let end := str // We write the string from rightmost digit to leftmost digit. // The following is essentially a do-while loop that also handles the zero case. for { let temp := value } 1 {} { str := sub(str, 1) // Write the character to the pointer. // The ASCII index of the '0' character is 48. mstore8(str, add(48, mod(temp, 10))) // Keep dividing `temp` until zero. temp := div(temp, 10) 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) } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 { let start := mload(0x40) // 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. let m := add(start, and(add(shl(1, length), 0x62), not(0x1f))) // Allocate the memory. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) 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 := sub(str, 2) mstore8(add(str, 1), mload(and(temp, 15))) mstore8(str, mload(and(shr(4, temp), 15))) temp := shr(8, temp) length := sub(length, 1) if iszero(length) { break } } if temp { // Store the function selector of `HexLengthInsufficient()`. mstore(0x00, 0x2194895a) // Revert with (offset, size). 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 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 { let start := mload(0x40) // 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. let m := add(start, 0xa0) // Allocate the memory. mstore(0x40, m) // Assign the `str` to the end. str := sub(m, 0x20) // Zeroize the slot after the string. mstore(str, 0) // Cache the end to calculate the length later. let end := str // Store "0123456789abcdef" in scratch space. mstore(0x0f, 0x30313233343536373839616263646566) // 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 := 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 toHexStringChecksumed(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 } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* 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 } } } } } /*´:°•.°+.*•´.*:˚.°*.˚•´.°:°•.°•.*•´.*:˚.°*.˚•´.°:°•.°+.*•´.*:*/ /* BYTE STRING OPERATIONS */ /*.•°:°.´+˚.*°.˚:*.´•*.+°.•°:´*.´•*.•°.•°:°.´:•˚°.*°.˚:*.´+°.•*/ // For performance and bytecode compactness, all indices of the following operations // are byte (ASCII) offsets, not UTF character offsets. /// @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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) 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) // Zeroize the slot after the string. let last := add(add(result, 0x20), k) mstore(last, 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) // Store the length of the result. mstore(result, k) } } /// @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)) { // `result = min(from, subjectLength)`. result := xor(from, mul(xor(from, subjectLength), lt(subjectLength, from))) break } let searchLength := mload(search) let subjectStart := add(subject, 0x20) result := not(0) // Initialize to `NOT_FOUND`. subject := add(subjectStart, from) let subjectSearchEnd := add(sub(add(subjectStart, subjectLength), searchLength), 1) let m := shl(3, sub(32, and(searchLength, 31))) let s := mload(add(search, 0x20)) if iszero(lt(subject, subjectSearchEnd)) { break } if iszero(lt(searchLength, 32)) { 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, subjectSearchEnd)) { 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, subjectSearchEnd)) { 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 {} { let searchLength := mload(search) let fromMax := sub(mload(subject), searchLength) if iszero(gt(fromMax, from)) { from := fromMax } if iszero(mload(search)) { result := from break } result := not(0) // Initialize to `NOT_FOUND`. let subjectSearchEnd := sub(add(subject, 0x20), 1) subject := add(add(subject, 0x20), from) if iszero(gt(subject, subjectSearchEnd)) { 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(subjectSearchEnd, 1)) break } subject := sub(subject, 1) if iszero(gt(subject, subjectSearchEnd)) { 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 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 } } // Zeroize the slot after the string. mstore(output, 0) // Store the length. let resultLength := sub(output, add(result, 0x20)) mstore(result, resultLength) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, add(result, and(add(resultLength, 63), not(31)))) } } } /// @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(31) // Copy the `subject` one word at a time, backwards. for { let o := and(add(resultLength, 31), 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, 63), 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, 32)) { h := keccak256(search, searchLength) } let m := shl(3, sub(32, and(searchLength, 31))) 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(31) 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, 31), 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, 63), 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(31) result := mload(0x40) let aLength := mload(a) // Copy `a` one word at a time, backwards. for { let o := and(add(mload(a), 32), 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, mload(a)) // Copy `b` one word at a time, backwards. for { let o := and(add(bLength, 32), 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, 31), w)) } } /// @dev Returns a copy of the string in either lowercase or UPPERCASE. 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)), 67108863) 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 } } // Restore the result. result := mload(0x40) // Stores the string length. mstore(result, length) // Zeroize the slot after the string. let last := add(add(result, 0x20), length) mstore(last, 0) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } } /// @dev Returns a lowercased copy of the string. function lower(string memory subject) internal pure returns (string memory result) { result = toCase(subject, false); } /// @dev Returns an UPPERCASED copy of the string. 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 { for { 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)) } 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, 31))) result := add(result, shr(5, t)) } let last := result // Zeroize the slot after the string. mstore(last, 0) // Restore the result to the start of the free memory. result := mload(0x40) // Store the length of the result. mstore(result, sub(last, add(result, 0x20))) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } /// @dev Escapes the string to be used within double-quotes in a JSON. function escapeJSON(string memory s) internal pure returns (string memory result) { /// @solidity memory-safe-assembly assembly { for { let end := add(s, mload(s)) result := add(mload(0x40), 0x20) // 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)) } 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) } let last := result // Zeroize the slot after the string. mstore(last, 0) // Restore the result to the start of the free memory. result := mload(0x40) // Store the length of the result. mstore(result, sub(last, add(result, 0x20))) // Allocate memory for the length and the bytes, // rounded up to a multiple of 32. mstore(0x40, and(add(last, 31), not(31))) } } /// @dev Returns whether `a` equals `b`. function eq(string memory a, string memory b) internal pure returns (bool result) { assembly { result := eq(keccak256(add(a, 0x20), mload(a)), keccak256(add(b, 0x20), mload(b))) } } /// @dev Packs a single string with its length into a single word. /// Returns `bytes32(0)` if the length is zero or greater than 31. function packOne(string memory a) internal pure returns (bytes32 result) { /// @solidity memory-safe-assembly assembly { // We don't need to zero right pad the string, // since this is our own custom non-standard packing scheme. result := mul( // Load the length and the bytes. mload(add(a, 0x1f)), // `length != 0 && length < 32`. Abuses underflow. // Assumes that the length is valid and within the block gas limit. lt(sub(mload(a), 1), 0x1f) ) } } /// @dev Unpacks a string packed using {packOne}. /// Returns the empty string if `packed` is `bytes32(0)`. /// If `packed` is not an output of {packOne}, the output behaviour 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 behaviour 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: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Simple single owner authorization mixin. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/auth/Owned.sol) abstract contract Owned { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event OwnershipTransferred(address indexed user, address indexed newOwner); /*////////////////////////////////////////////////////////////// OWNERSHIP STORAGE //////////////////////////////////////////////////////////////*/ address public owner; modifier onlyOwner() virtual { require(msg.sender == owner, "UNAUTHORIZED"); _; } /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(address _owner) { owner = _owner; emit OwnershipTransferred(address(0), _owner); } /*////////////////////////////////////////////////////////////// OWNERSHIP LOGIC //////////////////////////////////////////////////////////////*/ function transferOwnership(address newOwner) public virtual onlyOwner { owner = newOwner; emit OwnershipTransferred(msg.sender, newOwner); } }
// SPDX-License-Identifier: AGPL-3.0-only pragma solidity >=0.8.0; /// @notice Modern, minimalist, and gas efficient ERC-721 implementation. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721 { /*////////////////////////////////////////////////////////////// EVENTS //////////////////////////////////////////////////////////////*/ event Transfer(address indexed from, address indexed to, uint256 indexed id); event Approval(address indexed owner, address indexed spender, uint256 indexed id); event ApprovalForAll(address indexed owner, address indexed operator, bool approved); /*////////////////////////////////////////////////////////////// METADATA STORAGE/LOGIC //////////////////////////////////////////////////////////////*/ string public name; string public symbol; function tokenURI(uint256 id) public view virtual returns (string memory); /*////////////////////////////////////////////////////////////// ERC721 BALANCE/OWNER STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) internal _ownerOf; mapping(address => uint256) internal _balanceOf; function ownerOf(uint256 id) public view virtual returns (address owner) { require((owner = _ownerOf[id]) != address(0), "NOT_MINTED"); } function balanceOf(address owner) public view virtual returns (uint256) { require(owner != address(0), "ZERO_ADDRESS"); return _balanceOf[owner]; } /*////////////////////////////////////////////////////////////// ERC721 APPROVAL STORAGE //////////////////////////////////////////////////////////////*/ mapping(uint256 => address) public getApproved; mapping(address => mapping(address => bool)) public isApprovedForAll; /*////////////////////////////////////////////////////////////// CONSTRUCTOR //////////////////////////////////////////////////////////////*/ constructor(string memory _name, string memory _symbol) { name = _name; symbol = _symbol; } /*////////////////////////////////////////////////////////////// ERC721 LOGIC //////////////////////////////////////////////////////////////*/ function approve(address spender, uint256 id) public virtual { address owner = _ownerOf[id]; require(msg.sender == owner || isApprovedForAll[owner][msg.sender], "NOT_AUTHORIZED"); getApproved[id] = spender; emit Approval(owner, spender, id); } function setApprovalForAll(address operator, bool approved) public virtual { isApprovedForAll[msg.sender][operator] = approved; emit ApprovalForAll(msg.sender, operator, approved); } function transferFrom( address from, address to, uint256 id ) public virtual { require(from == _ownerOf[id], "WRONG_FROM"); require(to != address(0), "INVALID_RECIPIENT"); require( msg.sender == from || isApprovedForAll[from][msg.sender] || msg.sender == getApproved[id], "NOT_AUTHORIZED" ); // Underflow of the sender's balance is impossible because we check for // ownership above and the recipient's balance can't realistically overflow. unchecked { _balanceOf[from]--; _balanceOf[to]++; } _ownerOf[id] = to; delete getApproved[id]; emit Transfer(from, to, id); } function safeTransferFrom( address from, address to, uint256 id ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function safeTransferFrom( address from, address to, uint256 id, bytes calldata data ) public virtual { transferFrom(from, to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, from, id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } /*////////////////////////////////////////////////////////////// ERC165 LOGIC //////////////////////////////////////////////////////////////*/ function supportsInterface(bytes4 interfaceId) public view virtual returns (bool) { return interfaceId == 0x01ffc9a7 || // ERC165 Interface ID for ERC165 interfaceId == 0x80ac58cd || // ERC165 Interface ID for ERC721 interfaceId == 0x5b5e139f; // ERC165 Interface ID for ERC721Metadata } /*////////////////////////////////////////////////////////////// INTERNAL MINT/BURN LOGIC //////////////////////////////////////////////////////////////*/ function _mint(address to, uint256 id) internal virtual { require(to != address(0), "INVALID_RECIPIENT"); require(_ownerOf[id] == address(0), "ALREADY_MINTED"); // Counter overflow is incredibly unrealistic. unchecked { _balanceOf[to]++; } _ownerOf[id] = to; emit Transfer(address(0), to, id); } function _burn(uint256 id) internal virtual { address owner = _ownerOf[id]; require(owner != address(0), "NOT_MINTED"); // Ownership check above ensures no underflow. unchecked { _balanceOf[owner]--; } delete _ownerOf[id]; delete getApproved[id]; emit Transfer(owner, address(0), id); } /*////////////////////////////////////////////////////////////// INTERNAL SAFE MINT LOGIC //////////////////////////////////////////////////////////////*/ function _safeMint(address to, uint256 id) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, "") == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } function _safeMint( address to, uint256 id, bytes memory data ) internal virtual { _mint(to, id); require( to.code.length == 0 || ERC721TokenReceiver(to).onERC721Received(msg.sender, address(0), id, data) == ERC721TokenReceiver.onERC721Received.selector, "UNSAFE_RECIPIENT" ); } } /// @notice A generic interface for a contract which properly accepts ERC721 tokens. /// @author Solmate (https://github.com/transmissions11/solmate/blob/main/src/tokens/ERC721.sol) abstract contract ERC721TokenReceiver { function onERC721Received( address, address, uint256, bytes calldata ) external virtual returns (bytes4) { return ERC721TokenReceiver.onERC721Received.selector; } }
// SPDX-License-Identifier: UNLICENSED pragma solidity ^0.8.15; import "solmate/tokens/ERC721.sol"; import "solmate/auth/Owned.sol"; import "solady/utils/LibString.sol"; /// @title GobDrops /// @author EtDu contract GobDrops is ERC721, Owned { using LibString for uint256; uint256 public totalSupply = 0; string public baseURI; address public admin; modifier onlyAdmin() { require(msg.sender == admin, "Must be admin!"); _; } constructor(address adminAddress) ERC721("GOB DROPS", "DROP") Owned(msg.sender) { admin = adminAddress; } /// @notice Mint new trait. Only callable by ETH Gobblers contract on trait unlock. /// @param user User address to claim the NFT trait. function mint(address user) external onlyOwner { _mint(user, totalSupply); unchecked { totalSupply++; } } function tokenURI(uint tokenID) public view override returns (string memory) { require(tokenID < totalSupply, "This token does not exist"); return bytes(baseURI).length > 0 ? string(abi.encodePacked(baseURI, tokenID.toString())) : ""; } function changeBaseURI(string calldata newBaseURI) external onlyAdmin { baseURI = newBaseURI; } function changeAdmin(address newAdmin) external onlyAdmin { admin = newAdmin; } function withdraw() external onlyAdmin { assembly { let result := call(0, caller(), selfbalance(), 0, 0, 0, 0) switch result case 0 { revert(0, 0) } default { return(0, 0) } } } }
{ "remappings": [ "ds-test/=lib/solmate/lib/ds-test/src/", "forge-std/=lib/forge-std/src/", "solady/=lib/solady/src/", "solmate/=lib/solmate/src/" ], "optimizer": { "enabled": true, "runs": 200 }, "metadata": { "bytecodeHash": "ipfs" }, "outputSelection": { "*": { "*": [ "evm.bytecode", "evm.deployedBytecode", "devdoc", "userdoc", "metadata", "abi" ] } }, "evmVersion": "london", "libraries": {} }
Contract Security Audit
- No Contract Security Audit Submitted- Submit Audit Here
[{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","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":"approved","type":"bool"}],"name":"ApprovalForAll","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Bury","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"traitIDs","type":"uint256"}],"name":"ConfigureTraits","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"amount","type":"uint8"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Feed","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"gobblerGobblerID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"victimID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newGobblerGobblerID","type":"uint256"}],"name":"GobblerGobbled","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"uint8","name":"amount","type":"uint8"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Groom","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"parentTokenID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newTokenID","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Mitosis","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"user","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"tokenID","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"Sleep","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint256","name":"parentGobblerID","type":"uint256"},{"indexed":true,"internalType":"uint256","name":"newTraitTokenID","type":"uint256"},{"indexed":true,"internalType":"address","name":"owner","type":"address"}],"name":"TraitUnlocked","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":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"ETHGobbled","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"enum ETHGobblers.Action","name":"action","type":"uint8"},{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint8","name":"amount","type":"uint8"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"actionAlive","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"approve","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"baseURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"bury","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"newBaseURI","type":"string"}],"name":"changeBaseURI","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"changeFeedPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"changeGobbleGobblerPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"changeGroomPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"signer","type":"address"}],"name":"changeSigner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"price","type":"uint256"}],"name":"changeSleepPrice","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"traitIDs","type":"uint256"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"configureTraits","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"currentGobblerGobbler","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"equippedTraits","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"feedPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"flipPaused","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"getApproved","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"getTraitConfiguration","outputs":[{"internalType":"uint32","name":"wings","type":"uint32"},{"internalType":"uint32","name":"sidekick","type":"uint32"},{"internalType":"uint32","name":"food","type":"uint32"},{"internalType":"uint32","name":"accessory","type":"uint32"},{"internalType":"uint32","name":"weather","type":"uint32"},{"internalType":"uint32","name":"cushion","type":"uint32"},{"internalType":"uint32","name":"inflight","type":"uint32"},{"internalType":"uint32","name":"freeSlot","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"gobDrops","outputs":[{"internalType":"contract GobDrops","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"gobblerGobblerTokenID","type":"uint256"},{"internalType":"uint256","name":"victimTokenID","type":"uint256"},{"internalType":"uint256","name":"newGobblerGobbler","type":"uint256"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"gobbleGobbler","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"gobbleGobblerPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"groomPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"thisContract","type":"address"},{"internalType":"bytes4","name":"functionNameSig","type":"bytes4"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"hashMessage","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"thisContract","type":"address"},{"internalType":"bytes4","name":"functionNameSig","type":"bytes4"},{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"hashMessageBury","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"thisContract","type":"address"},{"internalType":"bytes4","name":"functionNameSig","type":"bytes4"},{"internalType":"uint256","name":"traitIDs","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"hashMessageConfigureTraits","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender","type":"address"},{"internalType":"address","name":"thisContract","type":"address"},{"internalType":"bytes4","name":"functionNameSig","type":"bytes4"},{"internalType":"uint256","name":"newGobblerGobbler","type":"uint256"},{"internalType":"uint256","name":"nonce","type":"uint256"}],"name":"hashMessageGobbleGobbler","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"isApprovedForAll","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"mitosis","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"mitosisSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"id","type":"uint256"}],"name":"ownerOf","outputs":[{"internalType":"address","name":"owner","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"paused","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"id","type":"uint256"}],"name":"safeTransferFrom","outputs":[],"stateMutability":"nonpayable","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":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"operator","type":"address"},{"internalType":"bool","name":"approved","type":"bool"}],"name":"setApprovalForAll","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"setGobblerGobbler","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"signatureNonce","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"signerAddress","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"sleepPrice","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes4","name":"interfaceId","type":"bytes4"}],"name":"supportsInterface","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"}],"name":"tokenURI","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"tokenID","type":"uint256"},{"internalType":"bytes32","name":"messageHash","type":"bytes32"},{"internalType":"bytes","name":"signature","type":"bytes"}],"name":"unlockTrait","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"withdraw","outputs":[],"stateMutability":"nonpayable","type":"function"}]
Contract Creation Code
60806040526000600755600060085566038d7ea4c68000600a55662386f26fc10000600b5567016345785d8a0000600c55670de0b6b3a7640000600d553480156200004957600080fd5b50604051620043e1380380620043e18339810160408190526200006c91620001b3565b336040518060400160405280600c81526020016b45544820474f42424c45525360a01b81525060405180604001604052806005815260200164474f4f455960d81b8152508160009081620000c191906200028a565b506001620000d082826200028a565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350601080546001600160a01b0319166001600160a01b03831617905560405133906200014a90620001a5565b6001600160a01b039091168152602001604051809103906000f08015801562000177573d6000803e3d6000fd5b50600f60016101000a8154816001600160a01b0302191690836001600160a01b031602179055505062000356565b6115c48062002e1d83390190565b600060208284031215620001c657600080fd5b81516001600160a01b0381168114620001de57600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200021057607f821691505b6020821081036200023157634e487b7160e01b600052602260045260246000fd5b50919050565b601f8211156200028557600081815260208120601f850160051c81016020861015620002605750805b601f850160051c820191505b8181101562000281578281556001016200026c565b5050505b505050565b81516001600160401b03811115620002a657620002a6620001e5565b620002be81620002b78454620001fb565b8462000237565b602080601f831160018114620002f65760008415620002dd5750858301515b600019600386901b1c1916600185901b17855562000281565b600085815260208120601f198616915b82811015620003275788860151825594840194600190910190840162000306565b5085821015620003465787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b612ab780620003666000396000f3fe6080604052600436106102c95760003560e01c80636c0360eb11610175578063a78c2965116100dc578063bac91c6a11610095578063d2d1cd4f1161006f578063d2d1cd4f146108ec578063e985e9c514610902578063f12615d61461093d578063f2fde38b1461095357600080fd5b8063bac91c6a1461088c578063c6b4102d146108ac578063c87b56dd146108cc57600080fd5b8063a78c296514610561578063aad2b723146107f9578063acd379cc14610819578063adc4f2bf14610839578063ae4875971461084c578063b88d4fde1461086c57600080fd5b806378e0b7601161012e57806378e0b760146106b35780638d7ba8ba146106d35780638da5cb5b1461078e57806395d89b41146107ae578063a04eecae146107c3578063a22cb465146107d957600080fd5b80636c0360eb146106085780636e33a9fb1461061d5780636ff5dfd41461063d578063700bfe001461065357806370a082311461066657806377f7a5cd1461068657600080fd5b80632ed73d681161023457806342842e0e116101ed5780635b7633d0116101c75780635b7633d0146105ae5780635c975abb146105ce5780635c9c01d1146105615780636352211e146105e857600080fd5b806342842e0e146105415780634db8f13c14610561578063567e34ba1461058157600080fd5b80632ed73d6814610494578063333171bb146104c1578063354cfe43146104d657806339a0c6f9146104f65780633a5a2995146105165780633ccfd60b1461052c57600080fd5b806318160ddd1161028657806318160ddd146103de5780631cdfffa4146103f45780631e7553821461041457806323b872dd1461043457806329ec57a1146104545780632b76f8ea1461047457600080fd5b806301ffc9a7146102ce57806306fdde031461030357806307de128e14610325578063081812fc14610362578063095ea7b314610398578063152d92da146103ba575b600080fd5b3480156102da57600080fd5b506102ee6102e9366004612188565b610973565b60405190151581526020015b60405180910390f35b34801561030f57600080fd5b506103186109c5565b6040516102fa91906121d5565b34801561033157600080fd5b50600f5461034a9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020016102fa565b34801561036e57600080fd5b5061034a61037d366004612208565b6004602052600090815260409020546001600160a01b031681565b3480156103a457600080fd5b506103b86103b3366004612238565b610a53565b005b3480156103c657600080fd5b506103d060095481565b6040519081526020016102fa565b3480156103ea57600080fd5b506103d060075481565b34801561040057600080fd5b506103b861040f366004612208565b610b3a565b34801561042057600080fd5b506103b861042f3660046122ab565b610b69565b34801561044057600080fd5b506103b861044f3660046122fe565b610d27565b34801561046057600080fd5b506103b861046f366004612208565b610edc565b34801561048057600080fd5b506103b861048f366004612208565b610f0b565b3480156104a057600080fd5b506103d06104af366004612208565b60126020526000908152604090205481565b3480156104cd57600080fd5b506103b8610f3a565b3480156104e257600080fd5b506103d06104f136600461233a565b610f78565b34801561050257600080fd5b506103b8610511366004612387565b610fdb565b34801561052257600080fd5b506103d0600b5481565b34801561053857600080fd5b506103b8611017565b34801561054d57600080fd5b506103b861055c3660046122fe565b611059565b34801561056d57600080fd5b506103d061057c3660046123c9565b61114c565b34801561058d57600080fd5b506103d061059c366004612420565b60136020526000908152604090205481565b3480156105ba57600080fd5b5060105461034a906001600160a01b031681565b3480156105da57600080fd5b50600f546102ee9060ff1681565b3480156105f457600080fd5b5061034a610603366004612208565b6111b7565b34801561061457600080fd5b5061031861120e565b34801561062957600080fd5b506103b8610638366004612208565b61121b565b34801561064957600080fd5b506103d0600c5481565b6103b861066136600461243b565b61124a565b34801561067257600080fd5b506103d0610681366004612420565b611489565b34801561069257600080fd5b506103d06106a1366004612208565b60116020526000908152604090205481565b3480156106bf57600080fd5b506103b86106ce3660046122ab565b6114ec565b3480156106df57600080fd5b5061073f6106ee366004612208565b6000908152601160209081526040918290205460e081901c9363ffffffff60c083901c81169460a084901c821694608085901c831694606081901c8416949281901c8416939181901c821692911690565b6040805163ffffffff998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a0840152831660c083015290911660e0820152610100016102fa565b34801561079a57600080fd5b5060065461034a906001600160a01b031681565b3480156107ba57600080fd5b50610318611632565b3480156107cf57600080fd5b506103d0600a5481565b3480156107e557600080fd5b506103b86107f43660046124a5565b61163f565b34801561080557600080fd5b506103b8610814366004612420565b6116ab565b34801561082557600080fd5b506103b86108343660046124e1565b6116f7565b6103b861084736600461252d565b611836565b34801561085857600080fd5b506103b8610867366004612595565b611a6b565b34801561087857600080fd5b506103b86108873660046125f6565b611b66565b34801561089857600080fd5b506103b86108a7366004612208565b611c4e565b3480156108b857600080fd5b506103b86108c73660046122ab565b611c7d565b3480156108d857600080fd5b506103186108e7366004612208565b611e44565b3480156108f857600080fd5b506103d060085481565b34801561090e57600080fd5b506102ee61091d366004612648565b600560209081526000928352604080842090915290825290205460ff1681565b34801561094957600080fd5b506103d0600d5481565b34801561095f57600080fd5b506103b861096e366004612420565b611ef3565b60006301ffc9a760e01b6001600160e01b0319831614806109a457506380ac58cd60e01b6001600160e01b03198316145b806109bf5750635b5e139f60e01b6001600160e01b03198316145b92915050565b600080546109d29061267b565b80601f01602080910402602001604051908101604052809291908181526020018280546109fe9061267b565b8015610a4b5780601f10610a2057610100808354040283529160200191610a4b565b820191906000526020600020905b815481529060010190602001808311610a2e57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610a9c57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610ade5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b03163314610b645760405162461bcd60e51b8152600401610ad5906126b5565b600a55565b82610bb83330604051602001610b8990636275727960e01b815260040190565b604051602081830303815290604052610ba1906126db565b33600090815260136020526040902054899061114c565b14610bd55760405162461bcd60e51b8152600401610ad590612712565b610be0838383611f69565b610bfc5760405162461bcd60e51b8152600401610ad59061273f565b6000610c07856111b7565b90506001600160a01b038116610c4c5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ad5565b6001600160a01b038116600081815260036020908152604080832080546000190190557f262bb27bbdd95c1cdc8e16957e36e38579ea44f7f6413dd7a9c75939def06b2c8054600101905588835260028252808320805461dead6001600160a01b03199182168117909255600490935281842080549093169092555188939192600080516020612a6283398151915291a4604051339086907f6d1f829e44cf0d38014e70d7b78b7a4251f29b55b319b387f7dd98359685c81d90600090a3505033600090815260136020526040902080546001019055505050565b6000818152600260205260409020546001600160a01b03848116911614610d7d5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610ad5565b6001600160a01b038216610dc75760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ad5565b336001600160a01b0384161480610e0157506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80610e2257506000818152600460205260409020546001600160a01b031633145b610e5f5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ad5565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b0319908116831790915560049092528483208054909216909155925184939291600080516020612a6283398151915291a4505050565b6006546001600160a01b03163314610f065760405162461bcd60e51b8152600401610ad5906126b5565b600c55565b6006546001600160a01b03163314610f355760405162461bcd60e51b8152600401610ad5906126b5565b600955565b6006546001600160a01b03163314610f645760405162461bcd60e51b8152600401610ad5906126b5565b600f805460ff19811660ff90911615179055565b6040516bffffffffffffffffffffffff19606086811b8216602084015285901b1660348201526001600160e01b031983166048820152604c8101829052600090606c01604051602081830303815290604052805190602001209050949350505050565b6006546001600160a01b031633146110055760405162461bcd60e51b8152600401610ad5906126b5565b600e6110128284836127d3565b505050565b6006546001600160a01b031633146110415760405162461bcd60e51b8152600401610ad5906126b5565b600080818283473386f18015611055578182f35b8182fd5b611064838383610d27565b6001600160a01b0382163b158061110d5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156110dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111019190612893565b6001600160e01b031916145b6110125760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ad5565b6040516bffffffffffffffffffffffff19606087811b8216602084015286901b1660348201526001600160e01b031984166048820152604c8101839052606c8101829052600090608c0160405160208183030381529060405280519060200120905095945050505050565b6000818152600260205260409020546001600160a01b0316806112095760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ad5565b919050565b600e80546109d29061267b565b6006546001600160a01b031633146112455760405162461bcd60e51b8152600401610ad5906126b5565b600b55565b853380611256836111b7565b6001600160a01b03161461127c5760405162461bcd60e51b8152600401610ad5906128b0565b87600954146112cd5760405162461bcd60e51b815260206004820152601c60248201527f4d7573742062652074686520476f62626c657220476f62626c657221000000006044820152606401610ad5565b600d5434146113155760405162461bcd60e51b81526020600482015260146024820152734e6f7420656e6f756768204554482073656e742160601b6044820152606401610ad5565b8461136d333060405160200161133e906c33b7b1313632a3b7b1313632b960991b8152600d0190565b604051602081830303815290604052611356906126db565b336000908152601360205260409020548b9061114c565b1461138a5760405162461bcd60e51b8152600401610ad590612712565b611395858585611f69565b6113b15760405162461bcd60e51b8152600401610ad59061273f565b60006113bc886111b7565b6001600160a01b0381166000818152600360209081526040808320805460001901905533808452818420805460010190558d84526002835281842080546001600160a01b0319908116831790915560049093528184208054909316909255519394508b93909291600080516020612a6283398151915291a486888a7f5fa0b7a4af71eaeec6c8b4e527f1c7d57b68825c59afce15cf5f7677fa4ae9cb60405160405180910390a4505050600993909355505033600090815260136020526040902080546001019055505050565b60006001600160a01b0382166114d05760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610ad5565b506001600160a01b031660009081526003602052604090205490565b8333806114f8836111b7565b6001600160a01b03161461151e5760405162461bcd60e51b8152600401610ad5906128b0565b8461156e333060405160200161154190666d69746f73697360c81b815260070190565b604051602081830303815290604052611559906126db565b33600090815260136020526040902054610f78565b1461158b5760405162461bcd60e51b8152600401610ad590612712565b611596858585611f69565b6115b25760405162461bcd60e51b8152600401610ad59061273f565b60006008546107d06115c491906128f3565b90506115d03382611fc3565b6040513390829089907fc115e05e23155867c7e139d51a6e7b80d8e9d029655b6f810119c030b973921b90600090a450506008805460019081019091556007805482019055336000908152601360205260409020805490910190555050505050565b600180546109d29061267b565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6006546001600160a01b031633146116d55760405162461bcd60e51b8152600401610ad5906126b5565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b6107d0600754600161170991906128f3565b11156117575760405162461bcd60e51b815260206004820152601a60248201527f47656e65736973206d617820737570706c7920726561636865640000000000006044820152606401610ad5565b600f5460ff161561179f5760405162461bcd60e51b8152602060048201526012602482015271135d5cdd081b9bdd081899481c185d5cd95960721b6044820152606401610ad5565b826117bf333060405160200161154190631b5a5b9d60e21b815260040190565b146117dc5760405162461bcd60e51b8152600401610ad590612712565b6117e7838383611f69565b6118035760405162461bcd60e51b8152600401610ad59061273f565b61180f33600754611fc3565b50506007805460019081019091553360009081526013602052604090208054909101905550565b843380611842836111b7565b6001600160a01b0316146118685760405162461bcd60e51b8152600401610ad5906128b0565b8461188f3330604051602001611541906a616374696f6e416c69766560a81b8152600b0190565b146118ac5760405162461bcd60e51b8152600401610ad590612712565b6118b7858585611f69565b6118d35760405162461bcd60e51b8152600401610ad59061273f565b60008860028111156118e7576118e761290b565b03611952578560ff16600a546118fd9190612921565b341461191b5760405162461bcd60e51b8152600401610ad590612940565b604051339060ff88169089907f34451d2406ea78fab417966fed7c007ca3143382b25cee653588abb9c8d9f00890600090a4611a39565b60018860028111156119665761196661290b565b036119d1578560ff16600b5461197c9190612921565b341461199a5760405162461bcd60e51b8152600401610ad590612940565b604051339060ff88169089907f9515093a0215bb0e2e2244374ea65a5c55b4e40f728f2255977d3aa2881e8c5090600090a4611a39565b60028860028111156119e5576119e561290b565b03611a3957600c543414611a0b5760405162461bcd60e51b8152600401610ad590612940565b604051339088907f2057376b06556f4cca13bb6be220c9eeae3ca2531e0e2dfd8f21126e56b8b61790600090a35b505050600093845250506012602090815260408084208054340190553384526013909152909120805460010190555050565b843380611a77836111b7565b6001600160a01b031614611a9d5760405162461bcd60e51b8152600401610ad5906128b0565b84611ac8333060405160200161133e906e636f6e66696775726554726169747360881b8152600f0190565b14611ae55760405162461bcd60e51b8152600401610ad590612712565b611af0858585611f69565b611b0c5760405162461bcd60e51b8152600401610ad59061273f565b60008781526011602052604080822088905551879189917f8f25dfe3ab2aa69e8c75a62082e281bad5a6837df174231b2e79db6cd67372aa9190a35050336000908152601360205260409020805460010190555050505050565b611b71858585610d27565b6001600160a01b0384163b1580611c085750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611bb99033908a9089908990899060040161296d565b6020604051808303816000875af1158015611bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfc9190612893565b6001600160e01b031916145b611c475760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ad5565b5050505050565b6006546001600160a01b03163314611c785760405162461bcd60e51b8152600401610ad5906126b5565b600d55565b833380611c89836111b7565b6001600160a01b031614611caf5760405162461bcd60e51b8152600401610ad5906128b0565b84611cd63330604051602001611541906a1d5b9b1bd8dad51c985a5d60aa1b8152600b0190565b14611cf35760405162461bcd60e51b8152600401610ad590612712565b611cfe858585611f69565b611d1a5760405162461bcd60e51b8152600401610ad59061273f565b6000600f60019054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9391906129c1565b600f546040516335313c2160e11b815233600482015291925061010090046001600160a01b031690636a62784290602401600060405180830381600087803b158015611dde57600080fd5b505af1158015611df2573d6000803e3d6000fd5b505060405133925083915089907fb9fd29c6d3a708dc686fbd2bb7d536911b863fda0a12c8e450aa88104108691390600090a45050336000908152601360205260409020805460010190555050505050565b60606007548210611e975760405162461bcd60e51b815260206004820152601960248201527f5468697320746f6b656e20646f6573206e6f74206578697374000000000000006044820152606401610ad5565b6000600e8054611ea69061267b565b905011611ec257604051806020016040528060008152506109bf565b600e611ecd836120bc565b604051602001611ede9291906129da565b60405160208183030381529060405292915050565b6006546001600160a01b03163314611f1d5760405162461bcd60e51b8152600401610ad5906126b5565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600080611fa78484611fa0886020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b9190612100565b6010546001600160a01b039081169116149150505b9392505050565b6001600160a01b03821661200d5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ad5565b6000818152600260205260409020546001600160a01b0316156120635760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610ad5565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020612a62833981519152908290a45050565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a9004806120d65750819003601f19909101908152919050565b600060418203611fbc576040516040846040377f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0606051116121655784600052604084013560001a602052602060406080600060015afa5060006060523d6060035191505b6040529392505050565b6001600160e01b03198116811461218557600080fd5b50565b60006020828403121561219a57600080fd5b8135611fbc8161216f565b60005b838110156121c05781810151838201526020016121a8565b838111156121cf576000848401525b50505050565b60208152600082518060208401526121f48160408501602087016121a5565b601f01601f19169190910160400192915050565b60006020828403121561221a57600080fd5b5035919050565b80356001600160a01b038116811461120957600080fd5b6000806040838503121561224b57600080fd5b61225483612221565b946020939093013593505050565b60008083601f84011261227457600080fd5b50813567ffffffffffffffff81111561228c57600080fd5b6020830191508360208285010111156122a457600080fd5b9250929050565b600080600080606085870312156122c157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156122e657600080fd5b6122f287828801612262565b95989497509550505050565b60008060006060848603121561231357600080fd5b61231c84612221565b925061232a60208501612221565b9150604084013590509250925092565b6000806000806080858703121561235057600080fd5b61235985612221565b935061236760208601612221565b925060408501356123778161216f565b9396929550929360600135925050565b6000806020838503121561239a57600080fd5b823567ffffffffffffffff8111156123b157600080fd5b6123bd85828601612262565b90969095509350505050565b600080600080600060a086880312156123e157600080fd5b6123ea86612221565b94506123f860208701612221565b935060408601356124088161216f565b94979396509394606081013594506080013592915050565b60006020828403121561243257600080fd5b611fbc82612221565b60008060008060008060a0878903121561245457600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff81111561248757600080fd5b61249389828a01612262565b979a9699509497509295939492505050565b600080604083850312156124b857600080fd5b6124c183612221565b9150602083013580151581146124d657600080fd5b809150509250929050565b6000806000604084860312156124f657600080fd5b83359250602084013567ffffffffffffffff81111561251457600080fd5b61252086828701612262565b9497909650939450505050565b60008060008060008060a0878903121561254657600080fd5b86356003811061255557600080fd5b955060208701359450604087013560ff8116811461257257600080fd5b935060608701359250608087013567ffffffffffffffff81111561248757600080fd5b6000806000806000608086880312156125ad57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8111156125d957600080fd5b6125e588828901612262565b969995985093965092949392505050565b60008060008060006080868803121561260e57600080fd5b61261786612221565b945061262560208701612221565b935060408601359250606086013567ffffffffffffffff8111156125d957600080fd5b6000806040838503121561265b57600080fd5b61266483612221565b915061267260208401612221565b90509250929050565b600181811c9082168061268f57607f821691505b6020821081036126af57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b805160208201516001600160e01b0319808216929190600483101561270a5780818460040360031b1b83161693505b505050919050565b60208082526013908201527257726f6e67206d65737361676520686173682160681b604082015260600190565b60208082526016908201527524b73b30b634b21030b2323932b9b99039b4b3b732b960511b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b601f82111561101257600081815260208120601f850160051c810160208610156127ac5750805b601f850160051c820191505b818110156127cb578281556001016127b8565b505050505050565b67ffffffffffffffff8311156127eb576127eb61276f565b6127ff836127f9835461267b565b83612785565b6000601f841160018114612833576000851561281b5750838201355b600019600387901b1c1916600186901b178355611c47565b600083815260209020601f19861690835b828110156128645786850135825560209485019460019092019101612844565b50868210156128815760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000602082840312156128a557600080fd5b8151611fbc8161216f565b60208082526013908201527226bab9ba103132903a37b5b2b71037bbb732b960691b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115612906576129066128dd565b500190565b634e487b7160e01b600052602160045260246000fd5b600081600019048311821515161561293b5761293b6128dd565b500290565b602080825260139082015272139bdd08195b9bdd59da081155120814d95b9d606a1b604082015260600190565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b6000602082840312156129d357600080fd5b5051919050565b60008084546129e88161267b565b60018281168015612a005760018114612a1557612a44565b60ff1984168752821515830287019450612a44565b8860005260208060002060005b85811015612a3b5781548a820152908401908201612a22565b50505082870194505b505050508351612a588183602088016121a5565b0194935050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220a70f8a086a9ef20b7c707e9b3f89f48c61d615dedeb263013c00bd0ef1e78ba864736f6c634300080f0033608060405260006007553480156200001657600080fd5b50604051620015c4380380620015c483398101604081905262000039916200010e565b3360405180604001604052806009815260200168474f422044524f505360b81b81525060405180604001604052806004815260200163044524f560e41b81525081600090816200008a9190620001e5565b506001620000998282620001e5565b5050600680546001600160a01b0319166001600160a01b0384169081179091556040519091506000907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e0908290a350600980546001600160a01b0319166001600160a01b0392909216919091179055620002b1565b6000602082840312156200012157600080fd5b81516001600160a01b03811681146200013957600080fd5b9392505050565b634e487b7160e01b600052604160045260246000fd5b600181811c908216806200016b57607f821691505b6020821081036200018c57634e487b7160e01b600052602260045260246000fd5b50919050565b601f821115620001e057600081815260208120601f850160051c81016020861015620001bb5750805b601f850160051c820191505b81811015620001dc57828155600101620001c7565b5050505b505050565b81516001600160401b0381111562000201576200020162000140565b620002198162000212845462000156565b8462000192565b602080601f831160018114620002515760008415620002385750858301515b600019600386901b1c1916600185901b178555620001dc565b600085815260208120601f198616915b82811015620002825788860151825594840194600190910190840162000261565b5085821015620002a15787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b61130380620002c16000396000f3fe608060405234801561001057600080fd5b50600436106101425760003560e01c80636c0360eb116100b8578063a22cb4651161007c578063a22cb465146102a1578063b88d4fde146102b4578063c87b56dd146102c7578063e985e9c5146102da578063f2fde38b14610308578063f851a4401461031b57600080fd5b80636c0360eb1461025857806370a08231146102605780638da5cb5b146102735780638f2839701461028657806395d89b411461029957600080fd5b806323b872dd1161010a57806323b872dd146101f157806339a0c6f9146102045780633ccfd60b1461021757806342842e0e1461021f5780636352211e146102325780636a6278421461024557600080fd5b806301ffc9a71461014757806306fdde031461016f578063081812fc14610184578063095ea7b3146101c557806318160ddd146101da575b600080fd5b61015a610155366004610dae565b61032e565b60405190151581526020015b60405180910390f35b610177610380565b6040516101669190610e02565b6101ad610192366004610e35565b6004602052600090815260409020546001600160a01b031681565b6040516001600160a01b039091168152602001610166565b6101d86101d3366004610e65565b61040e565b005b6101e360075481565b604051908152602001610166565b6101d86101ff366004610e8f565b6104f5565b6101d8610212366004610f14565b6106bc565b6101d86106f8565b6101d861022d366004610e8f565b61073a565b6101ad610240366004610e35565b61082d565b6101d8610253366004610f56565b610884565b6101776108e5565b6101e361026e366004610f56565b6108f2565b6006546101ad906001600160a01b031681565b6101d8610294366004610f56565b610955565b6101776109a1565b6101d86102af366004610f71565b6109ae565b6101d86102c2366004610fad565b610a1a565b6101776102d5366004610e35565b610b02565b61015a6102e836600461101c565b600560209081526000928352604080842090915290825290205460ff1681565b6101d8610316366004610f56565b610bb1565b6009546101ad906001600160a01b031681565b60006301ffc9a760e01b6001600160e01b03198316148061035f57506380ac58cd60e01b6001600160e01b03198316145b8061037a5750635b5e139f60e01b6001600160e01b03198316145b92915050565b6000805461038d9061104f565b80601f01602080910402602001604051908101604052809291908181526020018280546103b99061104f565b80156104065780601f106103db57610100808354040283529160200191610406565b820191906000526020600020905b8154815290600101906020018083116103e957829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b03163381148061045757506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b6104995760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6000818152600260205260409020546001600160a01b0384811691161461054b5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610490565b6001600160a01b0382166105955760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610490565b336001600160a01b03841614806105cf57506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b806105f057506000818152600460205260409020546001600160a01b031633145b61062d5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610490565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b03199081168317909155600490925284832080549092169091559251849392917fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91a4505050565b6009546001600160a01b031633146106e65760405162461bcd60e51b815260040161049090611089565b60086106f3828483611115565b505050565b6009546001600160a01b031633146107225760405162461bcd60e51b815260040161049090611089565b600080818283473386f18015610736578182f35b8182fd5b6107458383836104f5565b6001600160a01b0382163b15806107ee5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156107be573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906107e291906111d5565b6001600160e01b031916145b6106f35760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610490565b6000818152600260205260409020546001600160a01b03168061087f5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610490565b919050565b6006546001600160a01b031633146108cd5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610490565b6108d981600754610c46565b50600780546001019055565b6008805461038d9061104f565b60006001600160a01b0382166109395760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610490565b506001600160a01b031660009081526003602052604090205490565b6009546001600160a01b0316331461097f5760405162461bcd60e51b815260040161049090611089565b600980546001600160a01b0319166001600160a01b0392909216919091179055565b6001805461038d9061104f565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b610a258585856104f5565b6001600160a01b0384163b1580610abc5750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290610a6d9033908a908990899089906004016111f2565b6020604051808303816000875af1158015610a8c573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610ab091906111d5565b6001600160e01b031916145b610afb5760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610490565b5050505050565b60606007548210610b555760405162461bcd60e51b815260206004820152601960248201527f5468697320746f6b656e20646f6573206e6f74206578697374000000000000006044820152606401610490565b600060088054610b649061104f565b905011610b80576040518060200160405280600081525061037a565b6008610b8b83610d51565b604051602001610b9c929190611246565b60405160208183030381529060405292915050565b6006546001600160a01b03163314610bfa5760405162461bcd60e51b815260206004820152600c60248201526b15539055551213d49256915160a21b6044820152606401610490565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b6001600160a01b038216610c905760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610490565b6000818152600260205260409020546001600160a01b031615610ce65760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610490565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b0319168417905551839291907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef908290a45050565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a900480610d6b5750819003601f19909101908152919050565b6001600160e01b031981168114610dab57600080fd5b50565b600060208284031215610dc057600080fd5b8135610dcb81610d95565b9392505050565b60005b83811015610ded578181015183820152602001610dd5565b83811115610dfc576000848401525b50505050565b6020815260008251806020840152610e21816040850160208701610dd2565b601f01601f19169190910160400192915050565b600060208284031215610e4757600080fd5b5035919050565b80356001600160a01b038116811461087f57600080fd5b60008060408385031215610e7857600080fd5b610e8183610e4e565b946020939093013593505050565b600080600060608486031215610ea457600080fd5b610ead84610e4e565b9250610ebb60208501610e4e565b9150604084013590509250925092565b60008083601f840112610edd57600080fd5b50813567ffffffffffffffff811115610ef557600080fd5b602083019150836020828501011115610f0d57600080fd5b9250929050565b60008060208385031215610f2757600080fd5b823567ffffffffffffffff811115610f3e57600080fd5b610f4a85828601610ecb565b90969095509350505050565b600060208284031215610f6857600080fd5b610dcb82610e4e565b60008060408385031215610f8457600080fd5b610f8d83610e4e565b915060208301358015158114610fa257600080fd5b809150509250929050565b600080600080600060808688031215610fc557600080fd5b610fce86610e4e565b9450610fdc60208701610e4e565b935060408601359250606086013567ffffffffffffffff811115610fff57600080fd5b61100b88828901610ecb565b969995985093965092949392505050565b6000806040838503121561102f57600080fd5b61103883610e4e565b915061104660208401610e4e565b90509250929050565b600181811c9082168061106357607f821691505b60208210810361108357634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600e908201526d4d7573742062652061646d696e2160901b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b601f8211156106f357600081815260208120601f850160051c810160208610156110ee5750805b601f850160051c820191505b8181101561110d578281556001016110fa565b505050505050565b67ffffffffffffffff83111561112d5761112d6110b1565b6111418361113b835461104f565b836110c7565b6000601f841160018114611175576000851561115d5750838201355b600019600387901b1c1916600186901b178355610afb565b600083815260209020601f19861690835b828110156111a65786850135825560209485019460019092019101611186565b50868210156111c35760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000602082840312156111e757600080fd5b8151610dcb81610d95565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b60008084546112548161104f565b6001828116801561126c5760018114611281576112b0565b60ff19841687528215158302870194506112b0565b8860005260208060002060005b858110156112a75781548a82015290840190820161128e565b50505082870194505b5050505083516112c4818360208801610dd2565b0194935050505056fea2646970667358221220990304457e708a25e68d2f5222265656b5425adafa79d427414d69a00f5b641864736f6c634300080f003300000000000000000000000055c485924ececa49782d55d615bfde48856e2651
Deployed Bytecode
0x6080604052600436106102c95760003560e01c80636c0360eb11610175578063a78c2965116100dc578063bac91c6a11610095578063d2d1cd4f1161006f578063d2d1cd4f146108ec578063e985e9c514610902578063f12615d61461093d578063f2fde38b1461095357600080fd5b8063bac91c6a1461088c578063c6b4102d146108ac578063c87b56dd146108cc57600080fd5b8063a78c296514610561578063aad2b723146107f9578063acd379cc14610819578063adc4f2bf14610839578063ae4875971461084c578063b88d4fde1461086c57600080fd5b806378e0b7601161012e57806378e0b760146106b35780638d7ba8ba146106d35780638da5cb5b1461078e57806395d89b41146107ae578063a04eecae146107c3578063a22cb465146107d957600080fd5b80636c0360eb146106085780636e33a9fb1461061d5780636ff5dfd41461063d578063700bfe001461065357806370a082311461066657806377f7a5cd1461068657600080fd5b80632ed73d681161023457806342842e0e116101ed5780635b7633d0116101c75780635b7633d0146105ae5780635c975abb146105ce5780635c9c01d1146105615780636352211e146105e857600080fd5b806342842e0e146105415780634db8f13c14610561578063567e34ba1461058157600080fd5b80632ed73d6814610494578063333171bb146104c1578063354cfe43146104d657806339a0c6f9146104f65780633a5a2995146105165780633ccfd60b1461052c57600080fd5b806318160ddd1161028657806318160ddd146103de5780631cdfffa4146103f45780631e7553821461041457806323b872dd1461043457806329ec57a1146104545780632b76f8ea1461047457600080fd5b806301ffc9a7146102ce57806306fdde031461030357806307de128e14610325578063081812fc14610362578063095ea7b314610398578063152d92da146103ba575b600080fd5b3480156102da57600080fd5b506102ee6102e9366004612188565b610973565b60405190151581526020015b60405180910390f35b34801561030f57600080fd5b506103186109c5565b6040516102fa91906121d5565b34801561033157600080fd5b50600f5461034a9061010090046001600160a01b031681565b6040516001600160a01b0390911681526020016102fa565b34801561036e57600080fd5b5061034a61037d366004612208565b6004602052600090815260409020546001600160a01b031681565b3480156103a457600080fd5b506103b86103b3366004612238565b610a53565b005b3480156103c657600080fd5b506103d060095481565b6040519081526020016102fa565b3480156103ea57600080fd5b506103d060075481565b34801561040057600080fd5b506103b861040f366004612208565b610b3a565b34801561042057600080fd5b506103b861042f3660046122ab565b610b69565b34801561044057600080fd5b506103b861044f3660046122fe565b610d27565b34801561046057600080fd5b506103b861046f366004612208565b610edc565b34801561048057600080fd5b506103b861048f366004612208565b610f0b565b3480156104a057600080fd5b506103d06104af366004612208565b60126020526000908152604090205481565b3480156104cd57600080fd5b506103b8610f3a565b3480156104e257600080fd5b506103d06104f136600461233a565b610f78565b34801561050257600080fd5b506103b8610511366004612387565b610fdb565b34801561052257600080fd5b506103d0600b5481565b34801561053857600080fd5b506103b8611017565b34801561054d57600080fd5b506103b861055c3660046122fe565b611059565b34801561056d57600080fd5b506103d061057c3660046123c9565b61114c565b34801561058d57600080fd5b506103d061059c366004612420565b60136020526000908152604090205481565b3480156105ba57600080fd5b5060105461034a906001600160a01b031681565b3480156105da57600080fd5b50600f546102ee9060ff1681565b3480156105f457600080fd5b5061034a610603366004612208565b6111b7565b34801561061457600080fd5b5061031861120e565b34801561062957600080fd5b506103b8610638366004612208565b61121b565b34801561064957600080fd5b506103d0600c5481565b6103b861066136600461243b565b61124a565b34801561067257600080fd5b506103d0610681366004612420565b611489565b34801561069257600080fd5b506103d06106a1366004612208565b60116020526000908152604090205481565b3480156106bf57600080fd5b506103b86106ce3660046122ab565b6114ec565b3480156106df57600080fd5b5061073f6106ee366004612208565b6000908152601160209081526040918290205460e081901c9363ffffffff60c083901c81169460a084901c821694608085901c831694606081901c8416949281901c8416939181901c821692911690565b6040805163ffffffff998a16815297891660208901529588169587019590955292861660608601529085166080850152841660a0840152831660c083015290911660e0820152610100016102fa565b34801561079a57600080fd5b5060065461034a906001600160a01b031681565b3480156107ba57600080fd5b50610318611632565b3480156107cf57600080fd5b506103d0600a5481565b3480156107e557600080fd5b506103b86107f43660046124a5565b61163f565b34801561080557600080fd5b506103b8610814366004612420565b6116ab565b34801561082557600080fd5b506103b86108343660046124e1565b6116f7565b6103b861084736600461252d565b611836565b34801561085857600080fd5b506103b8610867366004612595565b611a6b565b34801561087857600080fd5b506103b86108873660046125f6565b611b66565b34801561089857600080fd5b506103b86108a7366004612208565b611c4e565b3480156108b857600080fd5b506103b86108c73660046122ab565b611c7d565b3480156108d857600080fd5b506103186108e7366004612208565b611e44565b3480156108f857600080fd5b506103d060085481565b34801561090e57600080fd5b506102ee61091d366004612648565b600560209081526000928352604080842090915290825290205460ff1681565b34801561094957600080fd5b506103d0600d5481565b34801561095f57600080fd5b506103b861096e366004612420565b611ef3565b60006301ffc9a760e01b6001600160e01b0319831614806109a457506380ac58cd60e01b6001600160e01b03198316145b806109bf5750635b5e139f60e01b6001600160e01b03198316145b92915050565b600080546109d29061267b565b80601f01602080910402602001604051908101604052809291908181526020018280546109fe9061267b565b8015610a4b5780601f10610a2057610100808354040283529160200191610a4b565b820191906000526020600020905b815481529060010190602001808311610a2e57829003601f168201915b505050505081565b6000818152600260205260409020546001600160a01b031633811480610a9c57506001600160a01b038116600090815260056020908152604080832033845290915290205460ff165b610ade5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b60448201526064015b60405180910390fd5b60008281526004602052604080822080546001600160a01b0319166001600160a01b0387811691821790925591518593918516917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b92591a4505050565b6006546001600160a01b03163314610b645760405162461bcd60e51b8152600401610ad5906126b5565b600a55565b82610bb83330604051602001610b8990636275727960e01b815260040190565b604051602081830303815290604052610ba1906126db565b33600090815260136020526040902054899061114c565b14610bd55760405162461bcd60e51b8152600401610ad590612712565b610be0838383611f69565b610bfc5760405162461bcd60e51b8152600401610ad59061273f565b6000610c07856111b7565b90506001600160a01b038116610c4c5760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ad5565b6001600160a01b038116600081815260036020908152604080832080546000190190557f262bb27bbdd95c1cdc8e16957e36e38579ea44f7f6413dd7a9c75939def06b2c8054600101905588835260028252808320805461dead6001600160a01b03199182168117909255600490935281842080549093169092555188939192600080516020612a6283398151915291a4604051339086907f6d1f829e44cf0d38014e70d7b78b7a4251f29b55b319b387f7dd98359685c81d90600090a3505033600090815260136020526040902080546001019055505050565b6000818152600260205260409020546001600160a01b03848116911614610d7d5760405162461bcd60e51b815260206004820152600a60248201526957524f4e475f46524f4d60b01b6044820152606401610ad5565b6001600160a01b038216610dc75760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ad5565b336001600160a01b0384161480610e0157506001600160a01b038316600090815260056020908152604080832033845290915290205460ff165b80610e2257506000818152600460205260409020546001600160a01b031633145b610e5f5760405162461bcd60e51b815260206004820152600e60248201526d1393d517d055551213d49256915160921b6044820152606401610ad5565b6001600160a01b0380841660008181526003602090815260408083208054600019019055938616808352848320805460010190558583526002825284832080546001600160a01b0319908116831790915560049092528483208054909216909155925184939291600080516020612a6283398151915291a4505050565b6006546001600160a01b03163314610f065760405162461bcd60e51b8152600401610ad5906126b5565b600c55565b6006546001600160a01b03163314610f355760405162461bcd60e51b8152600401610ad5906126b5565b600955565b6006546001600160a01b03163314610f645760405162461bcd60e51b8152600401610ad5906126b5565b600f805460ff19811660ff90911615179055565b6040516bffffffffffffffffffffffff19606086811b8216602084015285901b1660348201526001600160e01b031983166048820152604c8101829052600090606c01604051602081830303815290604052805190602001209050949350505050565b6006546001600160a01b031633146110055760405162461bcd60e51b8152600401610ad5906126b5565b600e6110128284836127d3565b505050565b6006546001600160a01b031633146110415760405162461bcd60e51b8152600401610ad5906126b5565b600080818283473386f18015611055578182f35b8182fd5b611064838383610d27565b6001600160a01b0382163b158061110d5750604051630a85bd0160e11b8082523360048301526001600160a01b03858116602484015260448301849052608060648401526000608484015290919084169063150b7a029060a4016020604051808303816000875af11580156110dd573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111019190612893565b6001600160e01b031916145b6110125760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ad5565b6040516bffffffffffffffffffffffff19606087811b8216602084015286901b1660348201526001600160e01b031984166048820152604c8101839052606c8101829052600090608c0160405160208183030381529060405280519060200120905095945050505050565b6000818152600260205260409020546001600160a01b0316806112095760405162461bcd60e51b815260206004820152600a6024820152691393d517d3525395115160b21b6044820152606401610ad5565b919050565b600e80546109d29061267b565b6006546001600160a01b031633146112455760405162461bcd60e51b8152600401610ad5906126b5565b600b55565b853380611256836111b7565b6001600160a01b03161461127c5760405162461bcd60e51b8152600401610ad5906128b0565b87600954146112cd5760405162461bcd60e51b815260206004820152601c60248201527f4d7573742062652074686520476f62626c657220476f62626c657221000000006044820152606401610ad5565b600d5434146113155760405162461bcd60e51b81526020600482015260146024820152734e6f7420656e6f756768204554482073656e742160601b6044820152606401610ad5565b8461136d333060405160200161133e906c33b7b1313632a3b7b1313632b960991b8152600d0190565b604051602081830303815290604052611356906126db565b336000908152601360205260409020548b9061114c565b1461138a5760405162461bcd60e51b8152600401610ad590612712565b611395858585611f69565b6113b15760405162461bcd60e51b8152600401610ad59061273f565b60006113bc886111b7565b6001600160a01b0381166000818152600360209081526040808320805460001901905533808452818420805460010190558d84526002835281842080546001600160a01b0319908116831790915560049093528184208054909316909255519394508b93909291600080516020612a6283398151915291a486888a7f5fa0b7a4af71eaeec6c8b4e527f1c7d57b68825c59afce15cf5f7677fa4ae9cb60405160405180910390a4505050600993909355505033600090815260136020526040902080546001019055505050565b60006001600160a01b0382166114d05760405162461bcd60e51b815260206004820152600c60248201526b5a45524f5f4144445245535360a01b6044820152606401610ad5565b506001600160a01b031660009081526003602052604090205490565b8333806114f8836111b7565b6001600160a01b03161461151e5760405162461bcd60e51b8152600401610ad5906128b0565b8461156e333060405160200161154190666d69746f73697360c81b815260070190565b604051602081830303815290604052611559906126db565b33600090815260136020526040902054610f78565b1461158b5760405162461bcd60e51b8152600401610ad590612712565b611596858585611f69565b6115b25760405162461bcd60e51b8152600401610ad59061273f565b60006008546107d06115c491906128f3565b90506115d03382611fc3565b6040513390829089907fc115e05e23155867c7e139d51a6e7b80d8e9d029655b6f810119c030b973921b90600090a450506008805460019081019091556007805482019055336000908152601360205260409020805490910190555050505050565b600180546109d29061267b565b3360008181526005602090815260408083206001600160a01b03871680855290835292819020805460ff191686151590811790915590519081529192917f17307eab39ab6107e8899845ad3d59bd9653f200f220920489ca2b5937696c31910160405180910390a35050565b6006546001600160a01b031633146116d55760405162461bcd60e51b8152600401610ad5906126b5565b601080546001600160a01b0319166001600160a01b0392909216919091179055565b6107d0600754600161170991906128f3565b11156117575760405162461bcd60e51b815260206004820152601a60248201527f47656e65736973206d617820737570706c7920726561636865640000000000006044820152606401610ad5565b600f5460ff161561179f5760405162461bcd60e51b8152602060048201526012602482015271135d5cdd081b9bdd081899481c185d5cd95960721b6044820152606401610ad5565b826117bf333060405160200161154190631b5a5b9d60e21b815260040190565b146117dc5760405162461bcd60e51b8152600401610ad590612712565b6117e7838383611f69565b6118035760405162461bcd60e51b8152600401610ad59061273f565b61180f33600754611fc3565b50506007805460019081019091553360009081526013602052604090208054909101905550565b843380611842836111b7565b6001600160a01b0316146118685760405162461bcd60e51b8152600401610ad5906128b0565b8461188f3330604051602001611541906a616374696f6e416c69766560a81b8152600b0190565b146118ac5760405162461bcd60e51b8152600401610ad590612712565b6118b7858585611f69565b6118d35760405162461bcd60e51b8152600401610ad59061273f565b60008860028111156118e7576118e761290b565b03611952578560ff16600a546118fd9190612921565b341461191b5760405162461bcd60e51b8152600401610ad590612940565b604051339060ff88169089907f34451d2406ea78fab417966fed7c007ca3143382b25cee653588abb9c8d9f00890600090a4611a39565b60018860028111156119665761196661290b565b036119d1578560ff16600b5461197c9190612921565b341461199a5760405162461bcd60e51b8152600401610ad590612940565b604051339060ff88169089907f9515093a0215bb0e2e2244374ea65a5c55b4e40f728f2255977d3aa2881e8c5090600090a4611a39565b60028860028111156119e5576119e561290b565b03611a3957600c543414611a0b5760405162461bcd60e51b8152600401610ad590612940565b604051339088907f2057376b06556f4cca13bb6be220c9eeae3ca2531e0e2dfd8f21126e56b8b61790600090a35b505050600093845250506012602090815260408084208054340190553384526013909152909120805460010190555050565b843380611a77836111b7565b6001600160a01b031614611a9d5760405162461bcd60e51b8152600401610ad5906128b0565b84611ac8333060405160200161133e906e636f6e66696775726554726169747360881b8152600f0190565b14611ae55760405162461bcd60e51b8152600401610ad590612712565b611af0858585611f69565b611b0c5760405162461bcd60e51b8152600401610ad59061273f565b60008781526011602052604080822088905551879189917f8f25dfe3ab2aa69e8c75a62082e281bad5a6837df174231b2e79db6cd67372aa9190a35050336000908152601360205260409020805460010190555050505050565b611b71858585610d27565b6001600160a01b0384163b1580611c085750604051630a85bd0160e11b808252906001600160a01b0386169063150b7a0290611bb99033908a9089908990899060040161296d565b6020604051808303816000875af1158015611bd8573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611bfc9190612893565b6001600160e01b031916145b611c475760405162461bcd60e51b815260206004820152601060248201526f155394d0519157d49150d2541251539560821b6044820152606401610ad5565b5050505050565b6006546001600160a01b03163314611c785760405162461bcd60e51b8152600401610ad5906126b5565b600d55565b833380611c89836111b7565b6001600160a01b031614611caf5760405162461bcd60e51b8152600401610ad5906128b0565b84611cd63330604051602001611541906a1d5b9b1bd8dad51c985a5d60aa1b8152600b0190565b14611cf35760405162461bcd60e51b8152600401610ad590612712565b611cfe858585611f69565b611d1a5760405162461bcd60e51b8152600401610ad59061273f565b6000600f60019054906101000a90046001600160a01b03166001600160a01b03166318160ddd6040518163ffffffff1660e01b8152600401602060405180830381865afa158015611d6f573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611d9391906129c1565b600f546040516335313c2160e11b815233600482015291925061010090046001600160a01b031690636a62784290602401600060405180830381600087803b158015611dde57600080fd5b505af1158015611df2573d6000803e3d6000fd5b505060405133925083915089907fb9fd29c6d3a708dc686fbd2bb7d536911b863fda0a12c8e450aa88104108691390600090a45050336000908152601360205260409020805460010190555050505050565b60606007548210611e975760405162461bcd60e51b815260206004820152601960248201527f5468697320746f6b656e20646f6573206e6f74206578697374000000000000006044820152606401610ad5565b6000600e8054611ea69061267b565b905011611ec257604051806020016040528060008152506109bf565b600e611ecd836120bc565b604051602001611ede9291906129da565b60405160208183030381529060405292915050565b6006546001600160a01b03163314611f1d5760405162461bcd60e51b8152600401610ad5906126b5565b600680546001600160a01b0319166001600160a01b03831690811790915560405133907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a350565b600080611fa78484611fa0886020527b19457468657265756d205369676e6564204d6573736167653a0a3332600052603c60042090565b9190612100565b6010546001600160a01b039081169116149150505b9392505050565b6001600160a01b03821661200d5760405162461bcd60e51b81526020600482015260116024820152701253959053125117d49150d25412515395607a1b6044820152606401610ad5565b6000818152600260205260409020546001600160a01b0316156120635760405162461bcd60e51b815260206004820152600e60248201526d1053149150511657d3525395115160921b6044820152606401610ad5565b6001600160a01b038216600081815260036020908152604080832080546001019055848352600290915280822080546001600160a01b031916841790555183929190600080516020612a62833981519152908290a45050565b606060a06040510180604052602081039150506000815280825b600183039250600a81066030018353600a9004806120d65750819003601f19909101908152919050565b600060418203611fbc576040516040846040377f7fffffffffffffffffffffffffffffff5d576e7357a4501ddfe92f46681b20a0606051116121655784600052604084013560001a602052602060406080600060015afa5060006060523d6060035191505b6040529392505050565b6001600160e01b03198116811461218557600080fd5b50565b60006020828403121561219a57600080fd5b8135611fbc8161216f565b60005b838110156121c05781810151838201526020016121a8565b838111156121cf576000848401525b50505050565b60208152600082518060208401526121f48160408501602087016121a5565b601f01601f19169190910160400192915050565b60006020828403121561221a57600080fd5b5035919050565b80356001600160a01b038116811461120957600080fd5b6000806040838503121561224b57600080fd5b61225483612221565b946020939093013593505050565b60008083601f84011261227457600080fd5b50813567ffffffffffffffff81111561228c57600080fd5b6020830191508360208285010111156122a457600080fd5b9250929050565b600080600080606085870312156122c157600080fd5b8435935060208501359250604085013567ffffffffffffffff8111156122e657600080fd5b6122f287828801612262565b95989497509550505050565b60008060006060848603121561231357600080fd5b61231c84612221565b925061232a60208501612221565b9150604084013590509250925092565b6000806000806080858703121561235057600080fd5b61235985612221565b935061236760208601612221565b925060408501356123778161216f565b9396929550929360600135925050565b6000806020838503121561239a57600080fd5b823567ffffffffffffffff8111156123b157600080fd5b6123bd85828601612262565b90969095509350505050565b600080600080600060a086880312156123e157600080fd5b6123ea86612221565b94506123f860208701612221565b935060408601356124088161216f565b94979396509394606081013594506080013592915050565b60006020828403121561243257600080fd5b611fbc82612221565b60008060008060008060a0878903121561245457600080fd5b86359550602087013594506040870135935060608701359250608087013567ffffffffffffffff81111561248757600080fd5b61249389828a01612262565b979a9699509497509295939492505050565b600080604083850312156124b857600080fd5b6124c183612221565b9150602083013580151581146124d657600080fd5b809150509250929050565b6000806000604084860312156124f657600080fd5b83359250602084013567ffffffffffffffff81111561251457600080fd5b61252086828701612262565b9497909650939450505050565b60008060008060008060a0878903121561254657600080fd5b86356003811061255557600080fd5b955060208701359450604087013560ff8116811461257257600080fd5b935060608701359250608087013567ffffffffffffffff81111561248757600080fd5b6000806000806000608086880312156125ad57600080fd5b853594506020860135935060408601359250606086013567ffffffffffffffff8111156125d957600080fd5b6125e588828901612262565b969995985093965092949392505050565b60008060008060006080868803121561260e57600080fd5b61261786612221565b945061262560208701612221565b935060408601359250606086013567ffffffffffffffff8111156125d957600080fd5b6000806040838503121561265b57600080fd5b61266483612221565b915061267260208401612221565b90509250929050565b600181811c9082168061268f57607f821691505b6020821081036126af57634e487b7160e01b600052602260045260246000fd5b50919050565b6020808252600c908201526b15539055551213d49256915160a21b604082015260600190565b805160208201516001600160e01b0319808216929190600483101561270a5780818460040360031b1b83161693505b505050919050565b60208082526013908201527257726f6e67206d65737361676520686173682160681b604082015260600190565b60208082526016908201527524b73b30b634b21030b2323932b9b99039b4b3b732b960511b604082015260600190565b634e487b7160e01b600052604160045260246000fd5b601f82111561101257600081815260208120601f850160051c810160208610156127ac5750805b601f850160051c820191505b818110156127cb578281556001016127b8565b505050505050565b67ffffffffffffffff8311156127eb576127eb61276f565b6127ff836127f9835461267b565b83612785565b6000601f841160018114612833576000851561281b5750838201355b600019600387901b1c1916600186901b178355611c47565b600083815260209020601f19861690835b828110156128645786850135825560209485019460019092019101612844565b50868210156128815760001960f88860031b161c19848701351681555b505060018560011b0183555050505050565b6000602082840312156128a557600080fd5b8151611fbc8161216f565b60208082526013908201527226bab9ba103132903a37b5b2b71037bbb732b960691b604082015260600190565b634e487b7160e01b600052601160045260246000fd5b60008219821115612906576129066128dd565b500190565b634e487b7160e01b600052602160045260246000fd5b600081600019048311821515161561293b5761293b6128dd565b500290565b602080825260139082015272139bdd08195b9bdd59da081155120814d95b9d606a1b604082015260600190565b6001600160a01b038681168252851660208201526040810184905260806060820181905281018290526000828460a0840137600060a0848401015260a0601f19601f85011683010190509695505050505050565b6000602082840312156129d357600080fd5b5051919050565b60008084546129e88161267b565b60018281168015612a005760018114612a1557612a44565b60ff1984168752821515830287019450612a44565b8860005260208060002060005b85811015612a3b5781548a820152908401908201612a22565b50505082870194505b505050508351612a588183602088016121a5565b0194935050505056feddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3efa2646970667358221220a70f8a086a9ef20b7c707e9b3f89f48c61d615dedeb263013c00bd0ef1e78ba864736f6c634300080f0033
Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)
00000000000000000000000055c485924ececa49782d55d615bfde48856e2651
-----Decoded View---------------
Arg [0] : signer (address): 0x55c485924ECECA49782D55D615bfdE48856E2651
-----Encoded View---------------
1 Constructor Arguments found :
Arg [0] : 00000000000000000000000055c485924ececa49782d55d615bfde48856e2651
Loading...
Loading
Loading...
Loading
[ Download: CSV Export ]
A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.