ETH Price: $2,630.09 (+2.05%)

Contract

0x0000000000000aF8FE6E4DE40F4804C90fA8Ea8F
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Set N Number Of ...165041172023-01-28 8:27:47571 days ago1674894467IN
0x00000000...90fA8Ea8F
0 ETH0.0003980415.15378596
Transfer164976472023-01-27 10:46:59572 days ago1674816419IN
0x00000000...90fA8Ea8F
0 ETH0.0009957714.78244301
Transfer164976282023-01-27 10:43:11572 days ago1674816191IN
0x00000000...90fA8Ea8F
0 ETH0.0013615316.09814402
Transfer164915442023-01-26 14:19:47573 days ago1674742787IN
0x00000000...90fA8Ea8F
0 ETH0.0013569820.14465736
Transfer164915362023-01-26 14:18:11573 days ago1674742691IN
0x00000000...90fA8Ea8F
0 ETH0.0017466820.65197364
Transfer164907122023-01-26 11:32:35573 days ago1674732755IN
0x00000000...90fA8Ea8F
0 ETH0.0010075314.95700793
Transfer164907042023-01-26 11:30:59573 days ago1674732659IN
0x00000000...90fA8Ea8F
0 ETH0.0012838315.17950003
Transfer164790702023-01-24 20:31:23575 days ago1674592283IN
0x00000000...90fA8Ea8F
0 ETH0.0015785723.43422485
Transfer164790662023-01-24 20:30:35575 days ago1674592235IN
0x00000000...90fA8Ea8F
0 ETH0.0018543821.92545037
Transfer164790612023-01-24 20:29:35575 days ago1674592175IN
0x00000000...90fA8Ea8F
0 ETH0.0007370121.36963199
Transfer164780302023-01-24 17:01:47575 days ago1674579707IN
0x00000000...90fA8Ea8F
0 ETH0.0019796229.38785398
Transfer164779202023-01-24 16:39:47575 days ago1674578387IN
0x00000000...90fA8Ea8F
0 ETH0.0017931621.20158018
Transfer164706402023-01-23 16:16:11576 days ago1674490571IN
0x00000000...90fA8Ea8F
0 ETH0.0013334719.79558257
Transfer164706302023-01-23 16:14:11576 days ago1674490451IN
0x00000000...90fA8Ea8F
0 ETH0.0016206519.16189284
Transfer164671182023-01-23 4:29:35576 days ago1674448175IN
0x00000000...90fA8Ea8F
0 ETH0.0009986214.82470123
Transfer164670992023-01-23 4:25:47576 days ago1674447947IN
0x00000000...90fA8Ea8F
0 ETH0.0011905914.07710084
Transfer164635902023-01-22 16:38:35577 days ago1674405515IN
0x00000000...90fA8Ea8F
0 ETH0.0004527713.94535436
Transfer164586922023-01-22 0:14:23577 days ago1674346463IN
0x00000000...90fA8Ea8F
0 ETH0.0013479720.01090328
Transfer164586542023-01-22 0:06:47578 days ago1674346007IN
0x00000000...90fA8Ea8F
0 ETH0.002691131.81839405
Transfer164446352023-01-20 1:09:35579 days ago1674176975IN
0x00000000...90fA8Ea8F
0 ETH0.0011141716.54312645
Transfer164446262023-01-20 1:07:47579 days ago1674176867IN
0x00000000...90fA8Ea8F
0 ETH0.0012791115.1236438
Transfer164446152023-01-20 1:05:35579 days ago1674176735IN
0x00000000...90fA8Ea8F
0 ETH0.0005409516.77430943
Transfer164445782023-01-20 0:58:11579 days ago1674176291IN
0x00000000...90fA8Ea8F
0 ETH0.0012720415.04010339
Transfer164387352023-01-19 5:22:23580 days ago1674105743IN
0x00000000...90fA8Ea8F
0 ETH0.0011508317.08430338
Transfer164387282023-01-19 5:20:59580 days ago1674105659IN
0x00000000...90fA8Ea8F
0 ETH0.0016369819.35496574
View all transactions

Latest 1 internal transaction

Advanced mode:
Parent Transaction Hash Block From To
161313812022-12-07 7:32:35623 days ago1670398355  Contract Creation0 ETH
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
EPSRegister

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 18 : EPSRegister.sol
// SPDX-License-Identifier: BUSL-1.1
// EPS Contracts v2.0.0

pragma solidity 0.8.17;
import "./IERC721DelegateRegister.sol";
import "./IERC1155DelegateRegister.sol";
import "./IERC20DelegateRegister.sol";
import "./ProxyRegister.sol";
import "./ENSReverseRegistrar.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";

/**
 *
 * @dev The EPS Register contract, implementing the proxy and deligate registers
 *
 */
contract EPSRegister is ProxyRegister {
  using SafeERC20 for IERC20;

  struct MigratedRecord {
    address hot;
    address cold;
    address delivery;
  }

  // Record migration complete:
  bool public migrationComplete;

  ENSReverseRegistrar public ensReverseRegistrar;

  // EPS treasury address:
  address public treasury;

  // EPS ERC721 delegation register
  IERC721DelegateRegister public erc721DelegationRegister;
  bool public erc721DelegationRegisterAddressLocked;

  // EPS ERC1155 delegation register
  IERC1155DelegateRegister public erc1155DelegationRegister;
  bool public erc1155DelegationRegisterAddressLocked;

  // EPS ERC20 delegation register
  IERC20DelegateRegister public erc20DelegationRegister;
  bool public erc20DelegationRegisterAddressLocked;

  // Count of active ETH addresses for total supply
  uint256 public activeEthAddresses = 1;

  // 'Air drop' of EPSAPI to every address
  uint256 public epsAPIBalance = 10000 * (10**decimals());

  error ColdWalletCannotInteractUseHot();
  error EthWithdrawFailed();
  error UnknownAmount();
  error RegisterAddressLocked();
  error MigrationIsAllowedOnceOnly();

  event ERC20FeeUpdated(address erc20, uint256 erc20Fee_);
  event MigrationComplete();
  event Transfer(address indexed from, address indexed to, uint256 value);
  event ENSReverseRegistrarSet(address ensReverseRegistrarAddress);

  /**
   * @dev Constructor - change ownership
   */
  constructor() {
    _transferOwnership(0x9F0773aF2b1d3f7cC7030304548A823B4E6b13bB);
  }

  // ======================================================
  // VIEW METHODS
  // ======================================================

  /**
   * @dev beneficiaryOf: Returns the beneficiary of the `tokenId` token for an ERC721
   */
  function beneficiaryOf(
    address tokenContract_,
    uint256 tokenId_,
    uint256 rightsIndex_
  ) external view returns (address beneficiary_) {
    // 1 Check for an active delegation. We need a concept of a 'senior right', which
    // we have elected to be airdrop rights, being the right of the holder to receive
    // free benefits associated with being a beneficiary. If we are looking for a beneficiary
    // rights index out of bounds default to an airdrop rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    beneficiary_ = erc721DelegationRegister.getBeneficiaryByRight(
      tokenContract_,
      tokenId_,
      rightsIndex_
    );

    if (beneficiary_ == address(0)) {
      // 2 No delegation. Get the owner:
      beneficiary_ = IERC721(tokenContract_).ownerOf(tokenId_);

      // 3 Check if this is a proxied benefit
      if (coldIsLive(beneficiary_)) {
        beneficiary_ = coldToHot[beneficiary_];
      }
    }
  }

  /**
   * @dev beneficiaryBalance: Returns the beneficiary balance of ETH.
   */
  function beneficiaryBalance(address queryAddress_)
    external
    view
    returns (uint256 balance_)
  {
    // Get any balances held at a nominated cold address
    if (hotIsLive(queryAddress_)) {
      // This is a hot address with a current record - include the balance
      // held natively by this address and the cold:
      balance_ += queryAddress_.balance;

      balance_ += hotToRecord[queryAddress_].cold.balance;
    } else {
      // Check if this is cold wallet on an active record. If so do not include balance as that is absorbed into the proxy
      if (!coldIsLive(queryAddress_)) {
        balance_ += queryAddress_.balance;
      }
    }
  }

  /**
   * @dev beneficiaryBalanceOf: Returns the beneficiary balance for an ERC721
   */
  function beneficiaryBalanceOf(
    address queryAddress_,
    address tokenContract_,
    uint256 rightsIndex_
  ) external view returns (uint256 balance_) {
    // 1a If this is a delegation container the balance is always 0, as the balance associated
    // will be for the benefit of either the original asset owner or the delegate, depending
    // on the delegation parameters:
    if (erc721DelegationRegister.containerToDelegationId(queryAddress_) != 0) {
      return (0);
    }

    // 1b We need a concept of a 'senior right', which we have elected to be airdrop rights,
    // being the right of the holder to receive free benefits associated with being a beneficiary.
    // If we are looking for a beneficiary rights index out of bounds default to an airdrop
    // rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    // 2 Get delegated balances:
    balance_ = erc721DelegationRegister.getBalanceByRight(
      tokenContract_,
      queryAddress_,
      rightsIndex_
    );

    // 3 Add any balances held at a nominated cold address
    if (hotIsLive(queryAddress_)) {
      // This is a hot address with a current record - add on the balances
      // held natively by this address and the cold:
      balance_ += (IERC721(tokenContract_).balanceOf(queryAddress_));

      address cold = hotToRecord[queryAddress_].cold;

      balance_ += IERC721(tokenContract_).balanceOf(cold);
    } else {
      // Check if this is cold wallet on an active record. If so do not include balance as that is absorbed into the proxy
      if (!coldIsLive(queryAddress_)) {
        balance_ += IERC721(tokenContract_).balanceOf(queryAddress_);
      }
    }
  }

  /**
   * @dev beneficiaryBalanceOf1155: Returns the beneficiary balance for an ERC1155.
   */
  function beneficiaryBalanceOf1155(
    address queryAddress_,
    address tokenContract_,
    uint256 id_,
    uint256 rightsIndex_
  ) external view returns (uint256 balance_) {
    // 1a If this is a delegation container the balance is always 0, as the balance associated
    // will be for the benefit of either the original asset owner or the delegate, depending
    // on the delegation parameters:
    if (erc1155DelegationRegister.containerToDelegationId(queryAddress_) != 0) {
      return (0);
    }

    // 1b We need a concept of a 'senior right', which we have elected to be airdrop rights,
    // being the right of the holder to receive free benefits associated with being a beneficiary.
    // If we are looking for a beneficiary rights index out of bounds default to an airdrop
    // rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    // 2 Get delegated balances:
    balance_ = erc1155DelegationRegister.getBalanceByRight(
      tokenContract_,
      id_,
      queryAddress_,
      rightsIndex_
    );

    // Add any balances held at a nominated cold address
    if (hotIsLive(queryAddress_)) {
      // This is a hot address with a current record - add on the balances
      // held natively by this address and the cold:
      balance_ += (IERC1155(tokenContract_).balanceOf(queryAddress_, id_));

      address cold = hotToRecord[queryAddress_].cold;

      balance_ += IERC1155(tokenContract_).balanceOf(cold, id_);
    } else {
      // Check if this is cold wallet on an active record. If so do not include balance as that is absorbed into the proxy
      if (!coldIsLive(queryAddress_)) {
        balance_ += IERC1155(tokenContract_).balanceOf(queryAddress_, id_);
      }
    }
  }

  /**
   * @dev beneficiaryBalanceOf20: Returns the beneficiary balance for an ERC20 or ERC777
   */
  function beneficiaryBalanceOf20(
    address queryAddress_,
    address tokenContract_,
    uint256 rightsIndex_
  ) external view returns (uint256 balance_) {
    // 1a If this is a delegation container the balance is always 0, as the balance associated
    // will be for the benefit of either the original asset owner or the delegate, depending
    // on the delegation parameters:
    if (erc20DelegationRegister.containerToDelegationId(queryAddress_) != 0) {
      return (0);
    }

    // 1b We need a concept of a 'senior right', which we have elected to be airdrop rights,
    // being the right of the holder to receive free benefits associated with being a beneficiary.
    // If we are looking for a beneficiary rights index out of bounds default to an airdrop
    // rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    // 2 Get delegated balances:
    balance_ = erc20DelegationRegister.getBalanceByRight(
      tokenContract_,
      queryAddress_,
      rightsIndex_
    );

    // 3 Add any balances held at a nominated cold address
    if (hotIsLive(queryAddress_)) {
      // This is a hot address with a current record - add on the balances
      // held natively by this address and the cold:
      balance_ += (IERC20(tokenContract_).balanceOf(queryAddress_));

      address cold = hotToRecord[queryAddress_].cold;

      balance_ += IERC20(tokenContract_).balanceOf(cold);
    } else {
      // Check if this is cold wallet on an active record. If so do not include balance as that is absorbed into the proxy
      if (!coldIsLive(queryAddress_)) {
        balance_ += IERC20(tokenContract_).balanceOf(queryAddress_);
      }
    }
  }

  /**
   * @dev getAddresses721: Returns the register addresses for the passed address and rights index for ERC721
   *
     Possible scenarios are:
   
      1) The receivedAddress_ is NOT on the proxy register and is NOT on the delegate register
         In this instance the return values will be:
          - proxyAddresses_: 
            - The recievedAddress_ at index 0
          - the receivedAddress_ as the delivery address
   
      2) The receivedAddress_ is a HOT address on the proxy register and is NOT on the delegate register
         In this instance the return values will be:
          - proxyAddresses_:
            - The receivedAddress_ at index 0
            - The COLD address at index 1
          - DELIVERY address as the delivery address

      3) The receivedAddress_ is a COLD address on the proxy register (whether it  has entries on the 
           delegate register or not)
          - proxyAddresses_:
            - NOTHING (i.e. empty array)
          - the receivedAddress_ as the delivery address 

      4) The receivedAddress_ is NOT on the proxy register BUT it DOES have entries on the delegate register
         In this instance the return values will be:
          - proxyAddresses_: 
            - The recievedAddress_ at index 0
            - The delegate register entries at index 1 to n
          - the receivedAddress_ as the delivery address

      5) The receivedAddress_ IS on the proxy register AND has entries on the delegate register
         In this instance the return values will be:
          - proxyAddresses_: 
            - The recievedAddress_ at index 0
            - The COLD address at index 1
            - The delegate register entries at index 2 to n
           - DELIVERY address as the delivery address

      Some points to note:
        * Index 0 in the returned address array will ALWAYS be the receivedAddress_ address UNLESS it's the address
          is a COLD wallet, in which case the array is empty. This enforces that a COLD wallet has no
          rights in its own right WITHOUT us needing to revert and have the caller handle the situation
        * Therefore if you wish to IGNORE the hot address, start any iteration over the returned list from index 1
          onwards. Index 1 (if it exists) will always either be the COLD address or the first entry from the delegate register.

   *
   */
  function getAddresses721(address receivedAddress_, uint256 rightsIndex_)
    public
    view
    returns (address[] memory proxyAddresses_, address delivery_)
  {
    // We need a concept of a 'senior right', which
    // we have elected to be airdrop rights, being the right of the holder to receive
    // free benefits associated with being a beneficiary. If we are looking for a beneficiary
    // rights index out of bounds default to an airdrop rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    address cold;
    delivery_ = receivedAddress_;

    if (coldIsLive(receivedAddress_)) {
      return (proxyAddresses_, receivedAddress_);
    }

    if (hotIsLive(receivedAddress_)) {
      cold = hotToRecord[receivedAddress_].cold;
      delivery_ = hotToRecord[receivedAddress_].delivery;
    }

    return (
      erc721DelegationRegister.getAllAddressesByRightsIndex(
        receivedAddress_,
        rightsIndex_,
        cold,
        true
      ),
      delivery_
    );
  }

  /**
   * @dev getAddresses1155: Returns the register addresses for the passed address and rights index for ERC1155
   *
   */
  function getAddresses1155(address receivedAddress_, uint256 rightsIndex_)
    public
    view
    returns (address[] memory proxyAddresses_, address delivery_)
  {
    // We need a concept of a 'senior right', which
    // we have elected to be airdrop rights, being the right of the holder to receive
    // free benefits associated with being a beneficiary. If we are looking for a beneficiary
    // rights index out of bounds default to an airdrop rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    address cold;
    delivery_ = receivedAddress_;

    if (coldIsLive(receivedAddress_)) {
      return (proxyAddresses_, receivedAddress_);
    }

    if (hotIsLive(receivedAddress_)) {
      cold = hotToRecord[receivedAddress_].cold;
      delivery_ = hotToRecord[receivedAddress_].delivery;
    }

    return (
      erc1155DelegationRegister.getAllAddressesByRightsIndex(
        receivedAddress_,
        rightsIndex_,
        cold,
        true
      ),
      delivery_
    );
  }

  /**
   * @dev getAddresses20: Returns the register addresses for the passed address and rights index for ERC20 and 777
   *
   */
  function getAddresses20(address receivedAddress_, uint256 rightsIndex_)
    public
    view
    returns (address[] memory proxyAddresses_, address delivery_)
  {
    // We need a concept of a 'senior right', which
    // we have elected to be airdrop rights, being the right of the holder to receive
    // free benefits associated with being a beneficiary. If we are looking for a beneficiary
    // rights index out of bounds default to an airdrop rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    address cold;
    delivery_ = receivedAddress_;

    if (coldIsLive(receivedAddress_)) {
      return (proxyAddresses_, receivedAddress_);
    }

    if (hotIsLive(receivedAddress_)) {
      cold = hotToRecord[receivedAddress_].cold;
      delivery_ = hotToRecord[receivedAddress_].delivery;
    }

    return (
      erc20DelegationRegister.getAllAddressesByRightsIndex(
        receivedAddress_,
        rightsIndex_,
        cold,
        true
      ),
      delivery_
    );
  }

  /**
   * @dev getAllAddresses: Returns ALL register addresses for the passed address and rights index
   *
   */
  function getAllAddresses(address receivedAddress_, uint256 rightsIndex_)
    public
    view
    returns (
      address[] memory erc721Addresses_,
      address[] memory erc1155Addresses_,
      address[] memory erc20Addresses_,
      address delivery_
    )
  {
    // We need a concept of a 'senior right', which
    // we have elected to be airdrop rights, being the right of the holder to receive
    // free benefits associated with being a beneficiary. If we are looking for a beneficiary
    // rights index out of bounds default to an airdrop rights query (rights index position 1)
    if (rightsIndex_ == 0 || rightsIndex_ > 15) {
      rightsIndex_ = 1;
    }

    address cold;
    delivery_ = receivedAddress_;

    if (coldIsLive(receivedAddress_)) {
      return (
        erc721Addresses_,
        erc1155Addresses_,
        erc20Addresses_,
        receivedAddress_
      );
    }

    if (hotIsLive(receivedAddress_)) {
      cold = hotToRecord[receivedAddress_].cold;
      delivery_ = hotToRecord[receivedAddress_].delivery;
    }

    if (
      address(erc721DelegationRegister) == address(0) &&
      address(erc1155DelegationRegister) == address(0) &&
      address(erc20DelegationRegister) == address(0)
    ) {
      // This is unexpected, but theoretically possible. In this case, return
      // the base addresses in the first return array:
      uint256 addIndexes;
      if (cold != address(0)) {
        addIndexes = 2;
      } else {
        addIndexes = 1;
      }

      address[] memory baseAddresses = new address[](addIndexes);

      baseAddresses[0] = receivedAddress_;
      if (cold != address(0)) {
        baseAddresses[1] = cold;
      }
      return (baseAddresses, erc1155Addresses_, erc20Addresses_, delivery_);
    } else {
      bool includeBaseAddresses = true;

      if (address(erc721DelegationRegister) != address(0)) {
        erc721Addresses_ = erc721DelegationRegister
          .getAllAddressesByRightsIndex(
            receivedAddress_,
            rightsIndex_,
            cold,
            includeBaseAddresses
          );
        includeBaseAddresses = false;
      }

      if (address(erc1155DelegationRegister) != address(0)) {
        erc1155Addresses_ = erc1155DelegationRegister
          .getAllAddressesByRightsIndex(
            receivedAddress_,
            rightsIndex_,
            cold,
            includeBaseAddresses
          );
        includeBaseAddresses = false;
      }

      if (address(erc20DelegationRegister) != address(0)) {
        erc20Addresses_ = erc20DelegationRegister.getAllAddressesByRightsIndex(
          receivedAddress_,
          rightsIndex_,
          cold,
          includeBaseAddresses
        );
        includeBaseAddresses = false;
      }
    }
    return (erc721Addresses_, erc1155Addresses_, erc20Addresses_, delivery_);
  }

  /**
   * @dev getColdAndDeliveryAddresses: Returns the register address details (cold and delivery address) for a passed hot address
   */
  function getColdAndDeliveryAddresses(address _receivedAddress)
    public
    view
    returns (
      address cold,
      address delivery,
      bool isProxied
    )
  {
    if (coldIsLive(_receivedAddress)) revert ColdWalletCannotInteractUseHot();

    if (hotIsLive(_receivedAddress)) {
      return (
        hotToRecord[_receivedAddress].cold,
        hotToRecord[_receivedAddress].delivery,
        true
      );
    } else {
      return (_receivedAddress, _receivedAddress, false);
    }
  }

  // ======================================================
  // ADMIN FUNCTIONS
  // ======================================================

  /**
   * @dev setRegisterFee: set the fee for accepting a registration:
   */
  function setRegisterFee(uint256 registerFee_) external onlyOwner {
    proxyRegisterFee = registerFee_;
  }

  /**
   * @dev setDeletionNominalEth: set the nominal ETH transfer that represents an address ending a proxy
   */
  function setDeletionNominalEth(uint256 deleteNominalEth_) external onlyOwner {
    deletionNominalEth = deleteNominalEth_;
  }

  /**
   *
   * @dev setRewardToken
   *
   */
  function setRewardToken(address rewardToken_) external onlyOwner {
    rewardToken = IOAT(rewardToken_);
    emit RewardTokenUpdated(rewardToken_);
  }

  /**
   *
   * @dev setRewardRate
   *
   */
  function setRewardRate(uint88 rewardRate_) external onlyOwner {
    if (rewardRateLocked) {
      revert RewardRateIsLocked();
    }
    rewardRate = rewardRate_;
    emit RewardRateUpdated(rewardRate_);
  }

  /**
   *
   * @dev lockRewardRate
   *
   */
  function lockRewardRate() external onlyOwner {
    rewardRateLocked = true;
    emit RewardRateLocked();
  }

  /**
   *
   * @dev setENSName (used to set reverse record so interactions with this contract are easy to
   * identify)
   *
   */
  function setENSName(string memory ensName_) external onlyOwner {
    ensReverseRegistrar.setName(ensName_);
  }

  /**
   * @dev setTreasuryAddress: set the treasury address:
   */
  function setTreasuryAddress(address treasuryAddress_) public onlyOwner {
    treasury = treasuryAddress_;
  }

  /**
   * @dev setERC721DelegationRegister: set the delegation register address:
   */
  function setERC721DelegationRegister(address erc721DelegationRegister_)
    public
    onlyOwner
  {
    if (erc721DelegationRegisterAddressLocked) {
      revert RegisterAddressLocked();
    }
    erc721DelegationRegister = IERC721DelegateRegister(
      erc721DelegationRegister_
    );
  }

  /**
   * @dev lockERC721DelegationRegisterAddress
   */
  function lockERC721DelegationRegisterAddress() public onlyOwner {
    erc721DelegationRegisterAddressLocked = true;
  }

  /**
   * @dev setERC1155DelegationRegister: set the delegation register address:
   */
  function setERC1155DelegationRegister(address erc1155DelegationRegister_)
    public
    onlyOwner
  {
    if (erc1155DelegationRegisterAddressLocked) {
      revert RegisterAddressLocked();
    }
    erc1155DelegationRegister = IERC1155DelegateRegister(
      erc1155DelegationRegister_
    );
  }

  /**
   * @dev lockERC1155DelegationRegisterAddress
   */
  function lockERC1155DelegationRegisterAddress() public onlyOwner {
    erc1155DelegationRegisterAddressLocked = true;
  }

  /**
   * @dev setERC20DelegationRegister: set the delegation register address:
   */
  function setERC20DelegationRegister(address erc20DelegationRegister_)
    public
    onlyOwner
  {
    if (erc20DelegationRegisterAddressLocked) {
      revert RegisterAddressLocked();
    }
    erc20DelegationRegister = IERC20DelegateRegister(erc20DelegationRegister_);
  }

  /**
   * @dev lockERC20DelegationRegisterAddress
   */
  function lockERC20DelegationRegisterAddress() public onlyOwner {
    erc20DelegationRegisterAddressLocked = true;
  }

  /**
   * @dev setActiveEthAddresses: used in the psuedo total supply calc:
   */
  function setNNumberOfEthAddressesAndAirdropAmount(
    uint256 count_,
    uint256 air_
  ) public onlyOwner {
    activeEthAddresses = count_;
    epsAPIBalance = air_;
  }

  /**
   * @dev withdrawETH: withdraw eth to the treasury:
   */
  function withdrawETH(uint256 amount_) external onlyOwner {
    (bool success, ) = treasury.call{value: amount_}("");

    if (!success) revert EthWithdrawFailed();
  }

  /**
   * @dev withdrawERC20: Allow any ERC20s to be withdrawn Note, this is provided to enable the
   * withdrawal of payments using valid ERC20s. Assets sent here in error are retrieved with
   * rescueERC20
   */
  function withdrawERC20(IERC20 token_, uint256 amount_) external onlyOwner {
    token_.safeTransfer(treasury, amount_);
  }

  /**
   * @dev rescueERC20: Allow any ERC20s to be rescued. Note, this is provided to enable the
   * withdrawal assets sent here in error. ERC20 fee payments are withdrawn to the treasury.
   * in withDrawERC1155
   */
  function rescueERC20(IERC20 token_, uint256 amount_) external onlyOwner {
    token_.safeTransfer(owner(), amount_);
  }

  /**
   * @dev rescueERC721: Allow any ERC721s to be rescued. Note, all delegated ERC721s are in their
   * own contract, NOT on this contract. This is provided to enable the withdrawal of
   * any assets sent here in error using transferFrom not safeTransferFrom.
   */

  function rescueERC721(IERC721 token_, uint256 tokenId_) external onlyOwner {
    token_.transferFrom(address(this), owner(), tokenId_);
  }

  /**
   * @dev rescueERC1155: Allow any ERC1155s to be rescued. Note, all delegated ERC1155s are in their
   * own contract, NOT on this contract. This is provided to enable the withdrawal of
   * any assets sent here in error using transferFrom not safeTransferFrom.
   */

  function rescueERC1155(IERC1155 token_, uint256 tokenId_) external onlyOwner {
    token_.safeTransferFrom(
      address(this),
      owner(),
      tokenId_,
      token_.balanceOf(address(this), tokenId_),
      ""
    );
  }

  /**
   *
   * @dev setERC20Fee
   *
   */
  function setERC20Fee(address erc20_, uint256 erc20Fee_) external onlyOwner {
    erc20PerTransactionFee[erc20_] = erc20Fee_;
    emit ERC20FeeUpdated(erc20_, erc20Fee_);
  }

  /**
   *
   * @dev setENSReverseRegistrar
   *
   */
  function setENSReverseRegistrar(address ensReverseRegistrar_)
    external
    onlyOwner
  {
    ensReverseRegistrar = ENSReverseRegistrar(ensReverseRegistrar_);
    emit ENSReverseRegistrarSet(ensReverseRegistrar_);
  }

  /**
   * @dev One-off migration routine to bring in register details from a previous version
   */
  function migration(MigratedRecord[] memory migratedRecords_)
    external
    onlyOwner
  {
    if (migrationComplete) {
      revert MigrationIsAllowedOnceOnly();
    }

    for (uint256 i = 0; i < migratedRecords_.length; ) {
      MigratedRecord memory currentRecord = migratedRecords_[i];

      _processNomination(
        currentRecord.hot,
        currentRecord.cold,
        currentRecord.delivery,
        true,
        0
      );

      _acceptNomination(currentRecord.hot, currentRecord.cold, 0, 0);

      unchecked {
        i++;
      }
    }

    migrationComplete = true;

    emit MigrationComplete();
  }

  // ======================================================
  // ETH CALL ENTRY POINT
  // ======================================================

  /**
   *
   * @dev receive: Wallets need never connect directly to add to EPS register, rather they can
   * interact through ETH or ERC20 transfers. This 'air gaps' your wallet(s) from
   * EPS. ETH transfers can be used to pay the fee or delete a record (sent from either
   * the hot or the cold wallet).
   *
   */
  receive() external payable {
    if (
      msg.value != proxyRegisterFee &&
      msg.value != deletionNominalEth &&
      erc721DelegationRegister.containerToDelegationId(msg.sender) == 0 &&
      erc1155DelegationRegister.containerToDelegationId(msg.sender) == 0 &&
      erc20DelegationRegister.containerToDelegationId(msg.sender) == 0 &&
      msg.sender != owner()
    ) revert UnknownAmount();

    if (msg.value == proxyRegisterFee) {
      _payFee(msg.sender);
    } else if (msg.value == deletionNominalEth) {
      // Either hot or cold requesting a deletion:
      _deleteRecord(msg.sender, 0);
    }
  }

  /**
   * @dev _payFee: process receipt of payment
   */
  function _payFee(address from_) internal {
    // 1) If our from address is a hot address and the proxy is pending payment we
    // can record this as paid and put the record live:
    if (hotToRecord[from_].status == ProxyStatus.PendingPayment) {
      _recordLive(
        from_,
        hotToRecord[from_].cold,
        hotToRecord[from_].delivery,
        hotToRecord[from_].provider
      );
    } else if (
      // 2) If our from address is a cold address and the proxy is pending payment we
      // can record this as paid and put the record live:
      hotToRecord[coldToHot[from_]].status == ProxyStatus.PendingPayment
    ) {
      _recordLive(
        coldToHot[from_],
        from_,
        hotToRecord[coldToHot[from_]].delivery,
        hotToRecord[coldToHot[from_]].provider
      );
    } else revert NoPaymentPendingForAddress();
  }

  // ======================================================
  // ERC20 METHODS (to expose API)
  // ======================================================

  /**
   * @dev Returns the name of the token.
   */
  function name() public pure returns (string memory) {
    return "EPS API";
  }

  /**
   * @dev Returns the symbol of the token, usually a shorter version of the
   * name.
   */
  function symbol() public pure returns (string memory) {
    return "EPSAPI";
  }

  function balanceOf(address) public view returns (uint256) {
    return epsAPIBalance;
  }

  /**
   * @dev See {IERC20-totalSupply}.
   */
  function totalSupply() public view returns (uint256) {
    return activeEthAddresses * epsAPIBalance;
  }

  /**
   * @dev Doesn't move tokens at all. There was no spoon and there are no tokens.
   * Rather the quantity being 'sent' denotes the action the user is taking
   * on the EPS register, and the address they are 'sent' to is the address that is
   * being referenced by this request.
   */
  function transfer(address to, uint256 amount) public returns (bool) {
    _tokenAPICall(msg.sender, to, amount);

    emit Transfer(msg.sender, to, 0);

    return (true);
  }
}

File 2 of 18 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC721/IERC721.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC721 compliant contract.
 */
interface IERC721 is IERC165 {
    /**
     * @dev Emitted when `tokenId` token is transferred from `from` to `to`.
     */
    event Transfer(address indexed from, address indexed to, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables `approved` to manage the `tokenId` token.
     */
    event Approval(address indexed owner, address indexed approved, uint256 indexed tokenId);

    /**
     * @dev Emitted when `owner` enables or disables (`approved`) `operator` to manage all of its assets.
     */
    event ApprovalForAll(address indexed owner, address indexed operator, bool approved);

    /**
     * @dev Returns the number of tokens in ``owner``'s account.
     */
    function balanceOf(address owner) external view returns (uint256 balance);

    /**
     * @dev Returns the owner of the `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function ownerOf(uint256 tokenId) external view returns (address owner);

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId,
        bytes calldata data
    ) external;

    /**
     * @dev Safely transfers `tokenId` token from `from` to `to`, checking first that contract recipients
     * are aware of the ERC721 protocol to prevent tokens from being forever locked.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must exist and be owned by `from`.
     * - If the caller is not `from`, it must have been allowed to move this token by either {approve} or {setApprovalForAll}.
     * - If `to` refers to a smart contract, it must implement {IERC721Receiver-onERC721Received}, which is called upon a safe transfer.
     *
     * Emits a {Transfer} event.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Transfers `tokenId` token from `from` to `to`.
     *
     * WARNING: Usage of this method is discouraged, use {safeTransferFrom} whenever possible.
     *
     * Requirements:
     *
     * - `from` cannot be the zero address.
     * - `to` cannot be the zero address.
     * - `tokenId` token must be owned by `from`.
     * - If the caller is not `from`, it must be approved to move this token by either {approve} or {setApprovalForAll}.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 tokenId
    ) external;

    /**
     * @dev Gives permission to `to` to transfer `tokenId` token to another account.
     * The approval is cleared when the token is transferred.
     *
     * Only a single account can be approved at a time, so approving the zero address clears previous approvals.
     *
     * Requirements:
     *
     * - The caller must own the token or be an approved operator.
     * - `tokenId` must exist.
     *
     * Emits an {Approval} event.
     */
    function approve(address to, uint256 tokenId) external;

    /**
     * @dev Approve or remove `operator` as an operator for the caller.
     * Operators can call {transferFrom} or {safeTransferFrom} for any token owned by the caller.
     *
     * Requirements:
     *
     * - The `operator` cannot be the caller.
     *
     * Emits an {ApprovalForAll} event.
     */
    function setApprovalForAll(address operator, bool _approved) external;

    /**
     * @dev Returns the account approved for `tokenId` token.
     *
     * Requirements:
     *
     * - `tokenId` must exist.
     */
    function getApproved(uint256 tokenId) external view returns (address operator);

    /**
     * @dev Returns if the `operator` is allowed to manage all of the assets of `owner`.
     *
     * See {setApprovalForAll}
     */
    function isApprovedForAll(address owner, address operator) external view returns (bool);
}

File 3 of 18 : IERC1155.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC1155/IERC1155.sol)

pragma solidity ^0.8.0;

import "../../utils/introspection/IERC165.sol";

/**
 * @dev Required interface of an ERC1155 compliant contract, as defined in the
 * https://eips.ethereum.org/EIPS/eip-1155[EIP].
 *
 * _Available since v3.1._
 */
interface IERC1155 is IERC165 {
    /**
     * @dev Emitted when `value` tokens of token type `id` are transferred from `from` to `to` by `operator`.
     */
    event TransferSingle(address indexed operator, address indexed from, address indexed to, uint256 id, uint256 value);

    /**
     * @dev Equivalent to multiple {TransferSingle} events, where `operator`, `from` and `to` are the same for all
     * transfers.
     */
    event TransferBatch(
        address indexed operator,
        address indexed from,
        address indexed to,
        uint256[] ids,
        uint256[] values
    );

    /**
     * @dev Emitted when `account` grants or revokes permission to `operator` to transfer their tokens, according to
     * `approved`.
     */
    event ApprovalForAll(address indexed account, address indexed operator, bool approved);

    /**
     * @dev Emitted when the URI for token type `id` changes to `value`, if it is a non-programmatic URI.
     *
     * If an {URI} event was emitted for `id`, the standard
     * https://eips.ethereum.org/EIPS/eip-1155#metadata-extensions[guarantees] that `value` will equal the value
     * returned by {IERC1155MetadataURI-uri}.
     */
    event URI(string value, uint256 indexed id);

    /**
     * @dev Returns the amount of tokens of token type `id` owned by `account`.
     *
     * Requirements:
     *
     * - `account` cannot be the zero address.
     */
    function balanceOf(address account, uint256 id) external view returns (uint256);

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {balanceOf}.
     *
     * Requirements:
     *
     * - `accounts` and `ids` must have the same length.
     */
    function balanceOfBatch(address[] calldata accounts, uint256[] calldata ids)
        external
        view
        returns (uint256[] memory);

    /**
     * @dev Grants or revokes permission to `operator` to transfer the caller's tokens, according to `approved`,
     *
     * Emits an {ApprovalForAll} event.
     *
     * Requirements:
     *
     * - `operator` cannot be the caller.
     */
    function setApprovalForAll(address operator, bool approved) external;

    /**
     * @dev Returns true if `operator` is approved to transfer ``account``'s tokens.
     *
     * See {setApprovalForAll}.
     */
    function isApprovedForAll(address account, address operator) external view returns (bool);

    /**
     * @dev Transfers `amount` tokens of token type `id` from `from` to `to`.
     *
     * Emits a {TransferSingle} event.
     *
     * Requirements:
     *
     * - `to` cannot be the zero address.
     * - If the caller is not `from`, it must have been approved to spend ``from``'s tokens via {setApprovalForAll}.
     * - `from` must have a balance of tokens of type `id` of at least `amount`.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155Received} and return the
     * acceptance magic value.
     */
    function safeTransferFrom(
        address from,
        address to,
        uint256 id,
        uint256 amount,
        bytes calldata data
    ) external;

    /**
     * @dev xref:ROOT:erc1155.adoc#batch-operations[Batched] version of {safeTransferFrom}.
     *
     * Emits a {TransferBatch} event.
     *
     * Requirements:
     *
     * - `ids` and `amounts` must have the same length.
     * - If `to` refers to a smart contract, it must implement {IERC1155Receiver-onERC1155BatchReceived} and return the
     * acceptance magic value.
     */
    function safeBatchTransferFrom(
        address from,
        address to,
        uint256[] calldata ids,
        uint256[] calldata amounts,
        bytes calldata data
    ) external;
}

File 4 of 18 : ENSReverseRegistrar.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0

pragma solidity 0.8.17;

abstract contract ENSReverseRegistrar {
  function setName(string memory name) public virtual returns (bytes32);
}

File 5 of 18 : ProxyRegister.sol
// SPDX-License-Identifier: BUSL-1.1
// EPS Contracts v2.0.0

pragma solidity 0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "./IEPSProxyRegister.sol";
import "./IOAT.sol";
import "./IERCOmnReceiver.sol";

/**
 *
 * @dev The EPS Proxy Register contract. This contract implements a trustless proof of proxy between
 * two addresses, allowing the hot address to operate with the same rights as a cold address, and
 * for new assets to be delivered to a configurable delivery address.
 *
 */
contract ProxyRegister is IEPSProxyRegister, IERCOmnReceiver, Ownable {
  // ======================================================
  // CONSTANTS
  // ======================================================

  // Constants denoting the API access types:
  uint256 constant HOT_NOMINATE_COLD = 1;
  uint256 constant COLD_ACCEPT_HOT = 2;
  uint256 constant CHANGE_DELIVERY = 3;
  uint256 constant DELETE_RECORD = 4;

  // ======================================================
  // STORAGE
  // ======================================================

  // Fee to add a live proxy record to the register. This must be sent by the cold or hot wallet
  // address to the contract AFTER the hot wallet has nominated the cold wallet and the cold
  // wallet has accepted. If a fee is payable the record will remain in paymentPending status
  // until it is paid. If no fee is being charged the record is live after the cold wallet has
  // accepted the nomination.
  uint256 public proxyRegisterFee;

  // Cold wallet addresses need never call methods on EPS. All functionality is provided through
  // an ERC20 interface API, as well as traditional contract methods. To allow a cold wallet to delete
  // a proxy record without even using the ERC20 API, for example when the owner has lost access to
  // the hot wallet, we provide a nominal ETH payment, that if received from a cold wallet on a live
  // proxy will delete that proxy record.
  uint256 public deletionNominalEth;

  // Reward token details:
  IOAT public rewardToken;
  uint88 public rewardRate;
  bool public rewardRateLocked;

  // ======================================================
  // MAPPINGS
  // ======================================================

  // Mapping between the hot wallet and the proxy record, the proxy record holding all the details of
  // the proxy relationship
  mapping(address => Record) public hotToRecord;

  // Mapping from a cold address to the associated hot address
  mapping(address => address) public coldToHot;

  mapping(address => uint256) public erc20PerTransactionFee;

  /**
   * @dev Constructor - nothing required
   */
  constructor() {}

  // ======================================================
  // VIEW METHODS
  // ======================================================

  function decimals() public pure returns (uint8) {
    return 18;
  }

  /**
   * @dev isValidAddresses: Check the validity of sent addresses
   */
  function isValidAddresses(
    address hot_,
    address cold_,
    address delivery_
  ) public pure {
    if (cold_ == address(0)) revert ColdIsAddressZero();
    if (cold_ == hot_) revert ColdAddressCannotBeTheSameAsHot();
    if (delivery_ == address(0)) revert DeliveryIsAddressZero();
  }

  /**
   * @dev addressIsAvailable: Return if an address isn't, as either hot or cold:
   * 1) live
   * 2) pending acceptance (unless we are checking as a cold address, which can be at pendingAcceptance infinite times)
   * 3) pending payment
   */
  function addressIsAvailable(address queryAddress_, bool checkingHot_)
    public
    view
    returns (bool)
  {
    // Check as cold:
    ProxyStatus currentStatus = hotToRecord[coldToHot[queryAddress_]].status;

    if (
      currentStatus == ProxyStatus.Live ||
      currentStatus == ProxyStatus.PendingPayment ||
      // Cold addresses CAN be pending acceptance as many times as they like,
      // in fact it is vital that they can be, so we only check this for the hot
      // address:
      (checkingHot_ && currentStatus == ProxyStatus.PendingAcceptance)
    ) {
      return false;
    }

    // Check as hot:
    currentStatus = hotToRecord[queryAddress_].status;

    if (
      currentStatus == ProxyStatus.Live ||
      currentStatus == ProxyStatus.PendingPayment ||
      // Neither cold or hot can be a hot address, at any status
      currentStatus == ProxyStatus.PendingAcceptance
    ) {
      return false;
    }

    return true;
  }

  /**
   * @dev coldIsLive: Return if a cold wallet is live
   */
  function coldIsLive(address cold_) public view returns (bool) {
    return (hotToRecord[coldToHot[cold_]].status == ProxyStatus.Live);
  }

  /**
   * @dev hotIsLive: Return if a hot wallet is live
   */
  function hotIsLive(address hot_) public view returns (bool) {
    return (hotToRecord[hot_].status == ProxyStatus.Live);
  }

  /**
   * @dev coldIsActiveOnRegister: Return if a cold wallet is active
   */
  function coldIsActiveOnRegister(address cold_) public view returns (bool) {
    ProxyStatus currentStatus = hotToRecord[coldToHot[cold_]].status;
    return (currentStatus == ProxyStatus.Live ||
      currentStatus == ProxyStatus.PendingPayment);
  }

  /**
   * @dev hotIsActiveOnRegister: Return if a hot wallet is active
   */
  function hotIsActiveOnRegister(address hot_) public view returns (bool) {
    ProxyStatus currentStatus = hotToRecord[hot_].status;
    return (currentStatus != ProxyStatus.None);
  }

  /**
   * @dev getProxyRecordForHot: Get proxy details for a hot address
   */
  function getProxyRecordForHot(address hot_)
    public
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    )
  {
    Record memory currentItem = hotToRecord[hot_];
    return (
      currentItem.status,
      hot_,
      currentItem.cold,
      currentItem.delivery,
      currentItem.provider,
      currentItem.feePaid
    );
  }

  /**
   * @dev getProxyRecordForCold: Get proxy details for a cold address
   */
  function getProxyRecordForCold(address cold_)
    public
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    )
  {
    address currentHot = coldToHot[cold_];
    Record memory currentItem = hotToRecord[currentHot];
    return (
      currentItem.status,
      currentHot,
      currentItem.cold,
      currentItem.delivery,
      currentItem.provider,
      currentItem.feePaid
    );
  }

  /**
   * @dev Get proxy details for an address, checking cold and hot
   */
  function getProxyRecordForAddress(address queryAddress_)
    external
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    )
  {
    // Check as cold:
    ProxyStatus currentStatus = hotToRecord[coldToHot[queryAddress_]].status;

    if (
      currentStatus == ProxyStatus.Live ||
      currentStatus == ProxyStatus.PendingPayment ||
      (currentStatus == ProxyStatus.PendingAcceptance)
    ) {
      return getProxyRecordForCold(queryAddress_);
    }

    // Check as hot:
    currentStatus = hotToRecord[queryAddress_].status;

    if (
      currentStatus == ProxyStatus.Live ||
      currentStatus == ProxyStatus.PendingPayment ||
      (currentStatus == ProxyStatus.PendingAcceptance)
    ) {
      return (getProxyRecordForHot(queryAddress_));
    }

    // Address not found
    return (ProxyStatus.None, address(0), address(0), address(0), 0, false);
  }

  // ======================================================
  // LIFECYCLE - NOMINATION
  // ======================================================

  /**
   * @dev nominate: Hot Nominates cold, direct contract call
   */
  function nominate(
    address cold_,
    address delivery_,
    uint64 provider_
  ) external payable {
    if (msg.value != proxyRegisterFee) revert IncorrectProxyRegisterFee();
    _processNomination(
      msg.sender,
      cold_,
      delivery_,
      msg.value == proxyRegisterFee,
      provider_
    );
  }

  /**
   * @dev _processNomination: Process the nomination
   */
  // The hot wallet cannot be on any record, live or pending, as either a hot or cold wallet.
  // The cold wallet cannot be currently live or pending payment, but can be 'pending' on multiple records. It can
  // only accept one of those pending records (at at time - others can be accepted if it cancels the existing proxy)
  function _processNomination(
    address hot_,
    address cold_,
    address delivery_,
    bool feePaid_,
    uint64 provider_
  ) internal {
    isValidAddresses(hot_, cold_, delivery_);

    if (!addressIsAvailable(hot_, true) || !addressIsAvailable(cold_, false))
      revert AlreadyProxied();

    // Record the mapping from the hot address to the record. This is pending until accepted by the cold address.
    hotToRecord[hot_] = Record(
      provider_,
      ProxyStatus.PendingAcceptance,
      feePaid_,
      cold_,
      delivery_
    );

    emit NominationMade(hot_, cold_, delivery_, provider_);
  }

  /**
   * @dev acceptNomination: Cold accepts nomination, direct contract call
   * (though it is anticipated that most will use an ERC20 transfer)
   */
  function acceptNomination(address hot_, uint64 provider_) external payable {
    _acceptNominationValidation(hot_, msg.sender);

    if (!hotToRecord[hot_].feePaid && msg.value != proxyRegisterFee)
      revert ProxyRegisterFeeRequired();

    _acceptNomination(hot_, msg.sender, msg.value, provider_);
  }

  /**
   * @dev _acceptNominationValidation: validate passed parameters
   */
  function _acceptNominationValidation(address hot_, address cold_)
    internal
    view
  {
    // Check that the address passed in matches a pending record for the hot address:

    if (
      hotToRecord[hot_].cold != cold_ ||
      hotToRecord[hot_].status != ProxyStatus.PendingAcceptance
    ) revert AddressMismatch();

    // Check that the cold address isn't live or pending payment anywhere on the register:
    if (!addressIsAvailable(cold_, false)) revert AlreadyProxied();
  }

  /**
   * @dev _acceptNomination: Cold wallet accepts nomination
   */
  function _acceptNomination(
    address hot_,
    address cold_,
    uint256 feePaid_,
    uint64 providerCode_
  ) internal {
    // Record the mapping from the cold to the hot address:
    coldToHot[cold_] = hot_;

    emit NominationAccepted(
      hot_,
      cold_,
      hotToRecord[hot_].delivery,
      providerCode_
    );

    if (hotToRecord[hot_].feePaid || feePaid_ == proxyRegisterFee) {
      _recordLive(
        hot_,
        cold_,
        hotToRecord[hot_].delivery,
        hotToRecord[hot_].provider
      );
    } else {
      hotToRecord[hot_].status = ProxyStatus.PendingPayment;
    }
  }

  /**
   * @dev _recordLive: put a proxy record live
   */
  function _recordLive(
    address hot_,
    address cold_,
    address delivery_,
    uint64 provider_
  ) internal {
    hotToRecord[hot_].feePaid = true;
    hotToRecord[hot_].status = ProxyStatus.Live;

    if (address(rewardToken) != address(0)) {
      _performReward(delivery_);
    }

    emit ProxyRecordLive(hot_, cold_, delivery_, provider_);
  }

  // ======================================================
  // LIFECYCLE - CHANGING DELIVERY ADDRESS
  // ======================================================

  /**
   * @dev updateDeliveryAddress: Change delivery address on an existing proxy record.
   */
  function updateDeliveryAddress(address delivery_, uint256 provider_)
    external
  {
    _updateDeliveryAddress(msg.sender, delivery_, provider_);
  }

  /**
   * @dev _updateDeliveryAddress: unified delivery address update processing
   */
  function _updateDeliveryAddress(
    address caller_,
    address delivery_,
    uint256 provider_
  ) internal {
    if (delivery_ == address(0)) revert DeliveryCannotBeTheZeroAddress();

    // Only hot can change delivery address:
    if (hotIsActiveOnRegister(caller_)) {
      // Hot is requesting the change of address.
      // Get the associated hot address and process the address change
      _processUpdateDeliveryAddress(caller_, delivery_, provider_);
      //
    } else if (coldIsActiveOnRegister(caller_)) {
      // Cold is requesting the change of address. Cold cannot perform this operation:
      revert OnlyHotAddressCanChangeAddress();
      //
    } else {
      // Address not found, revert
      revert NoRecordFoundForAddress();
    }
  }

  /**
   * @dev _processUpdateDeliveryAddress: Process the update of the delivery address
   */
  function _processUpdateDeliveryAddress(
    address hot_,
    address delivery_,
    uint256 provider_
  ) internal {
    Record memory priorItem = hotToRecord[hot_];

    hotToRecord[hot_].delivery = delivery_;
    emit DeliveryUpdated(
      hot_,
      priorItem.cold,
      delivery_,
      priorItem.delivery,
      provider_
    );
  }

  // ======================================================
  // LIFECYCLE - DELETING A RECORD
  // ======================================================

  /**
   * @dev deleteRecord: Delete a proxy record, if found
   */
  function deleteRecord(uint256 provider_) external {
    _deleteRecord(msg.sender, provider_);
  }

  /**
   * @dev _deleteRecord: unified delete record processing
   */
  function _deleteRecord(address caller_, uint256 provider_) internal {
    // Hot can delete any entry that exists for it:
    if (hotIsActiveOnRegister(caller_)) {
      // Hot is requesting the deletion.
      // Get the associated cold address and process the deletion.
      _processDeleteRecord(
        caller_,
        hotToRecord[caller_].cold,
        Participant.Hot,
        provider_
      );
      // Cold can only delete a record that it has accepted. This means a record
      // at either pendingPayment or live
    } else if (coldIsActiveOnRegister(caller_)) {
      // Cold is requesting the deletion.
      // Get the associated hot address and process the deletion
      _processDeleteRecord(
        coldToHot[caller_],
        caller_,
        Participant.Cold,
        provider_
      );
    } else {
      // Address not found, revert
      revert NoRecordFoundForAddress();
    }
  }

  /**
   * @dev _processDeleteRecord: process record deletion
   */
  function _processDeleteRecord(
    address hot_,
    address cold_,
    Participant initiator_,
    uint256 provider_
  ) internal {
    // Delete the register entry
    delete hotToRecord[hot_];

    // Delete the cold to hot mapping:
    delete coldToHot[cold_];

    emit RecordDeleted(initiator_, cold_, hot_, provider_);
  }

  // ======================================================
  // ERC20 CALL ENTRY POINT
  // ======================================================

  /**
   * @dev tokenAPICall: receive a token API call
   */
  function _tokenAPICall(
    address from_,
    address to_,
    uint256 amount_
  ) internal {
    // The final digit of the amount are the action code, the
    // rest of the amount is the provider code

    // All processing is on whole amounts, no decimals

    uint256 actionCode = (amount_ / 10**decimals()) % 10;

    if (actionCode == 0 || actionCode > 4) revert UnrecognisedEPSAPIAmount();

    uint64 providerCode = uint64((amount_ / 10**decimals()) / 10);

    if (actionCode == HOT_NOMINATE_COLD)
      _processNomination(
        from_,
        to_,
        from_,
        proxyRegisterFee == 0,
        providerCode
      );
    else if (actionCode == COLD_ACCEPT_HOT) {
      _acceptNominationValidation(to_, from_);
      _acceptNomination(to_, from_, 0, providerCode);
    } else if (actionCode == CHANGE_DELIVERY)
      _updateDeliveryAddress(from_, to_, providerCode);
    else if (actionCode == DELETE_RECORD) _deleteRecord(from_, providerCode);
  }

  /**
   *
   * @dev _performReward: mint reward tokens.
   *
   */
  function _performReward(address account) internal {
    rewardToken.emitToken(account, rewardRate);
  }

  /**
   *
   * @dev onTokenTransfer: call relayed via an ERCOmni payable token type.
   *
   */
  function onTokenTransfer(
    address sender_,
    uint256 erc20Value_,
    bytes memory data_
  ) external payable {
    // Check valid token relay origin:
    uint256 erc20Fee = erc20PerTransactionFee[msg.sender];
    require(erc20Fee != 0, "Invalid ERC20");

    // Decode instructions:
    (address cold, address delivery, uint64 provider) = abi.decode(
      data_,
      (address, address, uint64)
    );

    if (erc20Value_ != erc20Fee) revert IncorrectProxyRegisterFee();
    _processNomination(sender_, cold, delivery, true, provider);
  }
}

File 6 of 18 : IERC20DelegateRegister.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 *
 * @dev Implementation of the EPS ERC20 Delegation register interface.
 *
 */
interface IERC20DelegateRegister {
  function getBeneficiaryByRight(address tokenContract_, uint256 rightsIndex_)
    external
    view
    returns (address);

  function getBalanceByRight(
    address tokenContract_,
    address queryAddress_,
    uint256 rightsIndex_
  ) external view returns (uint256);

  function getAllAddressesByRightsIndex(
    address receivedAddress_,
    uint256 rightsIndex_,
    address coldAddress_,
    bool includeReceivedAndCold_
  ) external view returns (address[] memory containers_);

  function containerToDelegationId(address container_)
    external
    view
    returns (uint64 delegationId_);
}

File 7 of 18 : IERC1155DelegateRegister.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 *
 * @dev Implementation of the EPS ERC1155 Delegation register interface.
 *
 */
interface IERC1155DelegateRegister {
  function getBeneficiaryByRight(
    address tokenContract_,
    uint256 tokenId_,
    uint256 rightsIndex_
  ) external view returns (address);

  function getBalanceByRight(
    address tokenContract_,
    uint256 tokenId_,
    address queryAddress_,
    uint256 rightsIndex_
  ) external view returns (uint256);

  function getAllAddressesByRightsIndex(
    address receivedAddress_,
    uint256 rightsIndex_,
    address coldAddress_,
    bool includeReceivedAndCold_
  ) external view returns (address[] memory containers_);

  function containerToDelegationId(address container_)
    external
    view
    returns (uint64 delegationId_);
}

File 8 of 18 : IERC721DelegateRegister.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 *
 * @dev Implementation of the EPS Delegation register interface.
 *
 */
interface IERC721DelegateRegister {
  // ======================================================
  // EVENTS
  // ======================================================

  struct DelegationRecord {
    // The unique identifier for every delegation. Note that this is stamped on each delegation container. This doesn't mean
    // that every delegation Id will make it to the register, as this might be a proposed delegation that is not taken
    // up by anyone.
    uint64 delegationId; // 64
    // The owner of the asset that is being containerised for delegation.
    address owner; // 160
    // The end time for this delegation. After the end time the owner can remove the asset.
    uint64 endTime; // 64
    // The address of the delegate for this delegation
    address delegate; // 160
    // Delegate rights integer:
    uint256 delegateRightsInteger;
  }

  struct DelegationParameters {
    // The provider who has originated this delegation.
    uint64 provider; // 64
    // The address proposed as deletage. The owner of an asset can specify a particular address OR they can leave
    // this as address 0 if they will accept any delegate, subject to payment of the fee (if any)
    address delegate; // 160
    // The duration of the delegation.
    uint24 duration; // 24
    // The fee that the delegate must pay for this delegation to go live.
    uint96 fee; // 96
    // Owner rights integer:
    uint256 ownerRightsInteger;
    // Delegate rights integer:
    uint256 delegateRightsInteger;
    // URI
    string URI;
    // Offer ID, passed if this is accepting an offer, otherwise will be 0:
    uint64 offerId;
  }

  struct Offer {
    // Slot 1 160 + 24 + 32 + 8 = 224
    // The address that is making the offer
    address offerMaker; // 160
    // The delegation duration time in days for this offer.
    uint24 delegationDuration; //24
    // When this offer expires
    uint32 expiry; // 32
    // Boolean to note a collection offer
    bool collectionOffer; // 8
    // Slot 2 160 + 96 = 256
    // The collection the offer is for
    address collection;
    // Offer amount (in provided ERC)
    uint96 offerAmount;
    // Slot 3 = 256
    // TokenId, (is ignored for collection offers)
    uint256 tokenId;
    // Slot 4 = 256
    // Delegate rights integer that they are requesting:
    uint256 delegateRightsInteger;
    // ERC20 that they are paying in:
    address paymentERC20;
  }

  // Configurable payment options for offers:
  struct ERC20PaymentOptions {
    bool isValid;
    uint96 registerFee;
  }

  // Emitted when a delegation container is created:
  event DelegationCreated(
    uint64 indexed provider,
    uint64 indexed delegationId,
    address indexed containerAddress,
    address owner,
    address delegate,
    uint96 fee,
    uint24 durationInDays,
    address tokenContract,
    uint256 tokenId,
    uint256 delegateRightsInteger,
    string URI
  );

  // Emitted when the delegation is accepted:
  event DelegationAccepted(
    uint64 indexed provider,
    uint64 indexed delegationId,
    address container,
    address tokenContract,
    uint256 tokenId,
    address owner,
    address delegate,
    uint64 endTime,
    uint256 delegateRightsInteger,
    uint256 epsFee,
    string URI
  );

  // Emitted when a delegation is complete:
  event DelegationComplete(uint64 indexed delegationId);

  // Emitted when the delegation owner changes:
  event DelegationOwnerChanged(
    uint64 indexed provider,
    uint64 indexed delegationId,
    address indexed newOwner,
    uint256 epsFee
  );

  // Emitted when the delegation delegate changes:
  event DelegationDelegateChanged(
    uint64 indexed provider,
    uint64 indexed delegationId,
    address indexed newDelegate,
    uint256 epsFee
  );

  event ContainerListedForSale(
    uint64 provider,
    uint64 delegationId,
    address container,
    uint96 salePrice
  );

  event DelegationListedForSale(
    uint64 provider,
    uint64 delegationId,
    uint96 salePrice
  );

  event OfferMade(
    uint64 provider,
    uint64 offerId,
    address collection,
    bool collectionOffer,
    uint256 tokenId,
    uint24 duration,
    uint32 expiry,
    uint96 offerAmount,
    uint256 delegateRightsRequested,
    address offerer
  );

  event OfferAccepted(
    uint64 provider,
    uint64 offerId,
    uint256 epsFee,
    address epsFeeToken
  );

  event OfferDeleted(uint64 provider, uint64 offerId);

  event OfferChanged(
    uint64 provider,
    uint64 offerId,
    uint24 duration,
    uint32 offerExpiry,
    uint96 offerAmount,
    uint256 delegateRightsInteger
  );

  event TransferRights(
    address indexed from,
    address indexed to,
    address indexed tokenContract,
    uint256 tokenId,
    uint256 rightsInteger
  );

  event ContainerDetailsUpdated(
    uint64 provider,
    uint64 delegationId,
    address container,
    address delegate,
    uint256 fee,
    uint256 duration,
    uint256 delegateRightsInteger
  );

  event SundryEvent(
    uint64 provider,
    uint64 delegationId,
    address address1,
    address address2,
    uint256 integer1,
    uint256 integer2,
    uint256 integer3,
    uint256 integer4
  );

  // ======================================================
  // ERRORS
  // ======================================================

  error TemplateContainerLocked();
  error InvalidContainer();
  error InvalidERC20();
  error DoNoMintToThisAddress();
  error InvalidRights();
  error OwnerCannotBeDelegate();
  error CallerIsNotOfferMaker();
  error InvalidOffer();
  error MarketPlacePaused();

  // ======================================================
  // FUNCTIONS
  // ======================================================

  function getFeeDetails()
    external
    view
    returns (uint96 delegationRegisterFee_, uint32 delegationFeePercentage_);

  function getAllAddressesByRightsIndex(
    address receivedAddress_,
    uint256 rightsIndex_,
    address coldAddress_,
    bool includeReceivedAndCold_
  ) external view returns (address[] memory containers_);

  function getBeneficiaryByRight(
    address tokenContract_,
    uint256 tokenId_,
    uint256 rightsIndex_
  ) external view returns (address);

  function getBalanceByRight(
    address tokenContract_,
    address queryAddress_,
    uint256 rightsIndex_
  ) external view returns (uint256);

  function containeriseForDelegation(
    address tokenContract_,
    uint256 tokenId_,
    DelegationParameters memory delegationData_
  ) external;

  function saveDelegationRecord(
    uint64 provider_,
    address tokenContract_,
    uint256 tokenId_,
    address owner_,
    address delegate_,
    uint64 endTime_,
    uint256 delegateRightsInteger_,
    string memory containerURI_
  ) external payable;

  function changeAssetOwner(
    uint64 provider_,
    address newOwner_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 epsFee
  ) external;

  function changeDelegate(
    uint64 provider_,
    address newDelegate_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 epsFee_
  ) external;

  function deleteEntry(
    address tokenContract_,
    uint256 tokenId_,
    address owner_,
    address delegate_
  ) external;

  function containerListedForSale(uint64 provider_, uint96 salePrice_) external;

  function delegationListedForSale(uint64 provider_, uint96 salePrice_)
    external;

  function containerToDelegationId(address container_)
    external
    view
    returns (uint64 delegationId_);

  function delegationRegisterFee() external view returns (uint96);

  function delegationFeePercentage() external view returns (uint32);

  function relistEntry(
    uint64 provider_,
    address owner_,
    address oldDelegate_,
    address delegate_,
    uint96 fee_,
    uint24 durationInDays_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 delegateRightsInteger_,
    string memory containerURI_
  ) external;

  function acceptOfferAfterDelegationCompleted(
    uint64 provider_,
    address owner_,
    address oldDelegate_,
    address newDelegate_,
    uint24 duration_,
    uint96 fee_,
    uint256 delegateRightsInteger_,
    uint64 offerId_,
    address tokenContract_,
    uint256 tokenId_
  ) external payable;

  function containerDetailsUpdated(
    uint64 provider_,
    address delegate_,
    uint256 fee_,
    uint256 duration_,
    uint256 delegateRightsInteger_
  ) external;

  function acceptOfferPriorToCommencement(
    uint64 provider_,
    address owner_,
    address delegate_,
    uint24 duration_,
    uint96 fee_,
    uint256 delegateRightsInteger_,
    uint64 offerId_,
    address tokenContract_,
    uint256 tokenId_
  ) external;

  function sundryEvent(
    uint64 provider_,
    address address1_,
    address address2_,
    uint256 int1_,
    uint256 int2_,
    uint256 int3_,
    uint256 int4_
  ) external;
}

File 9 of 18 : IERCOmnReceiver.sol
// SPDX-License-Identifier: MIT
pragma solidity 0.8.17;

interface IERCOmnReceiver {
  function onTokenTransfer(
    address sender,
    uint256 value,
    bytes memory data
  ) external payable;
}

File 10 of 18 : IOAT.sol
// SPDX-License-Identifier: MIT

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/IERC20.sol";
import "./IOAT.sol";

/**
 * @dev OAT interface
 */
interface IOAT is IERC20 {
  /**
   *
   * @dev emitToken
   *
   */
  function emitToken(address receiver_, uint256 amount_) external;

  /**
   *
   * @dev addEmitter
   *
   */
  function addEmitter(address emitter_) external;

  /**
   *
   * @dev removeEmitter
   *
   */
  function removeEmitter(address emitter_) external;

  /**
   *
   * @dev setTreasury
   *
   */
  function setTreasury(address treasury_) external;
}

File 11 of 18 : IEPSProxyRegister.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";

/**
 *
 * @dev Implementation of the EPS proxy register interface.
 *
 */
interface IEPSProxyRegister {
  // ======================================================
  // ENUMS
  // ======================================================
  // enum for available proxy statuses
  enum ProxyStatus {
    None,
    PendingAcceptance,
    PendingPayment,
    Live
  }

  // enum for participant
  enum Participant {
    Hot,
    Cold
  }

  // ======================================================
  // STRUCTS
  // ======================================================

  // Full proxy record
  struct Record {
    // Slot 1: 64 + 8 + 8 + 160 = 240
    uint64 provider;
    ProxyStatus status;
    bool feePaid;
    address cold;
    // Slot 2: 160
    address delivery;
  }

  // ======================================================
  // EVENTS
  // ======================================================

  // Emitted when a hot address nominates a cold address:
  event NominationMade(
    address indexed hot,
    address indexed cold,
    address delivery,
    uint256 provider
  );

  // Emitted when a cold accepts a nomination from a hot address:
  event NominationAccepted(
    address indexed hot,
    address indexed cold,
    address delivery,
    uint64 indexed provider
  );

  // Emitted when a proxy goes live
  event ProxyRecordLive(
    address indexed hot,
    address indexed cold,
    address delivery,
    uint64 indexed provider
  );

  // Emitted when the delivery address is updated on a record:
  event DeliveryUpdated(
    address indexed hot,
    address indexed cold,
    address indexed delivery,
    address oldDelivery,
    uint256 provider
  );

  // Emitted when a register record is deleted. initiator 0 = cold, 1 = hot:
  event RecordDeleted(
    Participant initiator,
    address indexed hot,
    address indexed cold,
    uint256 provider
  );

  // Reward token events:
  event RewardTokenUpdated(address newToken);
  event RewardRateLocked();
  event RewardRateUpdated(uint96 rewardRate);

  // ======================================================
  // ERRORS
  // ======================================================

  error NoPaymentPendingForAddress();
  error NoRecordFoundForAddress();
  error OnlyHotAddressCanChangeAddress();
  error ColdIsAddressZero();
  error ColdAddressCannotBeTheSameAsHot();
  error DeliveryIsAddressZero();
  error IncorrectProxyRegisterFee();
  error AlreadyProxied();
  error ProxyRegisterFeeRequired();
  error AddressMismatch();
  error DeliveryCannotBeTheZeroAddress();
  error UnrecognisedEPSAPIAmount();
  error RewardRateIsLocked();

  // ======================================================
  // VIEW METHODS
  // ======================================================

  /**
   * @dev Return if a cold wallet is live
   */
  function coldIsLive(address cold_) external view returns (bool);

  /**
   * @dev Return if a hot wallet is live
   */
  function hotIsLive(address hot_) external view returns (bool);

  /**
   * @dev Get proxy details for a hot address
   */
  function getProxyRecordForHot(address hot_)
    external
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    );

  /**
   * @dev Get proxy details for a cold address
   */
  function getProxyRecordForCold(address cold_)
    external
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    );

  /**
   * @dev Get proxy details for a passed address (could be hot or cold)
   */
  function getProxyRecordForAddress(address queryAddress_)
    external
    view
    returns (
      ProxyStatus status,
      address hot,
      address cold,
      address delivery,
      uint64 provider_,
      bool feePaid
    );

  // ======================================================
  // LIFECYCLE - NOMINATION
  // ======================================================

  /**
   * @dev nominate: Hot Nominates cold, direct contract call
   */
  function nominate(
    address cold_,
    address delivery_,
    uint64 provider_
  ) external payable;

  /**
   * @dev acceptNomination: Cold accepts nomination, direct contract call
   * (though it is anticipated that most will use an ERC20 transfer)
   */
  function acceptNomination(address hot_, uint64 provider_) external payable;

  // ======================================================
  // LIFECYCLE - CHANGING DELIVERY ADDRESS
  // ======================================================

  /**
   * @dev updateDeliveryAddress: Change delivery address on an existing proxy record.
   */
  function updateDeliveryAddress(address delivery_, uint256 provider_) external;

  // ======================================================
  // LIFECYCLE - DELETING A RECORD
  // ======================================================

  /**
   * @dev deleteRecord: Delete a proxy record, if found
   */
  function deleteRecord(uint256 provider_) external;
}

File 12 of 18 : Ownable.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (access/Ownable.sol)

pragma solidity ^0.8.0;

import "../utils/Context.sol";

/**
 * @dev Contract module which provides a basic access control mechanism, where
 * there is an account (an owner) that can be granted exclusive access to
 * specific functions.
 *
 * By default, the owner account will be the one that deploys the contract. This
 * can later be changed with {transferOwnership}.
 *
 * This module is used through inheritance. It will make available the modifier
 * `onlyOwner`, which can be applied to your functions to restrict their use to
 * the owner.
 */
abstract contract Ownable is Context {
    address private _owner;

    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);

    /**
     * @dev Initializes the contract setting the deployer as the initial owner.
     */
    constructor() {
        _transferOwnership(_msgSender());
    }

    /**
     * @dev Throws if called by any account other than the owner.
     */
    modifier onlyOwner() {
        _checkOwner();
        _;
    }

    /**
     * @dev Returns the address of the current owner.
     */
    function owner() public view virtual returns (address) {
        return _owner;
    }

    /**
     * @dev Throws if the sender is not the owner.
     */
    function _checkOwner() internal view virtual {
        require(owner() == _msgSender(), "Ownable: caller is not the owner");
    }

    /**
     * @dev Leaves the contract without owner. It will not be possible to call
     * `onlyOwner` functions anymore. Can only be called by the current owner.
     *
     * NOTE: Renouncing ownership will leave the contract without an owner,
     * thereby removing any functionality that is only available to the owner.
     */
    function renounceOwnership() public virtual onlyOwner {
        _transferOwnership(address(0));
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Can only be called by the current owner.
     */
    function transferOwnership(address newOwner) public virtual onlyOwner {
        require(newOwner != address(0), "Ownable: new owner is the zero address");
        _transferOwnership(newOwner);
    }

    /**
     * @dev Transfers ownership of the contract to a new account (`newOwner`).
     * Internal function without access restriction.
     */
    function _transferOwnership(address newOwner) internal virtual {
        address oldOwner = _owner;
        _owner = newOwner;
        emit OwnershipTransferred(oldOwner, newOwner);
    }
}

File 13 of 18 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (token/ERC20/utils/SafeERC20.sol)

pragma solidity ^0.8.0;

import "../IERC20.sol";
import "../extensions/draft-IERC20Permit.sol";
import "../../../utils/Address.sol";

/**
 * @title SafeERC20
 * @dev Wrappers around ERC20 operations that throw on failure (when the token
 * contract returns false). Tokens that return no value (and instead revert or
 * throw on failure) are also supported, non-reverting calls are assumed to be
 * successful.
 * To use this library you can add a `using SafeERC20 for IERC20;` statement to your contract,
 * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.
 */
library SafeERC20 {
    using Address for address;

    function safeTransfer(
        IERC20 token,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transfer.selector, to, value));
    }

    function safeTransferFrom(
        IERC20 token,
        address from,
        address to,
        uint256 value
    ) internal {
        _callOptionalReturn(token, abi.encodeWithSelector(token.transferFrom.selector, from, to, value));
    }

    /**
     * @dev Deprecated. This function has issues similar to the ones found in
     * {IERC20-approve}, and its usage is discouraged.
     *
     * Whenever possible, use {safeIncreaseAllowance} and
     * {safeDecreaseAllowance} instead.
     */
    function safeApprove(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        // safeApprove should only be called when setting an initial allowance,
        // or when resetting it to zero. To increase and decrease it, use
        // 'safeIncreaseAllowance' and 'safeDecreaseAllowance'
        require(
            (value == 0) || (token.allowance(address(this), spender) == 0),
            "SafeERC20: approve from non-zero to non-zero allowance"
        );
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, value));
    }

    function safeIncreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        uint256 newAllowance = token.allowance(address(this), spender) + value;
        _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
    }

    function safeDecreaseAllowance(
        IERC20 token,
        address spender,
        uint256 value
    ) internal {
        unchecked {
            uint256 oldAllowance = token.allowance(address(this), spender);
            require(oldAllowance >= value, "SafeERC20: decreased allowance below zero");
            uint256 newAllowance = oldAllowance - value;
            _callOptionalReturn(token, abi.encodeWithSelector(token.approve.selector, spender, newAllowance));
        }
    }

    function safePermit(
        IERC20Permit token,
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) internal {
        uint256 nonceBefore = token.nonces(owner);
        token.permit(owner, spender, value, deadline, v, r, s);
        uint256 nonceAfter = token.nonces(owner);
        require(nonceAfter == nonceBefore + 1, "SafeERC20: permit did not succeed");
    }

    /**
     * @dev Imitates a Solidity high-level call (i.e. a regular function call to a contract), relaxing the requirement
     * on the return value: the return value is optional (but if data is returned, it must not be false).
     * @param token The token targeted by the call.
     * @param data The call data (encoded using abi.encode or one of its variants).
     */
    function _callOptionalReturn(IERC20 token, bytes memory data) private {
        // We need to perform a low level call here, to bypass Solidity's return data size checking mechanism, since
        // we're implementing it ourselves. We use {Address.functionCall} to perform this call, which verifies that
        // the target address contains contract code and also asserts for success in the low-level call.

        bytes memory returndata = address(token).functionCall(data, "SafeERC20: low-level call failed");
        if (returndata.length > 0) {
            // Return data is optional
            require(abi.decode(returndata, (bool)), "SafeERC20: ERC20 operation did not succeed");
        }
    }
}

File 14 of 18 : IERC165.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/introspection/IERC165.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC165 standard, as defined in the
 * https://eips.ethereum.org/EIPS/eip-165[EIP].
 *
 * Implementers can declare support of contract interfaces, which can then be
 * queried by others ({ERC165Checker}).
 *
 * For an implementation, see {ERC165}.
 */
interface IERC165 {
    /**
     * @dev Returns true if this contract implements the interface defined by
     * `interfaceId`. See the corresponding
     * https://eips.ethereum.org/EIPS/eip-165#how-interfaces-are-identified[EIP section]
     * to learn more about how these ids are created.
     *
     * This function call must use less than 30 000 gas.
     */
    function supportsInterface(bytes4 interfaceId) external view returns (bool);
}

File 15 of 18 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 standard as defined in the EIP.
 */
interface IERC20 {
    /**
     * @dev Emitted when `value` tokens are moved from one account (`from`) to
     * another (`to`).
     *
     * Note that `value` may be zero.
     */
    event Transfer(address indexed from, address indexed to, uint256 value);

    /**
     * @dev Emitted when the allowance of a `spender` for an `owner` is set by
     * a call to {approve}. `value` is the new allowance.
     */
    event Approval(address indexed owner, address indexed spender, uint256 value);

    /**
     * @dev Returns the amount of tokens in existence.
     */
    function totalSupply() external view returns (uint256);

    /**
     * @dev Returns the amount of tokens owned by `account`.
     */
    function balanceOf(address account) external view returns (uint256);

    /**
     * @dev Moves `amount` tokens from the caller's account to `to`.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transfer(address to, uint256 amount) external returns (bool);

    /**
     * @dev Returns the remaining number of tokens that `spender` will be
     * allowed to spend on behalf of `owner` through {transferFrom}. This is
     * zero by default.
     *
     * This value changes when {approve} or {transferFrom} are called.
     */
    function allowance(address owner, address spender) external view returns (uint256);

    /**
     * @dev Sets `amount` as the allowance of `spender` over the caller's tokens.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * IMPORTANT: Beware that changing an allowance with this method brings the risk
     * that someone may use both the old and the new allowance by unfortunate
     * transaction ordering. One possible solution to mitigate this race
     * condition is to first reduce the spender's allowance to 0 and set the
     * desired value afterwards:
     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729
     *
     * Emits an {Approval} event.
     */
    function approve(address spender, uint256 amount) external returns (bool);

    /**
     * @dev Moves `amount` tokens from `from` to `to` using the
     * allowance mechanism. `amount` is then deducted from the caller's
     * allowance.
     *
     * Returns a boolean value indicating whether the operation succeeded.
     *
     * Emits a {Transfer} event.
     */
    function transferFrom(
        address from,
        address to,
        uint256 amount
    ) external returns (bool);
}

File 16 of 18 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (utils/Address.sol)

pragma solidity ^0.8.1;

/**
 * @dev Collection of functions related to the address type
 */
library Address {
    /**
     * @dev Returns true if `account` is a contract.
     *
     * [IMPORTANT]
     * ====
     * It is unsafe to assume that an address for which this function returns
     * false is an externally-owned account (EOA) and not a contract.
     *
     * Among others, `isContract` will return false for the following
     * types of addresses:
     *
     *  - an externally-owned account
     *  - a contract in construction
     *  - an address where a contract will be created
     *  - an address where a contract lived, but was destroyed
     * ====
     *
     * [IMPORTANT]
     * ====
     * You shouldn't rely on `isContract` to protect against flash loan attacks!
     *
     * Preventing calls from contracts is highly discouraged. It breaks composability, breaks support for smart wallets
     * like Gnosis Safe, and does not provide security since it can be circumvented by calling from a contract
     * constructor.
     * ====
     */
    function isContract(address account) internal view returns (bool) {
        // This method relies on extcodesize/address.code.length, which returns 0
        // for contracts in construction, since the code is only stored at the end
        // of the constructor execution.

        return account.code.length > 0;
    }

    /**
     * @dev Replacement for Solidity's `transfer`: sends `amount` wei to
     * `recipient`, forwarding all available gas and reverting on errors.
     *
     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost
     * of certain opcodes, possibly making contracts go over the 2300 gas limit
     * imposed by `transfer`, making them unable to receive funds via
     * `transfer`. {sendValue} removes this limitation.
     *
     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].
     *
     * IMPORTANT: because control is transferred to `recipient`, care must be
     * taken to not create reentrancy vulnerabilities. Consider using
     * {ReentrancyGuard} or the
     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].
     */
    function sendValue(address payable recipient, uint256 amount) internal {
        require(address(this).balance >= amount, "Address: insufficient balance");

        (bool success, ) = recipient.call{value: amount}("");
        require(success, "Address: unable to send value, recipient may have reverted");
    }

    /**
     * @dev Performs a Solidity function call using a low level `call`. A
     * plain `call` is an unsafe replacement for a function call: use this
     * function instead.
     *
     * If `target` reverts with a revert reason, it is bubbled up by this
     * function (like regular Solidity function calls).
     *
     * Returns the raw returned data. To convert to the expected return value,
     * use https://solidity.readthedocs.io/en/latest/units-and-global-variables.html?highlight=abi.decode#abi-encoding-and-decoding-functions[`abi.decode`].
     *
     * Requirements:
     *
     * - `target` must be a contract.
     * - calling `target` with `data` must not revert.
     *
     * _Available since v3.1._
     */
    function functionCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionCall(target, data, "Address: low-level call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`], but with
     * `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, 0, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but also transferring `value` wei to `target`.
     *
     * Requirements:
     *
     * - the calling contract must have an ETH balance of at least `value`.
     * - the called Solidity function must be `payable`.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value
    ) internal returns (bytes memory) {
        return functionCallWithValue(target, data, value, "Address: low-level call with value failed");
    }

    /**
     * @dev Same as {xref-Address-functionCallWithValue-address-bytes-uint256-}[`functionCallWithValue`], but
     * with `errorMessage` as a fallback revert reason when `target` reverts.
     *
     * _Available since v3.1._
     */
    function functionCallWithValue(
        address target,
        bytes memory data,
        uint256 value,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(address(this).balance >= value, "Address: insufficient balance for call");
        require(isContract(target), "Address: call to non-contract");

        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(address target, bytes memory data) internal view returns (bytes memory) {
        return functionStaticCall(target, data, "Address: low-level static call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a static call.
     *
     * _Available since v3.3._
     */
    function functionStaticCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        require(isContract(target), "Address: static call to non-contract");

        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(address target, bytes memory data) internal returns (bytes memory) {
        return functionDelegateCall(target, data, "Address: low-level delegate call failed");
    }

    /**
     * @dev Same as {xref-Address-functionCall-address-bytes-string-}[`functionCall`],
     * but performing a delegate call.
     *
     * _Available since v3.4._
     */
    function functionDelegateCall(
        address target,
        bytes memory data,
        string memory errorMessage
    ) internal returns (bytes memory) {
        require(isContract(target), "Address: delegate call to non-contract");

        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResult(success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verifies that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason using the provided one.
     *
     * _Available since v4.3._
     */
    function verifyCallResult(
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal pure returns (bytes memory) {
        if (success) {
            return returndata;
        } else {
            // Look for revert reason and bubble it up if present
            if (returndata.length > 0) {
                // The easiest way to bubble the revert reason is using memory via assembly
                /// @solidity memory-safe-assembly
                assembly {
                    let returndata_size := mload(returndata)
                    revert(add(32, returndata), returndata_size)
                }
            } else {
                revert(errorMessage);
            }
        }
    }
}

File 17 of 18 : draft-IERC20Permit.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (token/ERC20/extensions/draft-IERC20Permit.sol)

pragma solidity ^0.8.0;

/**
 * @dev Interface of the ERC20 Permit extension allowing approvals to be made via signatures, as defined in
 * https://eips.ethereum.org/EIPS/eip-2612[EIP-2612].
 *
 * Adds the {permit} method, which can be used to change an account's ERC20 allowance (see {IERC20-allowance}) by
 * presenting a message signed by the account. By not relying on {IERC20-approve}, the token holder account doesn't
 * need to send a transaction, and thus is not required to hold Ether at all.
 */
interface IERC20Permit {
    /**
     * @dev Sets `value` as the allowance of `spender` over ``owner``'s tokens,
     * given ``owner``'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(
        address owner,
        address spender,
        uint256 value,
        uint256 deadline,
        uint8 v,
        bytes32 r,
        bytes32 s
    ) external;

    /**
     * @dev Returns the current nonce for `owner`. This value must be
     * included whenever a signature is generated for {permit}.
     *
     * Every successful call to {permit} increases ``owner``'s nonce by one. This
     * prevents a signature from being used multiple times.
     */
    function nonces(address owner) external view returns (uint256);

    /**
     * @dev Returns the domain separator used in the encoding of the signature for {permit}, as defined by {EIP712}.
     */
    // solhint-disable-next-line func-name-mixedcase
    function DOMAIN_SEPARATOR() external view returns (bytes32);
}

File 18 of 18 : Context.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts v4.4.1 (utils/Context.sol)

pragma solidity ^0.8.0;

/**
 * @dev Provides information about the current execution context, including the
 * sender of the transaction and its data. While these are generally available
 * via msg.sender and msg.data, they should not be accessed in such a direct
 * manner, since when dealing with meta-transactions the account sending and
 * paying for execution may not be the actual sender (as far as an application
 * is concerned).
 *
 * This contract is only required for intermediate, library-like contracts.
 */
abstract contract Context {
    function _msgSender() internal view virtual returns (address) {
        return msg.sender;
    }

    function _msgData() internal view virtual returns (bytes calldata) {
        return msg.data;
    }
}

Settings
{
  "optimizer": {
    "enabled": true,
    "runs": 200
  },
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressMismatch","type":"error"},{"inputs":[],"name":"AlreadyProxied","type":"error"},{"inputs":[],"name":"ColdAddressCannotBeTheSameAsHot","type":"error"},{"inputs":[],"name":"ColdIsAddressZero","type":"error"},{"inputs":[],"name":"ColdWalletCannotInteractUseHot","type":"error"},{"inputs":[],"name":"DeliveryCannotBeTheZeroAddress","type":"error"},{"inputs":[],"name":"DeliveryIsAddressZero","type":"error"},{"inputs":[],"name":"EthWithdrawFailed","type":"error"},{"inputs":[],"name":"IncorrectProxyRegisterFee","type":"error"},{"inputs":[],"name":"MigrationIsAllowedOnceOnly","type":"error"},{"inputs":[],"name":"NoPaymentPendingForAddress","type":"error"},{"inputs":[],"name":"NoRecordFoundForAddress","type":"error"},{"inputs":[],"name":"OnlyHotAddressCanChangeAddress","type":"error"},{"inputs":[],"name":"ProxyRegisterFeeRequired","type":"error"},{"inputs":[],"name":"RegisterAddressLocked","type":"error"},{"inputs":[],"name":"RewardRateIsLocked","type":"error"},{"inputs":[],"name":"UnknownAmount","type":"error"},{"inputs":[],"name":"UnrecognisedEPSAPIAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hot","type":"address"},{"indexed":true,"internalType":"address","name":"cold","type":"address"},{"indexed":true,"internalType":"address","name":"delivery","type":"address"},{"indexed":false,"internalType":"address","name":"oldDelivery","type":"address"},{"indexed":false,"internalType":"uint256","name":"provider","type":"uint256"}],"name":"DeliveryUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"ensReverseRegistrarAddress","type":"address"}],"name":"ENSReverseRegistrarSet","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"erc20","type":"address"},{"indexed":false,"internalType":"uint256","name":"erc20Fee_","type":"uint256"}],"name":"ERC20FeeUpdated","type":"event"},{"anonymous":false,"inputs":[],"name":"MigrationComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hot","type":"address"},{"indexed":true,"internalType":"address","name":"cold","type":"address"},{"indexed":false,"internalType":"address","name":"delivery","type":"address"},{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"}],"name":"NominationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hot","type":"address"},{"indexed":true,"internalType":"address","name":"cold","type":"address"},{"indexed":false,"internalType":"address","name":"delivery","type":"address"},{"indexed":false,"internalType":"uint256","name":"provider","type":"uint256"}],"name":"NominationMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"hot","type":"address"},{"indexed":true,"internalType":"address","name":"cold","type":"address"},{"indexed":false,"internalType":"address","name":"delivery","type":"address"},{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"}],"name":"ProxyRecordLive","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"enum IEPSProxyRegister.Participant","name":"initiator","type":"uint8"},{"indexed":true,"internalType":"address","name":"hot","type":"address"},{"indexed":true,"internalType":"address","name":"cold","type":"address"},{"indexed":false,"internalType":"uint256","name":"provider","type":"uint256"}],"name":"RecordDeleted","type":"event"},{"anonymous":false,"inputs":[],"name":"RewardRateLocked","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint96","name":"rewardRate","type":"uint96"}],"name":"RewardRateUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"newToken","type":"address"}],"name":"RewardTokenUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"}],"name":"acceptNomination","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"activeEthAddresses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"},{"internalType":"bool","name":"checkingHot_","type":"bool"}],"name":"addressIsAvailable","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"}],"name":"beneficiaryBalance","outputs":[{"internalType":"uint256","name":"balance_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"beneficiaryBalanceOf","outputs":[{"internalType":"uint256","name":"balance_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"beneficiaryBalanceOf1155","outputs":[{"internalType":"uint256","name":"balance_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"beneficiaryBalanceOf20","outputs":[{"internalType":"uint256","name":"balance_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"beneficiaryOf","outputs":[{"internalType":"address","name":"beneficiary_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"}],"name":"coldIsActiveOnRegister","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"}],"name":"coldIsLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"coldToHot","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"provider_","type":"uint256"}],"name":"deleteRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"deletionNominalEth","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"ensReverseRegistrar","outputs":[{"internalType":"contract ENSReverseRegistrar","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"epsAPIBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc1155DelegationRegister","outputs":[{"internalType":"contract IERC1155DelegateRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc1155DelegationRegisterAddressLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20DelegationRegister","outputs":[{"internalType":"contract IERC20DelegateRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc20DelegationRegisterAddressLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"erc20PerTransactionFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721DelegationRegister","outputs":[{"internalType":"contract IERC721DelegateRegister","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"erc721DelegationRegisterAddressLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receivedAddress_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"getAddresses1155","outputs":[{"internalType":"address[]","name":"proxyAddresses_","type":"address[]"},{"internalType":"address","name":"delivery_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receivedAddress_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"getAddresses20","outputs":[{"internalType":"address[]","name":"proxyAddresses_","type":"address[]"},{"internalType":"address","name":"delivery_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receivedAddress_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"getAddresses721","outputs":[{"internalType":"address[]","name":"proxyAddresses_","type":"address[]"},{"internalType":"address","name":"delivery_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receivedAddress_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"getAllAddresses","outputs":[{"internalType":"address[]","name":"erc721Addresses_","type":"address[]"},{"internalType":"address[]","name":"erc1155Addresses_","type":"address[]"},{"internalType":"address[]","name":"erc20Addresses_","type":"address[]"},{"internalType":"address","name":"delivery_","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receivedAddress","type":"address"}],"name":"getColdAndDeliveryAddresses","outputs":[{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"},{"internalType":"bool","name":"isProxied","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"queryAddress_","type":"address"}],"name":"getProxyRecordForAddress","outputs":[{"internalType":"enum IEPSProxyRegister.ProxyStatus","name":"status","type":"uint8"},{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"bool","name":"feePaid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"}],"name":"getProxyRecordForCold","outputs":[{"internalType":"enum IEPSProxyRegister.ProxyStatus","name":"status","type":"uint8"},{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"bool","name":"feePaid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"}],"name":"getProxyRecordForHot","outputs":[{"internalType":"enum IEPSProxyRegister.ProxyStatus","name":"status","type":"uint8"},{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"bool","name":"feePaid","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"}],"name":"hotIsActiveOnRegister","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"}],"name":"hotIsLive","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"hotToRecord","outputs":[{"internalType":"uint64","name":"provider","type":"uint64"},{"internalType":"enum IEPSProxyRegister.ProxyStatus","name":"status","type":"uint8"},{"internalType":"bool","name":"feePaid","type":"bool"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address","name":"delivery_","type":"address"}],"name":"isValidAddresses","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"lockERC1155DelegationRegisterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockERC20DelegationRegisterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockERC721DelegationRegisterAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"components":[{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"address","name":"delivery","type":"address"}],"internalType":"struct EPSRegister.MigratedRecord[]","name":"migratedRecords_","type":"tuple[]"}],"name":"migration","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"migrationComplete","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address","name":"delivery_","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"}],"name":"nominate","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"sender_","type":"address"},{"internalType":"uint256","name":"erc20Value_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"proxyRegisterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC1155","name":"token_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"rescueERC1155","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"rescueERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC721","name":"token_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"rescueERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint88","name":"","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRateLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IOAT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"deleteNominalEth_","type":"uint256"}],"name":"setDeletionNominalEth","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ensName_","type":"string"}],"name":"setENSName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ensReverseRegistrar_","type":"address"}],"name":"setENSReverseRegistrar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc1155DelegationRegister_","type":"address"}],"name":"setERC1155DelegationRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc20DelegationRegister_","type":"address"}],"name":"setERC20DelegationRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc20_","type":"address"},{"internalType":"uint256","name":"erc20Fee_","type":"uint256"}],"name":"setERC20Fee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"erc721DelegationRegister_","type":"address"}],"name":"setERC721DelegationRegister","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"count_","type":"uint256"},{"internalType":"uint256","name":"air_","type":"uint256"}],"name":"setNNumberOfEthAddressesAndAirdropAmount","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"registerFee_","type":"uint256"}],"name":"setRegisterFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint88","name":"rewardRate_","type":"uint88"}],"name":"setRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rewardToken_","type":"address"}],"name":"setRewardToken","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasuryAddress_","type":"address"}],"name":"setTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"treasury","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delivery_","type":"address"},{"internalType":"uint256","name":"provider_","type":"uint256"}],"name":"updateDeliveryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526001600c55620000176012600a620001cb565b6200002590612710620001e3565b600d553480156200003557600080fd5b50620000413362000066565b62000060739f0773af2b1d3f7cc7030304548a823b4e6b13bb62000066565b620001fd565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b634e487b7160e01b600052601160045260246000fd5b600181815b808511156200010d578160001904821115620000f157620000f1620000b6565b80851615620000ff57918102915b93841c9390800290620000d1565b509250929050565b6000826200012657506001620001c5565b816200013557506000620001c5565b81600181146200014e5760028114620001595762000179565b6001915050620001c5565b60ff8411156200016d576200016d620000b6565b50506001821b620001c5565b5060208310610133831016604e8410600b84101617156200019e575081810a620001c5565b620001aa8383620000cc565b8060001904821115620001c157620001c1620000b6565b0290505b92915050565b6000620001dc60ff84168362000115565b9392505050565b8082028115828204841417620001c557620001c5620000b6565b614475806200020d6000396000f3fe6080604052600436106104345760003560e01c80638aee812711610229578063b52d1c191161012e578063e575d025116100b6578063f2fde38b1161007a578063f2fde38b14610f9a578063f7c618c114610fba578063f8907b6014610fda578063fbbb04ed14610ffa578063fc2bc7b21461100f57600080fd5b8063e575d02514610eac578063e963134f14610ebf578063e9ee49b014610edf578063f0de57e914610eff578063f14210a614610f7a57600080fd5b8063d19050ee116100fd578063d19050ee14610e11578063d1d3e28f14610e36578063d361da9b14610e56578063d56bb05714610e76578063d798183414610e8c57600080fd5b8063b52d1c1914610da5578063bc0d9ded14610dc5578063c2f5dc4414610de5578063c93b228914610dfb57600080fd5b8063990a26b8116101b1578063a4c0ed3611610180578063a4c0ed3614610d10578063a5bc5b8414610d23578063a9059cbb14610d38578063ae4ef41814610d58578063b4bcae3514610d7857600080fd5b8063990a26b814610c9a5780639e5011a714610caf578063a0a3660614610cd0578063a1db978214610cf057600080fd5b8063913965c3116101f8578063913965c314610bde57806392be2ab814610bf457806394d41c1314610c1457806395d89b4114610c355780639735c30014610c6457600080fd5b80638aee812714610b605780638b2445bc14610b805780638cd4426d14610ba05780638da5cb5b14610bc057600080fd5b806333ac8aa81161033a5780636605bfda116102c257806377dd4ac31161028657806377dd4ac314610aae5780637afbd21214610ace5780637b0a47ee14610aee5780638523837014610b2d57806389c2c90614610b4057600080fd5b80636605bfda14610a175780636dc50fbb14610a3757806370a0823114610a57578063715018a614610a79578063727a3a2b14610a8e57600080fd5b80634b67bbba116103095780634b67bbba1461097757806353556440146109975780635ba58955146109b757806361d027b3146109d7578063657f9233146109f757600080fd5b806333ac8aa8146108e55780633a0236e31461091757806342de52551461093757806347e954631461095757600080fd5b8063274971b3116103bd5780632bff884f1161038c5780632bff884f146108345780632e57bdcc1461084e578063313ce5671461086357806333009cb11461087f57806333016e95146108ad57600080fd5b8063274971b31461077c5780632a9565f91461079c5780632b8b0aff146107bc5780632bf5c6fb1461080457600080fd5b80630956d8a7116104045780630956d8a7146106e657806311b7c607146107065780631718e0cf1461072657806318160ddd1461074657806320f35fdc1461075b57600080fd5b8062650a4a146106295780630186fce11461065c578063061f98111461068d57806306fdde03146106ad57600080fd5b3661062457600154341415801561044d57506002543414155b80156104cb5750600954604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa15801561049c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c09190613a4a565b6001600160401b0316155b80156105495750600a54604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa15801561051a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053e9190613a4a565b6001600160401b0316155b80156105c75750600b54604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190613a4a565b6001600160401b0316155b80156105de57506000546001600160a01b03163314155b156105fc5760405163020ad41b60e11b815260040160405180910390fd5b60015434036106105761060e3361102f565b005b600254340361060e5761060e33600061115a565b600080fd5b34801561063557600080fd5b50610649610644366004613a7c565b6111eb565b6040519081526020015b60405180910390f35b34801561066857600080fd5b5060035461067d90600160f81b900460ff1681565b6040519015158152602001610653565b34801561069957600080fd5b5061060e6106a8366004613ac2565b6114c7565b3480156106b957600080fd5b506040805180820190915260078152664550532041504960c81b60208201525b6040516106539190613aff565b3480156106f257600080fd5b5061067d610701366004613b32565b6114d1565b34801561071257600080fd5b5061060e610721366004613b32565b611510565b34801561073257600080fd5b5061060e610741366004613b4f565b611565565b34801561075257600080fd5b50610649611570565b34801561076757600080fd5b50600a5461067d90600160a01b900460ff1681565b34801561078857600080fd5b5061067d610797366004613b89565b611587565b3480156107a857600080fd5b5061060e6107b7366004613b4f565b6116ab565b3480156107c857600080fd5b506107dc6107d7366004613b32565b61170b565b604080516001600160a01b039485168152939092166020840152151590820152606001610653565b34801561081057600080fd5b5061082461081f366004613b4f565b61178c565b6040516106539493929190613c06565b34801561084057600080fd5b5060075461067d9060ff1681565b34801561085a57600080fd5b5061060e611ad9565b34801561086f57600080fd5b5060405160128152602001610653565b34801561088b57600080fd5b5061089f61089a366004613b4f565b611af6565b604051610653929190613c59565b3480156108b957600080fd5b506009546108cd906001600160a01b031681565b6040516001600160a01b039091168152602001610653565b3480156108f157600080fd5b50610905610900366004613b32565b611bf1565b60405161065396959493929190613cad565b34801561092357600080fd5b5061067d610932366004613b32565b611ce1565b34801561094357600080fd5b506108cd610952366004613cfb565b611d20565b34801561096357600080fd5b5061089f610972366004613b4f565b611e61565b34801561098357600080fd5b5061060e610992366004613b32565b611f0c565b3480156109a357600080fd5b5061067d6109b2366004613b32565b611f61565b3480156109c357600080fd5b506106496109d2366004613b32565b611fa8565b3480156109e357600080fd5b506008546108cd906001600160a01b031681565b348015610a0357600080fd5b5061067d610a12366004613b32565b612022565b348015610a2357600080fd5b5061060e610a32366004613b32565b61208d565b348015610a4357600080fd5b50600b546108cd906001600160a01b031681565b348015610a6357600080fd5b50610649610a72366004613b32565b50600d5490565b348015610a8557600080fd5b5061060e6120b7565b348015610a9a57600080fd5b50610649610aa9366004613d30565b6120cb565b348015610aba57600080fd5b5061060e610ac9366004613e36565b612387565b348015610ada57600080fd5b50610905610ae9366004613b32565b612406565b348015610afa57600080fd5b50600354610b1590600160a01b90046001600160581b031681565b6040516001600160581b039091168152602001610653565b61060e610b3b366004613e7e565b612548565b348015610b4c57600080fd5b50600a546108cd906001600160a01b031681565b348015610b6c57600080fd5b5061060e610b7b366004613b32565b612580565b348015610b8c57600080fd5b5061060e610b9b366004613b4f565b6125dd565b348015610bac57600080fd5b5061060e610bbb366004613b4f565b6126f5565b348015610bcc57600080fd5b506000546001600160a01b03166108cd565b348015610bea57600080fd5b50610649600c5481565b348015610c0057600080fd5b5061060e610c0f366004613ac2565b612723565b348015610c2057600080fd5b50600b5461067d90600160a01b900460ff1681565b348015610c4157600080fd5b5060408051808201909152600681526545505341504960d01b60208201526106d9565b348015610c7057600080fd5b506108cd610c7f366004613b32565b6005602052600090815260409020546001600160a01b031681565b348015610ca657600080fd5b5061060e612730565b348015610cbb57600080fd5b5060095461067d90600160a01b900460ff1681565b348015610cdc57600080fd5b5061060e610ceb366004613ec9565b61274d565b348015610cfc57600080fd5b5061060e610d0b366004613b4f565b612760565b61060e610d1e366004613eeb565b612782565b348015610d2f57600080fd5b5061060e61282d565b348015610d4457600080fd5b5061067d610d53366004613b4f565b612875565b348015610d6457600080fd5b5061060e610d73366004613f7a565b6128cc565b348015610d8457600080fd5b50610649610d93366004613b32565b60066020526000908152604090205481565b348015610db157600080fd5b5061060e610dc0366004613b32565b612995565b348015610dd157600080fd5b5061060e610de0366004614057565b6129f3565b348015610df157600080fd5b5061064960025481565b348015610e0757600080fd5b5061064960015481565b348015610e1d57600080fd5b506007546108cd9061010090046001600160a01b031681565b348015610e4257600080fd5b5061060e610e51366004613ac2565b612a84565b348015610e6257600080fd5b5061089f610e71366004613b4f565b612a91565b348015610e8257600080fd5b50610649600d5481565b348015610e9857600080fd5b5061060e610ea7366004613b4f565b612b3c565b61060e610eba366004614080565b612ba0565b348015610ecb57600080fd5b50610905610eda366004613b32565b612c06565b348015610eeb57600080fd5b5061060e610efa366004613b32565b612cdf565b348015610f0b57600080fd5b50610f69610f1a366004613b32565b600460205260009081526040902080546001909101546001600160401b0382169160ff600160401b8204811692600160481b8304909116916001600160a01b03600160501b9091048116911685565b6040516106539594939291906140ae565b348015610f8657600080fd5b5061060e610f95366004613ac2565b612d34565b348015610fa657600080fd5b5061060e610fb5366004613b32565b612db0565b348015610fc657600080fd5b506003546108cd906001600160a01b031681565b348015610fe657600080fd5b50610649610ff5366004613d30565b612e26565b34801561100657600080fd5b5061060e612f03565b34801561101b57600080fd5b5061060e61102a3660046140f1565b612f20565b60026001600160a01b038216600090815260046020526040902054600160401b900460ff16600381111561106557611065613c83565b036110b0576001600160a01b03808216600090815260046020526040902080546001909101546110ad928492600160501b8104821692909116906001600160401b0316612fa0565b50565b60026001600160a01b038281166000908152600560209081526040808320549093168252600490522054600160401b900460ff1660038111156110f5576110f5613c83565b03611141576001600160a01b0381811660009081526005602090815260408083205484168084526004909252909120600181015490546110ad93859216906001600160401b0316612fa0565b604051637115fdd360e01b815260040160405180910390fd5b611163826114d1565b1561119c576001600160a01b03808316600090815260046020526040812054611198928592600160501b90920416908461303e565b5050565b6111a582612022565b156111d2576001600160a01b0380831660009081526005602052604090205461119891168360018461303e565b60405163163e0acf60e21b815260040160405180910390fd5b600a54604051630292efd760e31b81526001600160a01b03868116600483015260009216906314977eb890602401602060405180830381865afa158015611236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125a9190613a4a565b6001600160401b031615611270575060006114bf565b81158061127d5750600f82115b1561128757600191505b600a546040516359726e5960e11b81526001600160a01b038681166004830152602482018690528781166044830152606482018590529091169063b2e4dcb290608401602060405180830381865afa1580156112e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130b9190614131565b905061131685611ce1565b1561143657604051627eeac760e11b81526001600160a01b0386811660048301526024820185905285169062fdd58e90604401602060405180830381865afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614131565b6113949082614160565b6001600160a01b03868116600090815260046020819052604091829020549151627eeac760e11b8152600160501b9092048316908201819052602482018790529293509086169062fdd58e90604401602060405180830381865afa158015611400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114249190614131565b61142e9083614160565b9150506114bf565b61143f85611f61565b6114bf57604051627eeac760e11b81526001600160a01b0386811660048301526024820185905285169062fdd58e90604401602060405180830381865afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614131565b6114bc9082614160565b90505b949350505050565b6110ad338261115a565b6001600160a01b038116600090815260046020526040812054600160401b900460ff168181600381111561150757611507613c83565b14159392505050565b6115186130d4565b600954600160a01b900460ff161561154357604051637d6d4ab160e11b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b61119833838361312e565b6000600d54600c546115829190614173565b905090565b6001600160a01b0382811660009081526005602090815260408083205490931682526004905290812054600160401b900460ff1660038160038111156115cf576115cf613c83565b14806115ec575060028160038111156115ea576115ea613c83565b145b8061161057508280156116105750600181600381111561160e5761160e613c83565b145b1561161f5760009150506116a5565b506001600160a01b038316600090815260046020526040902054600160401b900460ff16600381600381111561165757611657613c83565b14806116745750600281600381111561167257611672613c83565b145b806116905750600181600381111561168e5761168e613c83565b145b1561169f5760009150506116a5565b60019150505b92915050565b6116b36130d4565b6001600160a01b038216600081815260066020908152604091829020849055815192835282018390527f5126cb9dd0e1253073fda9897fa9bfa7d4769735dc505a9992e125628d7e5d2d910160405180910390a15050565b600080600061171984611f61565b156117375760405163b18dc5df60e01b815260040160405180910390fd5b61174084611ce1565b1561177b575050506001600160a01b0380821660009081526004602052604090208054600191820154600160501b9091048316921690611785565b5082915081905060005b9193909250565b60608080600084158061179f5750600f85115b156117a957600194505b508460006117b682611f61565b156117c45750859050611ad0565b6117cd87611ce1565b156118025750506001600160a01b0380861660009081526004602052604090208054600190910154821691600160501b909104165b6009546001600160a01b03161580156118245750600a546001600160a01b0316155b80156118395750600b546001600160a01b0316155b156119115760006001600160a01b038216156118575750600261185b565b5060015b6000816001600160401b0381111561187557611875613d71565b60405190808252806020026020018201604052801561189e578160200160208202803683370190505b50905088816000815181106118b5576118b561418a565b6001600160a01b0392831660209182029290920101528316156119075782816001815181106118e6576118e661418a565b60200260200101906001600160a01b031690816001600160a01b0316815250505b9550611ad0915050565b6009546001906001600160a01b0316156119a75760095460405163276d772560e11b81526001600160a01b0390911690634edaee4a9061195b908b908b90879087906004016141a0565b600060405180830381865afa158015611978573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119a091908101906141ca565b9550600090505b600a546001600160a01b031615611a3a57600a5460405163276d772560e11b81526001600160a01b0390911690634edaee4a906119ee908b908b90879087906004016141a0565b600060405180830381865afa158015611a0b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a3391908101906141ca565b9450600090505b600b546001600160a01b031615611acd57600b5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611a81908b908b90879087906004016141a0565b600060405180830381865afa158015611a9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ac691908101906141ca565b9350600090505b50505b92959194509250565b611ae16130d4565b6009805460ff60a01b1916600160a01b179055565b60606000821580611b075750600f83115b15611b1157600192505b50826000611b1e82611f61565b15611b2c5750839050611bea565b611b3585611ce1565b15611b6a5750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b60095460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b600060405180830381865afa158015611bbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611be691908101906141ca565b9250505b9250929050565b6001600160a01b0381811660009081526005602090815260408083205490931680835260048252838320845160a0810190955280546001600160401b038116865293948594859485948594859491938593830190600160401b900460ff166003811115611c6057611c60613c83565b6003811115611c7157611c71613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919b5094995093975095509350909150505b91939550919395565b600060036001600160a01b038316600090815260046020526040902054600160401b900460ff166003811115611d1957611d19613c83565b1492915050565b6000811580611d2f5750600f82115b15611d3957600191505b6009546040516349d0e8d560e11b81526001600160a01b0386811660048301526024820186905260448201859052909116906393a1d1aa90606401602060405180830381865afa158015611d91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db59190614258565b90506001600160a01b038116611e5a576040516331a9108f60e11b8152600481018490526001600160a01b03851690636352211e90602401602060405180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614258565b9050611e3981611f61565b15611e5a576001600160a01b03908116600090815260056020526040902054165b9392505050565b60606000821580611e725750600f83115b15611e7c57600192505b50826000611e8982611f61565b15611e975750839050611bea565b611ea085611ce1565b15611ed55750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b600b5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b611f146130d4565b600b54600160a01b900460ff1615611f3f57604051637d6d4ab160e11b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600060036001600160a01b038381166000908152600560209081526040808320549093168252600490522054600160401b900460ff166003811115611d1957611d19613c83565b6000611fb382611ce1565b15611ffc57611fcc6001600160a01b0383163182614160565b6001600160a01b038084166000908152600460205260409020549192506116a591600160501b9004163182614160565b61200582611f61565b61201d576116a56001600160a01b0383163182614160565b919050565b6001600160a01b0381811660009081526005602090815260408083205490931682526004905290812054600160401b900460ff16600381600381111561206a5761206a613c83565b1480611e5a5750600281600381111561208557612085613c83565b149392505050565b6120956130d4565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6120bf6130d4565b6120c96000613198565b565b600b54604051630292efd760e31b81526001600160a01b03858116600483015260009216906314977eb890602401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a9190613a4a565b6001600160401b03161561215057506000611e5a565b81158061215d5750600f82115b1561216757600191505b600b54604051630625da8960e21b81526001600160a01b038581166004830152868116602483015260448201859052909116906318976a24906064015b602060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e59190614131565b90506121f084611ce1565b15612306576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa15801561223b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225f9190614131565b6122699082614160565b6001600160a01b038581166000908152600460208190526040918290205491516370a0823160e01b8152600160501b9092048316908201819052929350908516906370a0823190602401602060405180830381865afa1580156122d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f49190614131565b6122fe9083614160565b915050611e5a565b61230f84611f61565b611e5a576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190614131565b6114bf9082614160565b61238f6130d4565b60075460405163c47f002760e01b81526101009091046001600160a01b03169063c47f0027906123c3908490600401613aff565b6020604051808303816000875af11580156123e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111989190614131565b6001600160a01b038181166000908152600560209081526040808320549093168252600490529081205481908190819081908190600160401b900460ff16600381600381111561245857612458613c83565b14806124755750600281600381111561247357612473613c83565b145b806124915750600181600381111561248f5761248f613c83565b145b156124b15761249f88611bf1565b96509650965096509650965050611cd8565b506001600160a01b038716600090815260046020526040902054600160401b900460ff1660038160038111156124e9576124e9613c83565b14806125065750600281600381111561250457612504613c83565b145b806125225750600181600381111561252057612520613c83565b145b156125305761249f88612c06565b50600097889750879650869550859450849350915050565b600154341461256a576040516333b18e6b60e11b815260040160405180910390fd5b61257b3384846001543414856131e8565b505050565b6125886130d4565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527fa5289ba11778999f4dfb9415023783188d42bbb5db0612cbfbe55999069612a0906020015b60405180910390a150565b6125e56130d4565b816001600160a01b031663f242432a306126076000546001600160a01b031690565b604051627eeac760e11b81523060048201526024810186905285906001600160a01b0388169062fdd58e90604401602060405180830381865afa158015612652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126769190614131565b6040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a06084820152600060a482015260c4015b600060405180830381600087803b1580156126d957600080fd5b505af11580156126ed573d6000803e3d6000fd5b505050505050565b6126fd6130d4565b6111986127126000546001600160a01b031690565b6001600160a01b03841690836133b1565b61272b6130d4565b600155565b6127386130d4565b600b805460ff60a01b1916600160a01b179055565b6127556130d4565b600c91909155600d55565b6127686130d4565b600854611198906001600160a01b038481169116836133b1565b33600090815260066020526040812054908190036127d75760405162461bcd60e51b815260206004820152600d60248201526c0496e76616c696420455243323609c1b60448201526064015b60405180910390fd5b6000806000848060200190518101906127f09190614275565b925092509250838614612816576040516333b18e6b60e11b815260040160405180910390fd5b6128248784846001856131e8565b50505050505050565b6128356130d4565b600380546001600160f81b0316600160f81b1790556040517fa8e99dd43192eea7c15fab7a8e9f086c3aa9ecd5a096c50deb88ef871aa17c6090600090a1565b6000612882338484613403565b604051600081526001600160a01b0384169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350600192915050565b6128d46130d4565b60075460ff16156128f857604051636c0bdb4b60e11b815260040160405180910390fd5b60005b815181101561295b5760008282815181106129185761291861418a565b6020026020010151905061293d816000015182602001518360400151600160006131e8565b612952816000015182602001516000806134f4565b506001016128fb565b506007805460ff191660011790556040517f96e718f44bd77cb63370212c5aa24a0396d8f43e88e7ce175d160e371c8e2a6a90600090a150565b61299d6130d4565b60078054610100600160a81b0319166101006001600160a01b038416908102919091179091556040519081527f24625640821500d1ed82bf4cfa7973b775a4403ba28f029db24efa6b80241aac906020016125d2565b6129fb6130d4565b600354600160f81b900460ff1615612a2657604051638b5acdcb60e01b815260040160405180910390fd5b600380546affffffffffffffffffffff60a01b1916600160a01b6001600160581b038416908102919091179091556040519081527f7f8f51cc4bfc1384be37bf64948c3c3ecc5c1f7a40e8d2b166a11492fb78b3be906020016125d2565b612a8c6130d4565b600255565b60606000821580612aa25750600f83115b15612aac57600192505b50826000612ab982611f61565b15612ac75750839050611bea565b612ad085611ce1565b15612b055750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b600a5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b612b446130d4565b816001600160a01b03166323b872dd30612b666000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018490526064016126bf565b612baa823361361c565b6001600160a01b038216600090815260046020526040902054600160481b900460ff16158015612bdc57506001543414155b15612bfa57604051632740b97160e11b815260040160405180910390fd5b611198823334846134f4565b6001600160a01b0381166000908152600460209081526040808320815160a0810190925280546001600160401b0381168352849384938493849384938493929190830190600160401b900460ff166003811115612c6557612c65613c83565b6003811115612c7657612c76613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919c909a5091985091965090945092505050565b612ce76130d4565b600a54600160a01b900460ff1615612d1257604051637d6d4ab160e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b612d3c6130d4565b6008546040516000916001600160a01b03169083908381818185875af1925050503d8060008114612d89576040519150601f19603f3d011682016040523d82523d6000602084013e612d8e565b606091505b50509050806111985760405163e53e5bcd60e01b815260040160405180910390fd5b612db86130d4565b6001600160a01b038116612e1d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016127ce565b6110ad81613198565b600954604051630292efd760e31b81526001600160a01b03858116600483015260009216906314977eb890602401602060405180830381865afa158015612e71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e959190613a4a565b6001600160401b031615612eab57506000611e5a565b811580612eb85750600f82115b15612ec257600191505b600954604051630625da8960e21b81526001600160a01b038581166004830152868116602483015260448201859052909116906318976a24906064016121a4565b612f0b6130d4565b600a805460ff60a01b1916600160a01b179055565b6001600160a01b038216612f475760405163bd78145160e01b815260040160405180910390fd5b826001600160a01b0316826001600160a01b031603612f79576040516304da706760e51b815260040160405180910390fd5b6001600160a01b03811661257b57604051634ca5048960e01b815260040160405180910390fd5b6001600160a01b038481166000908152600460205260409020805469ffff0000000000000000191669010300000000000000001790556003541615612fe857612fe8826136c9565b6040516001600160a01b0383811682526001600160401b03831691818616918716907f5717bcaec46242edc8fb07322221c02d6dd3de7a954d5c009ee550cd0cdf7685906020015b60405180910390a450505050565b6001600160a01b03808516600081815260046020908152604080832080546001600160f01b031916815560010180546001600160a01b03199081169091559488168084526005909252918290208054909416909355519091907fbd302a9bf683315c275f4a7f0092796d97d17fbb2a89bbc8938bd6842c38eb89906130c690869086906142b7565b60405180910390a350505050565b6000546001600160a01b031633146120c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016127ce565b6001600160a01b038216613155576040516334b1be0d60e21b815260040160405180910390fd5b61315e836114d1565b1561316e5761257b838383613739565b61317783612022565b156111d25760405160016208d37d60e21b0319815260040160405180910390fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6131f3858585612f20565b6131fe856001611587565b15806132125750613210846000611587565b155b15613230576040516307facddb60e11b815260040160405180910390fd5b6040805160a0810182526001600160401b03838116825260016020808401918252861515848601526001600160a01b03898116606086015288811660808601528a16600090815260049091529390932082518154921667ffffffffffffffff1983168117825593519293909291839168ffffffffffffffffff1990911617600160401b8360038111156132c5576132c5613c83565b0217905550604082810151825460608501517fffff000000000000000000000000000000000000000000ffffffffffffffffff909116600160481b921515929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff1691909117600160501b6001600160a01b0392831602178355608090930151600190920180546001600160a01b03191692841692909217909155805185831681526001600160401b0384166020820152868316928816917f752c94da010e5b94c0278334398a684d4a7bde91f0f38c9dbb1766ad4f586c69910160405180910390a35050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261257b90849061384f565b6000600a6134126012826143b9565b61341c90846143de565b61342691906143f2565b90508015806134355750600481115b1561345357604051631ec9ca4160e21b815260040160405180910390fd5b6000600a6134626012826143b9565b61346c90856143de565b61347691906143de565b90506001820361349757613492858587600154600014856131e8565b6134ed565b600282036134b6576134a9848661361c565b61349284866000846134f4565b600382036134d2576134928585836001600160401b031661312e565b600482036134ed576134ed85826001600160401b031661115a565b5050505050565b6001600160a01b03838116600081815260056020908152604080832080546001600160a01b0319168a87169081179091558084526004835292819020600101549051941684526001600160401b038516937fda23dc0f47967fd81e9b62f5207a955b77295fef190364f10a6c3cf26773c1ab910160405180910390a46001600160a01b038416600090815260046020526040902054600160481b900460ff168061359f575060015482145b156135e2576001600160a01b038085166000908152600460205260409020600181015490546135dd92879287929116906001600160401b0316612fa0565b613616565b6001600160a01b0384166000908152600460205260409020805468ff00000000000000001916680200000000000000001790555b50505050565b6001600160a01b03828116600090815260046020526040902054600160501b90048116908216141580613683575060016001600160a01b038316600090815260046020526040902054600160401b900460ff16600381111561368057613680613c83565b14155b156136a157604051634cd87fb560e01b815260040160405180910390fd5b6136ac816000611587565b611198576040516307facddb60e11b815260040160405180910390fd5b600354604051631737909b60e11b81526001600160a01b038381166004830152600160a01b83046001600160581b0316602483015290911690632e6f213690604401600060405180830381600087803b15801561372557600080fd5b505af11580156134ed573d6000803e3d6000fd5b6001600160a01b0383166000908152600460209081526040808320815160a0810190925280546001600160401b03811683529192909190830190600160401b900460ff16600381111561378e5761378e613c83565b600381111561379f5761379f613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b03908116604080850191909152600194850154821660609485015289821660008181526004855282902090950180546001600160a01b0319168a84169081179091559386015160808701518251908416815293840189905295965092941692917fa0aa3b38771c7ab4ece55c6009c41d814f4ff862285d0825c24528a87fd124d79101613030565b60006138a4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139219092919063ffffffff16565b80519091501561257b57808060200190518101906138c29190614406565b61257b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016127ce565b60606114bf8484600085856001600160a01b0385163b6139835760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016127ce565b600080866001600160a01b0316858760405161399f9190614423565b60006040518083038185875af1925050503d80600081146139dc576040519150601f19603f3d011682016040523d82523d6000602084013e6139e1565b606091505b50915091506139f18282866139fc565b979650505050505050565b60608315613a0b575081611e5a565b825115613a1b5782518084602001fd5b8160405162461bcd60e51b81526004016127ce9190613aff565b6001600160401b03811681146110ad57600080fd5b600060208284031215613a5c57600080fd5b8151611e5a81613a35565b6001600160a01b03811681146110ad57600080fd5b60008060008060808587031215613a9257600080fd5b8435613a9d81613a67565b93506020850135613aad81613a67565b93969395505050506040820135916060013590565b600060208284031215613ad457600080fd5b5035919050565b60005b83811015613af6578181015183820152602001613ade565b50506000910152565b6020815260008251806020840152613b1e816040850160208701613adb565b601f01601f19169190910160400192915050565b600060208284031215613b4457600080fd5b8135611e5a81613a67565b60008060408385031215613b6257600080fd5b8235613b6d81613a67565b946020939093013593505050565b80151581146110ad57600080fd5b60008060408385031215613b9c57600080fd5b8235613ba781613a67565b91506020830135613bb781613b7b565b809150509250929050565b600081518084526020808501945080840160005b83811015613bfb5781516001600160a01b031687529582019590820190600101613bd6565b509495945050505050565b608081526000613c196080830187613bc2565b8281036020840152613c2b8187613bc2565b90508281036040840152613c3f8186613bc2565b91505060018060a01b038316606083015295945050505050565b604081526000613c6c6040830185613bc2565b905060018060a01b03831660208301529392505050565b634e487b7160e01b600052602160045260246000fd5b60048110613ca957613ca9613c83565b9052565b60c08101613cbb8289613c99565b6001600160a01b03968716602083015294861660408201529290941660608301526001600160401b0316608082015291151560a090920191909152919050565b600080600060608486031215613d1057600080fd5b8335613d1b81613a67565b95602085013595506040909401359392505050565b600080600060608486031215613d4557600080fd5b8335613d5081613a67565b92506020840135613d6081613a67565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613da957613da9613d71565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613dd757613dd7613d71565b604052919050565b60006001600160401b03831115613df857613df8613d71565b613e0b601f8401601f1916602001613daf565b9050828152838383011115613e1f57600080fd5b828260208301376000602084830101529392505050565b600060208284031215613e4857600080fd5b81356001600160401b03811115613e5e57600080fd5b8201601f81018413613e6f57600080fd5b6114bf84823560208401613ddf565b600080600060608486031215613e9357600080fd5b8335613e9e81613a67565b92506020840135613eae81613a67565b91506040840135613ebe81613a35565b809150509250925092565b60008060408385031215613edc57600080fd5b50508035926020909101359150565b600080600060608486031215613f0057600080fd5b8335613f0b81613a67565b92506020840135915060408401356001600160401b03811115613f2d57600080fd5b8401601f81018613613f3e57600080fd5b613f4d86823560208401613ddf565b9150509250925092565b60006001600160401b03821115613f7057613f70613d71565b5060051b60200190565b60006020808385031215613f8d57600080fd5b82356001600160401b03811115613fa357600080fd5b8301601f81018513613fb457600080fd5b8035613fc7613fc282613f57565b613daf565b81815260609182028301840191848201919088841115613fe657600080fd5b938501935b8385101561404b5780858a0312156140035760008081fd5b61400b613d87565b853561401681613a67565b81528587013561402581613a67565b8188015260408681013561403881613a67565b9082015283529384019391850191613feb565b50979650505050505050565b60006020828403121561406957600080fd5b81356001600160581b0381168114611e5a57600080fd5b6000806040838503121561409357600080fd5b823561409e81613a67565b91506020830135613bb781613a35565b6001600160401b038616815260a081016140cb6020830187613c99565b93151560408201526001600160a01b039283166060820152911660809091015292915050565b60008060006060848603121561410657600080fd5b833561411181613a67565b9250602084013561412181613a67565b91506040840135613ebe81613a67565b60006020828403121561414357600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156116a5576116a561414a565b80820281158282048414176116a5576116a561414a565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152602081019390935292166040820152901515606082015260800190565b600060208083850312156141dd57600080fd5b82516001600160401b038111156141f357600080fd5b8301601f8101851361420457600080fd5b8051614212613fc282613f57565b81815260059190911b8201830190838101908783111561423157600080fd5b928401925b828410156139f157835161424981613a67565b82529284019290840190614236565b60006020828403121561426a57600080fd5b8151611e5a81613a67565b60008060006060848603121561428a57600080fd5b835161429581613a67565b60208501519093506142a681613a67565b6040850151909250613ebe81613a35565b60408101600284106142cb576142cb613c83565b9281526020015290565b600181815b808511156143105781600019048211156142f6576142f661414a565b8085161561430357918102915b93841c93908002906142da565b509250929050565b600082614327575060016116a5565b81614334575060006116a5565b816001811461434a576002811461435457614370565b60019150506116a5565b60ff8411156143655761436561414a565b50506001821b6116a5565b5060208310610133831016604e8410600b8410161715614393575081810a6116a5565b61439d83836142d5565b80600019048211156143b1576143b161414a565b029392505050565b6000611e5a60ff841683614318565b634e487b7160e01b600052601260045260246000fd5b6000826143ed576143ed6143c8565b500490565b600082614401576144016143c8565b500690565b60006020828403121561441857600080fd5b8151611e5a81613b7b565b60008251614435818460208701613adb565b919091019291505056fea2646970667358221220c5e7a0021d9e26f7ee1f186437161739670137aa0ebe8c9e6c9dd550b17e476864736f6c63430008110033

Deployed Bytecode

0x6080604052600436106104345760003560e01c80638aee812711610229578063b52d1c191161012e578063e575d025116100b6578063f2fde38b1161007a578063f2fde38b14610f9a578063f7c618c114610fba578063f8907b6014610fda578063fbbb04ed14610ffa578063fc2bc7b21461100f57600080fd5b8063e575d02514610eac578063e963134f14610ebf578063e9ee49b014610edf578063f0de57e914610eff578063f14210a614610f7a57600080fd5b8063d19050ee116100fd578063d19050ee14610e11578063d1d3e28f14610e36578063d361da9b14610e56578063d56bb05714610e76578063d798183414610e8c57600080fd5b8063b52d1c1914610da5578063bc0d9ded14610dc5578063c2f5dc4414610de5578063c93b228914610dfb57600080fd5b8063990a26b8116101b1578063a4c0ed3611610180578063a4c0ed3614610d10578063a5bc5b8414610d23578063a9059cbb14610d38578063ae4ef41814610d58578063b4bcae3514610d7857600080fd5b8063990a26b814610c9a5780639e5011a714610caf578063a0a3660614610cd0578063a1db978214610cf057600080fd5b8063913965c3116101f8578063913965c314610bde57806392be2ab814610bf457806394d41c1314610c1457806395d89b4114610c355780639735c30014610c6457600080fd5b80638aee812714610b605780638b2445bc14610b805780638cd4426d14610ba05780638da5cb5b14610bc057600080fd5b806333ac8aa81161033a5780636605bfda116102c257806377dd4ac31161028657806377dd4ac314610aae5780637afbd21214610ace5780637b0a47ee14610aee5780638523837014610b2d57806389c2c90614610b4057600080fd5b80636605bfda14610a175780636dc50fbb14610a3757806370a0823114610a57578063715018a614610a79578063727a3a2b14610a8e57600080fd5b80634b67bbba116103095780634b67bbba1461097757806353556440146109975780635ba58955146109b757806361d027b3146109d7578063657f9233146109f757600080fd5b806333ac8aa8146108e55780633a0236e31461091757806342de52551461093757806347e954631461095757600080fd5b8063274971b3116103bd5780632bff884f1161038c5780632bff884f146108345780632e57bdcc1461084e578063313ce5671461086357806333009cb11461087f57806333016e95146108ad57600080fd5b8063274971b31461077c5780632a9565f91461079c5780632b8b0aff146107bc5780632bf5c6fb1461080457600080fd5b80630956d8a7116104045780630956d8a7146106e657806311b7c607146107065780631718e0cf1461072657806318160ddd1461074657806320f35fdc1461075b57600080fd5b8062650a4a146106295780630186fce11461065c578063061f98111461068d57806306fdde03146106ad57600080fd5b3661062457600154341415801561044d57506002543414155b80156104cb5750600954604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa15801561049c573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906104c09190613a4a565b6001600160401b0316155b80156105495750600a54604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa15801561051a573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061053e9190613a4a565b6001600160401b0316155b80156105c75750600b54604051630292efd760e31b81523360048201526001600160a01b03909116906314977eb890602401602060405180830381865afa158015610598573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906105bc9190613a4a565b6001600160401b0316155b80156105de57506000546001600160a01b03163314155b156105fc5760405163020ad41b60e11b815260040160405180910390fd5b60015434036106105761060e3361102f565b005b600254340361060e5761060e33600061115a565b600080fd5b34801561063557600080fd5b50610649610644366004613a7c565b6111eb565b6040519081526020015b60405180910390f35b34801561066857600080fd5b5060035461067d90600160f81b900460ff1681565b6040519015158152602001610653565b34801561069957600080fd5b5061060e6106a8366004613ac2565b6114c7565b3480156106b957600080fd5b506040805180820190915260078152664550532041504960c81b60208201525b6040516106539190613aff565b3480156106f257600080fd5b5061067d610701366004613b32565b6114d1565b34801561071257600080fd5b5061060e610721366004613b32565b611510565b34801561073257600080fd5b5061060e610741366004613b4f565b611565565b34801561075257600080fd5b50610649611570565b34801561076757600080fd5b50600a5461067d90600160a01b900460ff1681565b34801561078857600080fd5b5061067d610797366004613b89565b611587565b3480156107a857600080fd5b5061060e6107b7366004613b4f565b6116ab565b3480156107c857600080fd5b506107dc6107d7366004613b32565b61170b565b604080516001600160a01b039485168152939092166020840152151590820152606001610653565b34801561081057600080fd5b5061082461081f366004613b4f565b61178c565b6040516106539493929190613c06565b34801561084057600080fd5b5060075461067d9060ff1681565b34801561085a57600080fd5b5061060e611ad9565b34801561086f57600080fd5b5060405160128152602001610653565b34801561088b57600080fd5b5061089f61089a366004613b4f565b611af6565b604051610653929190613c59565b3480156108b957600080fd5b506009546108cd906001600160a01b031681565b6040516001600160a01b039091168152602001610653565b3480156108f157600080fd5b50610905610900366004613b32565b611bf1565b60405161065396959493929190613cad565b34801561092357600080fd5b5061067d610932366004613b32565b611ce1565b34801561094357600080fd5b506108cd610952366004613cfb565b611d20565b34801561096357600080fd5b5061089f610972366004613b4f565b611e61565b34801561098357600080fd5b5061060e610992366004613b32565b611f0c565b3480156109a357600080fd5b5061067d6109b2366004613b32565b611f61565b3480156109c357600080fd5b506106496109d2366004613b32565b611fa8565b3480156109e357600080fd5b506008546108cd906001600160a01b031681565b348015610a0357600080fd5b5061067d610a12366004613b32565b612022565b348015610a2357600080fd5b5061060e610a32366004613b32565b61208d565b348015610a4357600080fd5b50600b546108cd906001600160a01b031681565b348015610a6357600080fd5b50610649610a72366004613b32565b50600d5490565b348015610a8557600080fd5b5061060e6120b7565b348015610a9a57600080fd5b50610649610aa9366004613d30565b6120cb565b348015610aba57600080fd5b5061060e610ac9366004613e36565b612387565b348015610ada57600080fd5b50610905610ae9366004613b32565b612406565b348015610afa57600080fd5b50600354610b1590600160a01b90046001600160581b031681565b6040516001600160581b039091168152602001610653565b61060e610b3b366004613e7e565b612548565b348015610b4c57600080fd5b50600a546108cd906001600160a01b031681565b348015610b6c57600080fd5b5061060e610b7b366004613b32565b612580565b348015610b8c57600080fd5b5061060e610b9b366004613b4f565b6125dd565b348015610bac57600080fd5b5061060e610bbb366004613b4f565b6126f5565b348015610bcc57600080fd5b506000546001600160a01b03166108cd565b348015610bea57600080fd5b50610649600c5481565b348015610c0057600080fd5b5061060e610c0f366004613ac2565b612723565b348015610c2057600080fd5b50600b5461067d90600160a01b900460ff1681565b348015610c4157600080fd5b5060408051808201909152600681526545505341504960d01b60208201526106d9565b348015610c7057600080fd5b506108cd610c7f366004613b32565b6005602052600090815260409020546001600160a01b031681565b348015610ca657600080fd5b5061060e612730565b348015610cbb57600080fd5b5060095461067d90600160a01b900460ff1681565b348015610cdc57600080fd5b5061060e610ceb366004613ec9565b61274d565b348015610cfc57600080fd5b5061060e610d0b366004613b4f565b612760565b61060e610d1e366004613eeb565b612782565b348015610d2f57600080fd5b5061060e61282d565b348015610d4457600080fd5b5061067d610d53366004613b4f565b612875565b348015610d6457600080fd5b5061060e610d73366004613f7a565b6128cc565b348015610d8457600080fd5b50610649610d93366004613b32565b60066020526000908152604090205481565b348015610db157600080fd5b5061060e610dc0366004613b32565b612995565b348015610dd157600080fd5b5061060e610de0366004614057565b6129f3565b348015610df157600080fd5b5061064960025481565b348015610e0757600080fd5b5061064960015481565b348015610e1d57600080fd5b506007546108cd9061010090046001600160a01b031681565b348015610e4257600080fd5b5061060e610e51366004613ac2565b612a84565b348015610e6257600080fd5b5061089f610e71366004613b4f565b612a91565b348015610e8257600080fd5b50610649600d5481565b348015610e9857600080fd5b5061060e610ea7366004613b4f565b612b3c565b61060e610eba366004614080565b612ba0565b348015610ecb57600080fd5b50610905610eda366004613b32565b612c06565b348015610eeb57600080fd5b5061060e610efa366004613b32565b612cdf565b348015610f0b57600080fd5b50610f69610f1a366004613b32565b600460205260009081526040902080546001909101546001600160401b0382169160ff600160401b8204811692600160481b8304909116916001600160a01b03600160501b9091048116911685565b6040516106539594939291906140ae565b348015610f8657600080fd5b5061060e610f95366004613ac2565b612d34565b348015610fa657600080fd5b5061060e610fb5366004613b32565b612db0565b348015610fc657600080fd5b506003546108cd906001600160a01b031681565b348015610fe657600080fd5b50610649610ff5366004613d30565b612e26565b34801561100657600080fd5b5061060e612f03565b34801561101b57600080fd5b5061060e61102a3660046140f1565b612f20565b60026001600160a01b038216600090815260046020526040902054600160401b900460ff16600381111561106557611065613c83565b036110b0576001600160a01b03808216600090815260046020526040902080546001909101546110ad928492600160501b8104821692909116906001600160401b0316612fa0565b50565b60026001600160a01b038281166000908152600560209081526040808320549093168252600490522054600160401b900460ff1660038111156110f5576110f5613c83565b03611141576001600160a01b0381811660009081526005602090815260408083205484168084526004909252909120600181015490546110ad93859216906001600160401b0316612fa0565b604051637115fdd360e01b815260040160405180910390fd5b611163826114d1565b1561119c576001600160a01b03808316600090815260046020526040812054611198928592600160501b90920416908461303e565b5050565b6111a582612022565b156111d2576001600160a01b0380831660009081526005602052604090205461119891168360018461303e565b60405163163e0acf60e21b815260040160405180910390fd5b600a54604051630292efd760e31b81526001600160a01b03868116600483015260009216906314977eb890602401602060405180830381865afa158015611236573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061125a9190613a4a565b6001600160401b031615611270575060006114bf565b81158061127d5750600f82115b1561128757600191505b600a546040516359726e5960e11b81526001600160a01b038681166004830152602482018690528781166044830152606482018590529091169063b2e4dcb290608401602060405180830381865afa1580156112e7573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061130b9190614131565b905061131685611ce1565b1561143657604051627eeac760e11b81526001600160a01b0386811660048301526024820185905285169062fdd58e90604401602060405180830381865afa158015611366573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061138a9190614131565b6113949082614160565b6001600160a01b03868116600090815260046020819052604091829020549151627eeac760e11b8152600160501b9092048316908201819052602482018790529293509086169062fdd58e90604401602060405180830381865afa158015611400573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114249190614131565b61142e9083614160565b9150506114bf565b61143f85611f61565b6114bf57604051627eeac760e11b81526001600160a01b0386811660048301526024820185905285169062fdd58e90604401602060405180830381865afa15801561148e573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906114b29190614131565b6114bc9082614160565b90505b949350505050565b6110ad338261115a565b6001600160a01b038116600090815260046020526040812054600160401b900460ff168181600381111561150757611507613c83565b14159392505050565b6115186130d4565b600954600160a01b900460ff161561154357604051637d6d4ab160e11b815260040160405180910390fd5b600980546001600160a01b0319166001600160a01b0392909216919091179055565b61119833838361312e565b6000600d54600c546115829190614173565b905090565b6001600160a01b0382811660009081526005602090815260408083205490931682526004905290812054600160401b900460ff1660038160038111156115cf576115cf613c83565b14806115ec575060028160038111156115ea576115ea613c83565b145b8061161057508280156116105750600181600381111561160e5761160e613c83565b145b1561161f5760009150506116a5565b506001600160a01b038316600090815260046020526040902054600160401b900460ff16600381600381111561165757611657613c83565b14806116745750600281600381111561167257611672613c83565b145b806116905750600181600381111561168e5761168e613c83565b145b1561169f5760009150506116a5565b60019150505b92915050565b6116b36130d4565b6001600160a01b038216600081815260066020908152604091829020849055815192835282018390527f5126cb9dd0e1253073fda9897fa9bfa7d4769735dc505a9992e125628d7e5d2d910160405180910390a15050565b600080600061171984611f61565b156117375760405163b18dc5df60e01b815260040160405180910390fd5b61174084611ce1565b1561177b575050506001600160a01b0380821660009081526004602052604090208054600191820154600160501b9091048316921690611785565b5082915081905060005b9193909250565b60608080600084158061179f5750600f85115b156117a957600194505b508460006117b682611f61565b156117c45750859050611ad0565b6117cd87611ce1565b156118025750506001600160a01b0380861660009081526004602052604090208054600190910154821691600160501b909104165b6009546001600160a01b03161580156118245750600a546001600160a01b0316155b80156118395750600b546001600160a01b0316155b156119115760006001600160a01b038216156118575750600261185b565b5060015b6000816001600160401b0381111561187557611875613d71565b60405190808252806020026020018201604052801561189e578160200160208202803683370190505b50905088816000815181106118b5576118b561418a565b6001600160a01b0392831660209182029290920101528316156119075782816001815181106118e6576118e661418a565b60200260200101906001600160a01b031690816001600160a01b0316815250505b9550611ad0915050565b6009546001906001600160a01b0316156119a75760095460405163276d772560e11b81526001600160a01b0390911690634edaee4a9061195b908b908b90879087906004016141a0565b600060405180830381865afa158015611978573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f191682016040526119a091908101906141ca565b9550600090505b600a546001600160a01b031615611a3a57600a5460405163276d772560e11b81526001600160a01b0390911690634edaee4a906119ee908b908b90879087906004016141a0565b600060405180830381865afa158015611a0b573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611a3391908101906141ca565b9450600090505b600b546001600160a01b031615611acd57600b5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611a81908b908b90879087906004016141a0565b600060405180830381865afa158015611a9e573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611ac691908101906141ca565b9350600090505b50505b92959194509250565b611ae16130d4565b6009805460ff60a01b1916600160a01b179055565b60606000821580611b075750600f83115b15611b1157600192505b50826000611b1e82611f61565b15611b2c5750839050611bea565b611b3585611ce1565b15611b6a5750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b60095460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b600060405180830381865afa158015611bbe573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052611be691908101906141ca565b9250505b9250929050565b6001600160a01b0381811660009081526005602090815260408083205490931680835260048252838320845160a0810190955280546001600160401b038116865293948594859485948594859491938593830190600160401b900460ff166003811115611c6057611c60613c83565b6003811115611c7157611c71613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919b5094995093975095509350909150505b91939550919395565b600060036001600160a01b038316600090815260046020526040902054600160401b900460ff166003811115611d1957611d19613c83565b1492915050565b6000811580611d2f5750600f82115b15611d3957600191505b6009546040516349d0e8d560e11b81526001600160a01b0386811660048301526024820186905260448201859052909116906393a1d1aa90606401602060405180830381865afa158015611d91573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611db59190614258565b90506001600160a01b038116611e5a576040516331a9108f60e11b8152600481018490526001600160a01b03851690636352211e90602401602060405180830381865afa158015611e0a573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611e2e9190614258565b9050611e3981611f61565b15611e5a576001600160a01b03908116600090815260056020526040902054165b9392505050565b60606000821580611e725750600f83115b15611e7c57600192505b50826000611e8982611f61565b15611e975750839050611bea565b611ea085611ce1565b15611ed55750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b600b5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b611f146130d4565b600b54600160a01b900460ff1615611f3f57604051637d6d4ab160e11b815260040160405180910390fd5b600b80546001600160a01b0319166001600160a01b0392909216919091179055565b600060036001600160a01b038381166000908152600560209081526040808320549093168252600490522054600160401b900460ff166003811115611d1957611d19613c83565b6000611fb382611ce1565b15611ffc57611fcc6001600160a01b0383163182614160565b6001600160a01b038084166000908152600460205260409020549192506116a591600160501b9004163182614160565b61200582611f61565b61201d576116a56001600160a01b0383163182614160565b919050565b6001600160a01b0381811660009081526005602090815260408083205490931682526004905290812054600160401b900460ff16600381600381111561206a5761206a613c83565b1480611e5a5750600281600381111561208557612085613c83565b149392505050565b6120956130d4565b600880546001600160a01b0319166001600160a01b0392909216919091179055565b6120bf6130d4565b6120c96000613198565b565b600b54604051630292efd760e31b81526001600160a01b03858116600483015260009216906314977eb890602401602060405180830381865afa158015612116573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061213a9190613a4a565b6001600160401b03161561215057506000611e5a565b81158061215d5750600f82115b1561216757600191505b600b54604051630625da8960e21b81526001600160a01b038581166004830152868116602483015260448201859052909116906318976a24906064015b602060405180830381865afa1580156121c1573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121e59190614131565b90506121f084611ce1565b15612306576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa15801561223b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061225f9190614131565b6122699082614160565b6001600160a01b038581166000908152600460208190526040918290205491516370a0823160e01b8152600160501b9092048316908201819052929350908516906370a0823190602401602060405180830381865afa1580156122d0573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122f49190614131565b6122fe9083614160565b915050611e5a565b61230f84611f61565b611e5a576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa158015612359573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061237d9190614131565b6114bf9082614160565b61238f6130d4565b60075460405163c47f002760e01b81526101009091046001600160a01b03169063c47f0027906123c3908490600401613aff565b6020604051808303816000875af11580156123e2573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906111989190614131565b6001600160a01b038181166000908152600560209081526040808320549093168252600490529081205481908190819081908190600160401b900460ff16600381600381111561245857612458613c83565b14806124755750600281600381111561247357612473613c83565b145b806124915750600181600381111561248f5761248f613c83565b145b156124b15761249f88611bf1565b96509650965096509650965050611cd8565b506001600160a01b038716600090815260046020526040902054600160401b900460ff1660038160038111156124e9576124e9613c83565b14806125065750600281600381111561250457612504613c83565b145b806125225750600181600381111561252057612520613c83565b145b156125305761249f88612c06565b50600097889750879650869550859450849350915050565b600154341461256a576040516333b18e6b60e11b815260040160405180910390fd5b61257b3384846001543414856131e8565b505050565b6125886130d4565b600380546001600160a01b0319166001600160a01b0383169081179091556040519081527fa5289ba11778999f4dfb9415023783188d42bbb5db0612cbfbe55999069612a0906020015b60405180910390a150565b6125e56130d4565b816001600160a01b031663f242432a306126076000546001600160a01b031690565b604051627eeac760e11b81523060048201526024810186905285906001600160a01b0388169062fdd58e90604401602060405180830381865afa158015612652573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906126769190614131565b6040516001600160e01b031960e087901b1681526001600160a01b0394851660048201529390921660248401526044830152606482015260a06084820152600060a482015260c4015b600060405180830381600087803b1580156126d957600080fd5b505af11580156126ed573d6000803e3d6000fd5b505050505050565b6126fd6130d4565b6111986127126000546001600160a01b031690565b6001600160a01b03841690836133b1565b61272b6130d4565b600155565b6127386130d4565b600b805460ff60a01b1916600160a01b179055565b6127556130d4565b600c91909155600d55565b6127686130d4565b600854611198906001600160a01b038481169116836133b1565b33600090815260066020526040812054908190036127d75760405162461bcd60e51b815260206004820152600d60248201526c0496e76616c696420455243323609c1b60448201526064015b60405180910390fd5b6000806000848060200190518101906127f09190614275565b925092509250838614612816576040516333b18e6b60e11b815260040160405180910390fd5b6128248784846001856131e8565b50505050505050565b6128356130d4565b600380546001600160f81b0316600160f81b1790556040517fa8e99dd43192eea7c15fab7a8e9f086c3aa9ecd5a096c50deb88ef871aa17c6090600090a1565b6000612882338484613403565b604051600081526001600160a01b0384169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350600192915050565b6128d46130d4565b60075460ff16156128f857604051636c0bdb4b60e11b815260040160405180910390fd5b60005b815181101561295b5760008282815181106129185761291861418a565b6020026020010151905061293d816000015182602001518360400151600160006131e8565b612952816000015182602001516000806134f4565b506001016128fb565b506007805460ff191660011790556040517f96e718f44bd77cb63370212c5aa24a0396d8f43e88e7ce175d160e371c8e2a6a90600090a150565b61299d6130d4565b60078054610100600160a81b0319166101006001600160a01b038416908102919091179091556040519081527f24625640821500d1ed82bf4cfa7973b775a4403ba28f029db24efa6b80241aac906020016125d2565b6129fb6130d4565b600354600160f81b900460ff1615612a2657604051638b5acdcb60e01b815260040160405180910390fd5b600380546affffffffffffffffffffff60a01b1916600160a01b6001600160581b038416908102919091179091556040519081527f7f8f51cc4bfc1384be37bf64948c3c3ecc5c1f7a40e8d2b166a11492fb78b3be906020016125d2565b612a8c6130d4565b600255565b60606000821580612aa25750600f83115b15612aac57600192505b50826000612ab982611f61565b15612ac75750839050611bea565b612ad085611ce1565b15612b055750506001600160a01b0380841660009081526004602052604090208054600190910154821691600160501b909104165b600a5460405163276d772560e11b81526001600160a01b0390911690634edaee4a90611ba1908890889086906001906004016141a0565b612b446130d4565b816001600160a01b03166323b872dd30612b666000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b03928316600482015291166024820152604481018490526064016126bf565b612baa823361361c565b6001600160a01b038216600090815260046020526040902054600160481b900460ff16158015612bdc57506001543414155b15612bfa57604051632740b97160e11b815260040160405180910390fd5b611198823334846134f4565b6001600160a01b0381166000908152600460209081526040808320815160a0810190925280546001600160401b0381168352849384938493849384938493929190830190600160401b900460ff166003811115612c6557612c65613c83565b6003811115612c7657612c76613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919c909a5091985091965090945092505050565b612ce76130d4565b600a54600160a01b900460ff1615612d1257604051637d6d4ab160e11b815260040160405180910390fd5b600a80546001600160a01b0319166001600160a01b0392909216919091179055565b612d3c6130d4565b6008546040516000916001600160a01b03169083908381818185875af1925050503d8060008114612d89576040519150601f19603f3d011682016040523d82523d6000602084013e612d8e565b606091505b50509050806111985760405163e53e5bcd60e01b815260040160405180910390fd5b612db86130d4565b6001600160a01b038116612e1d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084016127ce565b6110ad81613198565b600954604051630292efd760e31b81526001600160a01b03858116600483015260009216906314977eb890602401602060405180830381865afa158015612e71573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612e959190613a4a565b6001600160401b031615612eab57506000611e5a565b811580612eb85750600f82115b15612ec257600191505b600954604051630625da8960e21b81526001600160a01b038581166004830152868116602483015260448201859052909116906318976a24906064016121a4565b612f0b6130d4565b600a805460ff60a01b1916600160a01b179055565b6001600160a01b038216612f475760405163bd78145160e01b815260040160405180910390fd5b826001600160a01b0316826001600160a01b031603612f79576040516304da706760e51b815260040160405180910390fd5b6001600160a01b03811661257b57604051634ca5048960e01b815260040160405180910390fd5b6001600160a01b038481166000908152600460205260409020805469ffff0000000000000000191669010300000000000000001790556003541615612fe857612fe8826136c9565b6040516001600160a01b0383811682526001600160401b03831691818616918716907f5717bcaec46242edc8fb07322221c02d6dd3de7a954d5c009ee550cd0cdf7685906020015b60405180910390a450505050565b6001600160a01b03808516600081815260046020908152604080832080546001600160f01b031916815560010180546001600160a01b03199081169091559488168084526005909252918290208054909416909355519091907fbd302a9bf683315c275f4a7f0092796d97d17fbb2a89bbc8938bd6842c38eb89906130c690869086906142b7565b60405180910390a350505050565b6000546001600160a01b031633146120c95760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e657260448201526064016127ce565b6001600160a01b038216613155576040516334b1be0d60e21b815260040160405180910390fd5b61315e836114d1565b1561316e5761257b838383613739565b61317783612022565b156111d25760405160016208d37d60e21b0319815260040160405180910390fd5b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6131f3858585612f20565b6131fe856001611587565b15806132125750613210846000611587565b155b15613230576040516307facddb60e11b815260040160405180910390fd5b6040805160a0810182526001600160401b03838116825260016020808401918252861515848601526001600160a01b03898116606086015288811660808601528a16600090815260049091529390932082518154921667ffffffffffffffff1983168117825593519293909291839168ffffffffffffffffff1990911617600160401b8360038111156132c5576132c5613c83565b0217905550604082810151825460608501517fffff000000000000000000000000000000000000000000ffffffffffffffffff909116600160481b921515929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff1691909117600160501b6001600160a01b0392831602178355608090930151600190920180546001600160a01b03191692841692909217909155805185831681526001600160401b0384166020820152868316928816917f752c94da010e5b94c0278334398a684d4a7bde91f0f38c9dbb1766ad4f586c69910160405180910390a35050505050565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b17905261257b90849061384f565b6000600a6134126012826143b9565b61341c90846143de565b61342691906143f2565b90508015806134355750600481115b1561345357604051631ec9ca4160e21b815260040160405180910390fd5b6000600a6134626012826143b9565b61346c90856143de565b61347691906143de565b90506001820361349757613492858587600154600014856131e8565b6134ed565b600282036134b6576134a9848661361c565b61349284866000846134f4565b600382036134d2576134928585836001600160401b031661312e565b600482036134ed576134ed85826001600160401b031661115a565b5050505050565b6001600160a01b03838116600081815260056020908152604080832080546001600160a01b0319168a87169081179091558084526004835292819020600101549051941684526001600160401b038516937fda23dc0f47967fd81e9b62f5207a955b77295fef190364f10a6c3cf26773c1ab910160405180910390a46001600160a01b038416600090815260046020526040902054600160481b900460ff168061359f575060015482145b156135e2576001600160a01b038085166000908152600460205260409020600181015490546135dd92879287929116906001600160401b0316612fa0565b613616565b6001600160a01b0384166000908152600460205260409020805468ff00000000000000001916680200000000000000001790555b50505050565b6001600160a01b03828116600090815260046020526040902054600160501b90048116908216141580613683575060016001600160a01b038316600090815260046020526040902054600160401b900460ff16600381111561368057613680613c83565b14155b156136a157604051634cd87fb560e01b815260040160405180910390fd5b6136ac816000611587565b611198576040516307facddb60e11b815260040160405180910390fd5b600354604051631737909b60e11b81526001600160a01b038381166004830152600160a01b83046001600160581b0316602483015290911690632e6f213690604401600060405180830381600087803b15801561372557600080fd5b505af11580156134ed573d6000803e3d6000fd5b6001600160a01b0383166000908152600460209081526040808320815160a0810190925280546001600160401b03811683529192909190830190600160401b900460ff16600381111561378e5761378e613c83565b600381111561379f5761379f613c83565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b03908116604080850191909152600194850154821660609485015289821660008181526004855282902090950180546001600160a01b0319168a84169081179091559386015160808701518251908416815293840189905295965092941692917fa0aa3b38771c7ab4ece55c6009c41d814f4ff862285d0825c24528a87fd124d79101613030565b60006138a4826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b03166139219092919063ffffffff16565b80519091501561257b57808060200190518101906138c29190614406565b61257b5760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b60648201526084016127ce565b60606114bf8484600085856001600160a01b0385163b6139835760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e747261637400000060448201526064016127ce565b600080866001600160a01b0316858760405161399f9190614423565b60006040518083038185875af1925050503d80600081146139dc576040519150601f19603f3d011682016040523d82523d6000602084013e6139e1565b606091505b50915091506139f18282866139fc565b979650505050505050565b60608315613a0b575081611e5a565b825115613a1b5782518084602001fd5b8160405162461bcd60e51b81526004016127ce9190613aff565b6001600160401b03811681146110ad57600080fd5b600060208284031215613a5c57600080fd5b8151611e5a81613a35565b6001600160a01b03811681146110ad57600080fd5b60008060008060808587031215613a9257600080fd5b8435613a9d81613a67565b93506020850135613aad81613a67565b93969395505050506040820135916060013590565b600060208284031215613ad457600080fd5b5035919050565b60005b83811015613af6578181015183820152602001613ade565b50506000910152565b6020815260008251806020840152613b1e816040850160208701613adb565b601f01601f19169190910160400192915050565b600060208284031215613b4457600080fd5b8135611e5a81613a67565b60008060408385031215613b6257600080fd5b8235613b6d81613a67565b946020939093013593505050565b80151581146110ad57600080fd5b60008060408385031215613b9c57600080fd5b8235613ba781613a67565b91506020830135613bb781613b7b565b809150509250929050565b600081518084526020808501945080840160005b83811015613bfb5781516001600160a01b031687529582019590820190600101613bd6565b509495945050505050565b608081526000613c196080830187613bc2565b8281036020840152613c2b8187613bc2565b90508281036040840152613c3f8186613bc2565b91505060018060a01b038316606083015295945050505050565b604081526000613c6c6040830185613bc2565b905060018060a01b03831660208301529392505050565b634e487b7160e01b600052602160045260246000fd5b60048110613ca957613ca9613c83565b9052565b60c08101613cbb8289613c99565b6001600160a01b03968716602083015294861660408201529290941660608301526001600160401b0316608082015291151560a090920191909152919050565b600080600060608486031215613d1057600080fd5b8335613d1b81613a67565b95602085013595506040909401359392505050565b600080600060608486031215613d4557600080fd5b8335613d5081613a67565b92506020840135613d6081613a67565b929592945050506040919091013590565b634e487b7160e01b600052604160045260246000fd5b604051606081016001600160401b0381118282101715613da957613da9613d71565b60405290565b604051601f8201601f191681016001600160401b0381118282101715613dd757613dd7613d71565b604052919050565b60006001600160401b03831115613df857613df8613d71565b613e0b601f8401601f1916602001613daf565b9050828152838383011115613e1f57600080fd5b828260208301376000602084830101529392505050565b600060208284031215613e4857600080fd5b81356001600160401b03811115613e5e57600080fd5b8201601f81018413613e6f57600080fd5b6114bf84823560208401613ddf565b600080600060608486031215613e9357600080fd5b8335613e9e81613a67565b92506020840135613eae81613a67565b91506040840135613ebe81613a35565b809150509250925092565b60008060408385031215613edc57600080fd5b50508035926020909101359150565b600080600060608486031215613f0057600080fd5b8335613f0b81613a67565b92506020840135915060408401356001600160401b03811115613f2d57600080fd5b8401601f81018613613f3e57600080fd5b613f4d86823560208401613ddf565b9150509250925092565b60006001600160401b03821115613f7057613f70613d71565b5060051b60200190565b60006020808385031215613f8d57600080fd5b82356001600160401b03811115613fa357600080fd5b8301601f81018513613fb457600080fd5b8035613fc7613fc282613f57565b613daf565b81815260609182028301840191848201919088841115613fe657600080fd5b938501935b8385101561404b5780858a0312156140035760008081fd5b61400b613d87565b853561401681613a67565b81528587013561402581613a67565b8188015260408681013561403881613a67565b9082015283529384019391850191613feb565b50979650505050505050565b60006020828403121561406957600080fd5b81356001600160581b0381168114611e5a57600080fd5b6000806040838503121561409357600080fd5b823561409e81613a67565b91506020830135613bb781613a35565b6001600160401b038616815260a081016140cb6020830187613c99565b93151560408201526001600160a01b039283166060820152911660809091015292915050565b60008060006060848603121561410657600080fd5b833561411181613a67565b9250602084013561412181613a67565b91506040840135613ebe81613a67565b60006020828403121561414357600080fd5b5051919050565b634e487b7160e01b600052601160045260246000fd5b808201808211156116a5576116a561414a565b80820281158282048414176116a5576116a561414a565b634e487b7160e01b600052603260045260246000fd5b6001600160a01b039485168152602081019390935292166040820152901515606082015260800190565b600060208083850312156141dd57600080fd5b82516001600160401b038111156141f357600080fd5b8301601f8101851361420457600080fd5b8051614212613fc282613f57565b81815260059190911b8201830190838101908783111561423157600080fd5b928401925b828410156139f157835161424981613a67565b82529284019290840190614236565b60006020828403121561426a57600080fd5b8151611e5a81613a67565b60008060006060848603121561428a57600080fd5b835161429581613a67565b60208501519093506142a681613a67565b6040850151909250613ebe81613a35565b60408101600284106142cb576142cb613c83565b9281526020015290565b600181815b808511156143105781600019048211156142f6576142f661414a565b8085161561430357918102915b93841c93908002906142da565b509250929050565b600082614327575060016116a5565b81614334575060006116a5565b816001811461434a576002811461435457614370565b60019150506116a5565b60ff8411156143655761436561414a565b50506001821b6116a5565b5060208310610133831016604e8410600b8410161715614393575081810a6116a5565b61439d83836142d5565b80600019048211156143b1576143b161414a565b029392505050565b6000611e5a60ff841683614318565b634e487b7160e01b600052601260045260246000fd5b6000826143ed576143ed6143c8565b500490565b600082614401576144016143c8565b500690565b60006020828403121561441857600080fd5b8151611e5a81613b7b565b60008251614435818460208701613adb565b919091019291505056fea2646970667358221220c5e7a0021d9e26f7ee1f186437161739670137aa0ebe8c9e6c9dd550b17e476864736f6c63430008110033

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

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.