ETH Price: $3,317.61 (-4.40%)

Token

ETH GOBBLERS (GOOEY)
 

Overview

Max Total Supply

5,219 GOOEY

Holders

216

Market

Volume (24H)

N/A

Min Price (24H)

N/A

Max Price (24H)

N/A
Filtered by Token Holder
blankettheory.eth
Balance
8 GOOEY
0x10c1920bbe47a9806eae7082cdfe93af33ae369c
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

ETH GOBBLERS. Feed them. Groom them. Love them.

# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
ETHGobblers

Compiler Version
v0.8.15+commit.e14f2714

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 6 : ETHGobblers.sol
// 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) }
    }
  }
}

File 2 of 6 : ECDSA.sol
// 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)
        }
    }
}

File 3 of 6 : LibString.sol
// 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 "&quot;&amp;&#39;&lt;&gt;" 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)
        }
    }
}

File 4 of 6 : Owned.sol
// 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);
    }
}

File 5 of 6 : ERC721.sol
// 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;
    }
}

File 6 of 6 : GobDrops.sol
// 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) }
    }
  }
}

Settings
{
  "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

Contract ABI

[{"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"}]

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  ]
[ 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.