ETH Price: $3,802.63 (+5.23%)

Contract

0x032cCb98a0fadb150525631C587C1216d2535136
 

Overview

ETH Balance

0.000005 ETH

Eth Value

$0.02 (@ $3,802.63/ETH)

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer163919022023-01-12 16:25:47699 days ago1673540747IN
0x032cCb98...6d2535136
0 ETH0.0007974323.21704851
Transfer163906382023-01-12 12:11:23699 days ago1673525483IN
0x032cCb98...6d2535136
0 ETH0.0005731517.26013432
Transfer160854722022-11-30 21:26:23742 days ago1669843583IN
0x032cCb98...6d2535136
0 ETH0.0007647712.22028902
Transfer160854552022-11-30 21:22:59742 days ago1669843379IN
0x032cCb98...6d2535136
0 ETH0.0012396315.12594056
Transfer160854372022-11-30 21:19:23742 days ago1669843163IN
0x032cCb98...6d2535136
0 ETH0.0009557311.66182247
Transfer158855872022-11-02 23:22:35770 days ago1667431355IN
0x032cCb98...6d2535136
0 ETH0.0009212614.72089953
Transfer158855262022-11-02 23:10:23770 days ago1667430623IN
0x032cCb98...6d2535136
0 ETH0.001371516.73505708
Transfer158592242022-10-30 6:56:23773 days ago1667112983IN
0x032cCb98...6d2535136
0 ETH0.00052498.38739752
Transfer158592172022-10-30 6:54:59773 days ago1667112899IN
0x032cCb98...6d2535136
0 ETH0.000677218.26330983
Transfer158592072022-10-30 6:52:59773 days ago1667112779IN
0x032cCb98...6d2535136
0 ETH0.000510918.16399157
Transfer158592012022-10-30 6:51:47773 days ago1667112707IN
0x032cCb98...6d2535136
0 ETH0.00058437.12962903
Transfer158591942022-10-30 6:50:23773 days ago1667112623IN
0x032cCb98...6d2535136
0 ETH0.000531188.48784425
Transfer158591872022-10-30 6:48:59773 days ago1667112539IN
0x032cCb98...6d2535136
0 ETH0.000626947.64994697
Transfer158591752022-10-30 6:46:35773 days ago1667112395IN
0x032cCb98...6d2535136
0 ETH0.000512168.18539522
Transfer158591682022-10-30 6:45:11773 days ago1667112311IN
0x032cCb98...6d2535136
0 ETH0.000654117.98144222
Transfer158591632022-10-30 6:44:11773 days ago1667112251IN
0x032cCb98...6d2535136
0 ETH0.000507248.10524919
Transfer158591572022-10-30 6:42:59773 days ago1667112179IN
0x032cCb98...6d2535136
0 ETH0.00065778.02532154
Transfer158591522022-10-30 6:41:59773 days ago1667112119IN
0x032cCb98...6d2535136
0 ETH0.000529078.45412018
Transfer158591452022-10-30 6:40:35773 days ago1667112035IN
0x032cCb98...6d2535136
0 ETH0.000676628.25618586
Transfer158591392022-10-30 6:39:23773 days ago1667111963IN
0x032cCb98...6d2535136
0 ETH0.000461647.37671199
Transfer158591312022-10-30 6:37:47773 days ago1667111867IN
0x032cCb98...6d2535136
0 ETH0.000673778.22142511
Transfer158591242022-10-30 6:36:23773 days ago1667111783IN
0x032cCb98...6d2535136
0 ETH0.000504098.05501886
Transfer158591172022-10-30 6:34:59773 days ago1667111699IN
0x032cCb98...6d2535136
0 ETH0.000620267.56846383
Transfer158451312022-10-28 7:41:59775 days ago1666942919IN
0x032cCb98...6d2535136
0 ETH0.000625069.98787994
Transfer158451242022-10-28 7:40:35775 days ago1666942835IN
0x032cCb98...6d2535136
0 ETH0.00080859.86533057
View all transactions

Latest 4 internal transactions

Advanced mode:
Parent Transaction Hash Block From To
156354242022-09-29 0:29:23805 days ago1664411363
0x032cCb98...6d2535136
0.00005 ETH
156354062022-09-29 0:25:47805 days ago1664411147
0x032cCb98...6d2535136
0.000005 ETH
156353312022-09-29 0:10:35805 days ago1664410235
0x032cCb98...6d2535136
0.00005 ETH
156353192022-09-29 0:08:11805 days ago1664410091
0x032cCb98...6d2535136
 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 17 : EPSRegister.sol
// SPDX-License-Identifier: BUSL-1.1
// EPS Contracts v2.0.0

pragma solidity 0.8.17;
import "./DelegateRegister.sol";
import "./ProxyRegister.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";

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

  // ======================================================
  // VARIABLES
  // ======================================================

  // EPS treasury address:
  address public treasury;

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

  // 'Air drop' of EPSAPI to every address
  uint256 public epsAPIBalance = 10000;

  error ColdWalletCannotInteractUserHot();
  error EthWithdrawFailed();
  error UnknownAmount();

  /**
   * @dev Constructor initialises the parameters for the proxy and delegate registers.
   */
  constructor(
    uint256 proxyRegisterFee_,
    address treasury_,
    uint96 delegationRegisterFee_,
    uint32 delegationFeePercentage_,
    address weth_,
    uint256 deletionNominalEth_
  )
    ProxyRegister(proxyRegisterFee_, deletionNominalEth_)
    DelegateRegister(delegationRegisterFee_, delegationFeePercentage_, weth_)
  {
    setTreasuryAddress(treasury_);
  }

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

  /**
   * @dev beneficiaryOf: Returns the beneficiary of the `tokenId` token.
   */
  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_ = 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, ERC20 or ERC777 contract.
   */
  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 (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_ = 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_
  ) external view returns (uint256 balance_) {
    // 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 getAddresses: Returns the register address details (cold and delivery address) for a passed hot address
   */
  function getAddresses(address _receivedAddress)
    public
    view
    returns (
      address cold,
      address delivery,
      bool isProxied
    )
  {
    if (coldIsLive(_receivedAddress)) revert ColdWalletCannotInteractUserHot();

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

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

  /**
   * @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 any assets sent here in error
   */
  function withdrawERC20(IERC20 token_, uint256 amount_) external onlyOwner {
    token_.safeTransfer(owner(), amount_);
  }

  /**
   * @dev withdrawERC721: Allow any ERC721s to be withdrawn. 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 withdrawERC721(IERC721 token_, uint256 tokenId_) external onlyOwner {
    token_.transferFrom(address(this), owner(), tokenId_);
  }

  // ======================================================
  // 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 &&
      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 decimals() public pure returns (uint8) {
    return 0;
  }

  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);

    return (true);
  }
}

File 2 of 17 : 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 3 of 17 : 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";

/**
 *
 * @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, 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;

  // ======================================================
  // VARIABLES
  // ======================================================

  // 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;

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

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

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

  /**
   * @dev Constructor initialises the register fee and nominal ETH to which can be sent to
   * the contract to end an existing proxy.
   */
  constructor(uint256 registerFee_, uint256 deletionNominalEth_) {
    proxyRegisterFee = registerFee_;
    deletionNominalEth = deletionNominalEth_;
  }

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

  /**
   * @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, 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_,
    uint256 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_ == proxyRegisterFee,
      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;

    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

    uint256 actionCode = amount_ % 10;

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

    uint64 providerCode = uint64(amount_ / 10);

    if (actionCode == HOT_NOMINATE_COLD)
      _processNomination(from_, to_, from_, 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);
  }

  // ======================================================
  // CONFIGURATION
  // ======================================================

  /**
   * @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_;
  }
}

File 4 of 17 : DelegateRegister.sol
// SPDX-License-Identifier: BUSL-1.1
// EPS Contracts v2.0.0

pragma solidity 0.8.17;
import "@openzeppelin/contracts/access/Ownable.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721Receiver.sol";
import "@openzeppelin/contracts/proxy/Clones.sol";
import "./IDelegationContainer.sol";
import "./IEPSDelegateRegister.sol";

/**
 *
 * @dev The EPS Delegation Register contract. This contract is part of the EPSRegister, and allows the owner
 * of an ERC721 to delegate rights to another address (the delegate address). The owner decides what rights
 * they wish to delegate, how long for, and if they require payment for the delegation. For example, a holder
 * might decide that they wish to delegate physical event rights to another for three months. They want 0.5 ETH
 * for this privelidge. They load the delegation here, with the asset being custodied in a delegation container
 * that the original asset owner owns. Other addresses can accept that delegation proposal by paying the ETH
 * due. This loads the delegation details to the register, and means that query functions like beneficiaryOf and
 * beneficiaryBalanceOf return data that reflect this delegation.
 *
 */

contract DelegateRegister is IEPSDelegateRegister, Ownable, IERC721Receiver {
  using Clones for address payable;

  // =======================================
  // CONSTANTS
  // =======================================

  // Total rights, positions 13, 14 and 15 reserved for project specific rights.
  uint256 constant TOTAL_RIGHTS =
    10000100001000010000100001000010000100001000010000100001000010000100001;
  //15   14   13   12   11   10   9    8    7    6    5    4    3    2    1

  // Rights slice length - this is used in run time to slice up rights integers into their component parts.
  uint256 constant RIGHTS_SLICE_LENGTH = 5;

  // Default for any percentages, which must be held as a prortion of 100,000, i.e. a
  // percentage of 5% is held as 5,000.
  uint256 constant PERCENTAGE_DENOMINATOR = 100000;

  address immutable weth;

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

  // Unique ID for every proposed delegation.
  uint64 public delegationId;

  // Unique ID for every collection offer.
  uint64 public offerId;

  // Basic fee charged by the protocol for operations that require payment, namely the acceptance of a delegation
  // or the secondary sale of rights.
  uint96 public delegationRegisterFee;

  // Percentage fee applied to proceeds derived from protocol actions. For example, if this is set to 0.5% (500) and
  // an asset owner has charged 1 ETH for a delegation this will be a charge of 0.005 ETH. Note that this is charged in
  // addition to the base fee. This is important, as the base fee is all the protocol will take for fee free transactions,
  // and some revenue is required to maintain the service.
  uint32 public delegationFeePercentage;

  // The string descriptions associated with the default rights codes. Only position 1 to 12 will be used, but full length
  // provided here for future flexiblity
  string[16] public defaultRightsCodes;

  // Lock for delegation container address
  bool public delegationContainerTemplateLocked;

  // Provide ability to pause new sales (in-ife functionality including asset reclaim cannot be paused)
  bool public marketplacePaused;

  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;
  }

  // The address of the delegation container template.
  address payable public delegationContainer;

  // Map a tokenContract and Id to a delegation record.
  // bytes32 mapping for this is tokenContract and tokenId
  mapping(bytes32 => DelegationRecord) public tokenToDelegationRecord;

  // Map a token contract and query address to a balance struct:
  // bytes32 mapping for this is tokenContract and address being queried
  mapping(bytes32 => uint256) public contractToBalanceByRights;

  // Map a deployed container contract to a delegation record.
  mapping(address => uint64) public containerToDelegationId;

  // Map a token contract to a listing of contract specific rights codes:
  mapping(address => string[16]) public tokenContractToRightsCodes;

  // Map collection offer ID to offer:
  mapping(uint64 => Offer) public offerIdToOfferDetails;

  // Store offer ERC20 payment options, the returned value if the base fee for that ERC20
  mapping(address => ERC20PaymentOptions) public validERC20PaymentOption;

  /**
   *
   * @dev Constructor
   *
   */
  constructor(
    uint96 delegationRegisterFee_,
    uint32 delegationFeePercentage_,
    address weth_
  ) {
    delegationRegisterFee = delegationRegisterFee_;
    delegationFeePercentage = delegationFeePercentage_;
    weth = weth_;
  }

  // =======================================
  // GETTERS
  // =======================================

  /**
   *
   * @dev getFeeDetails: Get fee details (register fee and fee percentage).
   *
   */
  function getFeeDetails()
    external
    view
    returns (uint96 delegationRegisterFee_, uint32 delegationFeePercentage_)
  {
    return (delegationRegisterFee, delegationFeePercentage);
  }

  /**
   *
   * @dev getDelegationIdForContainer: Get delegation ID for a given container.
   *
   */
  function getDelegationIdForContainer(address container_)
    external
    view
    returns (uint64 delegationId_)
  {
    return (containerToDelegationId[container_]);
  }

  /**
   *
   * @dev getBalanceByRight: Get balance by rights
   *
   */
  function getBalanceByRight(
    address tokenContract_,
    address queryAddress_,
    uint256 rightsIndex_
  ) public view returns (uint256) {
    // Create the hash for this contract and address combination:

    bytes32 queryHash = _getParticipantHash(tokenContract_, queryAddress_);

    return (
      _sliceRightsInteger(rightsIndex_, contractToBalanceByRights[queryHash])
    );
  }

  /**
   *
   * @dev getBeneficiaryByRight: Get beneficiary by rights
   *
   */
  function getBeneficiaryByRight(
    address tokenContract_,
    uint256 tokenId_,
    uint256 rightsIndex_
  ) public view returns (address) {
    bytes32 keyHash = _getKeyHash(tokenContract_, tokenId_);

    DelegationRecord memory currentRecord = tokenToDelegationRecord[keyHash];

    // Check for delegation

    if (currentRecord.delegationId != 0) {
      if (
        _sliceRightsInteger(
          rightsIndex_,
          currentRecord.delegateRightsInteger
        ) == 0
      ) {
        // Owner has the rights
        return (currentRecord.owner);
      } else {
        // Delegate has the rights
        return (currentRecord.delegate);
      }
    }

    // Return 0 if there is nothing stored here.
    return (address(0));
  }

  // =======================================
  // SETTERS
  // =======================================

  /**
   * @dev addOfferPaymentERC20: add an offer ERC20 payment option
   */
  function addOfferPaymentERC20(address contractForERC20_, uint96 baseFee_)
    public
    onlyOwner
  {
    validERC20PaymentOption[contractForERC20_].isValid = true;
    validERC20PaymentOption[contractForERC20_].registerFee = baseFee_;
  }

  /**
   * @dev removeOfferPaymentERC20: remove an offer ERC20 payment option
   */
  function removeOfferPaymentERC20(address contractForERC20_) public onlyOwner {
    delete validERC20PaymentOption[contractForERC20_];
  }

  /**
   * @dev setDefaultRightsCodes: set the string description for the 12 defauls rights codes. Note this is for information only - these strings are
   * not used in the contract for any purpose.
   */
  function setDefaultRightsCodes(
    uint256 rightsIndex_,
    string memory rightsDescription_
  ) public onlyOwner {
    defaultRightsCodes[rightsIndex_] = rightsDescription_;
  }

  /**
   * @dev setProjectSpecificRightsCodes: set the string description for the 3 configurable rights codes that can be set per token contract. These
   * occupy positions 13, 14 and 15 on the rights index. These may be seldom used, but the idea is to give projects three positions in the rights
   * integer where they can determine their own authorities.
   */
  function setProjectSpecificRightsCodes(
    address tokenContract_,
    uint256 rightsIndex_,
    string memory rightsDescription_
  ) public onlyOwner {
    tokenContractToRightsCodes[tokenContract_][
      rightsIndex_
    ] = rightsDescription_;
  }

  /**
   * @dev setDelegationRegisterFee: set the base fee for transactions.
   */
  function setDelegationRegisterFee(uint96 delegationRegisterFee_)
    public
    onlyOwner
  {
    delegationRegisterFee = delegationRegisterFee_;
  }

  /**
   * @dev setDelegationFeePercentage: set the percentage fee taken from transactions that involve payment.
   */
  function setDelegationFeePercentage(uint32 delegationFeePercentage_)
    public
    onlyOwner
  {
    delegationFeePercentage = delegationFeePercentage_;
  }

  /**
   * @dev lockDelegationContainerTemplate: allow the delegation container template to be locked at a given address.
   */
  function lockDelegationContainerTemplate() public onlyOwner {
    delegationContainerTemplateLocked = true;
  }

  /**
   *
   * @dev setDelegationContainer: set the container address. Can only be called once. Not set in the constructor
   * as the container needs to know the address of the register (which IS set in the constructor)
   * so we have a chicken and egg situation to resolve. Only allow to be set ONCE.
   *
   */
  function setDelegationContainer(address payable delegationContainer_)
    public
    onlyOwner
  {
    if (delegationContainerTemplateLocked) revert TemplateContainerLocked();
    delegationContainer = delegationContainer_;
  }

  /**
   * @dev toggleMarketplace: allow the marketplace to be paused / unpaused
   */
  function pauseMarketplace(bool marketPlacePaused) public onlyOwner {
    marketplacePaused = marketPlacePaused;
  }

  // =======================================
  // VALIDATION
  // =======================================

  /**
   * @dev Throws if this is not a valid container, returnds delegation Id if it's valid.
   */
  function isValidContainer(address container_)
    public
    view
    returns (uint64 recordId_)
  {
    recordId_ = containerToDelegationId[container_];

    if (recordId_ == 0) revert InvalidContainer();

    return (recordId_);
  }

  /**
   * @dev Throws if marketplace is not open
   */
  function _isMarketOpen() internal view {
    if (marketplacePaused) revert MarketPlacePaused();
  }

  // =======================================
  // RIGHTS 'BOOKKEEPING'
  // =======================================

  /**
   *
   * @dev _increaseRightsInteger: increase the passed rights integer with the passed integer
   *
   */
  function _increaseRightsInteger(
    address containerAddress_,
    address participantAddress_,
    address tokenContract_,
    uint256 tokenId_,
    bytes32 participantHash_,
    uint256 rightsInteger_
  ) internal {
    contractToBalanceByRights[participantHash_] += rightsInteger_;

    // An increase of rights is implicitly a transfer from the container that holds the asset:
    emit TransferRights(
      containerAddress_,
      participantAddress_,
      tokenContract_,
      tokenId_,
      rightsInteger_
    );
  }

  /**
   *
   * @dev _decreaseRightsInteger: decrease the passed rights integer with the passed integer
   *
   */
  function _decreaseRightsInteger(
    address containerAddress_,
    address participantAddress_,
    address tokenContract_,
    uint256 tokenId_,
    bytes32 participantHash_,
    uint256 rightsInteger_
  ) internal {
    contractToBalanceByRights[participantHash_] -= rightsInteger_;

    // An decrease of rights is implicitly a transfer to the container that holds the asset:
    emit TransferRights(
      participantAddress_,
      containerAddress_,
      tokenContract_,
      tokenId_,
      rightsInteger_
    );
  }

  /**
   *
   * @dev _adjustBalancesAtEndOfDelegation: reduce balances when a delegation has ended
   *
   */
  function _adjustBalancesAtEndOfDelegation(
    address tokenContract_,
    address container_,
    address owner_,
    address delegate_,
    uint256 tokenId_,
    uint64 delegationId_
  ) internal returns (bytes32 keyHash_, bytes32 ownerHash_) {
    (bytes32 keyHash, bytes32 ownerHash, bytes32 delegateHash) = _getAllHashes(
      tokenContract_,
      tokenId_,
      owner_,
      delegate_
    );

    _decreaseRightsInteger(
      container_,
      owner_,
      tokenContract_,
      tokenId_,
      ownerHash,
      (TOTAL_RIGHTS - tokenToDelegationRecord[keyHash].delegateRightsInteger)
    );

    _decreaseRightsInteger(
      container_,
      delegate_,
      tokenContract_,
      tokenId_,
      delegateHash,
      tokenToDelegationRecord[keyHash].delegateRightsInteger
    );

    // Emit event to show that this delegation is now
    _emitComplete(delegationId_);

    return (keyHash, ownerHash);
  }

  // =======================================
  // DELEGATION RECORDS MANAGEMENT
  // =======================================

  /**
   *
   * @dev _assignDelegationId: Create new delegation Id and assign it.
   *
   */
  function _assignDelegationId(address container_) internal {
    delegationId += 1;

    containerToDelegationId[container_] = delegationId;
  }

  /**
   *
   * @dev _resetDelegationRecordDetails: reset to default on relist
   *
   */
  function _resetDelegationRecordDetails(bytes32 keyHash_) internal {
    _updateDelegationRecordDetails(keyHash_, 0, address(0), 0);
  }

  /**
   *
   * @dev _updateDelegationRecordDetails: common processing for delegation record updates
   *
   */
  function _updateDelegationRecordDetails(
    bytes32 keyHash_,
    uint64 endTime_,
    address delegate_,
    uint256 delegateRightsInteger_
  ) internal {
    tokenToDelegationRecord[keyHash_].endTime = endTime_;
    tokenToDelegationRecord[keyHash_].delegate = delegate_;
    tokenToDelegationRecord[keyHash_]
      .delegateRightsInteger = delegateRightsInteger_;
  }

  /**
   *
   * @dev _getAllHashes: get the hashes for tracking owner and delegate
   *
   */
  function _getAllHashes(
    address tokenContract_,
    uint256 tokenId_,
    address owner_,
    address delegate_
  )
    internal
    pure
    returns (
      bytes32 keyHash_,
      bytes32 ownerHash_,
      bytes32 delegateHash_
    )
  {
    (keyHash_, ownerHash_) = _getKeyAndParticipantHashes(
      tokenContract_,
      tokenId_,
      owner_
    );

    delegateHash_ = keccak256(abi.encodePacked(tokenContract_, delegate_));

    return (keyHash_, ownerHash_, delegateHash_);
  }

  /**
   *
   * @dev _getKeyAndParticipantHashes: get key and one participant hashes
   *
   */
  function _getKeyAndParticipantHashes(
    address tokenContract_,
    uint256 tokenId_,
    address participant_
  ) internal pure returns (bytes32 keyHash_, bytes32 participantHash_) {
    keyHash_ = _getKeyHash(tokenContract_, tokenId_);

    participantHash_ = _getParticipantHash(tokenContract_, participant_);

    return (keyHash_, participantHash_);
  }

  /**
   *
   * @dev _getParticipantHash: get one participant hash
   *
   */
  function _getParticipantHash(address tokenContract_, address participant_)
    internal
    pure
    returns (bytes32 participantHash_)
  {
    participantHash_ = keccak256(
      abi.encodePacked(tokenContract_, participant_)
    );

    return (participantHash_);
  }

  /**
   *
   * @dev _getKeyHash: get key hash
   *
   */
  function _getKeyHash(address tokenContract_, uint256 tokenId_)
    internal
    pure
    returns (bytes32 keyHash_)
  {
    keyHash_ = keccak256(abi.encodePacked(tokenContract_, tokenId_));

    return (keyHash_);
  }

  /**
   *
   * @dev _sliceRightsInteger: extract a position from the rights integer
   *
   */
  function _sliceRightsInteger(uint256 position_, uint256 rightsInteger_)
    internal
    pure
    returns (uint256 value)
  {
    uint256 exponent = (10**(position_ * RIGHTS_SLICE_LENGTH));
    uint256 divisor;
    if (position_ == 1) {
      divisor = 1;
    } else {
      divisor = (10**((position_ - 1) * RIGHTS_SLICE_LENGTH));
    }

    return ((rightsInteger_ % exponent) / divisor);
  }

  /**
   *
   * @dev sundryEvent: generic function for delegation register emits
   *
   */
  function sundryEvent(
    uint64 provider_,
    address address1_,
    address address2_,
    uint256 int1_,
    uint256 int2_,
    uint256 int3_,
    uint256 int4_
  ) external {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    // Emit a sundry event so we know about it:
    emit SundryEvent(
      provider_,
      recordId,
      address1_,
      address2_,
      int1_,
      int2_,
      int3_,
      int4_
    );
  }

  // =======================================
  // DELEGATION CREATION
  // =======================================

  /**
   *
   * @dev _createDelegationFromOffer: call when an offer is being accepted
   *_createDelegation
   */
  function _createDelegationFromOffer(
    DelegationParameters memory delegationData_,
    uint256 tokenId_,
    address owner_,
    bytes32 keyHash_,
    bytes32 ownerHash_,
    address tokenContract_,
    address container_
  ) internal {
    _offerAccepted(delegationData_, tokenId_, owner_, tokenContract_);

    _createDelegation(
      owner_,
      uint64(block.timestamp) + (uint64(delegationData_.duration) * 1 days),
      delegationData_.delegate,
      delegationData_.delegateRightsInteger,
      keyHash_
    );

    _increaseRightsInteger(
      container_,
      owner_,
      tokenContract_,
      tokenId_,
      ownerHash_,
      (TOTAL_RIGHTS - delegationData_.delegateRightsInteger)
    );

    _increaseRightsInteger(
      container_,
      delegationData_.delegate,
      tokenContract_,
      tokenId_,
      _getParticipantHash(tokenContract_, delegationData_.delegate),
      delegationData_.delegateRightsInteger
    );

    _emitDelegationAccepted(
      delegationData_,
      container_,
      tokenContract_,
      tokenId_,
      owner_
    );
  }

  /**
   *
   * @dev _emitDelegationAccepted
   *
   */
  function _emitDelegationAccepted(
    DelegationParameters memory delegationData_,
    address container_,
    address tokenContract_,
    uint256 tokenId_,
    address owner_
  ) internal {
    emit DelegationAccepted(
      delegationData_.provider,
      delegationId,
      container_,
      tokenContract_,
      tokenId_,
      owner_,
      delegationData_.delegate,
      uint64(block.timestamp) + (uint64(delegationData_.duration) * 1 days),
      delegationData_.delegateRightsInteger,
      0,
      delegationData_.URI
    );
  }

  /**
   *
   * @dev _createDelegation: create the delegation record
   *
   */
  function _createDelegation(
    address owner_,
    uint64 endTime_,
    address delegate_,
    uint256 delegateRightsInteger_,
    bytes32 keyHash_
  ) internal {
    tokenToDelegationRecord[keyHash_] = DelegationRecord(
      delegationId,
      owner_,
      endTime_,
      delegate_,
      delegateRightsInteger_
    );
  }

  /**
   *
   * @dev _offerAccepted: call when an offer is being accepted
   *
   */
  function _offerAccepted(
    DelegationParameters memory delegationData_,
    uint256 tokenId_,
    address owner_,
    address collection_
  ) internal {
    // 1) Check this is a valid match.
    Offer memory offerData = offerIdToOfferDetails[delegationData_.offerId];

    if (
      (offerData.collection != collection_) ||
      (!offerData.collectionOffer && offerData.tokenId != tokenId_) ||
      (delegationData_.delegate != offerData.offerMaker) ||
      (delegationData_.duration != offerData.delegationDuration) ||
      (delegationData_.fee != offerData.offerAmount) ||
      (delegationData_.delegateRightsInteger !=
        offerData.delegateRightsInteger) ||
      (block.timestamp > offerData.expiry)
    ) {
      revert InvalidOffer();
    }

    // 2) Perform payment processing:

    // If the payment ERC20 is address(0) this means the default, which is weth
    // (doing this saves a slot on the offer struct)
    address paymentERC20Address;
    uint256 registerFee;
    if (offerData.paymentERC20 == address(0)) {
      paymentERC20Address = weth;
      registerFee = delegationRegisterFee;
    } else {
      paymentERC20Address = offerData.paymentERC20;

      if (!validERC20PaymentOption[paymentERC20Address].isValid)
        revert InvalidERC20();

      registerFee = validERC20PaymentOption[paymentERC20Address].registerFee;
    }

    // Cancel the offer as it is being actioned
    delete offerIdToOfferDetails[delegationData_.offerId];

    uint256 claimAmount = (delegationData_.fee + registerFee);

    // Claim payment from the offerer:
    if (claimAmount > 0) {
      IERC20(paymentERC20Address).transferFrom(
        delegationData_.delegate,
        address(this),
        claimAmount
      );
    }

    uint256 epsFee;

    // The fee taken by the protocol is a percentage of the delegation fee + the register fee. This ensures
    // that even for free delegations the platform takes a small fee to remain sustainable.

    if (delegationData_.fee == 0) {
      epsFee = registerFee;
    } else {
      epsFee =
        ((delegationData_.fee * delegationFeePercentage) /
          PERCENTAGE_DENOMINATOR) +
        registerFee;
    }

    // Handle delegation Fee remittance
    if (delegationData_.fee != 0) {
      IERC20(paymentERC20Address).transfer(owner_, (claimAmount - epsFee));
    }

    emit OfferAccepted(
      delegationData_.provider,
      delegationData_.offerId,
      epsFee,
      paymentERC20Address
    );
  }

  /**
   *
   * @dev _decodeParameters
   *
   */
  function _decodeParameters(bytes memory data_)
    internal
    pure
    returns (DelegationParameters memory)
  {
    // Decode the delegation parameters from the data_ passed in:
    (
      uint64 paramProvider,
      address paramDelegate,
      uint24 paramDuration,
      uint96 paramFee,
      uint256 paramOwnerRights,
      uint256 paramDelegateRights,
      string memory paramURI,
      uint64 paramPfferId
    ) = abi.decode(
        data_,
        (uint64, address, uint24, uint96, uint256, uint256, string, uint64)
      );

    return (
      DelegationParameters(
        paramProvider,
        paramDelegate,
        paramDuration,
        paramFee,
        paramOwnerRights,
        paramDelegateRights,
        paramURI,
        paramPfferId
      )
    );
  }

  /**
   *
   * @dev onERC721Received - tokens are containerised for delegation by being sent to this
   * contract with the correct bytes data. NOTE - DO NOT JUST SEND ERC721s TO THIS
   * CONTRACT. This MUST be called from an interface that correctly encodes the
   * bytes parameter data for decode.
   *
   */

  function onERC721Received(
    address,
    address from_,
    uint256 tokenId_,
    bytes memory data_
  ) external override returns (bytes4) {
    if (from_ == address(0)) revert DoNoMintToThisAddress();

    address tokenContract = msg.sender;

    // Decode the delegation parameters from the data_ passed in:
    DelegationParameters memory delegationData = _decodeParameters(data_);

    // Check that we have been passed valid rights details for the owner and the beneficiary.
    if (
      delegationData.ownerRightsInteger +
        delegationData.delegateRightsInteger !=
      TOTAL_RIGHTS
    ) revert InvalidRights();

    // Cannot assign the current owner as the delegate:
    if (delegationData.delegate == from_) revert OwnerCannotBeDelegate();

    // Create the container contract:
    address newDelegationContainer = delegationContainer.clone();

    // Assign the container a delegation Id
    _assignDelegationId(newDelegationContainer);

    if (delegationData.offerId == 0) {
      emit DelegationCreated(
        delegationData.provider,
        delegationId,
        newDelegationContainer,
        from_,
        delegationData.delegate,
        delegationData.fee,
        delegationData.duration,
        tokenContract,
        tokenId_,
        delegationData.delegateRightsInteger,
        delegationData.URI
      );
    }

    (bytes32 keyHash, bytes32 ownerHash) = _getKeyAndParticipantHashes(
      tokenContract,
      tokenId_,
      from_
    );

    // If this was accepting an offer we save a full delegation record now:
    if (delegationData.offerId != 0) {
      _isMarketOpen();

      _createDelegationFromOffer(
        delegationData,
        tokenId_,
        from_,
        keyHash,
        ownerHash,
        tokenContract,
        newDelegationContainer
      );
    } else {
      _createDelegation(from_, 0, address(0), 0, keyHash);

      _increaseRightsInteger(
        newDelegationContainer,
        from_,
        tokenContract,
        tokenId_,
        ownerHash,
        TOTAL_RIGHTS
      );
    }

    // Initialise storage data:
    IDelegationContainer(newDelegationContainer).initialiseDelegationContainer(
      payable(from_),
      payable(delegationData.delegate),
      delegationData.fee,
      delegationData.duration,
      msg.sender,
      tokenId_,
      delegationData.delegateRightsInteger,
      delegationData.URI,
      delegationData.offerId
    );

    // Deliver the ERC721 to the container:
    IERC721(msg.sender).safeTransferFrom(
      address(this),
      newDelegationContainer,
      tokenId_
    );

    return this.onERC721Received.selector;
  }

  /**
   *
   * @dev saveDelegationRecord: Save the complete delegation to the register.
   *
   */
  function saveDelegationRecord(
    uint64 provider_,
    address tokenContract_,
    uint256 tokenId_,
    address owner_,
    address delegate_,
    uint64 endTime_,
    uint256 delegateRightsInteger_,
    string memory containerURI_
  ) external payable {
    _isMarketOpen();

    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 ownerHash, bytes32 delegateHash) = _getAllHashes(
      tokenContract_,
      tokenId_,
      owner_,
      delegate_
    );

    _updateDelegationRecordDetails(
      keyHash,
      endTime_,
      delegate_,
      delegateRightsInteger_
    );

    // We can just subtract the delegate rights integer as we added in a
    // TOTAL_RIGHTS for the owner while the delegation was pending:
    _decreaseRightsInteger(
      msg.sender,
      owner_,
      tokenContract_,
      tokenId_,
      ownerHash,
      delegateRightsInteger_
    );

    _increaseRightsInteger(
      msg.sender,
      delegate_,
      tokenContract_,
      tokenId_,
      delegateHash,
      delegateRightsInteger_
    );

    emit DelegationAccepted(
      provider_,
      recordId,
      msg.sender,
      tokenContract_,
      tokenId_,
      owner_,
      delegate_,
      endTime_,
      delegateRightsInteger_,
      msg.value,
      containerURI_
    );
  }

  /**
   *
   * @dev acceptOfferPriorToCommencement: Accept an offer from a container that is pre-commencement
   *
   */
  function acceptOfferPriorToCommencement(
    uint64 provider_,
    address owner_,
    address delegate_,
    uint24 duration_,
    uint96 fee_,
    uint256 delegateRightsInteger_,
    uint64 offerId_,
    address tokenContract_,
    uint256 tokenId_
  ) external {
    _isMarketOpen();

    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 ownerHash) = _getKeyAndParticipantHashes(
      tokenContract_,
      tokenId_,
      owner_
    );

    // Remove the temporary full rights for the owner:
    _decreaseRightsInteger(
      msg.sender,
      owner_,
      tokenContract_,
      tokenId_,
      ownerHash,
      TOTAL_RIGHTS
    );

    // Emit event to show that the previous listing is removed:
    _emitComplete(recordId);

    // Move the container to a new delegation Id:
    _assignDelegationId(msg.sender);

    _createDelegationFromOffer(
      DelegationParameters(
        provider_,
        delegate_,
        duration_,
        fee_,
        TOTAL_RIGHTS - delegateRightsInteger_,
        delegateRightsInteger_,
        "",
        offerId_
      ),
      tokenId_,
      owner_,
      keyHash,
      ownerHash,
      tokenContract_,
      msg.sender
    );
  }

  // =======================================
  // SECONDARY MARKET / TRANSFERS
  // =======================================

  /**
   *
   * @dev containerListedForSale: record that a delegation container has been listed for sale.
   *
   */
  function containerListedForSale(uint64 provider_, uint96 salePrice_)
    external
  {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    // Emit an event so we know about it:
    emit ContainerListedForSale(provider_, recordId, msg.sender, salePrice_);
  }

  /**
   *
   * @dev containerDetailsUpdated: record that an asset owner has updated container details.
   *
   */
  function containerDetailsUpdated(
    uint64 provider_,
    address delegate_,
    uint256 fee_,
    uint256 duration_,
    uint256 delegateRightsInteger_
  ) external {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    // Emit an event so we know about it:
    emit ContainerDetailsUpdated(
      provider_,
      recordId,
      msg.sender,
      delegate_,
      fee_,
      duration_,
      delegateRightsInteger_
    );
  }

  /**
   *
   * @dev changeAssetOwner: Change the owner of the container on sale.
   *
   */
  function changeAssetOwner(
    uint64 provider_,
    address newOwner_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 epsFee_
  ) external {
    _isMarketOpen();

    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 newOwnerHash) = _getKeyAndParticipantHashes(
      tokenContract_,
      tokenId_,
      newOwner_
    );

    // Save the old owner:
    address oldOwner = tokenToDelegationRecord[keyHash].owner;

    // Get hash for old owner:
    bytes32 oldOwnerHash = _getParticipantHash(tokenContract_, oldOwner);

    // This has been called from a container, and that method is assetOwner only. Procced to
    // update the register accordingly.

    // Update owner:
    tokenToDelegationRecord[keyHash].owner = newOwner_;

    // Reduce the contract to balance rights of the old owner by the owner rights integer
    // for this delegation record, and likewise increase it for the new owner:

    uint256 rightsInteger = TOTAL_RIGHTS -
      tokenToDelegationRecord[keyHash].delegateRightsInteger;

    _decreaseRightsInteger(
      msg.sender,
      oldOwner,
      tokenContract_,
      tokenId_,
      oldOwnerHash,
      rightsInteger
    );

    _increaseRightsInteger(
      msg.sender,
      newOwner_,
      tokenContract_,
      tokenId_,
      newOwnerHash,
      rightsInteger
    );

    emit DelegationOwnerChanged(provider_, recordId, newOwner_, epsFee_);
  }

  /**
   *
   * @dev List the delegation for sale.
   *
   */
  function delegationListedForSale(uint64 provider_, uint96 salePrice_)
    external
  {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    // Emit an event so we know about it:
    emit DelegationListedForSale(provider_, recordId, salePrice_);
  }

  /**
   *
   * @dev changeDelegate: Change the delegate on a delegation.
   *
   */
  function changeDelegate(
    uint64 provider_,
    address newDelegate_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 epsFee_
  ) external {
    _isMarketOpen();

    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 newDelegateHash) = _getKeyAndParticipantHashes(
      tokenContract_,
      tokenId_,
      newDelegate_
    );

    // Save the old delegate:
    address oldDelegate = tokenToDelegationRecord[keyHash].delegate;

    // Get hashes for new and old delegate:
    bytes32 oldDelegateHash = _getParticipantHash(tokenContract_, oldDelegate);

    // This has been called from a container, and that method is delegate only. Procced to
    // update the register accordingly:

    // Update delegate:
    tokenToDelegationRecord[keyHash].delegate = newDelegate_;

    // Reduce the contract to balance rights of the old delegate by the delegate rights integer
    // for this delegation record, and likewise increase it for the new delegate:

    uint256 rightsInteger = tokenToDelegationRecord[keyHash]
      .delegateRightsInteger;

    _decreaseRightsInteger(
      msg.sender,
      oldDelegate,
      tokenContract_,
      tokenId_,
      oldDelegateHash,
      rightsInteger
    );

    _increaseRightsInteger(
      msg.sender,
      newDelegate_,
      tokenContract_,
      tokenId_,
      newDelegateHash,
      rightsInteger
    );

    emit DelegationDelegateChanged(provider_, recordId, newDelegate_, epsFee_);
  }

  // =======================================
  // END OF DELEGATION
  // =======================================

  /**
   *
   * @dev acceptOfferAfterDelegationCompleted: Perform acceptance processing where the user is
   * ending a delegation and accepting an offer.
   *
   */
  function acceptOfferAfterDelegationCompleted(
    uint64 provider_,
    address owner_,
    address oldDelegate_,
    address newDelegate_,
    uint24 duration_,
    uint96 fee_,
    uint256 delegateRightsInteger_,
    uint64 offerId_,
    address tokenContract_,
    uint256 tokenId_
  ) external payable {
    _isMarketOpen();

    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 ownerHash) = _adjustBalancesAtEndOfDelegation(
      tokenContract_,
      msg.sender,
      owner_,
      oldDelegate_,
      tokenId_,
      recordId
    );

    // Move the container to a new delegation Id:
    _assignDelegationId(msg.sender);

    _createDelegationFromOffer(
      DelegationParameters(
        provider_,
        newDelegate_,
        duration_,
        fee_,
        TOTAL_RIGHTS - delegateRightsInteger_,
        delegateRightsInteger_,
        "",
        offerId_
      ),
      tokenId_,
      owner_,
      keyHash,
      ownerHash,
      tokenContract_,
      msg.sender
    );
  }

  /**
   *
   * @dev deleteEntry: remove a completed entry from the register.
   *
   */
  function deleteEntry(
    address tokenContract_,
    uint256 tokenId_,
    address owner_,
    address delegate_
  ) external {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, ) = _adjustBalancesAtEndOfDelegation(
      tokenContract_,
      msg.sender,
      owner_,
      delegate_,
      tokenId_,
      recordId
    );

    // Delete the register entry and owner and delegate data:
    delete tokenToDelegationRecord[keyHash];
    delete containerToDelegationId[msg.sender];
  }

  /**
   *
   * @dev relistEntry: relist an entry for a new delegation
   *
   */
  function relistEntry(
    uint64 provider_,
    address owner_,
    address oldDelegate_,
    address newDelegate_,
    uint96 fee_,
    uint24 durationInDays_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 delegateRightsInteger_,
    string memory containerURI_
  ) external {
    // Check this is a valid call from a delegationContainer:
    uint64 recordId = isValidContainer(msg.sender);

    (bytes32 keyHash, bytes32 ownerHash) = _adjustBalancesAtEndOfDelegation(
      tokenContract_,
      msg.sender,
      owner_,
      oldDelegate_,
      tokenId_,
      recordId
    );

    // Move the container to a new delegation Id:
    _assignDelegationId(msg.sender);

    _resetDelegationRecordDetails(keyHash);

    _increaseRightsInteger(
      msg.sender,
      owner_,
      tokenContract_,
      tokenId_,
      ownerHash,
      TOTAL_RIGHTS
    );

    emit DelegationCreated(
      provider_,
      delegationId,
      msg.sender,
      owner_,
      newDelegate_,
      fee_,
      durationInDays_,
      tokenContract_,
      tokenId_,
      delegateRightsInteger_,
      containerURI_
    );
  }

  /**
   *
   * @dev _emitComplete: signal that this delegation is complete
   *
   */
  function _emitComplete(uint64 delegationId_) internal {
    emit DelegationComplete(delegationId_);
  }

  // =======================================
  // OFFERS
  // =======================================

  /**
   *
   * @dev makeOffer: make an offer.
   *
   */
  function makeOffer(
    uint64 provider_,
    uint24 duration_,
    uint32 expiry_,
    bool collectionOffer_,
    address collection_,
    uint96 offerAmount_,
    address offerERC20_,
    uint256 tokenId_,
    uint256 delegateRightsRequested_
  ) external {
    // Check that the payment ERC20 is valid

    if (
      offerERC20_ != address(0) && !validERC20PaymentOption[offerERC20_].isValid
    ) revert InvalidERC20();

    // Increment offer id
    offerId += 1;

    offerIdToOfferDetails[offerId] = Offer(
      msg.sender,
      duration_,
      expiry_,
      collectionOffer_,
      collection_,
      offerAmount_,
      tokenId_,
      delegateRightsRequested_,
      offerERC20_
    );

    emit OfferMade(
      provider_,
      offerId,
      collection_,
      collectionOffer_,
      tokenId_,
      duration_,
      expiry_,
      offerAmount_,
      delegateRightsRequested_,
      msg.sender
    );
  }

  /**
   *
   * @dev cancelOffer: cancel an offer.
   *
   */
  function cancelOffer(uint64 provider_, uint64 offerId_) external {
    if (msg.sender != offerIdToOfferDetails[offerId_].offerMaker)
      revert CallerIsNotOfferMaker();
    delete offerIdToOfferDetails[offerId_];
    emit OfferDeleted(provider_, offerId_);
  }

  /**
   *
   * @dev changeOffer: change an offer.
   *
   */
  function changeOffer(
    uint64 provider_,
    uint64 offerId_,
    uint24 newDuration_,
    uint32 newExpiry_,
    uint96 newAmount_,
    uint256 newRightsInteger_
  ) external {
    if (msg.sender != offerIdToOfferDetails[offerId_].offerMaker)
      revert CallerIsNotOfferMaker();

    if (newDuration_ != 0)
      offerIdToOfferDetails[offerId_].delegationDuration = newDuration_;
    if (newExpiry_ != 0) offerIdToOfferDetails[offerId_].expiry = newExpiry_;
    if (newAmount_ != 0)
      offerIdToOfferDetails[offerId_].offerAmount = newAmount_;
    if (newRightsInteger_ != 0)
      offerIdToOfferDetails[offerId_].delegateRightsInteger = newRightsInteger_;

    emit OfferChanged(
      provider_,
      offerId_,
      newDuration_,
      newExpiry_,
      newAmount_,
      newRightsInteger_
    );
  }
}

File 5 of 17 : 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
  );

  // ======================================================
  // 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();

  // ======================================================
  // 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;

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

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

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

File 6 of 17 : 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 7 of 17 : IEPSDelegateRegister.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 IEPSDelegateRegister {
  // ======================================================
  // EVENTS
  // ======================================================
  // 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 getBeneficiaryByRight(
    address tokenContract_,
    uint256 tokenId_,
    uint256 rightsIndex_
  ) external view returns (address);

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

  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 getDelegationIdForContainer(address container_)
    external
    view
    returns (uint64 delegationId_);

  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 8 of 17 : IDelegationContainer.sol
// SPDX-License-Identifier: MIT
// EPSP Contracts v2.0.0

pragma solidity 0.8.17;

/**
 *
 * @dev The EPS Delegation container contract interface. Lightweight interface with just the functions required
 * by the register contract.
 *
 */
interface IDelegationContainer {
  event OwnershipTransferred(
    uint64 provider,
    address indexed previousOwner,
    address indexed newOwner
  );

  event Transfer(
    address indexed from,
    address indexed to,
    uint256 indexed tokenId
  );

  event EPSRegisterCallError(bytes reason);

  /**
   * @dev initialiseDelegationContainer - function to call to set storage correctly on a new clone:
   */
  function initialiseDelegationContainer(
    address payable owner_,
    address payable delegate_,
    uint96 fee_,
    uint24 durationInDays_,
    address tokenContract_,
    uint256 tokenId_,
    uint256 ownerRightsInteger,
    string memory containerURI_,
    uint64 offerId
  ) external;

  /**
   * @dev Delegate accepts delegation
   */
  function acceptDelegation(uint64 provider_) external payable;

  /**
   * @dev Get delegation details.
   */
  function getDelegationContainerDetails(uint64 passedDelegationId_)
    external
    view
    returns (
      uint64 delegationId_,
      address assetOwner_,
      address delegate_,
      address tokenContract_,
      uint256 tokenId_,
      bool terminated_,
      uint32 startTime_,
      uint24 durationInDays_,
      uint96 delegationFee_,
      uint256 delegateRightsInteger_,
      uint96 containerSalePrice_,
      uint96 delegationSalePrice_
    );
}

File 9 of 17 : Clones.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.7.0) (proxy/Clones.sol)

pragma solidity ^0.8.0;

/**
 * @dev https://eips.ethereum.org/EIPS/eip-1167[EIP 1167] is a standard for
 * deploying minimal proxy contracts, also known as "clones".
 *
 * > To simply and cheaply clone contract functionality in an immutable way, this standard specifies
 * > a minimal bytecode implementation that delegates all calls to a known, fixed address.
 *
 * The library includes functions to deploy a proxy using either `create` (traditional deployment) or `create2`
 * (salted deterministic deployment). It also includes functions to predict the addresses of clones deployed using the
 * deterministic method.
 *
 * _Available since v3.4._
 */
library Clones {
    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create opcode, which should never revert.
     */
    function clone(address implementation) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create(0, ptr, 0x37)
        }
        require(instance != address(0), "ERC1167: create failed");
    }

    /**
     * @dev Deploys and returns the address of a clone that mimics the behaviour of `implementation`.
     *
     * This function uses the create2 opcode and a `salt` to deterministically deploy
     * the clone. Using the same `implementation` and `salt` multiple time will revert, since
     * the clones cannot be deployed twice at the same address.
     */
    function cloneDeterministic(address implementation, bytes32 salt) internal returns (address instance) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000)
            instance := create2(0, ptr, 0x37, salt)
        }
        require(instance != address(0), "ERC1167: create2 failed");
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(
        address implementation,
        bytes32 salt,
        address deployer
    ) internal pure returns (address predicted) {
        /// @solidity memory-safe-assembly
        assembly {
            let ptr := mload(0x40)
            mstore(ptr, 0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000)
            mstore(add(ptr, 0x14), shl(0x60, implementation))
            mstore(add(ptr, 0x28), 0x5af43d82803e903d91602b57fd5bf3ff00000000000000000000000000000000)
            mstore(add(ptr, 0x38), shl(0x60, deployer))
            mstore(add(ptr, 0x4c), salt)
            mstore(add(ptr, 0x6c), keccak256(ptr, 0x37))
            predicted := keccak256(add(ptr, 0x37), 0x55)
        }
    }

    /**
     * @dev Computes the address of a clone deployed using {Clones-cloneDeterministic}.
     */
    function predictDeterministicAddress(address implementation, bytes32 salt)
        internal
        view
        returns (address predicted)
    {
        return predictDeterministicAddress(implementation, salt, address(this));
    }
}

File 10 of 17 : IERC721Receiver.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC721/IERC721Receiver.sol)

pragma solidity ^0.8.0;

/**
 * @title ERC721 token receiver interface
 * @dev Interface for any contract that wants to support safeTransfers
 * from ERC721 asset contracts.
 */
interface IERC721Receiver {
    /**
     * @dev Whenever an {IERC721} `tokenId` token is transferred to this contract via {IERC721-safeTransferFrom}
     * by `operator` from `from`, this function is called.
     *
     * It must return its Solidity selector to confirm the token transfer.
     * If any other value is returned or the interface is not implemented by the recipient, the transfer will be reverted.
     *
     * The selector can be obtained in Solidity with `IERC721Receiver.onERC721Received.selector`.
     */
    function onERC721Received(
        address operator,
        address from,
        uint256 tokenId,
        bytes calldata data
    ) external returns (bytes4);
}

File 11 of 17 : 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 12 of 17 : 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 13 of 17 : 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 17 : 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;
    }
}

File 15 of 17 : 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 16 of 17 : 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 17 of 17 : 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);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[{"internalType":"uint256","name":"proxyRegisterFee_","type":"uint256"},{"internalType":"address","name":"treasury_","type":"address"},{"internalType":"uint96","name":"delegationRegisterFee_","type":"uint96"},{"internalType":"uint32","name":"delegationFeePercentage_","type":"uint32"},{"internalType":"address","name":"weth_","type":"address"},{"internalType":"uint256","name":"deletionNominalEth_","type":"uint256"}],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"AddressMismatch","type":"error"},{"inputs":[],"name":"AlreadyProxied","type":"error"},{"inputs":[],"name":"CallerIsNotOfferMaker","type":"error"},{"inputs":[],"name":"ColdAddressCannotBeTheSameAsHot","type":"error"},{"inputs":[],"name":"ColdIsAddressZero","type":"error"},{"inputs":[],"name":"ColdWalletCannotInteractUserHot","type":"error"},{"inputs":[],"name":"DeliveryCannotBeTheZeroAddress","type":"error"},{"inputs":[],"name":"DeliveryIsAddressZero","type":"error"},{"inputs":[],"name":"DoNoMintToThisAddress","type":"error"},{"inputs":[],"name":"EthWithdrawFailed","type":"error"},{"inputs":[],"name":"IncorrectProxyRegisterFee","type":"error"},{"inputs":[],"name":"InvalidContainer","type":"error"},{"inputs":[],"name":"InvalidERC20","type":"error"},{"inputs":[],"name":"InvalidOffer","type":"error"},{"inputs":[],"name":"InvalidRights","type":"error"},{"inputs":[],"name":"MarketPlacePaused","type":"error"},{"inputs":[],"name":"NoPaymentPendingForAddress","type":"error"},{"inputs":[],"name":"NoRecordFoundForAddress","type":"error"},{"inputs":[],"name":"OnlyHotAddressCanChangeAddress","type":"error"},{"inputs":[],"name":"OwnerCannotBeDelegate","type":"error"},{"inputs":[],"name":"ProxyRegisterFeeRequired","type":"error"},{"inputs":[],"name":"TemplateContainerLocked","type":"error"},{"inputs":[],"name":"UnknownAmount","type":"error"},{"inputs":[],"name":"UnrecognisedEPSAPIAmount","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":false,"internalType":"address","name":"container","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"fee","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"duration","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"}],"name":"ContainerDetailsUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":false,"internalType":"address","name":"container","type":"address"},{"indexed":false,"internalType":"uint96","name":"salePrice","type":"uint96"}],"name":"ContainerListedForSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":false,"internalType":"address","name":"container","type":"address"},{"indexed":false,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint64","name":"endTime","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"epsFee","type":"uint256"},{"indexed":false,"internalType":"string","name":"URI","type":"string"}],"name":"DelegationAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"delegationId","type":"uint64"}],"name":"DelegationComplete","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":true,"internalType":"address","name":"containerAddress","type":"address"},{"indexed":false,"internalType":"address","name":"owner","type":"address"},{"indexed":false,"internalType":"address","name":"delegate","type":"address"},{"indexed":false,"internalType":"uint96","name":"fee","type":"uint96"},{"indexed":false,"internalType":"uint24","name":"durationInDays","type":"uint24"},{"indexed":false,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"},{"indexed":false,"internalType":"string","name":"URI","type":"string"}],"name":"DelegationCreated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":true,"internalType":"address","name":"newDelegate","type":"address"},{"indexed":false,"internalType":"uint256","name":"epsFee","type":"uint256"}],"name":"DelegationDelegateChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":false,"internalType":"uint96","name":"salePrice","type":"uint96"}],"name":"DelegationListedForSale","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":true,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"},{"indexed":false,"internalType":"uint256","name":"epsFee","type":"uint256"}],"name":"DelegationOwnerChanged","type":"event"},{"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":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":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"offerId","type":"uint64"},{"indexed":false,"internalType":"uint256","name":"epsFee","type":"uint256"},{"indexed":false,"internalType":"address","name":"epsFeeToken","type":"address"}],"name":"OfferAccepted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"offerId","type":"uint64"},{"indexed":false,"internalType":"uint24","name":"duration","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"offerExpiry","type":"uint32"},{"indexed":false,"internalType":"uint96","name":"offerAmount","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"}],"name":"OfferChanged","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"offerId","type":"uint64"}],"name":"OfferDeleted","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"offerId","type":"uint64"},{"indexed":false,"internalType":"address","name":"collection","type":"address"},{"indexed":false,"internalType":"bool","name":"collectionOffer","type":"bool"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint24","name":"duration","type":"uint24"},{"indexed":false,"internalType":"uint32","name":"expiry","type":"uint32"},{"indexed":false,"internalType":"uint96","name":"offerAmount","type":"uint96"},{"indexed":false,"internalType":"uint256","name":"delegateRightsRequested","type":"uint256"},{"indexed":false,"internalType":"address","name":"offerer","type":"address"}],"name":"OfferMade","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":[{"indexed":false,"internalType":"uint64","name":"provider","type":"uint64"},{"indexed":false,"internalType":"uint64","name":"delegationId","type":"uint64"},{"indexed":false,"internalType":"address","name":"address1","type":"address"},{"indexed":false,"internalType":"address","name":"address2","type":"address"},{"indexed":false,"internalType":"uint256","name":"integer1","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"integer2","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"integer3","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"integer4","type":"uint256"}],"name":"SundryEvent","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":true,"internalType":"address","name":"tokenContract","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"rightsInteger","type":"uint256"}],"name":"TransferRights","type":"event"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"uint64","name":"provider_","type":"uint64"}],"name":"acceptNomination","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"oldDelegate_","type":"address"},{"internalType":"address","name":"newDelegate_","type":"address"},{"internalType":"uint24","name":"duration_","type":"uint24"},{"internalType":"uint96","name":"fee_","type":"uint96"},{"internalType":"uint256","name":"delegateRightsInteger_","type":"uint256"},{"internalType":"uint64","name":"offerId_","type":"uint64"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"acceptOfferAfterDelegationCompleted","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"delegate_","type":"address"},{"internalType":"uint24","name":"duration_","type":"uint24"},{"internalType":"uint96","name":"fee_","type":"uint96"},{"internalType":"uint256","name":"delegateRightsInteger_","type":"uint256"},{"internalType":"uint64","name":"offerId_","type":"uint64"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"acceptOfferPriorToCommencement","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"activeEthAddresses","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractForERC20_","type":"address"},{"internalType":"uint96","name":"baseFee_","type":"uint96"}],"name":"addOfferPaymentERC20","outputs":[],"stateMutability":"nonpayable","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"}],"name":"beneficiaryBalanceOf1155","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":"uint64","name":"provider_","type":"uint64"},{"internalType":"uint64","name":"offerId_","type":"uint64"}],"name":"cancelOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"newOwner_","type":"address"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"epsFee_","type":"uint256"}],"name":"changeAssetOwner","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"newDelegate_","type":"address"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"epsFee_","type":"uint256"}],"name":"changeDelegate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"uint64","name":"offerId_","type":"uint64"},{"internalType":"uint24","name":"newDuration_","type":"uint24"},{"internalType":"uint32","name":"newExpiry_","type":"uint32"},{"internalType":"uint96","name":"newAmount_","type":"uint96"},{"internalType":"uint256","name":"newRightsInteger_","type":"uint256"}],"name":"changeOffer","outputs":[],"stateMutability":"nonpayable","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":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"delegate_","type":"address"},{"internalType":"uint256","name":"fee_","type":"uint256"},{"internalType":"uint256","name":"duration_","type":"uint256"},{"internalType":"uint256","name":"delegateRightsInteger_","type":"uint256"}],"name":"containerDetailsUpdated","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"uint96","name":"salePrice_","type":"uint96"}],"name":"containerListedForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"containerToDelegationId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"contractToBalanceByRights","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"uint256","name":"","type":"uint256"}],"name":"defaultRightsCodes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationContainer","outputs":[{"internalType":"address payable","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationContainerTemplateLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationFeePercentage","outputs":[{"internalType":"uint32","name":"","type":"uint32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"delegationId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"uint96","name":"salePrice_","type":"uint96"}],"name":"delegationListedForSale","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"delegationRegisterFee","outputs":[{"internalType":"uint96","name":"","type":"uint96"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"delegate_","type":"address"}],"name":"deleteEntry","outputs":[],"stateMutability":"nonpayable","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":"epsAPIBalance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_receivedAddress","type":"address"}],"name":"getAddresses","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":"tokenContract_","type":"address"},{"internalType":"address","name":"queryAddress_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"}],"name":"getBalanceByRight","outputs":[{"internalType":"uint256","name":"","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":"getBeneficiaryByRight","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"container_","type":"address"}],"name":"getDelegationIdForContainer","outputs":[{"internalType":"uint64","name":"delegationId_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFeeDetails","outputs":[{"internalType":"uint96","name":"delegationRegisterFee_","type":"uint96"},{"internalType":"uint32","name":"delegationFeePercentage_","type":"uint32"}],"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":"hot_","type":"address"},{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address","name":"delivery_","type":"address"}],"name":"isValidAddresses","outputs":[],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"container_","type":"address"}],"name":"isValidContainer","outputs":[{"internalType":"uint64","name":"recordId_","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockDelegationContainerTemplate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"uint24","name":"duration_","type":"uint24"},{"internalType":"uint32","name":"expiry_","type":"uint32"},{"internalType":"bool","name":"collectionOffer_","type":"bool"},{"internalType":"address","name":"collection_","type":"address"},{"internalType":"uint96","name":"offerAmount_","type":"uint96"},{"internalType":"address","name":"offerERC20_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"delegateRightsRequested_","type":"uint256"}],"name":"makeOffer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"marketplacePaused","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":[],"name":"offerId","outputs":[{"internalType":"uint64","name":"","type":"uint64"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"","type":"uint64"}],"name":"offerIdToOfferDetails","outputs":[{"internalType":"address","name":"offerMaker","type":"address"},{"internalType":"uint24","name":"delegationDuration","type":"uint24"},{"internalType":"uint32","name":"expiry","type":"uint32"},{"internalType":"bool","name":"collectionOffer","type":"bool"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint96","name":"offerAmount","type":"uint96"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"},{"internalType":"address","name":"paymentERC20","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"from_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"onERC721Received","outputs":[{"internalType":"bytes4","name":"","type":"bytes4"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bool","name":"marketPlacePaused","type":"bool"}],"name":"pauseMarketplace","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"proxyRegisterFee","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"oldDelegate_","type":"address"},{"internalType":"address","name":"newDelegate_","type":"address"},{"internalType":"uint96","name":"fee_","type":"uint96"},{"internalType":"uint24","name":"durationInDays_","type":"uint24"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"delegateRightsInteger_","type":"uint256"},{"internalType":"string","name":"containerURI_","type":"string"}],"name":"relistEntry","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"contractForERC20_","type":"address"}],"name":"removeOfferPaymentERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"address","name":"owner_","type":"address"},{"internalType":"address","name":"delegate_","type":"address"},{"internalType":"uint64","name":"endTime_","type":"uint64"},{"internalType":"uint256","name":"delegateRightsInteger_","type":"uint256"},{"internalType":"string","name":"containerURI_","type":"string"}],"name":"saveDelegationRecord","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"uint256","name":"rightsIndex_","type":"uint256"},{"internalType":"string","name":"rightsDescription_","type":"string"}],"name":"setDefaultRightsCodes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address payable","name":"delegationContainer_","type":"address"}],"name":"setDelegationContainer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint32","name":"delegationFeePercentage_","type":"uint32"}],"name":"setDelegationFeePercentage","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint96","name":"delegationRegisterFee_","type":"uint96"}],"name":"setDelegationRegisterFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"deleteNominalEth_","type":"uint256"}],"name":"setDeletionNominalEth","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":"address","name":"tokenContract_","type":"address"},{"internalType":"uint256","name":"rightsIndex_","type":"uint256"},{"internalType":"string","name":"rightsDescription_","type":"string"}],"name":"setProjectSpecificRightsCodes","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"registerFee_","type":"uint256"}],"name":"setRegisterFee","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_treasuryAddress","type":"address"}],"name":"setTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint64","name":"provider_","type":"uint64"},{"internalType":"address","name":"address1_","type":"address"},{"internalType":"address","name":"address2_","type":"address"},{"internalType":"uint256","name":"int1_","type":"uint256"},{"internalType":"uint256","name":"int2_","type":"uint256"},{"internalType":"uint256","name":"int3_","type":"uint256"},{"internalType":"uint256","name":"int4_","type":"uint256"}],"name":"sundryEvent","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"tokenContractToRightsCodes","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"tokenToDelegationRecord","outputs":[{"internalType":"uint64","name":"delegationId","type":"uint64"},{"internalType":"address","name":"owner","type":"address"},{"internalType":"uint64","name":"endTime","type":"uint64"},{"internalType":"address","name":"delegate","type":"address"},{"internalType":"uint256","name":"delegateRightsInteger","type":"uint256"}],"stateMutability":"view","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":"address","name":"","type":"address"}],"name":"validERC20PaymentOption","outputs":[{"internalType":"bool","name":"isValid","type":"bool"},{"internalType":"uint96","name":"registerFee","type":"uint96"}],"stateMutability":"view","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":"contract IERC721","name":"token_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"}],"name":"withdrawERC721","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawETH","outputs":[],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60a06040526001601e55612710601f553480156200001c57600080fd5b5060405162006016380380620060168339810160408190526200003f91620001bb565b83838388846200004f33620000c1565b6001919091556002556005805463ffffffff909316600160e01b026001600160e01b036001600160601b03909516600160801b0285166001600160801b0390941693909317929092179091556001600160a01b0316608052620000b59086906200011116565b50505050505062000243565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b6200011b6200013d565b601d80546001600160a01b0319166001600160a01b0392909216919091179055565b6000546001600160a01b031633146200019c5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e6572604482015260640160405180910390fd5b565b80516001600160a01b0381168114620001b657600080fd5b919050565b60008060008060008060c08789031215620001d557600080fd5b86519550620001e7602088016200019e565b60408801519095506001600160601b03811681146200020557600080fd5b606088015190945063ffffffff811681146200022057600080fd5b925062000230608088016200019e565b915060a087015190509295509295509295565b608051615db76200025f600039600061453b0152615db76000f3fe60806040526004361061048d5760003560e01c80638da5cb5b11610255578063c1f5c49a11610144578063dd2ebdb4116100c1578063f14210a611610085578063f14210a614611132578063f2fde38b14611152578063f3362fb914611172578063f3e414f814611192578063f8907b60146111b2578063fc2bc7b2146111d257600080fd5b8063dd2ebdb414611081578063e575d025146110a1578063e963134f146110b4578063ec8b9071146110d4578063f023a734146110f357600080fd5b8063cf135b9d11610108578063cf135b9d14610feb578063d1d3e28f1461100b578063d5472c181461102b578063d56bb0571461104b578063db7840cb1461106157600080fd5b8063c1f5c49a14610f5f578063c2f5dc4414610f7f578063c858380814610f95578063c93b228914610fb5578063ce46756914610fcb57600080fd5b8063a2966f5f116101d2578063b2969acf11610196578063b2969acf14610ea0578063b810c63614610ec0578063b9f97d4114610eff578063bd17532414610f2c578063c124eb1f14610f3f57600080fd5b8063a2966f5f14610d39578063a4c1408414610d4c578063a9059cbb14610e40578063ae7044c214610e60578063afb85e6214610e8057600080fd5b806393a1d1aa1161021957806393a1d1aa14610c8a57806395d89b4114610caa578063a0a3660614610cd9578063a1db978214610cf9578063a276c41514610d1957600080fd5b80638da5cb5b14610bce578063906f634314610bec57806390938e9514610c34578063913965c314610c5457806392be2ab814610c6a57600080fd5b806341e3196f1161037c578063657f9233116102f957806370a08231116102bd57806370a0823114610b0b578063715018a614610b2d5780637a3be00d14610b425780637afbd21214610b625780638523837014610b8257806388d6f15114610b9557600080fd5b8063657f923314610a375780636605bfda14610a575780636bcf608814610a775780636e22bad914610a8c5780636f1dcc3b14610aeb57600080fd5b80635205cb5b116103405780635205cb5b1461099757806353556440146109b757806357b14d9e146109d75780635ba58955146109f757806361d027b314610a1757600080fd5b806341e3196f146108f757806342b046901461091757806342de52551461093757806345065089146109575780634835de371461097757600080fd5b80631fc784101161040a578063274971b3116103ce578063274971b31461082b578063313ce5671461084b57806333ac8aa8146108675780633a0236e3146108995780633a30d464146108b957600080fd5b80631fc78410146106e0578063214cf7ad1461070057806321a0bd9e146107a557806321ce9f91146107e4578063265d97ee1461080b57600080fd5b8063150b7a0211610451578063150b7a02146106245780631718e0cf1461065d57806318160ddd1461067d5780631888f727146106a057806318976a24146106c057600080fd5b8063061f98111461052a57806306fdde031461054a5780630956d8a71461058c5780630ec735da146105bc57806314977eb8146105d657600080fd5b366105255760015434141580156104a657506002543414155b80156104c85750336000908152601960205260409020546001600160401b0316155b80156104df57506000546001600160a01b03163314155b156104fd5760405163020ad41b60e11b815260040160405180910390fd5b60015434036105115761050f336111f2565b005b600254340361050f5761050f336000611322565b600080fd5b34801561053657600080fd5b5061050f610545366004614bc1565b6113b3565b34801561055657600080fd5b506040805180820190915260078152664550532041504960c81b60208201525b6040516105839190614c2a565b60405180910390f35b34801561059857600080fd5b506105ac6105a7366004614c5d565b6113bd565b6040519015158152602001610583565b3480156105c857600080fd5b506016546105ac9060ff1681565b3480156105e257600080fd5b5061060c6105f1366004614c5d565b6019602052600090815260409020546001600160401b031681565b6040516001600160401b039091168152602001610583565b34801561063057600080fd5b5061064461063f366004614d25565b6113fc565b6040516001600160e01b03199091168152602001610583565b34801561066957600080fd5b5061050f610678366004614da4565b6116e9565b34801561068957600080fd5b506106926116f4565b604051908152602001610583565b3480156106ac57600080fd5b5061050f6106bb366004614dde565b61170b565b3480156106cc57600080fd5b506106926106db366004614dfb565b61172d565b3480156106ec57600080fd5b5061050f6106fb366004614e51565b611762565b34801561070c57600080fd5b5061076361071b366004614bc1565b6017602052600090815260409020805460018201546002909201546001600160401b03808316936001600160a01b03600160401b948590048116949282169392909104169085565b604080516001600160401b0396871681526001600160a01b0395861660208201529590931692850192909252919091166060830152608082015260a001610583565b3480156107b157600080fd5b506005546107cc90600160801b90046001600160601b031681565b6040516001600160601b039091168152602001610583565b3480156107f057600080fd5b5060055461060c90600160401b90046001600160401b031681565b34801561081757600080fd5b5061050f610826366004614ec1565b611888565b34801561083757600080fd5b506105ac610846366004614ede565b6118c1565b34801561085757600080fd5b5060405160008152602001610583565b34801561087357600080fd5b50610887610882366004614c5d565b6119eb565b60405161058396959493929190614f2d565b3480156108a557600080fd5b506105ac6108b4366004614c5d565b611ade565b3480156108c557600080fd5b506016546108df906201000090046001600160a01b031681565b6040516001600160a01b039091168152602001610583565b34801561090357600080fd5b5061050f610912366004614f81565b611b1a565b34801561092357600080fd5b50610576610932366004614bc1565b611b69565b34801561094357600080fd5b506108df610952366004614faf565b611c09565b34801561096357600080fd5b5061050f610972366004615004565b611cd8565b34801561098357600080fd5b5061050f610992366004614c5d565b611d05565b3480156109a357600080fd5b5061050f6109b236600461507a565b611d5b565b3480156109c357600080fd5b506105ac6109d2366004614c5d565b6120ad565b3480156109e357600080fd5b506106926109f2366004614dfb565b6120f7565b348015610a0357600080fd5b50610692610a12366004614c5d565b6122b1565b348015610a2357600080fd5b50601d546108df906001600160a01b031681565b348015610a4357600080fd5b506105ac610a52366004614c5d565b61232b565b348015610a6357600080fd5b5061050f610a72366004614c5d565b61239a565b348015610a8357600080fd5b5061050f6123c4565b348015610a9857600080fd5b50610acc610aa7366004614c5d565b601c6020526000908152604090205460ff81169061010090046001600160601b031682565b6040805192151583526001600160601b03909116602083015201610583565b348015610af757600080fd5b5061050f610b06366004615122565b6123db565b348015610b1757600080fd5b50610692610b26366004614c5d565b50601f5490565b348015610b3957600080fd5b5061050f612408565b348015610b4e57600080fd5b5061050f610b5d36600461513d565b61241c565b348015610b6e57600080fd5b50610887610b7d366004614c5d565b6125c7565b61050f610b903660046151b4565b61270e565b348015610ba157600080fd5b50600554610bb990600160e01b900463ffffffff1681565b60405163ffffffff9091168152602001610583565b348015610bda57600080fd5b506000546001600160a01b03166108df565b348015610bf857600080fd5b50610c0c610c07366004614c5d565b61273d565b604080516001600160a01b039485168152939092166020840152151590820152606001610583565b348015610c4057600080fd5b5061050f610c4f3660046151ff565b6127be565b348015610c6057600080fd5b50610692601e5481565b348015610c7657600080fd5b5061050f610c85366004614bc1565b61283a565b348015610c9657600080fd5b506108df610ca5366004614faf565b612847565b348015610cb657600080fd5b5060408051808201909152600681526545505341504960d01b6020820152610576565b348015610ce557600080fd5b5061050f610cf4366004615250565b6128fc565b348015610d0557600080fd5b5061050f610d14366004614da4565b61290f565b348015610d2557600080fd5b50610576610d34366004614da4565b61293d565b61050f610d47366004615272565b612969565b348015610d5857600080fd5b50610dd9610d6736600461531f565b601b60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0380851695600160a01b80870462ffffff1696600160b81b810463ffffffff1696600160d81b90910460ff169584821695929091046001600160601b0316939092911689565b604080516001600160a01b039a8b16815262ffffff90991660208a015263ffffffff90971696880196909652931515606087015291861660808601526001600160601b031660a085015260c084015260e08301529190911661010082015261012001610583565b348015610e4c57600080fd5b506105ac610e5b366004614da4565b612a26565b348015610e6c57600080fd5b5061050f610e7b366004614c5d565b612a3c565b348015610e8c57600080fd5b5061050f610e9b366004614e51565b612a71565b348015610eac57600080fd5b5061050f610ebb36600461533c565b612b6e565b348015610ecc57600080fd5b5060055460408051600160801b83046001600160601b03168152600160e01b90920463ffffffff16602083015201610583565b348015610f0b57600080fd5b50610692610f1a366004614bc1565b60186020526000908152604090205481565b61050f610f3a36600461536a565b612c3e565b348015610f4b57600080fd5b5061060c610f5a366004614c5d565b612d19565b348015610f6b57600080fd5b5061050f610f7a366004615428565b612d5c565b348015610f8b57600080fd5b5061069260025481565b348015610fa157600080fd5b5061050f610fb03660046154f8565b612e33565b348015610fc157600080fd5b5061069260015481565b348015610fd757600080fd5b5061050f610fe6366004615516565b612e9d565b348015610ff757600080fd5b5060055461060c906001600160401b031681565b34801561101757600080fd5b5061050f611026366004614bc1565b612f2d565b34801561103757600080fd5b5061050f611046366004615584565b612f3a565b34801561105757600080fd5b50610692601f5481565b34801561106d57600080fd5b5061050f61107c3660046155d7565b612fab565b34801561108d57600080fd5b5061050f61109c3660046154f8565b6130a7565b61050f6110af366004615681565b61310e565b3480156110c057600080fd5b506108876110cf366004614c5d565b613174565b3480156110e057600080fd5b506016546105ac90610100900460ff1681565b3480156110ff57600080fd5b5061060c61110e366004614c5d565b6001600160a01b03166000908152601960205260409020546001600160401b031690565b34801561113e57600080fd5b5061050f61114d366004614bc1565b61324f565b34801561115e57600080fd5b5061050f61116d366004614c5d565b6132cb565b34801561117e57600080fd5b5061050f61118d36600461569f565b613346565b34801561119e57600080fd5b5061050f6111ad366004614da4565b61338b565b3480156111be57600080fd5b506106926111cd366004614dfb565b613420565b3480156111de57600080fd5b5061050f6111ed3660046156f7565b61357e565b60026001600160a01b038216600090815260036020819052604090912054600160401b900460ff169081111561122a5761122a614f17565b03611275576001600160a01b0380821660009081526003602052604090208054600190910154611272928492600160501b8104821692909116906001600160401b03166135fe565b50565b60026001600160a01b03828116600090815260046020908152604080832054909316825260039081905291902054600160401b900460ff16908111156112bd576112bd614f17565b03611309576001600160a01b03818116600090815260046020908152604080832054841680845260039092529091206001810154905461127293859216906001600160401b03166135fe565b604051637115fdd360e01b815260040160405180910390fd5b61132b826113bd565b15611364576001600160a01b03808316600090815260036020526040812054611360928592600160501b909204169084613680565b5050565b61136d8261232b565b1561139a576001600160a01b03808316600090815260046020526040902054611360911683600184613680565b60405163163e0acf60e21b815260040160405180910390fd5b6112723382611322565b6001600160a01b038116600090815260036020526040812054600160401b900460ff16818160038111156113f3576113f3614f17565b14159392505050565b60006001600160a01b0384166114255760405163989992a560e01b815260040160405180910390fd5b33600061143184613716565b9050600080516020615d628339815191528160a001518260800151611456919061574d565b1461147457604051630eb911d560e01b815260040160405180910390fd5b856001600160a01b031681602001516001600160a01b0316036114aa57604051637c72ea1360e01b815260040160405180910390fd5b6016546000906114c8906201000090046001600160a01b03166137e5565b90506114d38161387d565b8160e001516001600160401b031660000361157957806001600160a01b0316600560009054906101000a90046001600160401b03166001600160401b031683600001516001600160401b03167f5a0f2eb6ae0aa35d6df4a692dcea08836a52a923522d010ac5241fce52a2180e8a8660200151876060015188604001518a8e8b60a001518c60c00151604051611570989796959493929190615760565b60405180910390a45b60008061158785898b6138f6565b915091508360e001516001600160401b03166000146115bc576115a8613919565b6115b784898b85858a89613945565b6115e7565b6115cb896000806000866139e9565b6115e7838a878b85600080516020615d62833981519152613a8c565b826001600160a01b0316636638439e8a866020015187606001518860400151338e8b60a001518c60c001518d60e001516040518a63ffffffff1660e01b815260040161163b999897969594939291906157cc565b600060405180830381600087803b15801561165557600080fd5b505af1158015611669573d6000803e3d6000fd5b5050604051632142170760e11b81523060048201526001600160a01b0386166024820152604481018b90523392506342842e0e9150606401600060405180830381600087803b1580156116bb57600080fd5b505af11580156116cf573d6000803e3d6000fd5b50630a85bd0160e11b9d9c50505050505050505050505050565b611360338383613b05565b6000601f54601e54611706919061584a565b905090565b611713613b6f565b601680549115156101000261ff0019909216919091179055565b60008061173a8585613bc9565b600081815260186020526040902054909150611757908490613c0f565b9150505b9392505050565b61176a613919565b600061177533612d19565b90506000806117858686896138f6565b600082815260176020526040812054929450909250600160401b9091046001600160a01b0316906117b68883613bc9565b60008581526017602052604081208054600160401b600160e01b031916600160401b6001600160a01b038e1602178155600201549192509061180690600080516020615d62833981519152615861565b905061181633848b8b8686613c7f565b611824338b8b8b8886613a8c565b896001600160a01b0316866001600160401b03168c6001600160401b03167f5dbf7557a2e3e90ad585a162df084f4b4e0c5b124740bf7821294703d0fe639c8a60405161187391815260200190565b60405180910390a45050505050505050505050565b611890613b6f565b600580546001600160601b03909216600160801b026bffffffffffffffffffffffff60801b19909216919091179055565b6001600160a01b038281166000908152600460209081526040808320549093168252600390819052918120549091600160401b90910460ff169081600381111561190d5761190d614f17565b148061192a5750600281600381111561192857611928614f17565b145b8061194e575082801561194e5750600181600381111561194c5761194c614f17565b145b1561195d5760009150506119e5565b506001600160a01b038316600090815260036020819052604090912054600160401b900460ff169081600381111561199757611997614f17565b14806119b4575060028160038111156119b2576119b2614f17565b145b806119d0575060018160038111156119ce576119ce614f17565b145b156119df5760009150506119e5565b60019150505b92915050565b6001600160a01b038181166000908152600460209081526040808320549093168083526003808352848420855160a0810190965280546001600160401b0381168752949586958695869586958695919486949093840191600160401b90910460ff1690811115611a5d57611a5d614f17565b6003811115611a6e57611a6e614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919b5094995093975095509350909150505b91939550919395565b6001600160a01b0381166000908152600360208190526040822054600160401b900460ff1681811115611b1357611b13614f17565b1492915050565b611b22613b6f565b6001600160a01b039091166000908152601c6020526040902080546001600160601b03909216610100026cffffffffffffffffffffffffff19909216919091176001179055565b60068160108110611b7957600080fd5b018054909150611b8890615874565b80601f0160208091040260200160405190810160405280929190818152602001828054611bb490615874565b8015611c015780601f10611bd657610100808354040283529160200191611c01565b820191906000526020600020905b815481529060010190602001808311611be457829003601f168201915b505050505081565b6000811580611c185750600f82115b15611c2257600191505b611c2d848484612847565b90506001600160a01b03811661175b576040516331a9108f60e11b8152600481018490526001600160a01b03851690636352211e90602401602060405180830381865afa158015611c82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca691906158ae565b9050611cb1816120ad565b1561175b576001600160a01b03908116600090815260046020526040902054169392505050565b611ce0613b6f565b8060068360108110611cf457611cf46158cb565b0190611d009082615927565b505050565b611d0d613b6f565b60165460ff1615611d3157604051632e6129eb60e11b815260040160405180910390fd5b601680546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001600160a01b03831615801590611d8c57506001600160a01b0383166000908152601c602052604090205460ff16155b15611daa57604051630eca12dd60e31b815260040160405180910390fd5b6001600560088282829054906101000a90046001600160401b0316611dcf91906159e6565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550604051806101200160405280336001600160a01b031681526020018962ffffff1681526020018863ffffffff1681526020018715158152602001866001600160a01b03168152602001856001600160601b03168152602001838152602001828152602001846001600160a01b0316815250601b6000600560089054906101000a90046001600160401b03166001600160401b03166001600160401b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548162ffffff021916908362ffffff16021790555060408201518160000160176101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601b6101000a81548160ff02191690831515021790555060808201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160010160146101000a8154816001600160601b0302191690836001600160601b0316021790555060c0820151816002015560e082015181600301556101008201518160040160006101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507fcfc9ed74ed2586915eb2ba885b6516120033d928b11ec45eb846af0700dabca489600560089054906101000a90046001600160401b03168789868d8d8b893360405161209a9a999897969594939291906001600160401b039a8b1681529890991660208901526001600160a01b0396871660408901529415156060880152608087019390935262ffffff9190911660a086015263ffffffff1660c08501526001600160601b031660e0840152610100830152919091166101208201526101400190565b60405180910390a1505050505050505050565b600060036001600160a01b03838116600090815260046020908152604080832054909316825260039081905291902054600160401b900460ff1690811115611b1357611b13614f17565b600061210284611ade565b1561222257604051627eeac760e11b81526001600160a01b0385811660048301526024820184905284169062fdd58e90604401602060405180830381865afa158015612152573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121769190615a0d565b612180908261574d565b6001600160a01b0385811660009081526003602052604090819020549051627eeac760e11b8152600160501b909104821660048201819052602482018690529293509085169062fdd58e906044015b602060405180830381865afa1580156121ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122109190615a0d565b61221a908361574d565b91505061175b565b61222b846120ad565b61175b57604051627eeac760e11b81526001600160a01b0385811660048301526024820184905284169062fdd58e906044015b602060405180830381865afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f9190615a0d565b6122a9908261574d565b949350505050565b60006122bc82611ade565b15612305576122d56001600160a01b038316318261574d565b6001600160a01b038084166000908152600360205260409020549192506119e591600160501b900416318261574d565b61230e826120ad565b612326576119e56001600160a01b038316318261574d565b919050565b6001600160a01b038181166000908152600460209081526040808320549093168252600390819052918120549091600160401b90910460ff169081600381111561237757612377614f17565b148061175b5750600281600381111561239257612392614f17565b149392505050565b6123a2613b6f565b601d80546001600160a01b0319166001600160a01b0392909216919091179055565b6123cc613b6f565b6016805460ff19166001179055565b6123e3613b6f565b6005805463ffffffff909216600160e01b026001600160e01b03909216919091179055565b612410613b6f565b61241a6000613cec565b565b6001600160401b0385166000908152601b60205260409020546001600160a01b0316331461245d5760405163471e5c3d60e11b815260040160405180910390fd5b62ffffff84161561249b576001600160401b0385166000908152601b60205260409020805462ffffff60a01b1916600160a01b62ffffff8716021790555b63ffffffff8316156124dc576001600160401b0385166000908152601b60205260409020805463ffffffff60b81b1916600160b81b63ffffffff8616021790555b6001600160601b03821615612525576001600160401b0385166000908152601b6020526040902060010180546001600160a01b0316600160a01b6001600160601b038516021790555b801561254a576001600160401b0385166000908152601b602052604090206003018190555b604080516001600160401b0380891682528716602082015262ffffff86169181019190915263ffffffff841660608201526001600160601b038316608082015260a081018290527f283ca86eb787b2e4eed53d42c177266ef3af5e5879ca7e291363d2eed932ee0e9060c0015b60405180910390a1505050505050565b6001600160a01b03818116600090815260046020908152604080832054909316825260039081905291812054909182918291829182918291600160401b900460ff169081600381111561261c5761261c614f17565b14806126395750600281600381111561263757612637614f17565b145b806126555750600181600381111561265357612653614f17565b145b1561267557612663886119eb565b96509650965096509650965050611ad5565b506001600160a01b038716600090815260036020819052604090912054600160401b900460ff16908160038111156126af576126af614f17565b14806126cc575060028160038111156126ca576126ca614f17565b145b806126e8575060018160038111156126e6576126e6614f17565b145b156126f65761266388613174565b50600097889750879650869550859450849350915050565b6001543414612730576040516333b18e6b60e11b815260040160405180910390fd5b611d003384843485613d3c565b600080600061274b846120ad565b156127695760405163125f0c1360e21b815260040160405180910390fd5b61277284611ade565b156127ad575050506001600160a01b0380821660009081526003602052604090208054600191820154600160501b90910483169216906127b7565b5082915081905060005b9193909250565b60006127c933612d19565b604080516001600160401b03808a1682528316602082015233918101919091526001600160a01b03871660608201526080810186905260a0810185905260c081018490529091507f64b5ca6749db1c615652096d273882ff7a1008ac9664f51568b14410b7a4f1a69060e0016125b7565b612842613b6f565b600155565b6000806128548585613f09565b600081815260176020908152604091829020825160a08101845281546001600160401b038082168084526001600160a01b03600160401b93849004811696850196909652600185015491821696840196909652049092166060830152600201546080820152919250156128f0576128cf848260800151613c0f565b6000036128e35760200151915061175b9050565b60600151915061175b9050565b50600095945050505050565b612904613b6f565b601e91909155601f55565b612917613b6f565b61136061292c6000546001600160a01b031690565b6001600160a01b0384169083613f32565b601a602052816000526040600020816010811061295957600080fd5b018054909250611b889150615874565b612971613919565b600061297c33612d19565b9050600080600061298f8b8b8b8b613f84565b9250925092506129a183888a89613fdf565b6129af338a8d8d868b613c7f565b6129bd33898d8d858b613a8c565b836001600160401b03168c6001600160401b03167f874a0ec379dec4a6469317f6b2eb8bcb7381c2e0074e09ba06e85ef2dcb2ce4b338e8e8e8e8e8e348f604051612a1099989796959493929190615a26565b60405180910390a3505050505050505050505050565b6000612a3333848461402d565b50600192915050565b612a44613b6f565b6001600160a01b03166000908152601c6020526040902080546cffffffffffffffffffffffffff19169055565b612a79613919565b6000612a8433612d19565b9050600080612a948686896138f6565b600082815260176020526040812060010154929450909250600160401b9091046001600160a01b031690612ac88883613bc9565b6000858152601760205260409020600181018054600160401b600160e01b031916600160401b6001600160a01b038e160217905560020154909150612b1133848b8b8686613c7f565b612b1f338b8b8b8886613a8c565b896001600160a01b0316866001600160401b03168c6001600160401b03167f140155fa1de4908485153ff90dc3ed5358f6cf7d8c89166509c6a6ae2a850ca28a60405161187391815260200190565b6001600160401b0381166000908152601b60205260409020546001600160a01b03163314612baf5760405163471e5c3d60e11b815260040160405180910390fd5b6001600160401b038181166000818152601b6020908152604080832080546001600160e01b031916815560018101849055600281018490556003810193909355600490920180546001600160a01b0319169055815193861684528301919091527fce37e681b0772d563a915fa6cbf7fde2d8a8889e12015eb50beb269910bcd011910160405180910390a15050565b612c46613919565b6000612c5133612d19565b9050600080612c6485338e8e88886140ee565b91509150612c713361387d565b612d0a6040518061010001604052808f6001600160401b031681526020018c6001600160a01b031681526020018b62ffffff1681526020018a6001600160601b0316815260200189600080516020615d62833981519152612cd29190615861565b8152602001898152602001604051806020016040528060008152508152602001886001600160401b0316815250858e85858a33613945565b50505050505050505050505050565b6001600160a01b0381166000908152601960205260408120546001600160401b03169081900361232657604051630ce1b58d60e21b815260040160405180910390fd5b6000612d6733612d19565b9050600080612d7a87338e8e8a886140ee565b91509150612d873361387d565b612d9082614182565b612dac338d898985600080516020615d62833981519152613a8c565b336001600160a01b0316600560009054906101000a90046001600160401b03166001600160401b03168e6001600160401b03167f5a0f2eb6ae0aa35d6df4a692dcea08836a52a923522d010ac5241fce52a2180e8f8e8e8e8e8e8e8e604051612e1c989796959493929190615760565b60405180910390a450505050505050505050505050565b6000612e3e33612d19565b604080516001600160401b038087168252831660208201526001600160601b038516918101919091529091507f8aadc94565cd0449ff6a891861dce3989ecfbd4c25311ed3926eac0d5d53aba4906060015b60405180910390a1505050565b6000612ea833612d19565b604080516001600160401b038b81168252831660208201526001600160a01b038a811682840152891660608201526080810188905260a0810187905260c0810186905260e0810185905290519192507f09f2adc90b22f76ff47f53431a42a7a5e0bcc5867d0ebaedce6ce5d5d7f5d74791908190036101000190a15050505050505050565b612f35613b6f565b600255565b6000612f4533612d19565b90506000612f578633868689876140ee565b50600090815260176020908152604080832080546001600160e01b03199081168255600182018054909116905560020183905533835260199091529020805467ffffffffffffffff19169055505050505050565b612fb3613919565b6000612fbe33612d19565b9050600080612fce85858d6138f6565b91509150612fee338c878785600080516020615d62833981519152613c7f565b612ff783614190565b6130003361387d565b6130996040518061010001604052808e6001600160401b031681526020018c6001600160a01b031681526020018b62ffffff1681526020018a6001600160601b0316815260200189600080516020615d628339815191526130619190615861565b8152602001898152602001604051806020016040528060008152508152602001886001600160401b0316815250858d85858a33613945565b505050505050505050505050565b60006130b233612d19565b604080516001600160401b0380871682528316602082015233918101919091526001600160601b03841660608201529091507fdf35dff92be2e5e7dae645fb3e7a3d43e9487ecbbfd323bfef15c43ad2de58a590608001612e90565b61311882336141c7565b6001600160a01b038216600090815260036020526040902054600160481b900460ff1615801561314a57506001543414155b1561316857604051632740b97160e11b815260040160405180910390fd5b61136082333484614276565b6001600160a01b0381166000908152600360208181526040808420815160a0810190925280546001600160401b03811683528594859485948594859485949293919291840191600160401b90910460ff16908111156131d5576131d5614f17565b60038111156131e6576131e6614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919c909a5091985091965090945092505050565b613257613b6f565b601d546040516000916001600160a01b03169083908381818185875af1925050503d80600081146132a4576040519150601f19603f3d011682016040523d82523d6000602084013e6132a9565b606091505b50509050806113605760405163e53e5bcd60e01b815260040160405180910390fd5b6132d3613b6f565b6001600160a01b03811661333d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61127281613cec565b61334e613b6f565b6001600160a01b0383166000908152601a6020526040902081908360108110613379576133796158cb565b01906133859082615927565b50505050565b613393613b6f565b816001600160a01b03166323b872dd306133b56000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101849052606401600060405180830381600087803b15801561340457600080fd5b505af1158015613418573d6000803e3d6000fd5b505050505050565b6001600160a01b0383166000908152601960205260408120546001600160401b03161561344f5750600061175b565b81158061345c5750600f82115b1561346657600191505b61347183858461172d565b905061347c84611ade565b15613543576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa1580156134c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134eb9190615a0d565b6134f5908261574d565b6001600160a01b03858116600090815260036020526040908190205490516370a0823160e01b8152600160501b909104821660048201819052929350908516906370a08231906024016121cf565b61354c846120ad565b61175b576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a082319060240161225e565b6001600160a01b0382166135a55760405163bd78145160e01b815260040160405180910390fd5b826001600160a01b0316826001600160a01b0316036135d7576040516304da706760e51b815260040160405180910390fd5b6001600160a01b038116611d0057604051634ca5048960e01b815260040160405180910390fd5b6001600160a01b03848116600081815260036020908152604091829020805469ffff000000000000000019166901030000000000000000179055905185841681526001600160401b03851693871692917f5717bcaec46242edc8fb07322221c02d6dd3de7a954d5c009ee550cd0cdf768591015b60405180910390a450505050565b6001600160a01b03808516600081815260036020908152604080832080546001600160f01b031916815560010180546001600160a01b03199081169091559488168084526004909252918290208054909416909355519091907fbd302a9bf683315c275f4a7f0092796d97d17fbb2a89bbc8938bd6842c38eb89906137089086908690615a98565b60405180910390a350505050565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e0810191909152600080600080600080600080898060200190518101906137769190615ac1565b60408051610100810182526001600160401b03998a1681526001600160a01b03909816602089015262ffffff909616958701959095526001600160601b039093166060860152608085019190915260a084015260c08301529190911660e08201529a9950505050505050505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b0381166123265760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606401613334565b600580546001919060009061389c9084906001600160401b03166159e6565b82546001600160401b039182166101009390930a9283029282021916919091179091556005546001600160a01b039093166000908152601960205260409020805467ffffffffffffffff1916939091169290921790915550565b6000806139038585613f09565b915061390f8584613bc9565b9050935093915050565b601654610100900460ff161561241a576040516001621dce6960e31b0319815260040160405180910390fd5b6139518787878561439b565b61398785886040015162ffffff166201518061396d9190615bac565b61397790426159e6565b89602001518a60a00151886139e9565b6139b281868489878c60a00151600080516020615d628339815191526139ad9190615861565b613a8c565b60208701516139d390829084896139c98284613bc9565b8c60a00151613a8c565b6139e0878284898961482e565b50505050505050565b6040805160a0810182526005546001600160401b0390811682526001600160a01b039788166020808401918252978216838501908152968916606084019081526080840196875260009586526017909852929093209051815492519084166001600160e01b031993841617600160401b91891682021782559451600182018054975191909416969092169590951795169092029390931790559051600290910155565b60008281526018602052604081208054839290613aaa90849061574d565b909155505060408051848152602081018390526001600160a01b038087169288821692918a16917fa1c0f6bb9ba071b3dfd066f852f622c51d4073a7cc058fd04296ae916b8b0bc691015b60405180910390a4505050505050565b6001600160a01b038216613b2c576040516334b1be0d60e21b815260040160405180910390fd5b613b35836113bd565b15613b4557611d008383836148c7565b613b4e8361232b565b1561139a5760405160016208d37d60e21b0319815260040160405180910390fd5b6000546001600160a01b0316331461241a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401613334565b6040516001600160601b0319606084811b8216602084015283901b1660348201526000906048015b60405160208183030381529060405280519060200120905092915050565b600080613c1d60058561584a565b613c2890600a615cbb565b9050600084600103613c3c57506001613c61565b6005613c49600187615861565b613c53919061584a565b613c5e90600a615cbb565b90505b80613c6c8386615cdd565b613c769190615cf1565b95945050505050565b60008281526018602052604081208054839290613c9d908490615861565b909155505060408051848152602081018390526001600160a01b038087169289821692918916917fa1c0f6bb9ba071b3dfd066f852f622c51d4073a7cc058fd04296ae916b8b0bc69101613af5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b613d4785858561357e565b613d528560016118c1565b1580613d665750613d648460006118c1565b155b15613d84576040516307facddb60e11b815260040160405180910390fd5b6040805160a0810182526001600160401b0383811682526001602080840182815291548714848601526001600160a01b03898116606086015288811660808601528a1660009081526003918290529490942083518154931667ffffffffffffffff1984168117825591519394909392849268ffffffffffffffffff199091161790600160401b908490811115613e1c57613e1c614f17565b0217905550604082810151825460608501517fffff000000000000000000000000000000000000000000ffffffffffffffffff909116600160481b921515929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff1691909117600160501b6001600160a01b0392831602178355608090930151600190920180546001600160a01b03191692841692909217909155805185831681526001600160401b0384166020820152868316928816917f752c94da010e5b94c0278334398a684d4a7bde91f0f38c9dbb1766ad4f586c6991015b60405180910390a35050505050565b6040516001600160601b0319606084901b16602082015260348101829052600090605401613bf1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d009084906149db565b6000806000613f948787876138f6565b6040516001600160601b031960608b811b8216602084015288901b16603482015291945092506048016040516020818303038152906040528051906020012090509450945094915050565b6000938452601760205260409093206001810180546001600160a01b03909316600160401b026001600160e01b03199093166001600160401b03909416939093179190911790915560020155565b600061403a600a83615cdd565b90508015806140495750600481115b1561406757604051631ec9ca4160e21b815260040160405180910390fd5b6000614074600a84615cf1565b9050600182036140915761408c858587600085613d3c565b6140e7565b600282036140b0576140a384866141c7565b61408c8486600084614276565b600382036140cc5761408c8585836001600160401b0316613b05565b600482036140e7576140e785826001600160401b0316611322565b5050505050565b60008060008060006141028b888b8b613f84565b9250925092506141458a8a8d8a86601760008a815260200190815260200160002060020154600080516020615d628339815191526141409190615861565b613c7f565b6141698a898d8a85601760008a815260200190815260200160002060020154613c7f565b61417286614190565b5090999098509650505050505050565b611272816000806000613fdf565b6040516001600160401b038216907ff4a42f4ac762c05af0cbe21a8c16a2a87cd93719bbcfae68dce6a1b7f353a16c90600090a250565b6001600160a01b03828116600090815260036020526040902054600160501b90048116908216141580614230575060016001600160a01b038316600090815260036020819052604090912054600160401b900460ff169081111561422d5761422d614f17565b14155b1561424e57604051634cd87fb560e01b815260040160405180910390fd5b6142598160006118c1565b611360576040516307facddb60e11b815260040160405180910390fd5b6001600160a01b03838116600081815260046020908152604080832080546001600160a01b0319168a87169081179091558084526003835292819020600101549051941684526001600160401b038516937fda23dc0f47967fd81e9b62f5207a955b77295fef190364f10a6c3cf26773c1ab910160405180910390a46001600160a01b038416600090815260036020526040902054600160481b900460ff1680614321575060015482145b15614364576001600160a01b0380851660009081526003602052604090206001810154905461435f92879287929116906001600160401b03166135fe565b613385565b5050506001600160a01b03166000908152600360205260409020805468ff0000000000000000191668020000000000000000179055565b60e0848101516001600160401b03166000908152601b602090815260409182902082516101208101845281546001600160a01b038082168352600160a01b80830462ffffff1695840195909552600160b81b820463ffffffff1695830195909552600160d81b900460ff16151560608201526001820154808516608083018190529390046001600160601b031660a0820152600282015460c0820152600382015494810194909452600401548216610100840152908316141580614470575080606001511580156144705750838160c0015114155b80614495575080600001516001600160a01b031685602001516001600160a01b031614155b806144b25750806020015162ffffff16856040015162ffffff1614155b806144d757508060a001516001600160601b031685606001516001600160601b031614155b806144ea57508060e001518560a0015114155b806144fe5750806040015163ffffffff1642115b1561451c57604051631771cc0160e11b815260040160405180910390fd5b61010081015160009081906001600160a01b03166145705750506005547f000000000000000000000000000000000000000000000000000000000000000090600160801b90046001600160601b03166145db565b6101008301516001600160a01b0381166000908152601c602052604090205490925060ff166145b257604051630eca12dd60e31b815260040160405180910390fd5b506001600160a01b0381166000908152601c602052604090205461010090046001600160601b03165b60e08701516001600160401b03166000908152601b6020526040812080546001600160e01b031916815560018101829055600281018290556003810182905560040180546001600160a01b031916905560608801516146449083906001600160601b031661574d565b905080156146cd5760208801516040516323b872dd60e01b81526001600160a01b03918216600482015230602482015260448101839052908416906323b872dd906064016020604051808303816000875af11580156146a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146cb9190615d05565b505b600088606001516001600160601b03166000036146eb575081614731565b60055460608a01518491620186a09161471191600160e01b900463ffffffff1690615d22565b6001600160601b03166147249190615cf1565b61472e919061574d565b90505b60608901516001600160601b0316156147cf576001600160a01b03841663a9059cbb8861475e8486615861565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156147a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147cd9190615d05565b505b885160e08a0151604080516001600160401b03938416815292909116602083015281018290526001600160a01b03851660608201527f848da897c5a8478af17be9c5fb6ebd38774ff21fc83fdc1a19216edb8dc1eb029060800161209a565b600560009054906101000a90046001600160401b03166001600160401b031685600001516001600160401b03167f874a0ec379dec4a6469317f6b2eb8bcb7381c2e0074e09ba06e85ef2dcb2ce4b868686868b602001518c6040015162ffffff166201518061489d9190615bac565b6148a790426159e6565b60a08e015160c08f0151604051613efa9897969594939291600091615a26565b6001600160a01b0383166000908152600360208181526040808420815160a0810190925280546001600160401b038116835291939092840191600160401b900460ff169081111561491a5761491a614f17565b600381111561492b5761492b614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b03908116604080850191909152600194850154821660609485015289821660008181526003855282902090950180546001600160a01b0319168a84169081179091559386015160808701518251908416815293840189905295965092941692917fa0aa3b38771c7ab4ece55c6009c41d814f4ff862285d0825c24528a87fd124d79101613672565b6000614a30826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614aad9092919063ffffffff16565b805190915015611d005780806020019051810190614a4e9190615d05565b611d005760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401613334565b60606122a98484600085856001600160a01b0385163b614b0f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401613334565b600080866001600160a01b03168587604051614b2b9190615d45565b60006040518083038185875af1925050503d8060008114614b68576040519150601f19603f3d011682016040523d82523d6000602084013e614b6d565b606091505b5091509150614b7d828286614b88565b979650505050505050565b60608315614b9757508161175b565b825115614ba75782518084602001fd5b8160405162461bcd60e51b81526004016133349190614c2a565b600060208284031215614bd357600080fd5b5035919050565b60005b83811015614bf5578181015183820152602001614bdd565b50506000910152565b60008151808452614c16816020860160208601614bda565b601f01601f19169290920160200192915050565b60208152600061175b6020830184614bfe565b6001600160a01b038116811461127257600080fd5b803561232681614c3d565b600060208284031215614c6f57600080fd5b813561175b81614c3d565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614cb857614cb8614c7a565b604052919050565b60006001600160401b03821115614cd957614cd9614c7a565b50601f01601f191660200190565b6000614cfa614cf584614cc0565b614c90565b9050828152838383011115614d0e57600080fd5b828260208301376000602084830101529392505050565b60008060008060808587031215614d3b57600080fd5b8435614d4681614c3d565b93506020850135614d5681614c3d565b92506040850135915060608501356001600160401b03811115614d7857600080fd5b8501601f81018713614d8957600080fd5b614d9887823560208401614ce7565b91505092959194509250565b60008060408385031215614db757600080fd5b8235614dc281614c3d565b946020939093013593505050565b801515811461127257600080fd5b600060208284031215614df057600080fd5b813561175b81614dd0565b600080600060608486031215614e1057600080fd5b8335614e1b81614c3d565b92506020840135614e2b81614c3d565b929592945050506040919091013590565b6001600160401b038116811461127257600080fd5b600080600080600060a08688031215614e6957600080fd5b8535614e7481614e3c565b94506020860135614e8481614c3d565b93506040860135614e9481614c3d565b94979396509394606081013594506080013592915050565b6001600160601b038116811461127257600080fd5b600060208284031215614ed357600080fd5b813561175b81614eac565b60008060408385031215614ef157600080fd5b8235614efc81614c3d565b91506020830135614f0c81614dd0565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60c0810160048810614f4157614f41614f17565b9681526001600160a01b03958616602082015293851660408501529190931660608301526001600160401b03909216608082015290151560a09091015290565b60008060408385031215614f9457600080fd5b8235614f9f81614c3d565b91506020830135614f0c81614eac565b600080600060608486031215614fc457600080fd5b8335614fcf81614c3d565b95602085013595506040909401359392505050565b600082601f830112614ff557600080fd5b61175b83833560208501614ce7565b6000806040838503121561501757600080fd5b8235915060208301356001600160401b0381111561503457600080fd5b61504085828601614fe4565b9150509250929050565b62ffffff8116811461127257600080fd5b80356123268161504a565b803563ffffffff8116811461232657600080fd5b60008060008060008060008060006101208a8c03121561509957600080fd5b89356150a481614e3c565b985060208a01356150b48161504a565b97506150c260408b01615066565b965060608a01356150d281614dd0565b955060808a01356150e281614c3d565b945060a08a01356150f281614eac565b935060c08a013561510281614c3d565b8093505060e08a013591506101008a013590509295985092959850929598565b60006020828403121561513457600080fd5b61175b82615066565b60008060008060008060c0878903121561515657600080fd5b863561516181614e3c565b9550602087013561517181614e3c565b945060408701356151818161504a565b935061518f60608801615066565b9250608087013561519f81614eac565b8092505060a087013590509295509295509295565b6000806000606084860312156151c957600080fd5b83356151d481614c3d565b925060208401356151e481614c3d565b915060408401356151f481614e3c565b809150509250925092565b600080600080600060a0868803121561521757600080fd5b853561522281614e3c565b9450602086013561523281614c3d565b94979496505050506040830135926060810135926080909101359150565b6000806040838503121561526357600080fd5b50508035926020909101359150565b600080600080600080600080610100898b03121561528f57600080fd5b883561529a81614e3c565b975060208901356152aa81614c3d565b96506040890135955060608901356152c181614c3d565b945060808901356152d181614c3d565b935060a08901356152e181614e3c565b925060c0890135915060e08901356001600160401b0381111561530357600080fd5b61530f8b828c01614fe4565b9150509295985092959890939650565b60006020828403121561533157600080fd5b813561175b81614e3c565b6000806040838503121561534f57600080fd5b823561535a81614e3c565b91506020830135614f0c81614e3c565b6000806000806000806000806000806101408b8d03121561538a57600080fd5b8a3561539581614e3c565b995060208b01356153a581614c3d565b985060408b01356153b581614c3d565b975060608b01356153c581614c3d565b965060808b01356153d58161504a565b955060a08b01356153e581614eac565b945060c08b0135935060e08b01356153fc81614e3c565b92506101008b013561540d81614c3d565b809250506101208b013590509295989b9194979a5092959850565b6000806000806000806000806000806101408b8d03121561544857600080fd5b8a3561545381614e3c565b995060208b013561546381614c3d565b985060408b013561547381614c3d565b975060608b013561548381614c3d565b965060808b013561549381614eac565b95506154a160a08c0161505b565b94506154af60c08c01614c52565b935060e08b013592506101008b013591506101208b01356001600160401b038111156154da57600080fd5b6154e68d828e01614fe4565b9150509295989b9194979a5092959850565b6000806040838503121561550b57600080fd5b8235614f9f81614e3c565b600080600080600080600060e0888a03121561553157600080fd5b873561553c81614e3c565b9650602088013561554c81614c3d565b9550604088013561555c81614c3d565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806000806080858703121561559a57600080fd5b84356155a581614c3d565b93506020850135925060408501356155bc81614c3d565b915060608501356155cc81614c3d565b939692955090935050565b60008060008060008060008060006101208a8c0312156155f657600080fd5b893561560181614e3c565b985060208a013561561181614c3d565b975060408a013561562181614c3d565b965060608a01356156318161504a565b955060808a013561564181614eac565b945060a08a0135935060c08a013561565881614e3c565b925060e08a013561566881614c3d565b809250506101008a013590509295985092959850929598565b6000806040838503121561569457600080fd5b823561535a81614c3d565b6000806000606084860312156156b457600080fd5b83356156bf81614c3d565b92506020840135915060408401356001600160401b038111156156e157600080fd5b6156ed86828701614fe4565b9150509250925092565b60008060006060848603121561570c57600080fd5b833561571781614c3d565b9250602084013561572781614c3d565b915060408401356151f481614c3d565b634e487b7160e01b600052601160045260246000fd5b808201808211156119e5576119e5615737565b6001600160a01b03898116825288811660208301526001600160601b038816604083015262ffffff871660608301528516608082015260a0810184905260c0810183905261010060e082018190526000906157bd83820185614bfe565b9b9a5050505050505050505050565b6001600160a01b038a8116825289811660208301526001600160601b038916604083015262ffffff881660608301528616608082015260a0810185905260c0810184905261012060e0820181905260009061582983820186614bfe565b9150506001600160401b0383166101008301529a9950505050505050505050565b80820281158282048414176119e5576119e5615737565b818103818111156119e5576119e5615737565b600181811c9082168061588857607f821691505b6020821081036158a857634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156158c057600080fd5b815161175b81614c3d565b634e487b7160e01b600052603260045260246000fd5b601f821115611d0057600081815260208120601f850160051c810160208610156159085750805b601f850160051c820191505b8181101561341857828155600101615914565b81516001600160401b0381111561594057615940614c7a565b6159548161594e8454615874565b846158e1565b602080601f83116001811461598957600084156159715750858301515b600019600386901b1c1916600185901b178555613418565b600085815260208120601f198616915b828110156159b857888601518255948401946001909101908401615999565b50858210156159d65787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160401b03818116838216019080821115615a0657615a06615737565b5092915050565b600060208284031215615a1f57600080fd5b5051919050565b6001600160a01b038a811682528981166020830152604082018990528781166060830152861660808201526001600160401b03851660a082015260c0810184905260e081018390526101206101008201819052600090615a8883820185614bfe565b9c9b505050505050505050505050565b6040810160028410615aac57615aac614f17565b9281526020015290565b805161232681614e3c565b600080600080600080600080610100898b031215615ade57600080fd5b8851615ae981614e3c565b60208a0151909850615afa81614c3d565b60408a0151909750615b0b8161504a565b60608a0151909650615b1c81614eac565b809550506080890151935060a0890151925060c08901516001600160401b03811115615b4757600080fd5b8901601f81018b13615b5857600080fd5b8051615b66614cf582614cc0565b8181528c6020838501011115615b7b57600080fd5b615b8c826020830160208601614bda565b9350615b9d91505060e08a01615ab6565b90509295985092959890939650565b6001600160401b03818116838216028082169190828114615bcf57615bcf615737565b505092915050565b600181815b80851115615c12578160001904821115615bf857615bf8615737565b80851615615c0557918102915b93841c9390800290615bdc565b509250929050565b600082615c29575060016119e5565b81615c36575060006119e5565b8160018114615c4c5760028114615c5657615c72565b60019150506119e5565b60ff841115615c6757615c67615737565b50506001821b6119e5565b5060208310610133831016604e8410600b8410161715615c95575081810a6119e5565b615c9f8383615bd7565b8060001904821115615cb357615cb3615737565b029392505050565b600061175b8383615c1a565b634e487b7160e01b600052601260045260246000fd5b600082615cec57615cec615cc7565b500690565b600082615d0057615d00615cc7565b500490565b600060208284031215615d1757600080fd5b815161175b81614dd0565b6001600160601b03818116838216028082169190828114615bcf57615bcf615737565b60008251615d57818460208701614bda565b919091019291505056fe00000172eca084a2dfd7bef9ff78b9eed31c81789db8f74134d76bc8e5e3eaa1a2646970667358221220f1fb24f530623c085a1848e4eb0747caac6bcda1a16bcf475a7e65a4c50792d864736f6c63430008110033000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028b224a23a6c66e4b496fef0e544ccf7bf1f9b96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000002540be400

Deployed Bytecode

0x60806040526004361061048d5760003560e01c80638da5cb5b11610255578063c1f5c49a11610144578063dd2ebdb4116100c1578063f14210a611610085578063f14210a614611132578063f2fde38b14611152578063f3362fb914611172578063f3e414f814611192578063f8907b60146111b2578063fc2bc7b2146111d257600080fd5b8063dd2ebdb414611081578063e575d025146110a1578063e963134f146110b4578063ec8b9071146110d4578063f023a734146110f357600080fd5b8063cf135b9d11610108578063cf135b9d14610feb578063d1d3e28f1461100b578063d5472c181461102b578063d56bb0571461104b578063db7840cb1461106157600080fd5b8063c1f5c49a14610f5f578063c2f5dc4414610f7f578063c858380814610f95578063c93b228914610fb5578063ce46756914610fcb57600080fd5b8063a2966f5f116101d2578063b2969acf11610196578063b2969acf14610ea0578063b810c63614610ec0578063b9f97d4114610eff578063bd17532414610f2c578063c124eb1f14610f3f57600080fd5b8063a2966f5f14610d39578063a4c1408414610d4c578063a9059cbb14610e40578063ae7044c214610e60578063afb85e6214610e8057600080fd5b806393a1d1aa1161021957806393a1d1aa14610c8a57806395d89b4114610caa578063a0a3660614610cd9578063a1db978214610cf9578063a276c41514610d1957600080fd5b80638da5cb5b14610bce578063906f634314610bec57806390938e9514610c34578063913965c314610c5457806392be2ab814610c6a57600080fd5b806341e3196f1161037c578063657f9233116102f957806370a08231116102bd57806370a0823114610b0b578063715018a614610b2d5780637a3be00d14610b425780637afbd21214610b625780638523837014610b8257806388d6f15114610b9557600080fd5b8063657f923314610a375780636605bfda14610a575780636bcf608814610a775780636e22bad914610a8c5780636f1dcc3b14610aeb57600080fd5b80635205cb5b116103405780635205cb5b1461099757806353556440146109b757806357b14d9e146109d75780635ba58955146109f757806361d027b314610a1757600080fd5b806341e3196f146108f757806342b046901461091757806342de52551461093757806345065089146109575780634835de371461097757600080fd5b80631fc784101161040a578063274971b3116103ce578063274971b31461082b578063313ce5671461084b57806333ac8aa8146108675780633a0236e3146108995780633a30d464146108b957600080fd5b80631fc78410146106e0578063214cf7ad1461070057806321a0bd9e146107a557806321ce9f91146107e4578063265d97ee1461080b57600080fd5b8063150b7a0211610451578063150b7a02146106245780631718e0cf1461065d57806318160ddd1461067d5780631888f727146106a057806318976a24146106c057600080fd5b8063061f98111461052a57806306fdde031461054a5780630956d8a71461058c5780630ec735da146105bc57806314977eb8146105d657600080fd5b366105255760015434141580156104a657506002543414155b80156104c85750336000908152601960205260409020546001600160401b0316155b80156104df57506000546001600160a01b03163314155b156104fd5760405163020ad41b60e11b815260040160405180910390fd5b60015434036105115761050f336111f2565b005b600254340361050f5761050f336000611322565b600080fd5b34801561053657600080fd5b5061050f610545366004614bc1565b6113b3565b34801561055657600080fd5b506040805180820190915260078152664550532041504960c81b60208201525b6040516105839190614c2a565b60405180910390f35b34801561059857600080fd5b506105ac6105a7366004614c5d565b6113bd565b6040519015158152602001610583565b3480156105c857600080fd5b506016546105ac9060ff1681565b3480156105e257600080fd5b5061060c6105f1366004614c5d565b6019602052600090815260409020546001600160401b031681565b6040516001600160401b039091168152602001610583565b34801561063057600080fd5b5061064461063f366004614d25565b6113fc565b6040516001600160e01b03199091168152602001610583565b34801561066957600080fd5b5061050f610678366004614da4565b6116e9565b34801561068957600080fd5b506106926116f4565b604051908152602001610583565b3480156106ac57600080fd5b5061050f6106bb366004614dde565b61170b565b3480156106cc57600080fd5b506106926106db366004614dfb565b61172d565b3480156106ec57600080fd5b5061050f6106fb366004614e51565b611762565b34801561070c57600080fd5b5061076361071b366004614bc1565b6017602052600090815260409020805460018201546002909201546001600160401b03808316936001600160a01b03600160401b948590048116949282169392909104169085565b604080516001600160401b0396871681526001600160a01b0395861660208201529590931692850192909252919091166060830152608082015260a001610583565b3480156107b157600080fd5b506005546107cc90600160801b90046001600160601b031681565b6040516001600160601b039091168152602001610583565b3480156107f057600080fd5b5060055461060c90600160401b90046001600160401b031681565b34801561081757600080fd5b5061050f610826366004614ec1565b611888565b34801561083757600080fd5b506105ac610846366004614ede565b6118c1565b34801561085757600080fd5b5060405160008152602001610583565b34801561087357600080fd5b50610887610882366004614c5d565b6119eb565b60405161058396959493929190614f2d565b3480156108a557600080fd5b506105ac6108b4366004614c5d565b611ade565b3480156108c557600080fd5b506016546108df906201000090046001600160a01b031681565b6040516001600160a01b039091168152602001610583565b34801561090357600080fd5b5061050f610912366004614f81565b611b1a565b34801561092357600080fd5b50610576610932366004614bc1565b611b69565b34801561094357600080fd5b506108df610952366004614faf565b611c09565b34801561096357600080fd5b5061050f610972366004615004565b611cd8565b34801561098357600080fd5b5061050f610992366004614c5d565b611d05565b3480156109a357600080fd5b5061050f6109b236600461507a565b611d5b565b3480156109c357600080fd5b506105ac6109d2366004614c5d565b6120ad565b3480156109e357600080fd5b506106926109f2366004614dfb565b6120f7565b348015610a0357600080fd5b50610692610a12366004614c5d565b6122b1565b348015610a2357600080fd5b50601d546108df906001600160a01b031681565b348015610a4357600080fd5b506105ac610a52366004614c5d565b61232b565b348015610a6357600080fd5b5061050f610a72366004614c5d565b61239a565b348015610a8357600080fd5b5061050f6123c4565b348015610a9857600080fd5b50610acc610aa7366004614c5d565b601c6020526000908152604090205460ff81169061010090046001600160601b031682565b6040805192151583526001600160601b03909116602083015201610583565b348015610af757600080fd5b5061050f610b06366004615122565b6123db565b348015610b1757600080fd5b50610692610b26366004614c5d565b50601f5490565b348015610b3957600080fd5b5061050f612408565b348015610b4e57600080fd5b5061050f610b5d36600461513d565b61241c565b348015610b6e57600080fd5b50610887610b7d366004614c5d565b6125c7565b61050f610b903660046151b4565b61270e565b348015610ba157600080fd5b50600554610bb990600160e01b900463ffffffff1681565b60405163ffffffff9091168152602001610583565b348015610bda57600080fd5b506000546001600160a01b03166108df565b348015610bf857600080fd5b50610c0c610c07366004614c5d565b61273d565b604080516001600160a01b039485168152939092166020840152151590820152606001610583565b348015610c4057600080fd5b5061050f610c4f3660046151ff565b6127be565b348015610c6057600080fd5b50610692601e5481565b348015610c7657600080fd5b5061050f610c85366004614bc1565b61283a565b348015610c9657600080fd5b506108df610ca5366004614faf565b612847565b348015610cb657600080fd5b5060408051808201909152600681526545505341504960d01b6020820152610576565b348015610ce557600080fd5b5061050f610cf4366004615250565b6128fc565b348015610d0557600080fd5b5061050f610d14366004614da4565b61290f565b348015610d2557600080fd5b50610576610d34366004614da4565b61293d565b61050f610d47366004615272565b612969565b348015610d5857600080fd5b50610dd9610d6736600461531f565b601b60205260009081526040902080546001820154600283015460038401546004909401546001600160a01b0380851695600160a01b80870462ffffff1696600160b81b810463ffffffff1696600160d81b90910460ff169584821695929091046001600160601b0316939092911689565b604080516001600160a01b039a8b16815262ffffff90991660208a015263ffffffff90971696880196909652931515606087015291861660808601526001600160601b031660a085015260c084015260e08301529190911661010082015261012001610583565b348015610e4c57600080fd5b506105ac610e5b366004614da4565b612a26565b348015610e6c57600080fd5b5061050f610e7b366004614c5d565b612a3c565b348015610e8c57600080fd5b5061050f610e9b366004614e51565b612a71565b348015610eac57600080fd5b5061050f610ebb36600461533c565b612b6e565b348015610ecc57600080fd5b5060055460408051600160801b83046001600160601b03168152600160e01b90920463ffffffff16602083015201610583565b348015610f0b57600080fd5b50610692610f1a366004614bc1565b60186020526000908152604090205481565b61050f610f3a36600461536a565b612c3e565b348015610f4b57600080fd5b5061060c610f5a366004614c5d565b612d19565b348015610f6b57600080fd5b5061050f610f7a366004615428565b612d5c565b348015610f8b57600080fd5b5061069260025481565b348015610fa157600080fd5b5061050f610fb03660046154f8565b612e33565b348015610fc157600080fd5b5061069260015481565b348015610fd757600080fd5b5061050f610fe6366004615516565b612e9d565b348015610ff757600080fd5b5060055461060c906001600160401b031681565b34801561101757600080fd5b5061050f611026366004614bc1565b612f2d565b34801561103757600080fd5b5061050f611046366004615584565b612f3a565b34801561105757600080fd5b50610692601f5481565b34801561106d57600080fd5b5061050f61107c3660046155d7565b612fab565b34801561108d57600080fd5b5061050f61109c3660046154f8565b6130a7565b61050f6110af366004615681565b61310e565b3480156110c057600080fd5b506108876110cf366004614c5d565b613174565b3480156110e057600080fd5b506016546105ac90610100900460ff1681565b3480156110ff57600080fd5b5061060c61110e366004614c5d565b6001600160a01b03166000908152601960205260409020546001600160401b031690565b34801561113e57600080fd5b5061050f61114d366004614bc1565b61324f565b34801561115e57600080fd5b5061050f61116d366004614c5d565b6132cb565b34801561117e57600080fd5b5061050f61118d36600461569f565b613346565b34801561119e57600080fd5b5061050f6111ad366004614da4565b61338b565b3480156111be57600080fd5b506106926111cd366004614dfb565b613420565b3480156111de57600080fd5b5061050f6111ed3660046156f7565b61357e565b60026001600160a01b038216600090815260036020819052604090912054600160401b900460ff169081111561122a5761122a614f17565b03611275576001600160a01b0380821660009081526003602052604090208054600190910154611272928492600160501b8104821692909116906001600160401b03166135fe565b50565b60026001600160a01b03828116600090815260046020908152604080832054909316825260039081905291902054600160401b900460ff16908111156112bd576112bd614f17565b03611309576001600160a01b03818116600090815260046020908152604080832054841680845260039092529091206001810154905461127293859216906001600160401b03166135fe565b604051637115fdd360e01b815260040160405180910390fd5b61132b826113bd565b15611364576001600160a01b03808316600090815260036020526040812054611360928592600160501b909204169084613680565b5050565b61136d8261232b565b1561139a576001600160a01b03808316600090815260046020526040902054611360911683600184613680565b60405163163e0acf60e21b815260040160405180910390fd5b6112723382611322565b6001600160a01b038116600090815260036020526040812054600160401b900460ff16818160038111156113f3576113f3614f17565b14159392505050565b60006001600160a01b0384166114255760405163989992a560e01b815260040160405180910390fd5b33600061143184613716565b9050600080516020615d628339815191528160a001518260800151611456919061574d565b1461147457604051630eb911d560e01b815260040160405180910390fd5b856001600160a01b031681602001516001600160a01b0316036114aa57604051637c72ea1360e01b815260040160405180910390fd5b6016546000906114c8906201000090046001600160a01b03166137e5565b90506114d38161387d565b8160e001516001600160401b031660000361157957806001600160a01b0316600560009054906101000a90046001600160401b03166001600160401b031683600001516001600160401b03167f5a0f2eb6ae0aa35d6df4a692dcea08836a52a923522d010ac5241fce52a2180e8a8660200151876060015188604001518a8e8b60a001518c60c00151604051611570989796959493929190615760565b60405180910390a45b60008061158785898b6138f6565b915091508360e001516001600160401b03166000146115bc576115a8613919565b6115b784898b85858a89613945565b6115e7565b6115cb896000806000866139e9565b6115e7838a878b85600080516020615d62833981519152613a8c565b826001600160a01b0316636638439e8a866020015187606001518860400151338e8b60a001518c60c001518d60e001516040518a63ffffffff1660e01b815260040161163b999897969594939291906157cc565b600060405180830381600087803b15801561165557600080fd5b505af1158015611669573d6000803e3d6000fd5b5050604051632142170760e11b81523060048201526001600160a01b0386166024820152604481018b90523392506342842e0e9150606401600060405180830381600087803b1580156116bb57600080fd5b505af11580156116cf573d6000803e3d6000fd5b50630a85bd0160e11b9d9c50505050505050505050505050565b611360338383613b05565b6000601f54601e54611706919061584a565b905090565b611713613b6f565b601680549115156101000261ff0019909216919091179055565b60008061173a8585613bc9565b600081815260186020526040902054909150611757908490613c0f565b9150505b9392505050565b61176a613919565b600061177533612d19565b90506000806117858686896138f6565b600082815260176020526040812054929450909250600160401b9091046001600160a01b0316906117b68883613bc9565b60008581526017602052604081208054600160401b600160e01b031916600160401b6001600160a01b038e1602178155600201549192509061180690600080516020615d62833981519152615861565b905061181633848b8b8686613c7f565b611824338b8b8b8886613a8c565b896001600160a01b0316866001600160401b03168c6001600160401b03167f5dbf7557a2e3e90ad585a162df084f4b4e0c5b124740bf7821294703d0fe639c8a60405161187391815260200190565b60405180910390a45050505050505050505050565b611890613b6f565b600580546001600160601b03909216600160801b026bffffffffffffffffffffffff60801b19909216919091179055565b6001600160a01b038281166000908152600460209081526040808320549093168252600390819052918120549091600160401b90910460ff169081600381111561190d5761190d614f17565b148061192a5750600281600381111561192857611928614f17565b145b8061194e575082801561194e5750600181600381111561194c5761194c614f17565b145b1561195d5760009150506119e5565b506001600160a01b038316600090815260036020819052604090912054600160401b900460ff169081600381111561199757611997614f17565b14806119b4575060028160038111156119b2576119b2614f17565b145b806119d0575060018160038111156119ce576119ce614f17565b145b156119df5760009150506119e5565b60019150505b92915050565b6001600160a01b038181166000908152600460209081526040808320549093168083526003808352848420855160a0810190965280546001600160401b0381168752949586958695869586958695919486949093840191600160401b90910460ff1690811115611a5d57611a5d614f17565b6003811115611a6e57611a6e614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919b5094995093975095509350909150505b91939550919395565b6001600160a01b0381166000908152600360208190526040822054600160401b900460ff1681811115611b1357611b13614f17565b1492915050565b611b22613b6f565b6001600160a01b039091166000908152601c6020526040902080546001600160601b03909216610100026cffffffffffffffffffffffffff19909216919091176001179055565b60068160108110611b7957600080fd5b018054909150611b8890615874565b80601f0160208091040260200160405190810160405280929190818152602001828054611bb490615874565b8015611c015780601f10611bd657610100808354040283529160200191611c01565b820191906000526020600020905b815481529060010190602001808311611be457829003601f168201915b505050505081565b6000811580611c185750600f82115b15611c2257600191505b611c2d848484612847565b90506001600160a01b03811661175b576040516331a9108f60e11b8152600481018490526001600160a01b03851690636352211e90602401602060405180830381865afa158015611c82573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611ca691906158ae565b9050611cb1816120ad565b1561175b576001600160a01b03908116600090815260046020526040902054169392505050565b611ce0613b6f565b8060068360108110611cf457611cf46158cb565b0190611d009082615927565b505050565b611d0d613b6f565b60165460ff1615611d3157604051632e6129eb60e11b815260040160405180910390fd5b601680546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b6001600160a01b03831615801590611d8c57506001600160a01b0383166000908152601c602052604090205460ff16155b15611daa57604051630eca12dd60e31b815260040160405180910390fd5b6001600560088282829054906101000a90046001600160401b0316611dcf91906159e6565b92506101000a8154816001600160401b0302191690836001600160401b03160217905550604051806101200160405280336001600160a01b031681526020018962ffffff1681526020018863ffffffff1681526020018715158152602001866001600160a01b03168152602001856001600160601b03168152602001838152602001828152602001846001600160a01b0316815250601b6000600560089054906101000a90046001600160401b03166001600160401b03166001600160401b0316815260200190815260200160002060008201518160000160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060208201518160000160146101000a81548162ffffff021916908362ffffff16021790555060408201518160000160176101000a81548163ffffffff021916908363ffffffff160217905550606082015181600001601b6101000a81548160ff02191690831515021790555060808201518160010160006101000a8154816001600160a01b0302191690836001600160a01b0316021790555060a08201518160010160146101000a8154816001600160601b0302191690836001600160601b0316021790555060c0820151816002015560e082015181600301556101008201518160040160006101000a8154816001600160a01b0302191690836001600160a01b031602179055509050507fcfc9ed74ed2586915eb2ba885b6516120033d928b11ec45eb846af0700dabca489600560089054906101000a90046001600160401b03168789868d8d8b893360405161209a9a999897969594939291906001600160401b039a8b1681529890991660208901526001600160a01b0396871660408901529415156060880152608087019390935262ffffff9190911660a086015263ffffffff1660c08501526001600160601b031660e0840152610100830152919091166101208201526101400190565b60405180910390a1505050505050505050565b600060036001600160a01b03838116600090815260046020908152604080832054909316825260039081905291902054600160401b900460ff1690811115611b1357611b13614f17565b600061210284611ade565b1561222257604051627eeac760e11b81526001600160a01b0385811660048301526024820184905284169062fdd58e90604401602060405180830381865afa158015612152573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906121769190615a0d565b612180908261574d565b6001600160a01b0385811660009081526003602052604090819020549051627eeac760e11b8152600160501b909104821660048201819052602482018690529293509085169062fdd58e906044015b602060405180830381865afa1580156121ec573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906122109190615a0d565b61221a908361574d565b91505061175b565b61222b846120ad565b61175b57604051627eeac760e11b81526001600160a01b0385811660048301526024820184905284169062fdd58e906044015b602060405180830381865afa15801561227b573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019061229f9190615a0d565b6122a9908261574d565b949350505050565b60006122bc82611ade565b15612305576122d56001600160a01b038316318261574d565b6001600160a01b038084166000908152600360205260409020549192506119e591600160501b900416318261574d565b61230e826120ad565b612326576119e56001600160a01b038316318261574d565b919050565b6001600160a01b038181166000908152600460209081526040808320549093168252600390819052918120549091600160401b90910460ff169081600381111561237757612377614f17565b148061175b5750600281600381111561239257612392614f17565b149392505050565b6123a2613b6f565b601d80546001600160a01b0319166001600160a01b0392909216919091179055565b6123cc613b6f565b6016805460ff19166001179055565b6123e3613b6f565b6005805463ffffffff909216600160e01b026001600160e01b03909216919091179055565b612410613b6f565b61241a6000613cec565b565b6001600160401b0385166000908152601b60205260409020546001600160a01b0316331461245d5760405163471e5c3d60e11b815260040160405180910390fd5b62ffffff84161561249b576001600160401b0385166000908152601b60205260409020805462ffffff60a01b1916600160a01b62ffffff8716021790555b63ffffffff8316156124dc576001600160401b0385166000908152601b60205260409020805463ffffffff60b81b1916600160b81b63ffffffff8616021790555b6001600160601b03821615612525576001600160401b0385166000908152601b6020526040902060010180546001600160a01b0316600160a01b6001600160601b038516021790555b801561254a576001600160401b0385166000908152601b602052604090206003018190555b604080516001600160401b0380891682528716602082015262ffffff86169181019190915263ffffffff841660608201526001600160601b038316608082015260a081018290527f283ca86eb787b2e4eed53d42c177266ef3af5e5879ca7e291363d2eed932ee0e9060c0015b60405180910390a1505050505050565b6001600160a01b03818116600090815260046020908152604080832054909316825260039081905291812054909182918291829182918291600160401b900460ff169081600381111561261c5761261c614f17565b14806126395750600281600381111561263757612637614f17565b145b806126555750600181600381111561265357612653614f17565b145b1561267557612663886119eb565b96509650965096509650965050611ad5565b506001600160a01b038716600090815260036020819052604090912054600160401b900460ff16908160038111156126af576126af614f17565b14806126cc575060028160038111156126ca576126ca614f17565b145b806126e8575060018160038111156126e6576126e6614f17565b145b156126f65761266388613174565b50600097889750879650869550859450849350915050565b6001543414612730576040516333b18e6b60e11b815260040160405180910390fd5b611d003384843485613d3c565b600080600061274b846120ad565b156127695760405163125f0c1360e21b815260040160405180910390fd5b61277284611ade565b156127ad575050506001600160a01b0380821660009081526003602052604090208054600191820154600160501b90910483169216906127b7565b5082915081905060005b9193909250565b60006127c933612d19565b604080516001600160401b03808a1682528316602082015233918101919091526001600160a01b03871660608201526080810186905260a0810185905260c081018490529091507f64b5ca6749db1c615652096d273882ff7a1008ac9664f51568b14410b7a4f1a69060e0016125b7565b612842613b6f565b600155565b6000806128548585613f09565b600081815260176020908152604091829020825160a08101845281546001600160401b038082168084526001600160a01b03600160401b93849004811696850196909652600185015491821696840196909652049092166060830152600201546080820152919250156128f0576128cf848260800151613c0f565b6000036128e35760200151915061175b9050565b60600151915061175b9050565b50600095945050505050565b612904613b6f565b601e91909155601f55565b612917613b6f565b61136061292c6000546001600160a01b031690565b6001600160a01b0384169083613f32565b601a602052816000526040600020816010811061295957600080fd5b018054909250611b889150615874565b612971613919565b600061297c33612d19565b9050600080600061298f8b8b8b8b613f84565b9250925092506129a183888a89613fdf565b6129af338a8d8d868b613c7f565b6129bd33898d8d858b613a8c565b836001600160401b03168c6001600160401b03167f874a0ec379dec4a6469317f6b2eb8bcb7381c2e0074e09ba06e85ef2dcb2ce4b338e8e8e8e8e8e348f604051612a1099989796959493929190615a26565b60405180910390a3505050505050505050505050565b6000612a3333848461402d565b50600192915050565b612a44613b6f565b6001600160a01b03166000908152601c6020526040902080546cffffffffffffffffffffffffff19169055565b612a79613919565b6000612a8433612d19565b9050600080612a948686896138f6565b600082815260176020526040812060010154929450909250600160401b9091046001600160a01b031690612ac88883613bc9565b6000858152601760205260409020600181018054600160401b600160e01b031916600160401b6001600160a01b038e160217905560020154909150612b1133848b8b8686613c7f565b612b1f338b8b8b8886613a8c565b896001600160a01b0316866001600160401b03168c6001600160401b03167f140155fa1de4908485153ff90dc3ed5358f6cf7d8c89166509c6a6ae2a850ca28a60405161187391815260200190565b6001600160401b0381166000908152601b60205260409020546001600160a01b03163314612baf5760405163471e5c3d60e11b815260040160405180910390fd5b6001600160401b038181166000818152601b6020908152604080832080546001600160e01b031916815560018101849055600281018490556003810193909355600490920180546001600160a01b0319169055815193861684528301919091527fce37e681b0772d563a915fa6cbf7fde2d8a8889e12015eb50beb269910bcd011910160405180910390a15050565b612c46613919565b6000612c5133612d19565b9050600080612c6485338e8e88886140ee565b91509150612c713361387d565b612d0a6040518061010001604052808f6001600160401b031681526020018c6001600160a01b031681526020018b62ffffff1681526020018a6001600160601b0316815260200189600080516020615d62833981519152612cd29190615861565b8152602001898152602001604051806020016040528060008152508152602001886001600160401b0316815250858e85858a33613945565b50505050505050505050505050565b6001600160a01b0381166000908152601960205260408120546001600160401b03169081900361232657604051630ce1b58d60e21b815260040160405180910390fd5b6000612d6733612d19565b9050600080612d7a87338e8e8a886140ee565b91509150612d873361387d565b612d9082614182565b612dac338d898985600080516020615d62833981519152613a8c565b336001600160a01b0316600560009054906101000a90046001600160401b03166001600160401b03168e6001600160401b03167f5a0f2eb6ae0aa35d6df4a692dcea08836a52a923522d010ac5241fce52a2180e8f8e8e8e8e8e8e8e604051612e1c989796959493929190615760565b60405180910390a450505050505050505050505050565b6000612e3e33612d19565b604080516001600160401b038087168252831660208201526001600160601b038516918101919091529091507f8aadc94565cd0449ff6a891861dce3989ecfbd4c25311ed3926eac0d5d53aba4906060015b60405180910390a1505050565b6000612ea833612d19565b604080516001600160401b038b81168252831660208201526001600160a01b038a811682840152891660608201526080810188905260a0810187905260c0810186905260e0810185905290519192507f09f2adc90b22f76ff47f53431a42a7a5e0bcc5867d0ebaedce6ce5d5d7f5d74791908190036101000190a15050505050505050565b612f35613b6f565b600255565b6000612f4533612d19565b90506000612f578633868689876140ee565b50600090815260176020908152604080832080546001600160e01b03199081168255600182018054909116905560020183905533835260199091529020805467ffffffffffffffff19169055505050505050565b612fb3613919565b6000612fbe33612d19565b9050600080612fce85858d6138f6565b91509150612fee338c878785600080516020615d62833981519152613c7f565b612ff783614190565b6130003361387d565b6130996040518061010001604052808e6001600160401b031681526020018c6001600160a01b031681526020018b62ffffff1681526020018a6001600160601b0316815260200189600080516020615d628339815191526130619190615861565b8152602001898152602001604051806020016040528060008152508152602001886001600160401b0316815250858d85858a33613945565b505050505050505050505050565b60006130b233612d19565b604080516001600160401b0380871682528316602082015233918101919091526001600160601b03841660608201529091507fdf35dff92be2e5e7dae645fb3e7a3d43e9487ecbbfd323bfef15c43ad2de58a590608001612e90565b61311882336141c7565b6001600160a01b038216600090815260036020526040902054600160481b900460ff1615801561314a57506001543414155b1561316857604051632740b97160e11b815260040160405180910390fd5b61136082333484614276565b6001600160a01b0381166000908152600360208181526040808420815160a0810190925280546001600160401b03811683528594859485948594859485949293919291840191600160401b90910460ff16908111156131d5576131d5614f17565b60038111156131e6576131e6614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b039081166040808501919091526001909401541660609283015283015190830151608084015184519490930151919c909a5091985091965090945092505050565b613257613b6f565b601d546040516000916001600160a01b03169083908381818185875af1925050503d80600081146132a4576040519150601f19603f3d011682016040523d82523d6000602084013e6132a9565b606091505b50509050806113605760405163e53e5bcd60e01b815260040160405180910390fd5b6132d3613b6f565b6001600160a01b03811661333d5760405162461bcd60e51b815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201526564647265737360d01b60648201526084015b60405180910390fd5b61127281613cec565b61334e613b6f565b6001600160a01b0383166000908152601a6020526040902081908360108110613379576133796158cb565b01906133859082615927565b50505050565b613393613b6f565b816001600160a01b03166323b872dd306133b56000546001600160a01b031690565b6040516001600160e01b031960e085901b1681526001600160a01b0392831660048201529116602482015260448101849052606401600060405180830381600087803b15801561340457600080fd5b505af1158015613418573d6000803e3d6000fd5b505050505050565b6001600160a01b0383166000908152601960205260408120546001600160401b03161561344f5750600061175b565b81158061345c5750600f82115b1561346657600191505b61347183858461172d565b905061347c84611ade565b15613543576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a0823190602401602060405180830381865afa1580156134c7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906134eb9190615a0d565b6134f5908261574d565b6001600160a01b03858116600090815260036020526040908190205490516370a0823160e01b8152600160501b909104821660048201819052929350908516906370a08231906024016121cf565b61354c846120ad565b61175b576040516370a0823160e01b81526001600160a01b0385811660048301528416906370a082319060240161225e565b6001600160a01b0382166135a55760405163bd78145160e01b815260040160405180910390fd5b826001600160a01b0316826001600160a01b0316036135d7576040516304da706760e51b815260040160405180910390fd5b6001600160a01b038116611d0057604051634ca5048960e01b815260040160405180910390fd5b6001600160a01b03848116600081815260036020908152604091829020805469ffff000000000000000019166901030000000000000000179055905185841681526001600160401b03851693871692917f5717bcaec46242edc8fb07322221c02d6dd3de7a954d5c009ee550cd0cdf768591015b60405180910390a450505050565b6001600160a01b03808516600081815260036020908152604080832080546001600160f01b031916815560010180546001600160a01b03199081169091559488168084526004909252918290208054909416909355519091907fbd302a9bf683315c275f4a7f0092796d97d17fbb2a89bbc8938bd6842c38eb89906137089086908690615a98565b60405180910390a350505050565b604080516101008101825260008082526020820181905291810182905260608082018390526080820183905260a0820183905260c082015260e0810191909152600080600080600080600080898060200190518101906137769190615ac1565b60408051610100810182526001600160401b03998a1681526001600160a01b03909816602089015262ffffff909616958701959095526001600160601b039093166060860152608085019190915260a084015260c08301529190911660e08201529a9950505050505050505050565b6000604051733d602d80600a3d3981f3363d3d373d3d3d363d7360601b81528260601b60148201526e5af43d82803e903d91602b57fd5bf360881b60288201526037816000f09150506001600160a01b0381166123265760405162461bcd60e51b8152602060048201526016602482015275115490cc4c4d8dce8818dc99585d194819985a5b195960521b6044820152606401613334565b600580546001919060009061389c9084906001600160401b03166159e6565b82546001600160401b039182166101009390930a9283029282021916919091179091556005546001600160a01b039093166000908152601960205260409020805467ffffffffffffffff1916939091169290921790915550565b6000806139038585613f09565b915061390f8584613bc9565b9050935093915050565b601654610100900460ff161561241a576040516001621dce6960e31b0319815260040160405180910390fd5b6139518787878561439b565b61398785886040015162ffffff166201518061396d9190615bac565b61397790426159e6565b89602001518a60a00151886139e9565b6139b281868489878c60a00151600080516020615d628339815191526139ad9190615861565b613a8c565b60208701516139d390829084896139c98284613bc9565b8c60a00151613a8c565b6139e0878284898961482e565b50505050505050565b6040805160a0810182526005546001600160401b0390811682526001600160a01b039788166020808401918252978216838501908152968916606084019081526080840196875260009586526017909852929093209051815492519084166001600160e01b031993841617600160401b91891682021782559451600182018054975191909416969092169590951795169092029390931790559051600290910155565b60008281526018602052604081208054839290613aaa90849061574d565b909155505060408051848152602081018390526001600160a01b038087169288821692918a16917fa1c0f6bb9ba071b3dfd066f852f622c51d4073a7cc058fd04296ae916b8b0bc691015b60405180910390a4505050505050565b6001600160a01b038216613b2c576040516334b1be0d60e21b815260040160405180910390fd5b613b35836113bd565b15613b4557611d008383836148c7565b613b4e8361232b565b1561139a5760405160016208d37d60e21b0319815260040160405180910390fd5b6000546001600160a01b0316331461241a5760405162461bcd60e51b815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401613334565b6040516001600160601b0319606084811b8216602084015283901b1660348201526000906048015b60405160208183030381529060405280519060200120905092915050565b600080613c1d60058561584a565b613c2890600a615cbb565b9050600084600103613c3c57506001613c61565b6005613c49600187615861565b613c53919061584a565b613c5e90600a615cbb565b90505b80613c6c8386615cdd565b613c769190615cf1565b95945050505050565b60008281526018602052604081208054839290613c9d908490615861565b909155505060408051848152602081018390526001600160a01b038087169289821692918916917fa1c0f6bb9ba071b3dfd066f852f622c51d4073a7cc058fd04296ae916b8b0bc69101613af5565b600080546001600160a01b038381166001600160a01b0319831681178455604051919092169283917f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e09190a35050565b613d4785858561357e565b613d528560016118c1565b1580613d665750613d648460006118c1565b155b15613d84576040516307facddb60e11b815260040160405180910390fd5b6040805160a0810182526001600160401b0383811682526001602080840182815291548714848601526001600160a01b03898116606086015288811660808601528a1660009081526003918290529490942083518154931667ffffffffffffffff1984168117825591519394909392849268ffffffffffffffffff199091161790600160401b908490811115613e1c57613e1c614f17565b0217905550604082810151825460608501517fffff000000000000000000000000000000000000000000ffffffffffffffffff909116600160481b921515929092027fffff0000000000000000000000000000000000000000ffffffffffffffffffff1691909117600160501b6001600160a01b0392831602178355608090930151600190920180546001600160a01b03191692841692909217909155805185831681526001600160401b0384166020820152868316928816917f752c94da010e5b94c0278334398a684d4a7bde91f0f38c9dbb1766ad4f586c6991015b60405180910390a35050505050565b6040516001600160601b0319606084901b16602082015260348101829052600090605401613bf1565b604080516001600160a01b038416602482015260448082018490528251808303909101815260649091019091526020810180516001600160e01b031663a9059cbb60e01b179052611d009084906149db565b6000806000613f948787876138f6565b6040516001600160601b031960608b811b8216602084015288901b16603482015291945092506048016040516020818303038152906040528051906020012090509450945094915050565b6000938452601760205260409093206001810180546001600160a01b03909316600160401b026001600160e01b03199093166001600160401b03909416939093179190911790915560020155565b600061403a600a83615cdd565b90508015806140495750600481115b1561406757604051631ec9ca4160e21b815260040160405180910390fd5b6000614074600a84615cf1565b9050600182036140915761408c858587600085613d3c565b6140e7565b600282036140b0576140a384866141c7565b61408c8486600084614276565b600382036140cc5761408c8585836001600160401b0316613b05565b600482036140e7576140e785826001600160401b0316611322565b5050505050565b60008060008060006141028b888b8b613f84565b9250925092506141458a8a8d8a86601760008a815260200190815260200160002060020154600080516020615d628339815191526141409190615861565b613c7f565b6141698a898d8a85601760008a815260200190815260200160002060020154613c7f565b61417286614190565b5090999098509650505050505050565b611272816000806000613fdf565b6040516001600160401b038216907ff4a42f4ac762c05af0cbe21a8c16a2a87cd93719bbcfae68dce6a1b7f353a16c90600090a250565b6001600160a01b03828116600090815260036020526040902054600160501b90048116908216141580614230575060016001600160a01b038316600090815260036020819052604090912054600160401b900460ff169081111561422d5761422d614f17565b14155b1561424e57604051634cd87fb560e01b815260040160405180910390fd5b6142598160006118c1565b611360576040516307facddb60e11b815260040160405180910390fd5b6001600160a01b03838116600081815260046020908152604080832080546001600160a01b0319168a87169081179091558084526003835292819020600101549051941684526001600160401b038516937fda23dc0f47967fd81e9b62f5207a955b77295fef190364f10a6c3cf26773c1ab910160405180910390a46001600160a01b038416600090815260036020526040902054600160481b900460ff1680614321575060015482145b15614364576001600160a01b0380851660009081526003602052604090206001810154905461435f92879287929116906001600160401b03166135fe565b613385565b5050506001600160a01b03166000908152600360205260409020805468ff0000000000000000191668020000000000000000179055565b60e0848101516001600160401b03166000908152601b602090815260409182902082516101208101845281546001600160a01b038082168352600160a01b80830462ffffff1695840195909552600160b81b820463ffffffff1695830195909552600160d81b900460ff16151560608201526001820154808516608083018190529390046001600160601b031660a0820152600282015460c0820152600382015494810194909452600401548216610100840152908316141580614470575080606001511580156144705750838160c0015114155b80614495575080600001516001600160a01b031685602001516001600160a01b031614155b806144b25750806020015162ffffff16856040015162ffffff1614155b806144d757508060a001516001600160601b031685606001516001600160601b031614155b806144ea57508060e001518560a0015114155b806144fe5750806040015163ffffffff1642115b1561451c57604051631771cc0160e11b815260040160405180910390fd5b61010081015160009081906001600160a01b03166145705750506005547f000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc290600160801b90046001600160601b03166145db565b6101008301516001600160a01b0381166000908152601c602052604090205490925060ff166145b257604051630eca12dd60e31b815260040160405180910390fd5b506001600160a01b0381166000908152601c602052604090205461010090046001600160601b03165b60e08701516001600160401b03166000908152601b6020526040812080546001600160e01b031916815560018101829055600281018290556003810182905560040180546001600160a01b031916905560608801516146449083906001600160601b031661574d565b905080156146cd5760208801516040516323b872dd60e01b81526001600160a01b03918216600482015230602482015260448101839052908416906323b872dd906064016020604051808303816000875af11580156146a7573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906146cb9190615d05565b505b600088606001516001600160601b03166000036146eb575081614731565b60055460608a01518491620186a09161471191600160e01b900463ffffffff1690615d22565b6001600160601b03166147249190615cf1565b61472e919061574d565b90505b60608901516001600160601b0316156147cf576001600160a01b03841663a9059cbb8861475e8486615861565b6040516001600160e01b031960e085901b1681526001600160a01b03909216600483015260248201526044016020604051808303816000875af11580156147a9573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906147cd9190615d05565b505b885160e08a0151604080516001600160401b03938416815292909116602083015281018290526001600160a01b03851660608201527f848da897c5a8478af17be9c5fb6ebd38774ff21fc83fdc1a19216edb8dc1eb029060800161209a565b600560009054906101000a90046001600160401b03166001600160401b031685600001516001600160401b03167f874a0ec379dec4a6469317f6b2eb8bcb7381c2e0074e09ba06e85ef2dcb2ce4b868686868b602001518c6040015162ffffff166201518061489d9190615bac565b6148a790426159e6565b60a08e015160c08f0151604051613efa9897969594939291600091615a26565b6001600160a01b0383166000908152600360208181526040808420815160a0810190925280546001600160401b038116835291939092840191600160401b900460ff169081111561491a5761491a614f17565b600381111561492b5761492b614f17565b81528154600160481b810460ff161515602080840191909152600160501b9091046001600160a01b03908116604080850191909152600194850154821660609485015289821660008181526003855282902090950180546001600160a01b0319168a84169081179091559386015160808701518251908416815293840189905295965092941692917fa0aa3b38771c7ab4ece55c6009c41d814f4ff862285d0825c24528a87fd124d79101613672565b6000614a30826040518060400160405280602081526020017f5361666545524332303a206c6f772d6c6576656c2063616c6c206661696c6564815250856001600160a01b0316614aad9092919063ffffffff16565b805190915015611d005780806020019051810190614a4e9190615d05565b611d005760405162461bcd60e51b815260206004820152602a60248201527f5361666545524332303a204552433230206f7065726174696f6e20646964206e6044820152691bdd081cdd58d8d9595960b21b6064820152608401613334565b60606122a98484600085856001600160a01b0385163b614b0f5760405162461bcd60e51b815260206004820152601d60248201527f416464726573733a2063616c6c20746f206e6f6e2d636f6e74726163740000006044820152606401613334565b600080866001600160a01b03168587604051614b2b9190615d45565b60006040518083038185875af1925050503d8060008114614b68576040519150601f19603f3d011682016040523d82523d6000602084013e614b6d565b606091505b5091509150614b7d828286614b88565b979650505050505050565b60608315614b9757508161175b565b825115614ba75782518084602001fd5b8160405162461bcd60e51b81526004016133349190614c2a565b600060208284031215614bd357600080fd5b5035919050565b60005b83811015614bf5578181015183820152602001614bdd565b50506000910152565b60008151808452614c16816020860160208601614bda565b601f01601f19169290920160200192915050565b60208152600061175b6020830184614bfe565b6001600160a01b038116811461127257600080fd5b803561232681614c3d565b600060208284031215614c6f57600080fd5b813561175b81614c3d565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614cb857614cb8614c7a565b604052919050565b60006001600160401b03821115614cd957614cd9614c7a565b50601f01601f191660200190565b6000614cfa614cf584614cc0565b614c90565b9050828152838383011115614d0e57600080fd5b828260208301376000602084830101529392505050565b60008060008060808587031215614d3b57600080fd5b8435614d4681614c3d565b93506020850135614d5681614c3d565b92506040850135915060608501356001600160401b03811115614d7857600080fd5b8501601f81018713614d8957600080fd5b614d9887823560208401614ce7565b91505092959194509250565b60008060408385031215614db757600080fd5b8235614dc281614c3d565b946020939093013593505050565b801515811461127257600080fd5b600060208284031215614df057600080fd5b813561175b81614dd0565b600080600060608486031215614e1057600080fd5b8335614e1b81614c3d565b92506020840135614e2b81614c3d565b929592945050506040919091013590565b6001600160401b038116811461127257600080fd5b600080600080600060a08688031215614e6957600080fd5b8535614e7481614e3c565b94506020860135614e8481614c3d565b93506040860135614e9481614c3d565b94979396509394606081013594506080013592915050565b6001600160601b038116811461127257600080fd5b600060208284031215614ed357600080fd5b813561175b81614eac565b60008060408385031215614ef157600080fd5b8235614efc81614c3d565b91506020830135614f0c81614dd0565b809150509250929050565b634e487b7160e01b600052602160045260246000fd5b60c0810160048810614f4157614f41614f17565b9681526001600160a01b03958616602082015293851660408501529190931660608301526001600160401b03909216608082015290151560a09091015290565b60008060408385031215614f9457600080fd5b8235614f9f81614c3d565b91506020830135614f0c81614eac565b600080600060608486031215614fc457600080fd5b8335614fcf81614c3d565b95602085013595506040909401359392505050565b600082601f830112614ff557600080fd5b61175b83833560208501614ce7565b6000806040838503121561501757600080fd5b8235915060208301356001600160401b0381111561503457600080fd5b61504085828601614fe4565b9150509250929050565b62ffffff8116811461127257600080fd5b80356123268161504a565b803563ffffffff8116811461232657600080fd5b60008060008060008060008060006101208a8c03121561509957600080fd5b89356150a481614e3c565b985060208a01356150b48161504a565b97506150c260408b01615066565b965060608a01356150d281614dd0565b955060808a01356150e281614c3d565b945060a08a01356150f281614eac565b935060c08a013561510281614c3d565b8093505060e08a013591506101008a013590509295985092959850929598565b60006020828403121561513457600080fd5b61175b82615066565b60008060008060008060c0878903121561515657600080fd5b863561516181614e3c565b9550602087013561517181614e3c565b945060408701356151818161504a565b935061518f60608801615066565b9250608087013561519f81614eac565b8092505060a087013590509295509295509295565b6000806000606084860312156151c957600080fd5b83356151d481614c3d565b925060208401356151e481614c3d565b915060408401356151f481614e3c565b809150509250925092565b600080600080600060a0868803121561521757600080fd5b853561522281614e3c565b9450602086013561523281614c3d565b94979496505050506040830135926060810135926080909101359150565b6000806040838503121561526357600080fd5b50508035926020909101359150565b600080600080600080600080610100898b03121561528f57600080fd5b883561529a81614e3c565b975060208901356152aa81614c3d565b96506040890135955060608901356152c181614c3d565b945060808901356152d181614c3d565b935060a08901356152e181614e3c565b925060c0890135915060e08901356001600160401b0381111561530357600080fd5b61530f8b828c01614fe4565b9150509295985092959890939650565b60006020828403121561533157600080fd5b813561175b81614e3c565b6000806040838503121561534f57600080fd5b823561535a81614e3c565b91506020830135614f0c81614e3c565b6000806000806000806000806000806101408b8d03121561538a57600080fd5b8a3561539581614e3c565b995060208b01356153a581614c3d565b985060408b01356153b581614c3d565b975060608b01356153c581614c3d565b965060808b01356153d58161504a565b955060a08b01356153e581614eac565b945060c08b0135935060e08b01356153fc81614e3c565b92506101008b013561540d81614c3d565b809250506101208b013590509295989b9194979a5092959850565b6000806000806000806000806000806101408b8d03121561544857600080fd5b8a3561545381614e3c565b995060208b013561546381614c3d565b985060408b013561547381614c3d565b975060608b013561548381614c3d565b965060808b013561549381614eac565b95506154a160a08c0161505b565b94506154af60c08c01614c52565b935060e08b013592506101008b013591506101208b01356001600160401b038111156154da57600080fd5b6154e68d828e01614fe4565b9150509295989b9194979a5092959850565b6000806040838503121561550b57600080fd5b8235614f9f81614e3c565b600080600080600080600060e0888a03121561553157600080fd5b873561553c81614e3c565b9650602088013561554c81614c3d565b9550604088013561555c81614c3d565b969995985095966060810135965060808101359560a0820135955060c0909101359350915050565b6000806000806080858703121561559a57600080fd5b84356155a581614c3d565b93506020850135925060408501356155bc81614c3d565b915060608501356155cc81614c3d565b939692955090935050565b60008060008060008060008060006101208a8c0312156155f657600080fd5b893561560181614e3c565b985060208a013561561181614c3d565b975060408a013561562181614c3d565b965060608a01356156318161504a565b955060808a013561564181614eac565b945060a08a0135935060c08a013561565881614e3c565b925060e08a013561566881614c3d565b809250506101008a013590509295985092959850929598565b6000806040838503121561569457600080fd5b823561535a81614c3d565b6000806000606084860312156156b457600080fd5b83356156bf81614c3d565b92506020840135915060408401356001600160401b038111156156e157600080fd5b6156ed86828701614fe4565b9150509250925092565b60008060006060848603121561570c57600080fd5b833561571781614c3d565b9250602084013561572781614c3d565b915060408401356151f481614c3d565b634e487b7160e01b600052601160045260246000fd5b808201808211156119e5576119e5615737565b6001600160a01b03898116825288811660208301526001600160601b038816604083015262ffffff871660608301528516608082015260a0810184905260c0810183905261010060e082018190526000906157bd83820185614bfe565b9b9a5050505050505050505050565b6001600160a01b038a8116825289811660208301526001600160601b038916604083015262ffffff881660608301528616608082015260a0810185905260c0810184905261012060e0820181905260009061582983820186614bfe565b9150506001600160401b0383166101008301529a9950505050505050505050565b80820281158282048414176119e5576119e5615737565b818103818111156119e5576119e5615737565b600181811c9082168061588857607f821691505b6020821081036158a857634e487b7160e01b600052602260045260246000fd5b50919050565b6000602082840312156158c057600080fd5b815161175b81614c3d565b634e487b7160e01b600052603260045260246000fd5b601f821115611d0057600081815260208120601f850160051c810160208610156159085750805b601f850160051c820191505b8181101561341857828155600101615914565b81516001600160401b0381111561594057615940614c7a565b6159548161594e8454615874565b846158e1565b602080601f83116001811461598957600084156159715750858301515b600019600386901b1c1916600185901b178555613418565b600085815260208120601f198616915b828110156159b857888601518255948401946001909101908401615999565b50858210156159d65787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b6001600160401b03818116838216019080821115615a0657615a06615737565b5092915050565b600060208284031215615a1f57600080fd5b5051919050565b6001600160a01b038a811682528981166020830152604082018990528781166060830152861660808201526001600160401b03851660a082015260c0810184905260e081018390526101206101008201819052600090615a8883820185614bfe565b9c9b505050505050505050505050565b6040810160028410615aac57615aac614f17565b9281526020015290565b805161232681614e3c565b600080600080600080600080610100898b031215615ade57600080fd5b8851615ae981614e3c565b60208a0151909850615afa81614c3d565b60408a0151909750615b0b8161504a565b60608a0151909650615b1c81614eac565b809550506080890151935060a0890151925060c08901516001600160401b03811115615b4757600080fd5b8901601f81018b13615b5857600080fd5b8051615b66614cf582614cc0565b8181528c6020838501011115615b7b57600080fd5b615b8c826020830160208601614bda565b9350615b9d91505060e08a01615ab6565b90509295985092959890939650565b6001600160401b03818116838216028082169190828114615bcf57615bcf615737565b505092915050565b600181815b80851115615c12578160001904821115615bf857615bf8615737565b80851615615c0557918102915b93841c9390800290615bdc565b509250929050565b600082615c29575060016119e5565b81615c36575060006119e5565b8160018114615c4c5760028114615c5657615c72565b60019150506119e5565b60ff841115615c6757615c67615737565b50506001821b6119e5565b5060208310610133831016604e8410600b8410161715615c95575081810a6119e5565b615c9f8383615bd7565b8060001904821115615cb357615cb3615737565b029392505050565b600061175b8383615c1a565b634e487b7160e01b600052601260045260246000fd5b600082615cec57615cec615cc7565b500690565b600082615d0057615d00615cc7565b500490565b600060208284031215615d1757600080fd5b815161175b81614dd0565b6001600160601b03818116838216028082169190828114615bcf57615bcf615737565b60008251615d57818460208701614bda565b919091019291505056fe00000172eca084a2dfd7bef9ff78b9eed31c81789db8f74134d76bc8e5e3eaa1a2646970667358221220f1fb24f530623c085a1848e4eb0747caac6bcda1a16bcf475a7e65a4c50792d864736f6c63430008110033

Constructor Arguments (ABI-Encoded and is the last bytes of the Contract Creation Code above)

000000000000000000000000000000000000000000000000000000000000000000000000000000000000000028b224a23a6c66e4b496fef0e544ccf7bf1f9b96000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001f4000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc200000000000000000000000000000000000000000000000000000002540be400

-----Decoded View---------------
Arg [0] : proxyRegisterFee_ (uint256): 0
Arg [1] : treasury_ (address): 0x28b224a23A6C66E4B496feF0E544CCf7Bf1F9b96
Arg [2] : delegationRegisterFee_ (uint96): 0
Arg [3] : delegationFeePercentage_ (uint32): 500
Arg [4] : weth_ (address): 0xC02aaA39b223FE8D0A0e5C4F27eAD9083C756Cc2
Arg [5] : deletionNominalEth_ (uint256): 10000000000

-----Encoded View---------------
6 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [1] : 00000000000000000000000028b224a23a6c66e4b496fef0e544ccf7bf1f9b96
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000000
Arg [3] : 00000000000000000000000000000000000000000000000000000000000001f4
Arg [4] : 000000000000000000000000c02aaa39b223fe8d0a0e5c4f27ead9083c756cc2
Arg [5] : 00000000000000000000000000000000000000000000000000000002540be400


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.