ETH Price: $2,673.28 (-1.40%)

Contract

0x0A8D311B99DdAA9EBb45FD606Eb0A1533004f26b
 

Overview

ETH Balance

0.361 ETH

Eth Value

$965.06 (@ $2,673.28/ETH)

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set Approval For...218183942025-02-10 20:05:356 days ago1739217935IN
ETH GOBBLERS: GOOEY Token
0 ETH0.00004321.78410124
Set Approval For...218069972025-02-09 5:53:598 days ago1739080439IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000021950.90652931
Set Approval For...217529082025-02-01 16:37:1115 days ago1738427831IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000084843.5
Set Approval For...217191142025-01-27 23:22:1120 days ago1738020131IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000101274.18198824
Set Approval For...216045652025-01-11 23:36:5936 days ago1736638619IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000107174.42157119
Set Approval For...215851352025-01-09 6:28:1138 days ago1736404091IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000096864
Set Approval For...215780362025-01-08 6:42:5939 days ago1736318579IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000153926.35629856
Set Approval For...214601232024-12-22 19:27:4756 days ago1734895667IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000148026.11249922
Set Approval For...214283662024-12-18 8:56:4760 days ago1734512207IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000414548.98674702
Set Approval For...214283642024-12-18 8:56:2360 days ago1734512183IN
ETH GOBBLERS: GOOEY Token
0 ETH0.00041599
Set Approval For...214278632024-12-18 7:15:2360 days ago1734506123IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000410288.89445804
Set Approval For...214274482024-12-18 5:51:4761 days ago1734501107IN
ETH GOBBLERS: GOOEY Token
0 ETH0.0005303411.49715988
Set Approval For...214266742024-12-18 3:16:4761 days ago1734491807IN
ETH GOBBLERS: GOOEY Token
0 ETH0.0004897710.59844403
Mitosis214030962024-12-14 20:19:4764 days ago1734207587IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000645868.17338658
Mitosis214030942024-12-14 20:19:2364 days ago1734207563IN
ETH GOBBLERS: GOOEY Token
0 ETH0.00067688.56482025
Mitosis214030712024-12-14 20:14:4764 days ago1734207287IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000654948.2882475
Mitosis214030682024-12-14 20:14:1164 days ago1734207251IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000600767.60259777
Mitosis214030632024-12-14 20:13:1164 days ago1734207191IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000654058.27693909
Mitosis214030602024-12-14 20:12:3564 days ago1734207155IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000657868.32650072
Mitosis214030562024-12-14 20:11:4764 days ago1734207107IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000614957.78218615
Mitosis214030272024-12-14 20:05:5964 days ago1734206759IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000614457.77586316
Mitosis214030222024-12-14 20:04:5964 days ago1734206699IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000707548.95387121
Mitosis214004202024-12-14 11:20:4764 days ago1734175247IN
ETH GOBBLERS: GOOEY Token
0 ETH0.000576157.2911119
Set Approval For...213860062024-12-12 11:04:1166 days ago1734001451IN
ETH GOBBLERS: GOOEY Token
0 ETH0.0008410618.23330833
Set Approval For...213829872024-12-12 0:57:1167 days ago1733965031IN
ETH GOBBLERS: GOOEY Token
0 ETH0.0006640914.3968776
View all transactions

Latest 25 internal transactions (View All)

Advanced mode:
Parent Transaction Hash Block
From
To
208165232024-09-23 23:19:35146 days ago1727133575
ETH GOBBLERS: GOOEY Token
0.183 ETH
206229772024-08-27 22:41:47173 days ago1724798507
ETH GOBBLERS: GOOEY Token
0.322 ETH
199958592024-06-01 8:44:59260 days ago1717231499
ETH GOBBLERS: GOOEY Token
0.358 ETH
197152772024-04-23 3:01:35300 days ago1713841295
ETH GOBBLERS: GOOEY Token
0.32 ETH
194663242024-03-19 4:09:23335 days ago1710821363
ETH GOBBLERS: GOOEY Token
0.726 ETH
190884452024-01-26 4:37:11388 days ago1706243831
ETH GOBBLERS: GOOEY Token
0.784 ETH
188971642023-12-30 8:30:47414 days ago1703925047
ETH GOBBLERS: GOOEY Token
0.291 ETH
186946882023-12-01 22:57:23443 days ago1701471443
ETH GOBBLERS: GOOEY Token
1.023 ETH
184947632023-11-03 23:19:35471 days ago1699053575
ETH GOBBLERS: GOOEY Token
0.05 ETH
183099612023-10-09 2:33:59497 days ago1696818839
ETH GOBBLERS: GOOEY Token
1.049 ETH
181544412023-09-17 7:59:35518 days ago1694937575
ETH GOBBLERS: GOOEY Token
1.846 ETH
179248692023-08-16 4:00:23551 days ago1692158423
ETH GOBBLERS: GOOEY Token
0.266 ETH
179034342023-08-13 4:04:47554 days ago1691899487
ETH GOBBLERS: GOOEY Token
0.756 ETH
178671982023-08-08 2:22:35559 days ago1691461355
ETH GOBBLERS: GOOEY Token
1.417 ETH
178143702023-07-31 17:05:47566 days ago1690823147
ETH GOBBLERS: GOOEY Token
0.703 ETH
177793142023-07-26 19:22:47571 days ago1690399367
ETH GOBBLERS: GOOEY Token
3.044 ETH
176927562023-07-14 16:02:35583 days ago1689350555
ETH GOBBLERS: GOOEY Token
0.968 ETH
176708522023-07-11 14:05:11586 days ago1689084311
ETH GOBBLERS: GOOEY Token
1.814 ETH
176336802023-07-06 8:40:35591 days ago1688632835
ETH GOBBLERS: GOOEY Token
1.145 ETH
176043942023-07-02 5:57:47596 days ago1688277467
ETH GOBBLERS: GOOEY Token
2.391 ETH
175644232023-06-26 15:15:11601 days ago1687792511
ETH GOBBLERS: GOOEY Token
2.658 ETH
174912472023-06-16 8:34:59611 days ago1686904499
ETH GOBBLERS: GOOEY Token
10.494 ETH
173159322023-05-22 16:11:11636 days ago1684771871
ETH GOBBLERS: GOOEY Token
2.805 ETH
172695722023-05-16 3:19:59643 days ago1684207199
ETH GOBBLERS: GOOEY Token
1.026 ETH
172492802023-05-13 6:27:47645 days ago1683959267
ETH GOBBLERS: GOOEY Token
0.851 ETH
View All Internal Transactions
Loading...
Loading

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


Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

Block Uncle Number Difficulty Gas Used Reward
View All Uncles
Loading...
Loading
Loading...
Loading

OVERVIEW

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

Validator Index Block Amount
View All Withdrawals

Transaction Hash Block Value Eth2 PubKey Valid
View All Deposits
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A contract address hosts a smart contract, which is a set of code stored on the blockchain that runs when predetermined conditions are met. Learn more about addresses in our Knowledge Base.