ETH Price: $3,078.31 (-1.12%)
Gas: 5 Gwei

Token

EPSAPI (EPSAPI)
 

Overview

Max Total Supply

115,792,089,237,316,195,423,570,985,008,687,907,853,269,984,665,640,564,039,457,584,007,913,129,639.935 EPSAPI

Holders

448

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 3 Decimals)

Filtered by Token Holder
satenyonn.eth
Balance
115792089237316195423570985008687907853... EPSAPI

Value
$0.00
0xc06486d3dd5bdb44cef965e75055daa6465e93e8
Loading...
Loading
Loading...
Loading
Loading...
Loading

Click here to update the token information / general information
# Exchange Pair Price  24H Volume % Volume

Contract Source Code Verified (Exact Match)

Contract Name:
EPSDelegationRegister

Compiler Version
v0.8.17+commit.8df45f5f

Optimization Enabled:
Yes with 200 runs

Other Settings:
default evmVersion
File 1 of 14 : EPSDelegationRegister.sol
// SPDX-License-Identifier: CC0-1.0
// EPS Contracts v2.0.0
// www.eternalproxy.com

/**
 
@dev EPS Delegation Register. Features include: 

  * Primary, Secondary and Rental delegation classes.
    * Primary and Rental: only one delegation per global / collection / token / usage type combination.
    * Secondary: unlimited delegations (useful for many use cases, including consolidation).
  * Filter returned address lists to include only primary delegations, or include secondary and rental classes  
  * All delegations of primary and rental class are checked to ensure they are unique.
  * Sub-delegation.
    * A sub-delegate can add new delegations for the cold wallet. The internal delegation framework forms a structured auth model.
  * Consolidation.
    * Through matching secondary delegations (0xA to 0xB and 0xB to 0xA) we consolidate the usages for two addresses together.
  * Revoke from hot and cold in 0(1) time.
  * Revoke for all.
    * Both hot and cold can revoke for all with minimal gas (about 40k).
  * Multiple usages per delegation
    * Each delegation can have 1 to 25 usages, all stored in a single slot.
  * Multiple collection delegations per call
    * A single delegation call can set up delegations for n collections.
  * Structured ‘Delegation Report’ by address
    * For hot and cold wallets
  * Delegation locking
    * Set by the hot address, can be time bound or not
    * Hot addresses can unlock for a time period (e.g. unlock for the next five minutes). The lock automatically reinstates, no call or gas required.
  * Delegation lock bypass list
    * A hot wallet can load a list of addresses that can bypass the lock. For example, they can lock but add that 0xC can bypass the lock
  * Default descriptions for usage codes
  * Project specific descriptions for usage codes that can be set by admin or collection owners
  * Contract uses sub-delegation and delegation as its own internal auth model, allowing a structured approach to multi-user admin.
  * beneficiaryOf function: return the beneficiary of a token given a usage code
  * beneficiaryBalanceOf function: return the beneficiary balance for an address.
  * Both of the above can be filtered to include primary, secondary or rental delegation classes.
    * A useful method: beneficiaryBalanceOf for just primary classes is a very simple API for projects to implement
  * Headless protocol can:
    * Make a global delegation for any or all usage types
    * Make a collection specific delegation for any or all usage types
    * Revoke from hot
    * Revoke from cold
    * Revoke a token delegation
    * Revoke all for hot
    * Revoke all for cold
    * Lock a hot wallet
    * Unlock a hot wallet
  * Many view functions, including:
    * All addresses for a hot wallet, filtered by primary, secondary, rental
    * Address lock details
    * Validity status for a delegation
    * Whether a delegation from / to an address exists
    * All delegation keys for a hot or cold address (each delegation has a unique key which is the first 20 bytes of the hash of the delegation arguments)
    * If a cold or hot delegation exists for an address (in 0(1) time).
 */

// Usage list:
// 1) All
// 2) Minting / Allowlist
// 3) Airdrops
// 4) Voting / Governance
// 5) Avatar Display
// 6) Social Media
// 7) Physical Events Access
// 8) Virtual Events Access
// 9) Club / Community Access
// 10) Metaverse Access
// 11) Metaverse Land
// 12) Gameplay
// 13) IP Licensing
// 14) Sub-delegation
// 15) Merch / Digital Assets
// 16) -- currently vacant
// 17) -- currently vacant
// 18) -- currently vacant
// 19) -- currently vacant
// 20) -- currently vacant
// 21) -- currently vacant
// 22) -- currently vacant
// 23) -- community reserved
// 24) -- community reserved
// 25) -- community reserved

pragma solidity 0.8.17;
import "@openzeppelin/contracts/utils/Context.sol";
import "@openzeppelin/contracts/utils/structs/EnumerableSet.sol";
import "./IEPSDelegationRegister.sol";
import "../Utils/ENSReverseRegistrar.sol";

contract EPSDelegationRegister is
  Context,
  IEPSDelegationRegister,
  IERCOmnReceiver
{
  using EnumerableSet for EnumerableSet.AddressSet;

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

  // Delegation Scopes control integers:
  uint96 private constant COLLECTION_DELEGATION = 1 * (10**27);
  uint96 private constant TOKEN_DELEGATION = 2 * (10**27);

  // Delegation Classes control integers:
  uint96 private constant TIME_BASED_DELEGATION = 1 * (10**26);
  uint96 private constant SECONDARY_DELEGATION = 1 * (10**25);
  uint96 private constant RENTAL_DELEGATION = 2 * (10**25);

  // Number of positions in the control integer:
  uint256 private constant LENGTH_OF_CONTROL_INTEGER = 29;

  // Number of usage types:
  uint256 private constant NUMBER_OF_USAGE_TYPES = 25;

  // Token API call transaction types:
  uint256 private constant MAKE_PRIMARY_DELEGATION = 1;
  uint256 private constant REVOKE = 2;
  uint256 private constant REVOKE_ALL_FOR_HOT = 3;
  uint256 private constant REVOKE_ALL_FOR_COLD = 4;
  uint256 private constant LOCK_HOT = 5;
  uint256 private constant UNLOCK_HOT = 6;
  uint256 private constant MAKE_SECONDARY_DELEGATION = 7;
  uint256 private constant MAKE_30_DAY_PRIMARY_DELEGATION = 8;
  uint256 private constant MAKE_90_DAY_PRIMARY_DELEGATION = 9;

  // Internal authority model
  uint256 private constant ALL_DELEGATION = 1;
  uint256 private constant SUB_DELEGATION = 14;
  uint256 private constant LEVEL_ONE = 25;
  uint256 private constant LEVEL_TWO = 24;
  uint256 private constant LEVEL_THREE = 23;
  uint96 private constant LEVEL_ONE_KEY = 11000000000000000000000000;
  uint96 private constant LEVEL_TWO_KEY = 10100000000000000000000000;
  uint96 private constant LEVEL_THREE_KEY = 10010000000000000000000000;
  address private constant INITIAL_ADMIN =
    0x9F0773aF2b1d3f7cC7030304548A823B4E6b13bB;

  IEPSDelegationRegister private constant LEGACY_REGISTER =
    IEPSDelegationRegister(0x88888888888806458312bB6B7Ae0f9a7ad30Ea40);

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

  // 'Air drop' of EPSAPI to every address
  uint256 private _epsAPIBalance = type(uint256).max;

  // Fee to add a live proxy record to the register. If a fee is required this must be sent either:
  // 1) On the call from the cold to nominate the hot,
  // 2) If the cold calls through the ERC20 API the record will be in a pending state until
  //    the eth payment has been made from the cold to the register address (note when there is no
  //    fee this step is never required).

  uint256 private _proxyRegisterFee;

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

  // Load one item from legacy register?
  bool public includeLegacy = true;

  // Decimals
  uint8 private _decimals = 3;

  // ENS reverse registrar
  ENSReverseRegistrar private _ensReverseRegistrar;

  // EPS treasury address:
  address private _treasury;

  // Note that collection delegation 'overrides' global delegation. For example, address A delegates
  // to address B for all. Address A also delegates to address C for byWassies. When checking
  // for this delegation for byWassies address B will NOT have the delegation to address A, but address
  // C WILL. For all collections that are NOT byWassies address B will have the delegation from address A,
  // and address C will NOT.
  mapping(bytes32 => uint256) internal _delegationTypesForAddress;

  // The control integer tells us about the delegation, and is structured as follows:
  // 98765432129876543211987654321    29 integers per uint96
  // ^^^^^-----------------------^
  // ||||            | 25 Usage types
  // ||| DelegationClass: 0 = Primary, 1 = Secondary, 2 = Rental (position 26)
  // || DelegationTimeLimit: Is eternal or time limited. 0 = eternal, 1 = time limited (position 27)
  // | DelegationScope: Is global, collection or token. 0  = global, 1 = collection, 2 = token (position 28)
  // Reserved for transaction type on headless protocol calls (position 29)
  // Note that in token API calls positions 27 and 28 when received hold the provider code
  // Example 1: this is an entry that delegates primary for all rights for an unlimited time for all
  // collections:
  // 00000000000000000000000000001
  // Example 2: this is an entry that delegates secondary for all rights for an limited time for all
  // collections for usages 2, 3, 5 and 24:
  // 00110100000000000000000010110
  // Example 3: this is an entry that delegates rental for all rights for an unlimited time for all
  // collections:
  // 00020000000000000000000000001

  // Map addresses hashed with tranche to delegation key. The delegation key is the first 20 bytes of a hash
  // of the delegation data:
  mapping(bytes32 => EnumerableSet.AddressSet) internal _hotToDelegation;
  mapping(bytes32 => EnumerableSet.AddressSet) internal _coldToDelegation;
  mapping(bytes32 => EnumerableSet.AddressSet) internal _tokenToDelegation;

  // Map a delegation key to delegation record:
  mapping(address => DelegationRecord) private _delegationRecord;

  // Map a delegation record to it's metadata (if required).
  mapping(address => DelegationMetadata) public delegationMetadata;

  // Hot wallet delegation tranche number
  mapping(address => uint256) internal _hotWalletTranche;

  // Cold wallet delegation tranche number
  mapping(address => uint256) internal _coldWalletTranche;

  // Map an address to a lock struct
  mapping(address => LockDetails) private _addressLockDetails;

  // Map an address to a lock bypass list:
  mapping(address => EnumerableSet.AddressSet) internal _lockBypassList;

  // Map cold address to pending payments
  mapping(address => address[]) public pendingPayments;

  // ERC20 token relayed fee
  mapping(address => uint256) private _erc20PerTransactionFee;

  /**
   *
   *
   * @dev Constructor
   *
   *
   */
  constructor() {
    _addAuthority(SUB_DELEGATION);
    _addAuthority(LEVEL_ONE);
    _addAuthority(LEVEL_TWO);
    _addAuthority(LEVEL_THREE);
  }

  // ======================================================
  // MODIFIERS
  // ======================================================

  /**
   *
   *
   * @dev onlyLevelOneAdmin - functionality for level one admins
   *
   *
   */
  modifier onlyLevelOneAdmin() {
    if (!isLevelAdmin(_msgSender(), LEVEL_ONE, LEVEL_ONE_KEY)) {
      revert IncorrectAdminLevel(1);
    }
    _;
  }

  /**
   *
   *
   * @dev onlyLevelTwoAdmin - functionality for level two admins
   *
   *
   */
  modifier onlyLevelTwoAdmin() {
    if (!isLevelAdmin(_msgSender(), LEVEL_TWO, LEVEL_TWO_KEY)) {
      revert IncorrectAdminLevel(2);
    }
    _;
  }

  /**
   *
   *
   * @dev onlyLevelThreeAdmin - functionality for level three admins
   *
   *
   */
  modifier onlyLevelThreeAdmin() {
    if (!isLevelAdmin(_msgSender(), LEVEL_THREE, LEVEL_THREE_KEY)) {
      revert IncorrectAdminLevel(3);
    }
    _;
  }

  // ======================================================
  // GET DELEGATIONS
  // ======================================================

  /**
   *
   *
   * @dev getDelegationRecord - return the delegation record object for
   * the provided delegationKey argument
   *
   * @param delegationKey_ The address key for this delegation
   * @return DelegationRecord The delegation record for the passed key
   *
   *
   */
  function getDelegationRecord(address delegationKey_)
    external
    view
    returns (DelegationRecord memory)
  {
    return (_delegationRecord[delegationKey_]);
  }

  /**
   *
   *
   * @dev isValidDelegation - returns whether the arguments passed
   * result in a valid delegation
   *
   * @param hot_ The hot address for the delegation
   * @param cold_ The cold address for the delegation
   * @param collection_ The collection for the delegation. Note that address(0)
   * is passed for global delegations
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return isValid_ Whether this is valid (true) or not (false)
   *
   *
   */
  function isValidDelegation(
    address hot_,
    address cold_,
    address collection_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  ) external view returns (bool isValid_) {
    (, isValid_) = _getAddresses(
      hot_,
      collection_,
      usageType_,
      includeSecondary_,
      includeRental_,
      cold_
    );
    return (isValid_);
  }

  /**
   *
   *
   * @dev getAddresses - Get all currently valid addresses for a hot address.
   * - Pass in address(0) to return records that are for ALL collections
   * - Pass in a collection address to get records for just that collection
   * - Usage type must be supplied. Only records that match usage type will be returned
   * @param hot_ The hot address for the delegation
   * @param collection_ The collection for the delegation. Note that address(0)
   * is passed for global delegations
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return addresses_ An array of addresses valid for the passed arguments
   *
   *
   */
  function getAddresses(
    address hot_,
    address collection_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  ) public view returns (address[] memory addresses_) {
    (addresses_, ) = _getAddresses(
      hot_,
      collection_,
      usageType_,
      includeSecondary_,
      includeRental_,
      address(0)
    );
    return (addresses_);
  }

  /**
   *
   *
   * @dev _getAddresses - Get all currently valid addresses for a hot address.
   * - Pass in address(0) to return records that are for ALL collections
   * - Pass in a collection address to get records for just that collection
   * - Usage type must be supplied. Only records that match usage type will be returned
   *
   * @param hot_ The hot address for the delegation
   * @param collection_ The collection for the delegation. Note that address(0)
   * is passed for global delegations
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   * @param targetCold_ If we are looking for a specifc cold address this will be used
   * to determine the result of the isValid_ return parameter
   *
   * @return addresses_ An array of addresses valid for the passed arguments
   * @return isValid_ Whether this is valid (true) or not (false)
   *
   *
   */
  function _getAddresses(
    address hot_,
    address collection_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_,
    address targetCold_
  ) internal view returns (address[] memory addresses_, bool isValid_) {
    if (
      _includesUsageTypeOrAll(
        usageType_,
        _delegationTypesForAddress[
          _getDelegationTypeHash(hot_, collection_, false, 0)
        ]
      ) ||
      (collection_ != address(0) &&
        _includesUsageTypeOrAll(
          usageType_,
          _delegationTypesForAddress[
            _getDelegationTypeHash(hot_, address(0), false, 0)
          ]
        ))
    ) {
      // OK, so the hot_ address has delegated to another address for usage type for this
      // collection (or globally) for the PRIMARY. This means that
      // balances associated with the hot_ address will be represented on OTHER addresse(s) for PRIMARY
      // usage.

      // As 'rental' is also a primary scoped item we can only proceed if we were including secondary
      // delegations, and are therefore OK with multiple return results across the register for a
      // collection / usage type combination:
      if (!includeSecondary_) {
        return (new address[](0), false);
      }
    }

    uint256 delegationCount;
    uint256 addedAddressesCount;

    (
      addresses_,
      delegationCount,
      addedAddressesCount,
      isValid_
    ) = _getDelegations(
      DelegationCheckAddresses(hot_, targetCold_, collection_),
      usageType_,
      includeSecondary_,
      includeRental_
    );

    if (isValid_) {
      return (addresses_, isValid_);
    }

    if (delegationCount > addedAddressesCount) {
      assembly {
        let decrease := sub(delegationCount, addedAddressesCount)
        mstore(addresses_, sub(mload(addresses_), decrease))
      }
    }

    if (includeLegacy && addresses_.length == 1) {
      // One result is the calling hot (no delegations), so check legacy for ONE cold address delegation:

      address[] memory legacyRecords = LEGACY_REGISTER.getAddresses(
        hot_,
        collection_,
        usageType_,
        includeSecondary_,
        includeRental_
      );

      if (legacyRecords.length > 1) {
        // See if this cold has an entry on this register, as if it does it has been overriden
        // and won't be returned from the legacy register:

        if (
          _hasExistingDelegation(
            legacyRecords[1],
            address(0),
            false,
            0,
            usageType_
          ) ||
          _hasExistingDelegation(
            legacyRecords[1],
            collection_,
            false,
            0,
            usageType_
          )
        ) {
          // We have an overriding delegation on this register, do not include this
          return (addresses_, false);
        }

        if (legacyRecords[1] == targetCold_) {
          return (addresses_, true);
        }

        addresses_ = new address[](2);
        addresses_[0] = legacyRecords[0];
        addresses_[1] = legacyRecords[1];
      }
    }

    return (addresses_, false);
  }

  /**
   *
   *
   * @dev _hasExistingDelegation - return if the passed parameters resolve to an existing
   * delegaiton on this register
   *
   * @param cold_ The cold address for the delegation
   * @param collection_ The collection for the delegation. Note that address(0)
   * is passed for global delegations
   * @param tokenBased_ If this is a token based delegation (true) or not (false)
   * @param tokenId_ The token ID for token based delegations
   * @param usageType_ The usage type for the delegation
   *
   * @return bool If the passet arguments resolve to an existing delegation (true) ot
   * not (false)
   *
   *
   */
  function _hasExistingDelegation(
    address cold_,
    address collection_,
    bool tokenBased_,
    uint256 tokenId_,
    uint256 usageType_
  ) internal view returns (bool) {
    // Get the delegation types for this cold address with the collection scope
    uint256 currentDelegationTypes = _delegationTypesForAddress[
      _getDelegationTypeHash(cold_, collection_, tokenBased_, tokenId_)
    ];

    // Check if this cold address has delegated with collection scope for this usage type:
    if (
      currentDelegationTypes != 0 &&
      ((usageType_ == 1) ||
        _includesUsageTypeOrAll(usageType_, currentDelegationTypes))
    ) {
      // There is an existing delegation
      return (true);
    } else {
      // There is no existing delegation
      return (false);
    }
  }

  /**
   *
   *
   * @dev _getDelegations - Get delegations for the passed arguments
   *
   * @param checkAddresses_ An object holding the hot, cold and collection
   * addresses for this query
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return addresses_ The valid return addresses for this query
   * @return delegationCount_ How many delegations were queried
   * @return addedAddressesCount_ How many addresses were added to the return array
   * @return isValid_ If we are looking for a specific cold address this will
   * provide that information.
   *
   *
   *
   */
  function _getDelegations(
    DelegationCheckAddresses memory checkAddresses_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    internal
    view
    returns (
      address[] memory addresses_,
      uint256 delegationCount_,
      uint256 addedAddressesCount_,
      bool isValid_
    )
  {
    if (checkAddresses_.targetCollection == address(0)) {
      // We will only be looking for global delegations, collection level delegations will
      // not be relevant:
      return
        _getGlobalDelegations(
          checkAddresses_,
          usageType_,
          includeSecondary_,
          includeRental_
        );
    } else {
      return
        _getCollectionDelegations(
          checkAddresses_,
          usageType_,
          includeSecondary_,
          includeRental_
        );
    }
  }

  /**
   *
   *
   * @dev _getGlobalDelegations - Get global delegations for the passed arguments
   *
   * @param checkAddresses_ An object holding the hot, cold and collection
   * addresses for this query
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return addresses_ The valid return addresses for this query
   * @return possibleCount_ How many delegations were queried
   * @return actualCount_ How many addresses were added to the return array
   * @return isValid_ If we are looking for a specific cold address this will
   * provide that information.
   *
   *
   */
  function _getGlobalDelegations(
    DelegationCheckAddresses memory checkAddresses_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    internal
    view
    returns (
      address[] memory addresses_,
      uint256 possibleCount_,
      uint256 actualCount_,
      bool isValid_
    )
  {
    EnumerableSet.AddressSet storage delegationsToCheck = _hotToDelegation[
      _hotMappingKey(checkAddresses_.hot)
    ];

    unchecked {
      possibleCount_ = delegationsToCheck.length() + 1;

      addresses_ = new address[](possibleCount_);

      addresses_[0] = checkAddresses_.hot;

      actualCount_++;
    }

    for (uint256 i = 0; i < (possibleCount_ - 1); i++) {
      DelegationRecord memory currentDelegation = _delegationRecord[
        delegationsToCheck.at(i)
      ];

      if (
        // Only proceeed if this ISN'T a collection specific delegation:
        (_collectionSpecific(currentDelegation.controlInteger)) ||
        (
          !_delegationIsValid(
            DelegationCheckAddresses(
              checkAddresses_.hot,
              currentDelegation.cold,
              address(0)
            ),
            DelegationCheckClasses(includeSecondary_, includeRental_, false),
            currentDelegation.controlInteger,
            usageType_,
            0,
            ValidityDates(
              currentDelegation.startDate,
              currentDelegation.endDate
            ),
            delegationsToCheck.at(i)
          )
        )
      ) {
        continue;
      }

      if (currentDelegation.cold == checkAddresses_.cold) {
        return (addresses_, 0, 0, true);
      }

      // Made it here. Add it:
      addresses_[actualCount_] = currentDelegation.cold;

      unchecked {
        actualCount_++;
      }
    }

    return (addresses_, possibleCount_, actualCount_, false);
  }

  /**
   *
   *
   * @dev _getCollectionDelegations - get collection level delegations for the
   * passed arguments
   *
   * @param checkAddresses_ An object holding the hot, cold and collection
   * addresses for this query
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return addresses_ The valid return addresses for this query
   * @return possibleCount_ How many delegations were queried
   * @return actualCount_ How many addresses were added to the return array
   * @return isValid_ If we are looking for a specific cold address this will
   * provide that information.
   *
   *
   */
  function _getCollectionDelegations(
    DelegationCheckAddresses memory checkAddresses_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    internal
    view
    returns (
      address[] memory addresses_,
      uint256 possibleCount_,
      uint256 actualCount_,
      bool isValid_
    )
  {
    EnumerableSet.AddressSet storage delegationsToCheck = _hotToDelegation[
      _hotMappingKey(checkAddresses_.hot)
    ];

    unchecked {
      possibleCount_ = delegationsToCheck.length() + 1;

      addresses_ = new address[](possibleCount_);

      addresses_[0] = checkAddresses_.hot;

      actualCount_++;
    }

    // Slightly more complicated, as we have these possibilities:
    // 1) If the collection on the delegation matches the collection we have been
    // asked about then this is valid.
    // 2) If there is a collection on the delegation and it DOESN'T match the
    // collection we have been asked about then it is invalid.
    // 3) If there is no collection on the delegation (i.e. it is global) AND
    // there is no collection level delegation for the cold address it is valid
    // 4) If there is no collection on the delegation (i.e. it is global) AND
    // there IS a collection level delegation for the cold address it is INVALID,
    // as the specific collection delegation 'trumps' the global delegation.

    for (uint256 i = 0; i < (possibleCount_ - 1); i++) {
      DelegationRecord memory currentDelegation = _delegationRecord[
        delegationsToCheck.at(i)
      ];

      // Is this token specific? If so continue, as we do not return whole
      // address based delegations for token specific delegations. They can be
      // access through the beneficiaryOf method
      if (
        _delegationScope(currentDelegation.controlInteger) ==
        DelegationScope.token
      ) {
        continue;
      }

      address collectionToCheck = address(0);

      // Is this a collection specific delegation?
      if (_collectionSpecific(currentDelegation.controlInteger)) {
        collectionToCheck = checkAddresses_.targetCollection;
      } else {
        // Check if the cold address has a collection specific delegation for this collection:
        // Only proceed if there ISN'T a collection specific delegation for this usage type:
        if (
          _hasCollectionDelegation(
            currentDelegation.cold,
            checkAddresses_.targetCollection,
            usageType_
          )
        ) {
          continue;
        }
      }

      if (
        !_delegationIsValid(
          DelegationCheckAddresses(
            checkAddresses_.hot,
            currentDelegation.cold,
            collectionToCheck
          ),
          DelegationCheckClasses(includeSecondary_, includeRental_, false),
          currentDelegation.controlInteger,
          usageType_,
          0,
          ValidityDates(currentDelegation.startDate, currentDelegation.endDate),
          delegationsToCheck.at(i)
        )
      ) {
        continue;
      }

      if (currentDelegation.cold == checkAddresses_.cold) {
        return (addresses_, 0, 0, true);
      }

      // Made it here. Add it:
      addresses_[actualCount_] = currentDelegation.cold;

      unchecked {
        actualCount_++;
      }
    }
    return (addresses_, possibleCount_, actualCount_, false);
  }

  /**
   *
   *
   * @dev _hasCollectionDelegation - Return if this cold address has a
   * collection level delegation
   *
   * @param cold_ The cold address for the delegation
   * @param collection_ The collection for the delegation.
   * @param usageType_ The usage type for the delegation
   *
   * @return bool If this has a collection level delegation (true) or not (false)
   *
   *
   */
  function _hasCollectionDelegation(
    address cold_,
    address collection_,
    uint256 usageType_
  ) internal view returns (bool) {
    return (
      _includesUsageTypeOrAll(
        usageType_,
        _delegationTypesForAddress[
          _getDelegationTypeHash(cold_, collection_, false, 0)
        ]
      )
    );
  }

  /**
   *
   *
   * @dev beneficiaryBalanceOf: Returns the beneficiary balance
   *
   * @param queryAddress_ The beneficiary address that we are querying
   * @param contractAddress_ The contract we are checking balances on
   * @param usageType_ The usage type for the delegation
   * @param erc1155_ If this is an 1155 contract
   * @param id_ If we have an 1155 contract to query this has the token Id
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return balance_ The balance for this beneficiary
   *
   *
   */
  function beneficiaryBalanceOf(
    address queryAddress_,
    address contractAddress_,
    uint256 usageType_,
    bool erc1155_,
    uint256 id_,
    bool includeSecondary_,
    bool includeRental_
  ) external view returns (uint256 balance_) {
    address[] memory delegatedAddresses = getAddresses(
      queryAddress_,
      contractAddress_,
      usageType_,
      includeSecondary_,
      includeRental_
    );

    if (!erc1155_) {
      for (uint256 i = 0; i < delegatedAddresses.length; ) {
        unchecked {
          balance_ += (
            IERC721(contractAddress_).balanceOf(delegatedAddresses[i])
          );

          i++;
        }
      }
    } else {
      for (uint256 i = 0; i < delegatedAddresses.length; ) {
        unchecked {
          balance_ += (
            IERC1155(contractAddress_).balanceOf(delegatedAddresses[i], id_)
          );

          i++;
        }
      }
    }

    return (balance_);
  }

  /**
   *
   *
   * @dev beneficiaryOf - The beneficiary of for a token, traversing all levels of the
   * register
   *
   * @param collection_ The contract we are checking beneficiaries on
   * @param tokenId_ The token Id we are querying
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return primaryBeneficiary_ The primary beneficiary - there can be only one
   * @return secondaryBeneficiaries_ An array of secondary beneficiaries i.e. thos
   * referenced on non-atomic secondary delegations
   *
   *
   */
  function beneficiaryOf(
    address collection_,
    uint256 tokenId_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    external
    view
    returns (
      address primaryBeneficiary_,
      address[] memory secondaryBeneficiaries_
    )
  {
    address owner = IERC721(collection_).ownerOf(tokenId_);

    (
      primaryBeneficiary_,
      secondaryBeneficiaries_
    ) = _getBeneficiaryByTokenDelegation(
      owner,
      collection_,
      tokenId_,
      usageType_,
      includeSecondary_,
      includeRental_
    );

    // If the benficiary is still the token owner we now want to check if that
    // owner has a delegation in place for this usageType
    if (primaryBeneficiary_ == address(0)) {
      (
        primaryBeneficiary_,
        secondaryBeneficiaries_
      ) = _getBeneficiaryByGlobalOrCollectionDelegation(
        owner,
        collection_,
        usageType_,
        [includeSecondary_, includeRental_]
      );
    }

    if (primaryBeneficiary_ == address(0)) {
      primaryBeneficiary_ = owner;
    }

    return (primaryBeneficiary_, secondaryBeneficiaries_);
  }

  /**
   *
   *
   * @dev _getBeneficiaryByTokenDelegation - get the beneficiary for a token by
   * valid token delegations
   *
   * @param owner_ The owner of the token
   * @param collection_ The contract we are checking beneficiaries on
   * @param tokenId_ The token Id we are querying
   * @param usageType_ The usage type for the delegation
   * @param includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * @param includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return primaryBeneficiary_ The primary beneficiary - there can be only one
   * @return secondaryBeneficiaries_ An array of secondary beneficiaries i.e. thos
   * referenced on non-atomic secondary delegations
   *
   *
   */
  function _getBeneficiaryByTokenDelegation(
    address owner_,
    address collection_,
    uint256 tokenId_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    internal
    view
    returns (
      address primaryBeneficiary_,
      address[] memory secondaryBeneficiaries_
    )
  {
    EnumerableSet.AddressSet storage ownedTokenDelegations = _tokenToDelegation[
      _getTokenDelegationHash(owner_, collection_, tokenId_)
    ];

    // We have a local object with an enumerable set of delegation key hashes
    uint256 tokenDelegationCount = ownedTokenDelegations.length();
    uint256 actualCount;

    secondaryBeneficiaries_ = new address[](tokenDelegationCount);

    for (uint256 i = 0; i < tokenDelegationCount; i++) {
      DelegationRecord memory currentDelegation = _delegationRecord[
        ownedTokenDelegations.at(i)
      ];

      if (
        (!_delegationIsValid(
          DelegationCheckAddresses(currentDelegation.hot, owner_, collection_),
          DelegationCheckClasses(includeSecondary_, includeRental_, true),
          currentDelegation.controlInteger,
          usageType_,
          tokenId_,
          ValidityDates(currentDelegation.startDate, currentDelegation.endDate),
          ownedTokenDelegations.at(i)
        ) ||
          (_delegationRecord[ownedTokenDelegations.at(i)].status ==
            DelegationStatus.pending))
      ) {
        continue;
      }

      if (
        _delegationClass(currentDelegation.controlInteger) !=
        DelegationClass.secondary
      ) {
        primaryBeneficiary_ = currentDelegation.hot;
      } else {
        // Made it here. Add it:
        secondaryBeneficiaries_[actualCount] = currentDelegation.hot;

        unchecked {
          actualCount++;
        }
      }
    }

    if (tokenDelegationCount > actualCount) {
      assembly {
        let decrease := sub(tokenDelegationCount, actualCount)
        mstore(
          secondaryBeneficiaries_,
          sub(mload(secondaryBeneficiaries_), decrease)
        )
      }
    }

    return (primaryBeneficiary_, secondaryBeneficiaries_);
  }

  /**
   *
   *
   * @dev _getBeneficiaryByGlobalOrCollectionDelegation - get token Beneficiary by
   * colleciton or global delegation
   *
   * @param owner_ The owner of the token
   * @param collection_ The contract we are checking beneficiaries on
   * @param usageType_ The usage type for the delegation
   * @param inclusionParams_ Placed in an array to reduce local variable count. These are:
   * [0] includeSecondary_ If this is set to true the register will also check
   * secondary delegations (i.e. non-atomic delegations)
   * [1] includeRental_ If this is set to true the register will also check
   * rental delegations. Note that rental delegations ARE atomic.
   *
   * @return primaryBeneficiary_ The primary beneficiary - there can be only one
   * @return secondaryBeneficiaries_ An array of secondary beneficiaries i.e. thos
   * referenced on non-atomic secondary delegations
   *
   *
   */
  function _getBeneficiaryByGlobalOrCollectionDelegation(
    address owner_,
    address collection_,
    uint256 usageType_,
    bool[2] memory inclusionParams_
  )
    internal
    view
    returns (
      address primaryBeneficiary_,
      address[] memory secondaryBeneficiaries_
    )
  {
    EnumerableSet.AddressSet storage ownerDelegations = _coldToDelegation[
      _coldMappingKey(owner_)
    ];

    uint256 actualCount;

    secondaryBeneficiaries_ = new address[](ownerDelegations.length());

    for (uint256 i = 0; i < ownerDelegations.length(); i++) {
      DelegationRecord memory currentDelegation = _delegationRecord[
        ownerDelegations.at(i)
      ];

      address collectionToCheck = address(0);

      if (_collectionSpecific(currentDelegation.controlInteger)) {
        collectionToCheck = collection_;
      }

      if (
        !_delegationIsValid(
          DelegationCheckAddresses(
            currentDelegation.hot,
            owner_,
            collectionToCheck
          ),
          DelegationCheckClasses(
            inclusionParams_[0],
            inclusionParams_[1],
            false
          ),
          currentDelegation.controlInteger,
          usageType_,
          0,
          ValidityDates(currentDelegation.startDate, currentDelegation.endDate),
          ownerDelegations.at(i)
        ) ||
        // Check if the cold address has a collection specific delegation for this collection:
        // Only proceed if there ISN'T a collection specific delegation for this usage type:
        (!_collectionSpecific(currentDelegation.controlInteger) &&
          (
            _includesUsageTypeOrAll(
              usageType_,
              _delegationTypesForAddress[
                _getDelegationTypeHash(owner_, collection_, false, 0)
              ]
            )
          ))
      ) {
        continue;
      }

      if (
        _delegationClass(currentDelegation.controlInteger) !=
        DelegationClass.secondary
      ) {
        primaryBeneficiary_ = currentDelegation.hot;
      } else {
        // Made it here. Add it:
        secondaryBeneficiaries_[actualCount] = currentDelegation.hot;

        unchecked {
          actualCount++;
        }
      }
    }

    return (primaryBeneficiary_, secondaryBeneficiaries_);
  }

  /**
   *
   *
   * @dev delegationFromColdExists - check a cold delegation exists
   *
   * @param cold_ The cold address we are querying
   * @param delegationKey_ The specific address key for a delegation
   *
   * @return bool if this exists (true) or not (false)
   *
   *
   */
  function delegationFromColdExists(address cold_, address delegationKey_)
    public
    view
    returns (bool)
  {
    if (!_coldToDelegation[_coldMappingKey(cold_)].contains(delegationKey_)) {
      return (false);
    }

    return (true);
  }

  /**
   *
   *
   * @dev delegationFromHotExists - check a hot delegation exists
   *
   * @param hot_ The hot address we are querying
   * @param delegationKey_ The specific address key for a delegation
   *
   * @return bool if this exists (true) or not (false)
   *
   *
   */
  function delegationFromHotExists(address hot_, address delegationKey_)
    public
    view
    returns (bool)
  {
    if (!_hotToDelegation[_hotMappingKey(hot_)].contains(delegationKey_)) {
      return (false);
    }

    return (true);
  }

  /**
   *
   *
   * @dev getAllForHot - Get all delegations at a hot address, formatted nicely
   *
   * @param hot_ The hot address we are querying
   *
   * @return DelegationReport[] An array of delegation report objects providing
   * full details of all delegations for this hot address
   *
   *
   */
  function getAllForHot(address hot_)
    external
    view
    returns (DelegationReport[] memory)
  {
    EnumerableSet.AddressSet storage hotDelegations = _hotToDelegation[
      _hotMappingKey(hot_)
    ];

    uint256 delegationCount = hotDelegations.length();

    DelegationReport[] memory allForHot = new DelegationReport[](
      delegationCount
    );

    for (uint256 i = 0; i < delegationCount; ) {
      address delegationKey = hotDelegations.at(i);

      DelegationRecord memory currentDelegation = _delegationRecord[
        delegationKey
      ];

      allForHot[i] = _getAllReportLine(
        hot_,
        currentDelegation.cold,
        currentDelegation.controlInteger,
        delegationFromColdExists(currentDelegation.cold, delegationKey),
        currentDelegation.startDate,
        currentDelegation.endDate,
        delegationKey,
        currentDelegation.status
      );

      unchecked {
        i++;
      }
    }

    return (allForHot);
  }

  /**
   *
   *
   * @dev getAllForCold - Get all delegations at a cold address, formatted nicely
   *
   * @param cold_ The cold address we are querying
   *
   * @return DelegationReport[] An array of delegation report objects providing
   * full details of all delegations for this cold address
   *
   *
   */
  function getAllForCold(address cold_)
    external
    view
    returns (DelegationReport[] memory)
  {
    EnumerableSet.AddressSet storage coldDelegations = _coldToDelegation[
      _coldMappingKey(cold_)
    ];

    uint256 delegationCount = coldDelegations.length();

    DelegationReport[] memory allForCold = new DelegationReport[](
      delegationCount
    );

    for (uint256 i = 0; i < delegationCount; ) {
      address delegationKey = coldDelegations.at(i);

      DelegationRecord memory currentDelegation = _delegationRecord[
        delegationKey
      ];

      allForCold[i] = _getAllReportLine(
        currentDelegation.hot,
        cold_,
        currentDelegation.controlInteger,
        delegationFromHotExists(currentDelegation.hot, delegationKey),
        currentDelegation.startDate,
        currentDelegation.endDate,
        delegationKey,
        currentDelegation.status
      );

      unchecked {
        i++;
      }
    }

    return (allForCold);
  }

  /**
   *
   *
   * @dev _getAllReportLine - Get a line for the All report
   *
   * @param hot_ The hot address we are querying
   * @param cold_ The cold address we are querying
   * @param controlInteger_ The control integer for this record
   * @param bilaterallyValid_ If this entry has a delegation record from the
   * hot to the cold AND the cold to the hot. This may not be the case, as a result
   * of revoke all transactions
   * @param startDate_ The start date of the delegation
   * @param endDate_ The end date of the delegation
   * @param delegationKey_ The address key for this delegation
   * @param status_ The status of this delegation
   *
   * @return DelegationReport An object providing full details of this delegation
   *
   *
   */
  function _getAllReportLine(
    address hot_,
    address cold_,
    uint96 controlInteger_,
    bool bilaterallyValid_,
    uint40 startDate_,
    uint40 endDate_,
    address delegationKey_,
    DelegationStatus status_
  ) internal view returns (DelegationReport memory) {
    DelegationMetadata memory currentMetadata = delegationMetadata[
      delegationKey_
    ];

    return
      DelegationReport(
        hot_,
        cold_,
        _delegationScope(controlInteger_),
        _delegationClass(controlInteger_),
        _delegationTimeLimit(controlInteger_),
        currentMetadata.collection,
        currentMetadata.tokenId,
        startDate_,
        endDate_,
        !_hasDates(controlInteger_) || _datesAreValid(startDate_, endDate_),
        bilaterallyValid_,
        _delegationScope(controlInteger_) != DelegationScope.token ||
          IERC721(currentMetadata.collection).ownerOf(
            currentMetadata.tokenId
          ) ==
          cold_,
        _decodedUsageTypes(controlInteger_),
        delegationKey_,
        controlInteger_,
        currentMetadata.data,
        status_
      );
  }

  // ======================================================
  // MAKE DELEGATIONS
  // ======================================================

  /**
   *
   *
   * @dev makeDelegation - A direct call to setup a new proxy record
   *
   * @param hot_ The hot address we are querying
   * @param cold_ The cold address we are querying
   * @param targetAddresses_ An array of addresses to make delegations for. These
   * should be collection addresses, other contract addresses or address(0) for global
   * @param tokenId_ If this is a token level delegation this should be provided
   * @param tokenDelegation_ If this is a token delegation (true) or not (false)
   * @param usageTypes_ An array of usage types for this delegation
   * @param startDate_ The start date of the delegation
   * @param endDate_ The end date of the delegation
   * @param providerCode_ If this delegation has been introduced through a provider this
   * should hold their unique code
   * @param delegationClass_ The class of the delegation: 0 = primary, 1 = secondary,
   * 3 = rental
   * @param subDelegateKey_ Provide the subdelegate key is performing this delegation from a
   * valid subdelegate
   * @param data_ Additional data to include in the delegation e.g. a hyperlink or details
   * of an IP licensing agreement
   *
   *
   */
  function makeDelegation(
    address hot_,
    address cold_,
    address[] memory targetAddresses_,
    uint256 tokenId_,
    bool tokenDelegation_,
    uint8[] memory usageTypes_,
    uint40 startDate_,
    uint40 endDate_,
    uint16 providerCode_,
    DelegationClass delegationClass_, //0 = primary, 1 = secondary, 2 = rental
    uint96 subDelegateKey_,
    bytes memory data_
  ) external payable {
    if (msg.value != _proxyRegisterFee) revert IncorrectProxyRegisterFee();

    Delegation memory newDelegation = Delegation(
      hot_,
      cold_,
      targetAddresses_,
      tokenId_,
      tokenDelegation_,
      usageTypes_,
      startDate_,
      endDate_,
      providerCode_,
      delegationClass_,
      subDelegateKey_,
      data_,
      DelegationStatus.live
    );

    _makeDelegation(newDelegation, _msgSender());
  }

  /**
   *
   *
   * @dev _makeDelegation - perform unified processing for making delegations
   *
   * @param newDelegation_ The new delegation object containing all details of the
   * delegation
   * @param caller_ The address that has made this call
   *
   *
   */
  function _makeDelegation(Delegation memory newDelegation_, address caller_)
    internal
  {
    for (uint256 i = 0; i < newDelegation_.targetAddresses.length; ) {
      _initialValidation(
        newDelegation_.hot,
        newDelegation_.cold,
        newDelegation_.subDelegateKey,
        caller_
      );

      uint96 controlInteger = _constructAndCheckControlInteger(
        newDelegation_.cold,
        newDelegation_.targetAddresses[i],
        newDelegation_.tokenId,
        newDelegation_.tokenDelegation,
        newDelegation_.usageTypes,
        newDelegation_.startDate,
        newDelegation_.endDate,
        newDelegation_.delegationClass
      );

      // Create the delegation key:
      address delegationKey = getDelegationKey(
        newDelegation_.hot,
        newDelegation_.cold,
        newDelegation_.targetAddresses[i],
        newDelegation_.tokenId,
        newDelegation_.tokenDelegation,
        controlInteger,
        newDelegation_.startDate,
        newDelegation_.endDate
      );

      if (newDelegation_.tokenDelegation) {
        // Map the token to the delegation so that it can retrieve and check the details
        // later. Note that token delegations are mapped in a different way to global
        // and collection delegations.

        // Mapping is the cold wallet (current owner), with the contract and token Id

        _tokenToDelegation[
          _getTokenDelegationHash(
            newDelegation_.cold,
            newDelegation_.targetAddresses[i],
            newDelegation_.tokenId
          )
        ].add(delegationKey);
      }

      if (
        newDelegation_.targetAddresses[i] != address(0) ||
        newDelegation_.data.length != 0
      ) {
        delegationMetadata[delegationKey] = DelegationMetadata(
          newDelegation_.targetAddresses[i],
          newDelegation_.tokenId,
          newDelegation_.data
        );
      }

      if (newDelegation_.status == DelegationStatus.pending) {
        pendingPayments[newDelegation_.cold].push(delegationKey);
      }

      // Save the delegation for the hot:
      _hotToDelegation[_hotMappingKey(newDelegation_.hot)].add(delegationKey);

      // Save the delegation for the cold:
      _coldToDelegation[_coldMappingKey(newDelegation_.cold)].add(
        delegationKey
      );

      _delegationRecord[delegationKey] = DelegationRecord(
        newDelegation_.hot,
        uint96(controlInteger),
        newDelegation_.cold,
        newDelegation_.startDate,
        newDelegation_.endDate,
        newDelegation_.status
      );

      _emitDelegationMade(newDelegation_, i);

      unchecked {
        i++;
      }
    }

    if (address(rewardToken) != address(0)) {
      if (newDelegation_.status == DelegationStatus.live) {
        rewardToken.emitToken(
          _msgSender(),
          rewardRate * newDelegation_.targetAddresses.length
        );
      }
    }
  }

  /**
   *
   *
   * @dev _emitDelegationMade - Emit the event for a new delegation
   *
   * @param newDelegation_ The new delegation object containing all details of the
   * delegation
   * @param index_ The contract / collection address from the addresses array that
   * has been delegated
   *
   *
   */
  function _emitDelegationMade(Delegation memory newDelegation_, uint256 index_)
    internal
  {
    emit DelegationMade(
      newDelegation_.hot,
      newDelegation_.cold,
      newDelegation_.targetAddresses[index_],
      newDelegation_.tokenId,
      newDelegation_.tokenDelegation,
      newDelegation_.usageTypes,
      newDelegation_.startDate,
      newDelegation_.endDate,
      newDelegation_.providerCode,
      newDelegation_.delegationClass,
      newDelegation_.subDelegateKey,
      newDelegation_.data,
      newDelegation_.status
    );
  }

  /**
   *
   *
   * @dev _initialValidation - Initial validation of a make delegation call
   *
   * @param hot_ The hot address for the delegation
   * @param cold_ The cold address for the delegation
   * @param subDelegateKey_ If this is a subdelegate called delegation this will
   * include the subdelegate key
   * @param caller_ The caller on this transaction
   *
   *
   */
  function _initialValidation(
    address hot_,
    address cold_,
    uint96 subDelegateKey_,
    address caller_
  ) internal view {
    if (_hotAddressIsLocked(hot_, cold_)) {
      revert HotAddressIsLockedAndCannotBeDelegatedTo();
    }

    _delegatedAuthorityCheck(caller_, cold_, subDelegateKey_);
  }

  /**
   *
   *
   * @dev _getTokenDelegationHash - create a token delegation hash
   *
   * @param cold_ The cold address for the delegation
   * @param collection_ The collection for this delegation hadsh (note is
   * address(0) for global delegations)
   * @param tokenId_ The token Id for the hash
   *
   * @return bytes32 Hash of the arguments
   *
   *
   */
  function _getTokenDelegationHash(
    address cold_,
    address collection_,
    uint256 tokenId_
  ) internal view returns (bytes32) {
    return
      keccak256(
        abi.encodePacked(
          cold_,
          _coldWalletTranche[cold_],
          collection_,
          tokenId_
        )
      );
  }

  /**
   *
   *
   * @dev _constructAndCheckControlInteger - check for overlapping delegations
   * and build the control integer for storage
   *
   * @param cold_ The cold address for the delegation
   * @param collection_ The collection for this delegation hadsh (note is
   * address(0) for global delegations
   * @param tokenId_ The token Id for this delegation (if relevant)
   * @param tokenDelegation_ If this is a token delegation (true) or not (false)
   * @param startDate_ The start date of the delegation
   * @param endDate_ The end date of the delegation
   * @param delegationClass_ The class of the delegation: 0 = primary, 1 = secondary,
   * 3 = rental
   *
   *
   */
  function _constructAndCheckControlInteger(
    address cold_,
    address collection_,
    uint256 tokenId_,
    bool tokenDelegation_,
    uint8[] memory usageTypes_,
    uint40 startDate_,
    uint40 endDate_,
    DelegationClass delegationClass_ //0 = primary, 1 = secondary, 2 = rental
  ) internal returns (uint96 controlInteger_) {
    uint256 usageTypesInteger;

    unchecked {
      // Is this global, collection or token based?
      if (collection_ != address(0)) {
        if (tokenDelegation_) {
          // If a cold is delegating a specific token it HAS to own it
          if (IERC721(collection_).ownerOf(tokenId_) != cold_) {
            revert CannotDelegatedATokenYouDontOwn();
          }
          controlInteger_ += TOKEN_DELEGATION;
        } else {
          controlInteger_ += COLLECTION_DELEGATION;
        }
      }

      // Is this a secondary delegation?
      if (delegationClass_ == DelegationClass.secondary) {
        controlInteger_ += SECONDARY_DELEGATION;
      }

      // Is this a rental delegation?
      if (delegationClass_ == DelegationClass.rental) {
        controlInteger_ += RENTAL_DELEGATION;
      }

      // Is this eternal or time based?
      if (startDate_ + endDate_ != 0) {
        controlInteger_ += TIME_BASED_DELEGATION;
      }
    }

    // Construct control integers, checking that the cold address hasn't already delegated
    // these usage codes to another address.

    for (uint256 i = 0; i < usageTypes_.length; ) {
      // Check for duplication IF this is a primary delegation:

      if (
        delegationClass_ != DelegationClass.secondary &&
        _hasExistingDelegation(
          cold_,
          collection_,
          tokenDelegation_,
          tokenId_,
          usageTypes_[i]
        )
      ) {
        // Uh oh, we have already delegated this type for this:
        revert UsageTypeAlreadyDelegated(usageTypes_[i]);
      }

      unchecked {
        if (usageTypes_[i] == 1) {
          usageTypesInteger += 1;
        } else {
          usageTypesInteger += 1 * (10**(usageTypes_[i] - 1));
        }

        i++;
      }
    }

    // All good? OK, record that this delegation is using these usage types by incrementing
    // the delegation type hash IF this is not a secondary delegation
    unchecked {
      if (delegationClass_ != DelegationClass.secondary) {
        _delegationTypesForAddress[
          _getDelegationTypeHash(cold_, collection_, tokenDelegation_, tokenId_)
        ] += usageTypesInteger;
      }

      controlInteger_ += uint96(usageTypesInteger);
    }

    return (controlInteger_);
  }

  /**
   *
   *
   * @dev _delegationIsValid - Return if a delegation is valid or not
   *
   * @param addresses_ The addresses to be checked (hot, cold and collection)
   * @param classes_ What classes to check (0 = primary, 1 = secondary, 3 = rental)
   * @param controlInteger_ The conrol integer for this delegation
   * @param usageType_ The usage type being checked
   * @param tokenId_ The delegated token Id, if relevant
   * @param dates_ The start and end date of the delegation
   * @param receivedDelegationKey_ A received delegation key to check, if provided
   *
   * @return valid_ If this is valid (true) or not (false)
   *
   *
   */
  function _delegationIsValid(
    DelegationCheckAddresses memory addresses_,
    DelegationCheckClasses memory classes_,
    uint96 controlInteger_,
    uint256 usageType_,
    uint256 tokenId_,
    ValidityDates memory dates_,
    address receivedDelegationKey_
  ) internal view returns (bool valid_) {
    // If this is a secondary delegation only proceed if we have been
    // passed that argument
    if (
      (!classes_.secondary &&
        _delegationClass(controlInteger_) == DelegationClass.secondary) ||
      (!classes_.rental &&
        _delegationClass(controlInteger_) == DelegationClass.rental) ||
      !_includesUsageTypeOrAll(usageType_, controlInteger_)
    ) {
      return (false);
    }

    // Create the delegation key:
    address delegationKey = getDelegationKey(
      addresses_.hot,
      addresses_.cold,
      addresses_.targetCollection,
      tokenId_,
      classes_.token,
      controlInteger_,
      dates_.start,
      dates_.end
    );

    if (
      (!delegationFromColdExists(addresses_.cold, delegationKey)) ||
      (!delegationFromHotExists(addresses_.hot, delegationKey)) ||
      (_delegationRecord[delegationKey].status == DelegationStatus.pending) ||
      (_collectionSpecific(controlInteger_) &&
        (delegationMetadata[delegationKey].collection !=
          addresses_.targetCollection)) ||
      (_hasDates(controlInteger_) &&
        !_datesAreValid(dates_.start, dates_.end)) ||
      (receivedDelegationKey_ != address(0) &&
        receivedDelegationKey_ != delegationKey)
    ) {
      return (false);
    }

    // Made it here. It's valid:
    return (true);
  }

  /**
   *
   *
   * @dev _decodedUsageTypes - decode a control integer into a uint8 array of usage types
   *
   * @param controlInteger_ The conrol integer for this delegation
   *
   * @return usageTypes_ A uint8 array of usage types
   *
   *
   */
  function _decodedUsageTypes(uint256 controlInteger_)
    internal
    pure
    returns (bool[NUMBER_OF_USAGE_TYPES] memory usageTypes_)
  {
    for (uint256 i = 0; i < NUMBER_OF_USAGE_TYPES; ) {
      usageTypes_[i] = _includesUsageType(i + 1, controlInteger_);
      unchecked {
        i++;
      }
    }

    return (usageTypes_);
  }

  /**
   *
   *
   * @dev _hotMappingKey - Hashes the hot address with the current tranch
   *
   * @param hot_ The hot address
   *
   * @return bytes32 A hash of the hot with the current tranche for that hot
   *
   *
   */
  function _hotMappingKey(address hot_) internal view returns (bytes32) {
    return (keccak256(abi.encodePacked(hot_, _hotWalletTranche[hot_])));
  }

  /**
   *
   *
   * @dev _coldMappingKey - Hashes the cold address with the current tranch
   *
   * @param cold_ The cold address
   *
   * @return bytes32 A hash of the cold with the current tranche for that cold
   *
   *
   */
  function _coldMappingKey(address cold_) internal view returns (bytes32) {
    return (keccak256(abi.encodePacked(cold_, _coldWalletTranche[cold_])));
  }

  /**
   *
   *
   * @dev _collectionSpecific - return if delegation is collection specific
   *
   * @param controlInteger_ The control integer being queried
   *
   * @return bool If this is collection specific (or not)
   *
   *
   */
  function _collectionSpecific(uint256 controlInteger_)
    internal
    pure
    returns (bool)
  {
    return (_delegationScope(controlInteger_) == DelegationScope.collection);
  }

  /**
   *
   *
   * @dev _hasDates - return if delegation is date limited
   *
   * @param controlInteger_ The control integer being queried
   *
   * @return bool If this delegation has dates (or not)
   *
   *
   */
  function _hasDates(uint256 controlInteger_) internal pure returns (bool) {
    return (_delegationTimeLimit(controlInteger_) ==
      DelegationTimeLimit.limited);
  }

  /**
   *
   *
   * @dev _delegationClass - returns the type of delegation (primary, secondary or rental)
   *
   * @param controlInteger_ The control integer being queried
   *
   * @return DelegationClass The delegation class (primary, secondary, rental)
   *
   *
   */
  function _delegationClass(uint256 controlInteger_)
    internal
    pure
    returns (DelegationClass)
  {
    if (_controlIntegerValue(26, controlInteger_) == 0) {
      return (DelegationClass.primary);
    }
    if (_controlIntegerValue(26, controlInteger_) == 1) {
      return (DelegationClass.secondary);
    } else {
      return (DelegationClass.rental);
    }
  }

  /**
   *
   *
   * @dev _coldOwnerOrSubDelegate - returns if the passed address is the cold or subdelegate
   * for the cold
   *
   * @param caller_ The calling address
   * @param cold_ The cold address
   * @param controlInteger_ The control integer being queried
   *
   * @return bool If the caller is a subdelegate for this cold (true), or not (false)
   *
   *
   */
  function _coldOwnerOrSubDelegate(
    address caller_,
    address cold_,
    uint96 controlInteger_
  ) internal view returns (bool) {
    if (cold_ == caller_) return (true);

    return (
      _delegationIsValid(
        DelegationCheckAddresses(caller_, cold_, address(0)),
        DelegationCheckClasses(true, true, false),
        controlInteger_,
        SUB_DELEGATION,
        0,
        ValidityDates(0, 0),
        address(0)
      )
    );
  }

  /**
   *
   *
   * @dev _delegationTimeLimit - returns the type of time limit (eternal, limited))
   *
   * @param controlInteger_ The control integer being queried
   *
   * @return DelegationTimeLimit The delegation time limit (eternal or timelimted)
   *
   *
   */
  function _delegationTimeLimit(uint256 controlInteger_)
    internal
    pure
    returns (DelegationTimeLimit)
  {
    if (_controlIntegerValue(27, controlInteger_) == 0) {
      return (DelegationTimeLimit.eternal);
    } else {
      return (DelegationTimeLimit.limited);
    }
  }

  /**
   *
   *
   * @dev _delegationScope - returns the scope of the delegation
   * (0 = global, 1 = collection, 2 = token)
   *
   * @param controlInteger_ The control integer being queried
   *
   * @return DelegationScope The scope of the delegation (0 = global,
   * 1 = collection, 2 = token)
   *
   *
   */
  function _delegationScope(uint256 controlInteger_)
    internal
    pure
    returns (DelegationScope)
  {
    uint256 scope = _controlIntegerValue(28, controlInteger_);

    if (scope == 0) {
      return (DelegationScope.global);
    }
    if (scope == 1) {
      return (DelegationScope.collection);
    } else {
      return (DelegationScope.token);
    }
  }

  /**
   *
   *
   * @dev _datesAreValid - check if the passed dates are valid
   *
   * @param startDate_ The start date of the delegation
   * @param endDate_ The end date of the delegation
   *
   * @return bool If these dates are valid
   *
   *
   */
  function _datesAreValid(uint256 startDate_, uint256 endDate_)
    internal
    view
    returns (bool)
  {
    return (startDate_ < block.timestamp && endDate_ > block.timestamp);
  }

  /**
   *
   *
   * @dev _includesUsageType - check if this includes a given usage type
   *
   * @param usageType_ The usage type we are interested in
   * @param controlInteger_ The control integer being queried
   *
   * @return bool If the control integer includes the usage type
   *
   *
   */
  function _includesUsageType(uint256 usageType_, uint256 controlInteger_)
    internal
    pure
    returns (bool)
  {
    return (_controlIntegerIsTrue(usageType_, controlInteger_));
  }

  /**
   *
   *
   * @dev _includesUsageTypeOrAll - check if this includes a given usage type or is for all
   *
   * @param usageType_ The usage type we are interested in
   * @param controlInteger_ The control integer being queried
   *
   * @return bool If the control integer includes the usage type OR all
   *
   *
   */
  function _includesUsageTypeOrAll(uint256 usageType_, uint256 controlInteger_)
    internal
    pure
    returns (bool)
  {
    // Sub delegation type ALWAYS has to match, it is not included in 'all'
    if (
      usageType_ != SUB_DELEGATION &&
      _controlIntegerIsTrue(ALL_DELEGATION, controlInteger_)
    ) {
      return (true);
    } else {
      return (_controlIntegerIsTrue(usageType_, controlInteger_));
    }
  }

  /**
   *
   *
   * @dev getDelegationKey - get the link hash to the delegation metadata
   *
   * @param hot_ The hot address we are querying
   * @param cold_ The cold address we are querying
   * @param targetAddress_ The collection or contract for the scope of the delegation
   * @param tokenId_ The token ID for token delegations
   * @param tokenDelegation_ A bool to indicate this is a token delegation
   * @param controlInteger_ The control integer for this record
   * @param startDate_ The start date of the delegation
   * @param endDate_ The end date of the delegation
   *
   * @return address The delegation key
   *
   *
   */
  function getDelegationKey(
    address hot_,
    address cold_,
    address targetAddress_,
    uint256 tokenId_,
    bool tokenDelegation_,
    uint96 controlInteger_,
    uint40 startDate_,
    uint40 endDate_
  ) public pure returns (address) {
    return (
      address(
        uint160(
          uint256(
            keccak256(
              abi.encodePacked(
                hot_,
                cold_,
                targetAddress_,
                tokenId_,
                tokenDelegation_,
                controlInteger_,
                startDate_,
                endDate_
              )
            )
          )
        )
      )
    );
  }

  /**
   *
   *
   * @dev _getDelegationTypeHash - get the hash that points to what delegations
   * this cold has already made, either for a token, targetAddress (collection),
   * or for all (using address(0))
   *
   * @param cold_ The cold address we are querying
   * @param collection_ The collection or contract for the scope of the delegation
   * @param tokenBased_ A bool to indicate this is a token delegation
   * @param tokenId_ The token ID for token delegations
   *
   * @return bytes32 The delegation type hash
   *
   *
   */
  function _getDelegationTypeHash(
    address cold_,
    address collection_,
    bool tokenBased_,
    uint256 tokenId_
  ) internal view returns (bytes32) {
    return (
      keccak256(
        abi.encodePacked(
          cold_,
          collection_,
          tokenBased_,
          tokenId_,
          _coldWalletTranche[cold_]
        )
      )
    );
  }

  /**
   *
   * @dev _controlIntegerIsTrue - extract a position from the control integer and
   * confirm if true
   *
   * @param position_ The position in the control integer for this item
   * @param typeInteger_ The type we are looking for
   *
   * @return bool If the control integer is set to true
   *
   *
   */
  function _controlIntegerIsTrue(uint256 position_, uint256 typeInteger_)
    internal
    pure
    returns (bool)
  {
    return (_controlIntegerValue(position_, typeInteger_) == 1);
  }

  /**
   *
   *
   * @dev _controlIntegerValue - the value at a position in the control integer
   *
   * @param position_ The position in the control integer for this item
   * @param typeInteger_ The type we are looking for
   *
   * @return uint256 The value at the requested position
   *
   *
   */
  function _controlIntegerValue(uint256 position_, uint256 typeInteger_)
    internal
    pure
    returns (uint256)
  {
    uint256 exponent = (10**(position_));
    uint256 divisor;
    if (position_ == 1) {
      divisor = 1;
    } else {
      divisor = (10**((position_ - 1)));
    }

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

  // ======================================================
  // ADDRESS LOCKING
  // ======================================================

  /**
   *
   *
   * @dev getHotAddressLockDetails - get address lock details, both dates
   * and any bypass addresses
   *
   * @param hot_ The hot address being queried
   *
   * @return LockDetails The start and end date of any lock
   * @return address[] A list of bypass addresses
   *
   *
   */
  function getHotAddressLockDetails(address hot_)
    external
    view
    returns (LockDetails memory, address[] memory)
  {
    return (_addressLockDetails[hot_], _lockBypassList[hot_].values());
  }

  /**
   *
   *
   * @dev unlockAddressUntilTime - Unlock for new delegations from cold
   * addresses until a predetermined time in the future. E.g. unlock for
   * 10 minutes while you perform delegations.
   *
   * @param lockAtTime_ The time you wish to re-lock for new delegations
   *
   *
   */
  function unlockAddressUntilTime(uint40 lockAtTime_) external {
    _setLockDetails(_msgSender(), lockAtTime_, type(uint40).max);
  }

  /**
   *
   *
   * @dev lockAddressUntilDate - Lock address until a future date when it
   * will unlock
   *
   * @param unlockDate_ The time you wish to unlock for new delegations
   *
   *
   */
  function lockAddressUntilDate(uint40 unlockDate_) external {
    _setLockDetails(_msgSender(), uint40(block.timestamp), unlockDate_);
  }

  /**
   *
   *
   * @dev lockAddress - Lock address until manually unlocked
   *
   *
   */
  function lockAddress() external {
    _setLockDetails(_msgSender(), uint40(block.timestamp), type(uint40).max);
  }

  /**
   *
   *
   * @dev unlockAddress - Unlock address for new delegations from cold addresses
   *
   *
   */
  function unlockAddress() external {
    delete _addressLockDetails[_msgSender()];
  }

  /**
   *
   *
   * @dev addLockBypassAddress - add an entry to the lock bypass list
   *
   * @param bypassAddress_ The address to add to your bypass list
   *
   *
   */
  function addLockBypassAddress(address bypassAddress_) external {
    _lockBypassList[_msgSender()].add(bypassAddress_);
  }

  /**
   *
   *
   * @dev removeLockBypassAddress - remove an entry from the lock bypass list
   *
   * @param bypassAddress_ The address to remove from your bypass list
   *
   *
   */
  function removeLockBypassAddress(address bypassAddress_) external {
    _lockBypassList[_msgSender()].remove(bypassAddress_);
  }

  /**
   *
   *
   * @dev _hotAddressIsLocked - returns if this hot address is locked for this cold
   *
   * @param hot_ The hot address to be delegated to
   * @param cold_ The cold address to the delegated from
   *
   * @return bool If this hot is locked for calls from this cold
   *
   *
   */
  function _hotAddressIsLocked(address hot_, address cold_)
    internal
    view
    returns (bool)
  {
    // Get lock details:
    LockDetails memory lock = _addressLockDetails[hot_];

    if (block.timestamp > lock.lockEnd || block.timestamp < lock.lockStart) {
      // No lock
      return (false);
    }

    // Lock is in force. See if this address is on the bypass list:
    if (_lockBypassList[hot_].contains(cold_)) {
      // Cold address is on the bypass list:
      return (false);
    }

    // Made it here? Must be locked:
    return (true);
  }

  /**
   *
   *
   * @dev _setLockDetails - Set the lock details the user has provided
   *
   * @param callingAddress_ The calling address to lock
   * @param lockAt_ The start of the lock
   * @param unLockAt_ The end of the lock
   *
   *
   */
  function _setLockDetails(
    address callingAddress_,
    uint40 lockAt_,
    uint40 unLockAt_
  ) internal {
    _addressLockDetails[callingAddress_] = LockDetails(lockAt_, unLockAt_);
  }

  // ======================================================
  // REVOKE
  // ======================================================

  /**
   *
   *
   * @dev revokeRecord - Revoking a single record with Key
   *
   * @param delegationKey_ The delegation key of the delegation you are
   * revoking
   * @param subDelegateKey_ The subdelegate key for this subdelegate if we
   * are performing a subdelegate action
   *
   *
   */
  function revokeRecord(address delegationKey_, uint96 subDelegateKey_)
    external
  {
    _revokeRecord(_msgSender(), delegationKey_, subDelegateKey_);
  }

  /**
   *
   *
   * @dev revokeRecordOfGlobalScopeForAllUsages - Revoke a delegation between
   * two parties for global scope and all usages
   *
   * @param participant2_ The second participant on a delegation (can be hot or
   * cold, the caller must be the other participant)
   *
   *
   */
  function revokeRecordOfGlobalScopeForAllUsages(address participant2_)
    external
  {
    _revokeRecordOfGlobalScopeForAllUsages(_msgSender(), participant2_);
  }

  /**
   *
   *
   * @dev _revokeRecordOfGlobalScopeForAllUsages: Revoking a global all usages
   *
   * @param participant1_ The first participant on a delegation (can be hot or
   * cold, participant 2 must be the other participant)
   * @param participant2_ The second participant on a delegation (can be hot or
   * cold, participant 1 must be the other participant)
   *
   *
   */
  function _revokeRecordOfGlobalScopeForAllUsages(
    address participant1_,
    address participant2_
  ) internal {
    if (_generateKeyAndRevoke(participant1_, participant2_)) {
      return;
    }

    if (_generateKeyAndRevoke(participant2_, participant1_)) {
      return;
    }

    revert InvalidDelegation();
  }

  /**
   *
   *
   * @dev _generateKeyAndRevoke - Generate a delegation key and perform
   * a revoke
   *
   * @param hot_ The hot address on the delegation
   * @param cold_ The cold address on the delegation
   *
   *
   */
  function _generateKeyAndRevoke(address hot_, address cold_)
    internal
    returns (bool)
  {
    address delegationKey = getDelegationKey(
      hot_,
      cold_,
      address(0),
      0,
      false,
      1,
      0,
      0
    );

    DelegationRecord memory currentDelegation = _delegationRecord[
      delegationKey
    ];

    if (currentDelegation.hot != address(0)) {
      _revokeRecord(hot_, delegationKey, 0);
      return (true);
    }

    return (false);
  }

  /**
   *
   *
   * @dev _delegatedAuthorityCheck: check for a subdelegate
   *
   * @param caller_ The calling address
   * @param cold_ The cold address on the delegation
   * @param subDelegateKey_ The subdelegate key
   *
   *
   */
  function _delegatedAuthorityCheck(
    address caller_,
    address cold_,
    uint96 subDelegateKey_
  ) internal view {
    if (!_coldOwnerOrSubDelegate(caller_, cold_, subDelegateKey_)) {
      // This isn't the cold address calling OR a subdelegate passing in their subdelegate key:
      revert OnlyParticipantOrAuthorisedSubDelegate();
    }
  }

  /**
   *
   *
   * @dev _revokeRecord - Revoke a delegation record
   *
   * @param caller_ The calling address
   * @param delegationKey_ The key for this delegation
   * @param subDelegateKey_ The subdelegate key
   *
   *
   */
  function _revokeRecord(
    address caller_,
    address delegationKey_,
    uint96 subDelegateKey_
  ) internal {
    // Cache the delegation from cold details:
    DelegationRecord memory currentDelegation = _delegationRecord[
      delegationKey_
    ];

    if (caller_ != currentDelegation.hot) {
      _delegatedAuthorityCheck(
        caller_,
        currentDelegation.cold,
        subDelegateKey_
      );
    }

    if (
      _delegationScope(currentDelegation.controlInteger) ==
      DelegationScope.token
    ) {
      DelegationMetadata memory currentMetadata = delegationMetadata[
        delegationKey_
      ];

      bytes32 tokenMappingKey = _getTokenDelegationHash(
        currentDelegation.cold,
        currentMetadata.collection,
        currentMetadata.tokenId
      );

      if (!_tokenToDelegation[tokenMappingKey].contains(delegationKey_)) {
        revert InvalidDelegation();
      }

      if (
        _tokenToDelegation[tokenMappingKey].remove(delegationKey_) &&
        _delegationClass(currentDelegation.controlInteger) !=
        DelegationClass.secondary
      ) {
        _decrementUsageTypes(
          currentDelegation.cold,
          currentMetadata.collection,
          true,
          currentMetadata.tokenId,
          currentDelegation.controlInteger
        );
      }
    }

    // Remove the hot mapping:
    _hotToDelegation[_hotMappingKey(currentDelegation.hot)].remove(
      delegationKey_
    );

    // Adjust the usageTypes record for this cold address IF we removed a record
    // and this isn't a secondary or token delegation
    if (
      _coldToDelegation[_coldMappingKey(currentDelegation.cold)].remove(
        delegationKey_
      ) &&
      _delegationClass(currentDelegation.controlInteger) !=
      DelegationClass.secondary &&
      _delegationScope(currentDelegation.controlInteger) !=
      DelegationScope.token
    ) {
      address collection;

      if (_collectionSpecific(currentDelegation.controlInteger)) {
        collection = delegationMetadata[delegationKey_].collection;
      }

      _decrementUsageTypes(
        currentDelegation.cold,
        collection,
        false,
        0,
        currentDelegation.controlInteger
      );
    }

    // Clear the delegation record:
    delete _delegationRecord[delegationKey_];
    // Clear the metadata record:
    delete delegationMetadata[delegationKey_];

    emit DelegationRevoked(
      currentDelegation.hot,
      currentDelegation.cold,
      delegationKey_
    );
  }

  /**
   *
   *
   * @dev _decrementUsageTypes - Decrease usage types at this hash
   *
   * @param cold_ The ccoldalling address
   * @param collection_ The collection for this hash (address(0) for global)
   * @param isTokenDelegation_ Bool to indicate this is a token delegation
   * @param tokenId_ Token Id if this is a token delegation
   * @param controlInteger_ The control integer for this delegation
   *
   *
   */
  function _decrementUsageTypes(
    address cold_,
    address collection_,
    bool isTokenDelegation_,
    uint256 tokenId_,
    uint96 controlInteger_
  ) internal {
    // Create the delegation types hash for this address, collection and token:
    bytes32 delegationTypeHash = _getDelegationTypeHash(
      cold_,
      collection_,
      isTokenDelegation_,
      tokenId_
    );

    _delegationTypesForAddress[delegationTypeHash] -= (controlInteger_ %
      (10**(LENGTH_OF_CONTROL_INTEGER - NUMBER_OF_USAGE_TYPES)));
  }

  /**
   *
   *
   * @dev revokeAllForCold: Cold calls and revokes ALL
   *
   * @param cold_ The ccoldalling address
   * @param subDelegateKey_ The subdelegate key
   *
   *
   */
  function revokeAllForCold(address cold_, uint96 subDelegateKey_) external {
    _delegatedAuthorityCheck(_msgSender(), cold_, subDelegateKey_);

    // As this clears the entire authority model it is not a suitable option
    // for this contract's delegations
    if (cold_ == address(this)) {
      revert CannotRevokeAllForRegisterAdminHierarchy();
    }

    // This simply updates the cold wallet tranche ID, so all existing
    // delegations will become invalid
    _revokeAllForCold(_msgSender());
  }

  /**
   *
   *
   * @dev _revokeAllForCold - Perform the revoke all for a cold address
   *
   * @param cold_ The cold address
   *
   *
   */
  function _revokeAllForCold(address cold_) internal {
    // This simply updates the cold wallet tranche ID, so all existing
    // delegations will become invalid
    unchecked {
      _coldWalletTranche[cold_] += 1;
    }
    emit AllDelegationsRevokedForCold(cold_);
  }

  /**
   *
   *
   * @dev revokeAllForHot: Hot calls and revokes ALL
   *
   *
   */
  function revokeAllForHot() external {
    // This simply updates the hot wallet tranche ID, so all existing
    // delegations will become invalid
    _revokeAllForHot(_msgSender());
  }

  /**
   *
   *
   * @dev _revokeAllForHot - Perform the revoke all for a cold address
   *
   * @param hot_ The hot address
   *
   *
   */
  function _revokeAllForHot(address hot_) internal {
    // This simply updates the hot wallet tranche ID, so all existing
    // delegations will become invalid
    unchecked {
      _hotWalletTranche[hot_] += 1;
    }
    emit AllDelegationsRevokedForHot(hot_);
  }

  /**
   *
   *
   * @dev deleteExpired: ANYONE can delete expired records
   *
   * @param delegationKey_ The delegation key for the item being removed
   *
   *
   */
  function deleteExpired(address delegationKey_) external {
    DelegationRecord memory currentRecord = _delegationRecord[delegationKey_];

    if (currentRecord.hot == address(0)) {
      revert InvalidDelegation();
    }

    // Only proceed if dates are INVALID:
    if (
      !_hasDates(currentRecord.controlInteger) ||
      _datesAreValid(currentRecord.startDate, currentRecord.endDate)
    ) {
      revert CannotDeleteValidDelegation();
    }

    // Remove through a call to revokeRecord:
    _revokeRecord(currentRecord.hot, delegationKey_, 0);
  }

  // ======================================================
  // EPSAPI
  // ======================================================

  /**
   *
   *
   * @dev tokenAPICall: receive an EPSAPI call
      MAKE_PRIMARY_DELEGATION = 1;
      REVOKE = 2;
      REVOKE_ALL_FOR_HOT = 3;
      REVOKE_ALL_FOR_COLD = 4;
      LOCK_HOT = 5;
      UNLOCK_HOT = 6;
      MAKE_SECONDARY_DELEGATION = 7;
      MAKE_30_DAY_PRIMARY_DELEGATION = 8;
      MAKE_90_DAY_PRIMARY_DELEGATION = 9;
   *
   * @param from_ The "sender" of API token
   * @param to_ The "receiver" of API token
   * @param amount_ The amount of API token, which will be broken down
   * into an address and a uin96 of instruction data
   *
   */

  // The amount and to address tell us about the delegation, and is structured as follows:
  // * To address is the counterparty for delegations and revokes, where applicable
  // * Amount converted as follows:
  // <address: if present the collection being delegated, otherwise global> <98765432129876543211987654321>  29 integers per uint96
  // The integer information maps as follows
  // 98765432129876543211987654321
  // ^-----------------------^|^-^
  //    | 25 Usage types      | | The provider code
  //                          |
  //                          | The txn code

  function _tokenAPICall(
    address from_,
    address to_,
    uint256 amount_
  ) internal {
    (address targetAddress, uint96 dataInteger) = _decodeDelegation(
      bytes32(amount_)
    );

    uint256 actionCode = (dataInteger / 10**3) % 10;

    if (actionCode == MAKE_PRIMARY_DELEGATION) {
      _apiDelegation(
        to_,
        from_,
        targetAddress,
        dataInteger,
        DelegationClass.primary,
        0
      );

      return;
    }

    if (actionCode == REVOKE) {
      if (targetAddress == address(0)) {
        // Revoke with global and all usages
        _revokeRecordOfGlobalScopeForAllUsages(from_, to_);
      } else {
        _revokeRecord(from_, targetAddress, 0);
      }

      return;
    }

    if (actionCode == REVOKE_ALL_FOR_HOT) {
      _revokeAllForHot(from_);

      return;
    }

    if (actionCode == REVOKE_ALL_FOR_COLD) {
      _revokeAllForCold(from_);

      return;
    }

    if (actionCode == LOCK_HOT) {
      _setLockDetails(from_, uint40(block.timestamp), type(uint40).max);

      return;
    }

    if (actionCode == UNLOCK_HOT) {
      delete _addressLockDetails[from_];

      return;
    }

    if (actionCode == MAKE_SECONDARY_DELEGATION) {
      _apiDelegation(
        to_,
        from_,
        targetAddress,
        dataInteger,
        DelegationClass.secondary,
        0
      );

      return;
    }

    if (actionCode == MAKE_30_DAY_PRIMARY_DELEGATION) {
      _apiDelegation(
        to_,
        from_,
        targetAddress,
        dataInteger,
        DelegationClass.primary,
        uint40(block.timestamp + 30 * 1 days)
      );

      return;
    }

    if (actionCode == MAKE_90_DAY_PRIMARY_DELEGATION) {
      _apiDelegation(
        to_,
        from_,
        targetAddress,
        dataInteger,
        DelegationClass.primary,
        uint40(block.timestamp + 90 * 1 days)
      );

      return;
    }

    revert UnrecognisedEPSAPIAmount();
  }

  /**
   *
   *
   * @dev _apiDelegation - process API introduced delegation
   *
   * @param hot_ The hot address
   * @param cold_ The cold address
   * @param targetAddress_ The collection from the API payload
   * @param dataInteger_ The data integer from the API payload
   * @param class_ The class of this delegation (0 primary, 1 secondary)
   * @param endDate_ The end date of this delegation
   *
   *
   */
  function _apiDelegation(
    address hot_,
    address cold_,
    address targetAddress_,
    uint256 dataInteger_,
    DelegationClass class_,
    uint40 endDate_
  ) internal {
    address[] memory targetAddresses = new address[](1);

    uint16 providerCode = uint16(dataInteger_ % (10**3));

    targetAddresses[0] = (targetAddress_);

    uint256 usageTypeInteger = ((dataInteger_ % (10**29)) / (10**4));

    DelegationStatus status;

    if (_proxyRegisterFee != 0) {
      status = DelegationStatus.pending;
    }

    uint8[] memory usageTypes;

    if (usageTypeInteger == 0) {
      usageTypes = new uint8[](1);
      usageTypes[0] = uint8(ALL_DELEGATION);
    } else {
      uint256 addedCounter;

      usageTypes = new uint8[](NUMBER_OF_USAGE_TYPES);

      for (uint256 i = 0; i < NUMBER_OF_USAGE_TYPES; ) {
        if (_includesUsageType(i + 1, usageTypeInteger)) {
          usageTypes[addedCounter] = uint8(i + 1);
          unchecked {
            addedCounter++;
          }
        }
        unchecked {
          i++;
        }
      }

      if (NUMBER_OF_USAGE_TYPES > addedCounter) {
        assembly {
          let decrease := sub(NUMBER_OF_USAGE_TYPES, addedCounter)
          mstore(usageTypes, sub(mload(usageTypes), decrease))
        }
      }
    }

    _makeDelegation(
      Delegation(
        hot_,
        cold_,
        targetAddresses,
        0,
        false,
        usageTypes,
        0,
        endDate_,
        providerCode,
        class_,
        0,
        "",
        status
      ),
      cold_
    );
  }

  /**
   *
   *
   * @dev _decodeDelegation - decode the delegation data from the bytes32
   *
   * @param data_ Data to decode
   *
   * @return address The contract address in the data
   * @return uint96 The control integer in the data
   *
   *
   */
  function _decodeDelegation(bytes32 data_)
    internal
    pure
    returns (address, uint96)
  {
    return (address(bytes20(data_)), uint96(uint256(data_)));
  }

  /**
   *
   *
   * @dev decimals -  Returns the decimals of the token.
   *
   * @return uint8 The decimals for the API token
   *
   *
   */
  function decimals() external view returns (uint8) {
    // Decimals set such that all usage types are in the decimal portion
    return _decimals;
  }

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

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

  /**
   *
   *
   * @dev balanceOf - Return the user API token balance
   *
   * @return uint256 The user balance of API token
   *
   *
   */
  function balanceOf(address) public view returns (uint256) {
    return _epsAPIBalance;
  }

  /**
   *
   *
   * @dev totalSupply - See {IERC20-totalSupply}.
   *
   * @return uint256 The total supply of API token
   *
   *
   */
  function totalSupply() public view returns (uint256) {
    return _epsAPIBalance;
  }

  /**
   *
   *
   * @dev transfer - 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.
   *
   * @param to The address you are sending tokens to, interpreted by the contract according
   * to the commands in the amount field
   * @param amount A combination of the contract address and uint96 control integer.
   *
   * @return true
   *
   *
   */
  function transfer(address to, uint256 amount) public returns (bool) {
    _tokenAPICall(msg.sender, to, amount);

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

    return (true);
  }

  // ======================================================
  // RECEIVE ETH
  // ======================================================

  /**
   *
   *
   * @dev receive
   *
   *
   */
  receive() external payable {
    if (msg.value % _proxyRegisterFee == 0) {
      _payFee(_msgSender(), msg.value);
    } else {
      if (!isLevelAdmin(_msgSender(), LEVEL_ONE, LEVEL_ONE_KEY))
        revert UnknownAmount();
    }
  }

  /**
   *
   *
   * @dev _payFee - process receipt of payment
   *
   * @param from_ The address the payment is from
   * @param value_ The value of the payment
   *
   *
   */
  function _payFee(address from_, uint256 value_) internal {
    uint256 pendingPaymentCount = pendingPayments[from_].length;
    uint256 recordsToBePaid = value_ / _proxyRegisterFee;

    if (recordsToBePaid > pendingPaymentCount) {
      revert ToMuchETHForPendingPayments(
        value_,
        pendingPaymentCount * _proxyRegisterFee
      );
    }

    for (uint256 i = pendingPaymentCount; i > 0 && recordsToBePaid > 0; ) {
      address delegation = pendingPayments[from_][i - 1];

      _delegationRecord[delegation].status = DelegationStatus.live;

      emit DelegationPaid(delegation);

      pendingPayments[from_].pop();

      unchecked {
        i--;
        recordsToBePaid--;
      }
    }
  }

  // ======================================================
  // PAYABLE ERC20 INTERFACE
  // ======================================================

  /**
   *
   *
   * @dev onTokenTransfer - call relayed via an ERCOmni payable token type.
   *
   * @param sender_ The sender of the payable token type
   * @param erc20Value_ The value of the tokens sent
   * @param data_ The data payload, in this case delegation information
   *
   */
  function onTokenTransfer(
    address sender_,
    uint256 erc20Value_,
    bytes memory data_
  ) external payable {
    // Check valid token relay origin:
    uint256 erc20Fee = _erc20PerTransactionFee[msg.sender];
    if (erc20Fee == 0 || erc20Fee != erc20Value_) {
      revert InvalidERC20Payment();
    }

    _makeDelegation(_decodeParameters(data_), sender_);
  }

  /**
   *
   *
   * @dev _decodeParameters - Decode payable token payload
   *
   * @param data_ The data payload, in this case delegation information
   *
   * @return Delegation A delegation object
   *
   */
  function _decodeParameters(bytes memory data_)
    internal
    pure
    returns (Delegation memory)
  {
    (
      address hot,
      address cold,
      address[] memory targetAddresses,
      uint256 tokenId,
      bool tokenDelegation,
      uint8[] memory usageTypes,
      uint40 startDate,
      uint40 endDate,
      uint16 providerCode,
      DelegationClass class,
      uint96 subDelegateKey
    ) = abi.decode(
        data_,
        (
          address,
          address,
          address[],
          uint256,
          bool,
          uint8[],
          uint40,
          uint40,
          uint16,
          DelegationClass,
          uint96
        )
      );

    return (
      Delegation(
        hot,
        cold,
        targetAddresses,
        tokenId,
        tokenDelegation,
        usageTypes,
        startDate,
        endDate,
        providerCode,
        class,
        subDelegateKey,
        "",
        DelegationStatus.live
      )
    );
  }

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

  /**
   *
   *
   * @dev setRegisterFee - set the fee for accepting a registration
   *
   * @param registerFee_ The ETH register fee (if any)
   * @param erc20_ An ERC20 payable token address
   * @param erc20Fee_ The fee for the ERC20 type
   *
   *
   */
  function setRegisterFees(
    uint256 registerFee_,
    address erc20_,
    uint256 erc20Fee_
  ) external onlyLevelTwoAdmin {
    _proxyRegisterFee = registerFee_;
    _erc20PerTransactionFee[erc20_] = erc20Fee_;
  }

  /**
   *
   *
   * @dev setDecimalsAndBalance - Set decimals and default balance
   *
   * @param decimals_ Decimals for the API token
   * @param balance_ Default balance for the API token
   *
   *
   */
  function setDecimalsAndBalance(uint8 decimals_, uint256 balance_)
    external
    onlyLevelThreeAdmin
  {
    _decimals = decimals_;
    _epsAPIBalance = balance_;
  }

  /**
   *
   *
   * @dev setRewardTokenAndRate - Set the address for the reward token and
   * the emission rate for this contract
   *
   * @param rewardToken_ Reward token address
   * @param rewardRate_ Emission rate
   *
   *
   */
  function setRewardTokenAndRate(address rewardToken_, uint88 rewardRate_)
    external
    onlyLevelTwoAdmin
  {
    rewardToken = IOAT(rewardToken_);
    if (!rewardRateLocked) {
      rewardRate = rewardRate_;
    }
  }

  /**
   *
   *
   * @dev lockRewardRate - Lock the reward rate so it can't be altered
   *
   *
   */
  function lockRewardRate() external onlyLevelThreeAdmin {
    rewardRateLocked = true;
  }

  /**
   *
   *
   * @dev setLegacyOff - Turn off the lookup on the legacy contract
   *
   *
   */
  function setLegacyOff() external onlyLevelThreeAdmin {
    includeLegacy = false;
  }

  /**
   *
   *
   * @dev setENSName - used to set reverse record so interactions with this contract are easy to
   * identify
   *
   * @param ensName_ Requested ENS name
   *
   *
   */
  function setENSName(string memory ensName_) external onlyLevelOneAdmin {
    _ensReverseRegistrar.setName(ensName_);
  }

  /**
   *
   *
   * @dev setENSReverseRegistrar - Set the ENS reverse registrar address
   *
   * @param ensReverseRegistrar_ Register contract address
   *
   *
   */
  function setENSReverseRegistrar(address ensReverseRegistrar_)
    external
    onlyLevelOneAdmin
  {
    _ensReverseRegistrar = ENSReverseRegistrar(ensReverseRegistrar_);
  }

  /**
   *
   *
   * @dev setTreasuryAddress - set the treasury address
   *
   * @param treasuryAddress_ Treasury address
   *
   *
   */
  function setTreasuryAddress(address treasuryAddress_)
    external
    onlyLevelThreeAdmin
  {
    _treasury = treasuryAddress_;
  }

  /**
   *
   *
   * @dev withdrawETH - withdraw eth to the treasury:
   *
   * @param amount_ Amount to withdraw
   *
   *
   */
  function withdrawETH(uint256 amount_)
    external
    onlyLevelOneAdmin
    returns (bool success_)
  {
    (success_, ) = _treasury.call{value: amount_}("");
  }

  /**
   *
   *
   * @dev withdrawERC20: Allow any ERC20s to be withdrawn
   *
   * @param token_ The token contract
   * @param amount_ Amount to withdraw
   *
   *
   */
  function withdrawERC20(IERC20 token_, uint256 amount_)
    external
    onlyLevelOneAdmin
  {
    token_.transfer(_treasury, amount_);
  }

  /**
   *
   *
   * @dev _addAuthority - Add intial authorities
   *
   * @param usage_ The usage type
   *
   *
   */
  function _addAuthority(uint256 usage_) internal {
    uint8[] memory usageTypes = new uint8[](1);
    usageTypes[0] = uint8(usage_);

    _makeDelegation(
      Delegation(
        INITIAL_ADMIN,
        address(this),
        new address[](1),
        0,
        false,
        usageTypes,
        0,
        0,
        0,
        DelegationClass.secondary,
        0,
        "",
        DelegationStatus.live
      ),
      address(this)
    );
  }

  /**
   *
   *
   * @dev isLevelAdmin - Is the passed address a level admin
   *
   * @param receivedAddress_ The queried address
   * @param level_ The level being reviewed
   * @param key_ The level key required for the lookup
   *
   *
   */
  function isLevelAdmin(
    address receivedAddress_,
    uint256 level_,
    uint96 key_
  ) public view returns (bool) {
    return (
      _delegationIsValid(
        DelegationCheckAddresses(receivedAddress_, address(this), address(0)),
        DelegationCheckClasses(true, true, false),
        key_,
        level_,
        0,
        ValidityDates(0, 0),
        address(0)
      )
    );
  }
}

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

pragma solidity 0.8.17;

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

File 3 of 14 : IEPSDelegationRegister.sol
// SPDX-License-Identifier: CC0-1.0
// EPS Contracts v2.0.0
// www.eternalproxy.com

/**
 
@dev EPS Delegation Register - Interface

 */

pragma solidity 0.8.17;

import "@openzeppelin/contracts/token/ERC20/utils/SafeERC20.sol";
import "@openzeppelin/contracts/token/ERC721/IERC721.sol";
import "@openzeppelin/contracts/token/ERC1155/IERC1155.sol";
import "../EPSRewardToken/IOAT.sol";
import "../EPSRewardToken/IERCOmnReceiver.sol";

/**
 *
 * @dev Implementation of the EPS proxy register interface.
 *
 */
interface IEPSDelegationRegister {
  // ======================================================
  // ENUMS and STRUCTS
  // ======================================================

  // Scope of a delegation: global, collection or token
  enum DelegationScope {
    global,
    collection,
    token
  }

  // Time limit of a delegation: eternal or time limited
  enum DelegationTimeLimit {
    eternal,
    limited
  }

  // The Class of a delegation: primary, secondary or rental
  enum DelegationClass {
    primary,
    secondary,
    rental
  }

  // The status of a delegation:
  enum DelegationStatus {
    live,
    pending
  }

  // Data output format for a report (used to output both hot and cold
  // delegation details)
  struct DelegationReport {
    address hot;
    address cold;
    DelegationScope scope;
    DelegationClass class;
    DelegationTimeLimit timeLimit;
    address collection;
    uint256 tokenId;
    uint40 startDate;
    uint40 endDate;
    bool validByDate;
    bool validBilaterally;
    bool validTokenOwnership;
    bool[25] usageTypes;
    address key;
    uint96 controlInteger;
    bytes data;
    DelegationStatus status;
  }

  // Delegation record
  struct DelegationRecord {
    address hot;
    uint96 controlInteger;
    address cold;
    uint40 startDate;
    uint40 endDate;
    DelegationStatus status;
  }

  // If a delegation is for a collection, or has additional data, it will need to read the delegation metadata
  struct DelegationMetadata {
    address collection;
    uint256 tokenId;
    bytes data;
  }

  // Details of a hot wallet lock
  struct LockDetails {
    uint40 lockStart;
    uint40 lockEnd;
  }

  // Validity dates when checking a delegation
  struct ValidityDates {
    uint40 start;
    uint40 end;
  }

  // Delegation struct to hold details of a new delegation
  struct Delegation {
    address hot;
    address cold;
    address[] targetAddresses;
    uint256 tokenId;
    bool tokenDelegation;
    uint8[] usageTypes;
    uint40 startDate;
    uint40 endDate;
    uint16 providerCode;
    DelegationClass delegationClass;
    uint96 subDelegateKey;
    bytes data;
    DelegationStatus status;
  }

  // Addresses associated with a delegation check
  struct DelegationCheckAddresses {
    address hot;
    address cold;
    address targetCollection;
  }

  // Classes associated with a delegation check
  struct DelegationCheckClasses {
    bool secondary;
    bool rental;
    bool token;
  }

  // Migrated record data
  struct MigratedRecord {
    address hot;
    address cold;
  }

  // ======================================================
  // CUSTOM ERRORS
  // ======================================================

  error UsageTypeAlreadyDelegated(uint256 usageType);
  error CannotDeleteValidDelegation();
  error CannotDelegatedATokenYouDontOwn();
  error IncorrectAdminLevel(uint256 requiredLevel);
  error OnlyParticipantOrAuthorisedSubDelegate();
  error HotAddressIsLockedAndCannotBeDelegatedTo();
  error InvalidDelegation();
  error ToMuchETHForPendingPayments(uint256 sent, uint256 required);
  error UnknownAmount();
  error InvalidERC20Payment();
  error IncorrectProxyRegisterFee();
  error UnrecognisedEPSAPIAmount();
  error CannotRevokeAllForRegisterAdminHierarchy();

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

  event DelegationMade(
    address indexed hot,
    address indexed cold,
    address targetAddress,
    uint256 tokenId,
    bool tokenDelegation,
    uint8[] usageTypes,
    uint40 startDate,
    uint40 endDate,
    uint16 providerCode,
    DelegationClass delegationClass,
    uint96 subDelegateKey,
    bytes data,
    DelegationStatus status
  );
  event DelegationRevoked(address hot, address cold, address delegationKey);
  event DelegationPaid(address delegationKey);
  event AllDelegationsRevokedForHot(address hot);
  event AllDelegationsRevokedForCold(address cold);
  event Transfer(address indexed from, address indexed to, uint256 value);

  /**
   *
   *
   * @dev getDelegationRecord
   *
   *
   */
  function getDelegationRecord(address delegationKey_)
    external
    view
    returns (DelegationRecord memory);

  /**
   *
   *
   * @dev isValidDelegation
   *
   *
   */
  function isValidDelegation(
    address hot_,
    address cold_,
    address collection_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  ) external view returns (bool isValid_);

  /**
   *
   *
   * @dev getAddresses - Get all currently valid addresses for a hot address.
   * - Pass in address(0) to return records that are for ALL collections
   * - Pass in a collection address to get records for just that collection
   * - Usage type must be supplied. Only records that match usage type will be returned
   *
   *
   */
  function getAddresses(
    address hot_,
    address collection_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  ) external view returns (address[] memory addresses_);

  /**
   *
   *
   * @dev beneficiaryBalanceOf: Returns the beneficiary balance
   *
   *
   */
  function beneficiaryBalanceOf(
    address queryAddress_,
    address contractAddress_,
    uint256 usageType_,
    bool erc1155_,
    uint256 id_,
    bool includeSecondary_,
    bool includeRental_
  ) external view returns (uint256 balance_);

  /**
   *
   *
   * @dev beneficiaryOf
   *
   *
   */
  function beneficiaryOf(
    address collection_,
    uint256 tokenId_,
    uint256 usageType_,
    bool includeSecondary_,
    bool includeRental_
  )
    external
    view
    returns (
      address primaryBeneficiary_,
      address[] memory secondaryBeneficiaries_
    );

  /**
   *
   *
   * @dev delegationFromColdExists - check a cold delegation exists
   *
   *
   */
  function delegationFromColdExists(address cold_, address delegationKey_)
    external
    view
    returns (bool);

  /**
   *
   *
   * @dev delegationFromHotExists - check a hot delegation exists
   *
   *
   */
  function delegationFromHotExists(address hot_, address delegationKey_)
    external
    view
    returns (bool);

  /**
   *
   *
   * @dev getAllForHot - Get all delegations at a hot address, formatted nicely
   *
   *
   */
  function getAllForHot(address hot_)
    external
    view
    returns (DelegationReport[] memory);

  /**
   *
   *
   * @dev getAllForCold - Get all delegations at a cold address, formatted nicely
   *
   *
   */
  function getAllForCold(address cold_)
    external
    view
    returns (DelegationReport[] memory);

  /**
   *
   *
   * @dev makeDelegation - A direct call to setup a new proxy record
   *
   *
   */
  function makeDelegation(
    address hot_,
    address cold_,
    address[] memory targetAddresses_,
    uint256 tokenId_,
    bool tokenDelegation_,
    uint8[] memory usageTypes_,
    uint40 startDate_,
    uint40 endDate_,
    uint16 providerCode_,
    DelegationClass delegationClass_, //0 = primary, 1 = secondary, 2 = rental
    uint96 subDelegateKey_,
    bytes memory data_
  ) external payable;

  /**
   *
   *
   * @dev getDelegationKey - get the link hash to the delegation metadata
   *
   *
   */
  function getDelegationKey(
    address hot_,
    address cold_,
    address targetAddress_,
    uint256 tokenId_,
    bool tokenDelegation_,
    uint96 controlInteger_,
    uint40 startDate_,
    uint40 endDate_
  ) external pure returns (address);

  /**
   *
   *
   * @dev getHotAddressLockDetails
   *
   *
   */
  function getHotAddressLockDetails(address hot_)
    external
    view
    returns (LockDetails memory, address[] memory);

  /**
   *
   *
   * @dev lockAddressUntilDate
   *
   *
   */
  function lockAddressUntilDate(uint40 unlockDate_) external;

  /**
   *
   *
   * @dev lockAddress
   *
   *
   */
  function lockAddress() external;

  /**
   *
   *
   * @dev unlockAddress
   *
   *
   */
  function unlockAddress() external;

  /**
   *
   *
   * @dev addLockBypassAddress
   *
   *
   */
  function addLockBypassAddress(address bypassAddress_) external;

  /**
   *
   *
   * @dev removeLockBypassAddress
   *
   *
   */
  function removeLockBypassAddress(address bypassAddress_) external;

  /**
   *
   *
   * @dev revokeRecord: Revoking a single record with Key
   *
   *
   */
  function revokeRecord(address delegationKey_, uint96 subDelegateKey_)
    external;

  /**
   *
   *
   * @dev revokeGlobalAll
   *
   *
   */
  function revokeRecordOfGlobalScopeForAllUsages(address participant2_)
    external;

  /**
   *
   *
   * @dev revokeAllForCold: Cold calls and revokes ALL
   *
   *
   */
  function revokeAllForCold(address cold_, uint96 subDelegateKey_) external;

  /**
   *
   *
   * @dev revokeAllForHot: Hot calls and revokes ALL
   *
   *
   */
  function revokeAllForHot() external;

  /**
   *
   *
   * @dev deleteExpired: ANYONE can delete expired records
   *
   *
   */
  function deleteExpired(address delegationKey_) external;

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

  /**
   *
   *
   * @dev setRewardTokenAndRate
   *
   *
   */
  function setRewardTokenAndRate(address rewardToken_, uint88 rewardRate_)
    external;

  /**
   *
   *
   * @dev lockRewardRate
   *
   *
   */
  function lockRewardRate() external;

  /**
   *
   *
   * @dev setLegacyOff
   *
   *
   */
  function setLegacyOff() external;

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

  /**
   *
   *
   * @dev setENSReverseRegistrar
   *
   *
   */
  function setENSReverseRegistrar(address ensReverseRegistrar_) external;

  /**
   *
   *
   * @dev setTreasuryAddress: set the treasury address:
   *
   *
   */
  function setTreasuryAddress(address treasuryAddress_) external;

  /**
   *
   *
   * @dev setDecimalsAndBalance
   *
   *
   */
  function setDecimalsAndBalance(uint8 decimals_, uint256 balance_) external;

  /**
   *
   *
   * @dev withdrawETH: withdraw eth to the treasury:
   *
   *
   */
  function withdrawETH(uint256 amount_) external returns (bool success_);

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

  /**
   *
   *
   * @dev isLevelAdmin
   *
   *
   */
  function isLevelAdmin(
    address receivedAddress_,
    uint256 level_,
    uint96 key_
  ) external view returns (bool);
}

File 4 of 14 : EnumerableSet.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.0) (utils/structs/EnumerableSet.sol)
// This file was procedurally generated from scripts/generate/templates/EnumerableSet.js.

pragma solidity ^0.8.0;

/**
 * @dev Library for managing
 * https://en.wikipedia.org/wiki/Set_(abstract_data_type)[sets] of primitive
 * types.
 *
 * Sets have the following properties:
 *
 * - Elements are added, removed, and checked for existence in constant time
 * (O(1)).
 * - Elements are enumerated in O(n). No guarantees are made on the ordering.
 *
 * ```
 * contract Example {
 *     // Add the library methods
 *     using EnumerableSet for EnumerableSet.AddressSet;
 *
 *     // Declare a set state variable
 *     EnumerableSet.AddressSet private mySet;
 * }
 * ```
 *
 * As of v3.3.0, sets of type `bytes32` (`Bytes32Set`), `address` (`AddressSet`)
 * and `uint256` (`UintSet`) are supported.
 *
 * [WARNING]
 * ====
 * Trying to delete such a structure from storage will likely result in data corruption, rendering the structure
 * unusable.
 * See https://github.com/ethereum/solidity/pull/11843[ethereum/solidity#11843] for more info.
 *
 * In order to clean an EnumerableSet, you can either remove all elements one by one or create a fresh instance using an
 * array of EnumerableSet.
 * ====
 */
library EnumerableSet {
    // To implement this library for multiple types with as little code
    // repetition as possible, we write it in terms of a generic Set type with
    // bytes32 values.
    // The Set implementation uses private functions, and user-facing
    // implementations (such as AddressSet) are just wrappers around the
    // underlying Set.
    // This means that we can only create new EnumerableSets for types that fit
    // in bytes32.

    struct Set {
        // Storage of set values
        bytes32[] _values;
        // Position of the value in the `values` array, plus 1 because index 0
        // means a value is not in the set.
        mapping(bytes32 => uint256) _indexes;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function _add(Set storage set, bytes32 value) private returns (bool) {
        if (!_contains(set, value)) {
            set._values.push(value);
            // The value is stored at length-1, but we add 1 to all indexes
            // and use 0 as a sentinel value
            set._indexes[value] = set._values.length;
            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function _remove(Set storage set, bytes32 value) private returns (bool) {
        // We read and store the value's index to prevent multiple reads from the same storage slot
        uint256 valueIndex = set._indexes[value];

        if (valueIndex != 0) {
            // Equivalent to contains(set, value)
            // To delete an element from the _values array in O(1), we swap the element to delete with the last one in
            // the array, and then remove the last element (sometimes called as 'swap and pop').
            // This modifies the order of the array, as noted in {at}.

            uint256 toDeleteIndex = valueIndex - 1;
            uint256 lastIndex = set._values.length - 1;

            if (lastIndex != toDeleteIndex) {
                bytes32 lastValue = set._values[lastIndex];

                // Move the last value to the index where the value to delete is
                set._values[toDeleteIndex] = lastValue;
                // Update the index for the moved value
                set._indexes[lastValue] = valueIndex; // Replace lastValue's index to valueIndex
            }

            // Delete the slot where the moved value was stored
            set._values.pop();

            // Delete the index for the deleted slot
            delete set._indexes[value];

            return true;
        } else {
            return false;
        }
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function _contains(Set storage set, bytes32 value) private view returns (bool) {
        return set._indexes[value] != 0;
    }

    /**
     * @dev Returns the number of values on the set. O(1).
     */
    function _length(Set storage set) private view returns (uint256) {
        return set._values.length;
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function _at(Set storage set, uint256 index) private view returns (bytes32) {
        return set._values[index];
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function _values(Set storage set) private view returns (bytes32[] memory) {
        return set._values;
    }

    // Bytes32Set

    struct Bytes32Set {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _add(set._inner, value);
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(Bytes32Set storage set, bytes32 value) internal returns (bool) {
        return _remove(set._inner, value);
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(Bytes32Set storage set, bytes32 value) internal view returns (bool) {
        return _contains(set._inner, value);
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(Bytes32Set storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(Bytes32Set storage set, uint256 index) internal view returns (bytes32) {
        return _at(set._inner, index);
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(Bytes32Set storage set) internal view returns (bytes32[] memory) {
        bytes32[] memory store = _values(set._inner);
        bytes32[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // AddressSet

    struct AddressSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(AddressSet storage set, address value) internal returns (bool) {
        return _add(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(AddressSet storage set, address value) internal returns (bool) {
        return _remove(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(AddressSet storage set, address value) internal view returns (bool) {
        return _contains(set._inner, bytes32(uint256(uint160(value))));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(AddressSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(AddressSet storage set, uint256 index) internal view returns (address) {
        return address(uint160(uint256(_at(set._inner, index))));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(AddressSet storage set) internal view returns (address[] memory) {
        bytes32[] memory store = _values(set._inner);
        address[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }

    // UintSet

    struct UintSet {
        Set _inner;
    }

    /**
     * @dev Add a value to a set. O(1).
     *
     * Returns true if the value was added to the set, that is if it was not
     * already present.
     */
    function add(UintSet storage set, uint256 value) internal returns (bool) {
        return _add(set._inner, bytes32(value));
    }

    /**
     * @dev Removes a value from a set. O(1).
     *
     * Returns true if the value was removed from the set, that is if it was
     * present.
     */
    function remove(UintSet storage set, uint256 value) internal returns (bool) {
        return _remove(set._inner, bytes32(value));
    }

    /**
     * @dev Returns true if the value is in the set. O(1).
     */
    function contains(UintSet storage set, uint256 value) internal view returns (bool) {
        return _contains(set._inner, bytes32(value));
    }

    /**
     * @dev Returns the number of values in the set. O(1).
     */
    function length(UintSet storage set) internal view returns (uint256) {
        return _length(set._inner);
    }

    /**
     * @dev Returns the value stored at position `index` in the set. O(1).
     *
     * Note that there are no guarantees on the ordering of values inside the
     * array, and it may change when more values are added or removed.
     *
     * Requirements:
     *
     * - `index` must be strictly less than {length}.
     */
    function at(UintSet storage set, uint256 index) internal view returns (uint256) {
        return uint256(_at(set._inner, index));
    }

    /**
     * @dev Return the entire set in an array
     *
     * WARNING: This operation will copy the entire storage to memory, which can be quite expensive. This is designed
     * to mostly be used by view accessors that are queried without any gas fees. Developers should keep in mind that
     * this function has an unbounded cost, and using it as part of a state-changing function may render the function
     * uncallable if the set grows to a point where copying to memory consumes too much gas to fit in a block.
     */
    function values(UintSet storage set) internal view returns (uint256[] memory) {
        bytes32[] memory store = _values(set._inner);
        uint256[] memory result;

        /// @solidity memory-safe-assembly
        assembly {
            result := store
        }

        return result;
    }
}

File 5 of 14 : 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 6 of 14 : IERCOmnReceiver.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0
// www.eternalproxy.com

/**
 
@dev IERCOmnReceiver - Interface

 */

pragma solidity 0.8.17;

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

File 7 of 14 : IOAT.sol
// SPDX-License-Identifier: MIT
// EPS Contracts v2.0.0
// www.eternalproxy.com

/**
 
@dev IOAT - Interface

 */

pragma solidity 0.8.17;

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

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

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

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

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

File 8 of 14 : 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 9 of 14 : IERC721.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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: Note that the caller is responsible to confirm that the recipient is capable of receiving ERC721
     * or else they may be permanently lost. Usage of {safeTransferFrom} prevents loss, though the caller must
     * understand this adds an external call which potentially creates a reentrancy vulnerability.
     *
     * 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 10 of 14 : SafeERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 11 of 14 : IERC20.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.6.0) (token/ERC20/IERC20.sol)

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

File 12 of 14 : 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 14 : Address.sol
// SPDX-License-Identifier: MIT
// OpenZeppelin Contracts (last updated v4.8.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 functionCallWithValue(target, data, 0, "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");
        (bool success, bytes memory returndata) = target.call{value: value}(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.staticcall(data);
        return verifyCallResultFromTarget(target, 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) {
        (bool success, bytes memory returndata) = target.delegatecall(data);
        return verifyCallResultFromTarget(target, success, returndata, errorMessage);
    }

    /**
     * @dev Tool to verify that a low level call to smart-contract was successful, and revert (either by bubbling
     * the revert reason or using the provided one) in case of unsuccessful call or if target was not a contract.
     *
     * _Available since v4.8._
     */
    function verifyCallResultFromTarget(
        address target,
        bool success,
        bytes memory returndata,
        string memory errorMessage
    ) internal view returns (bytes memory) {
        if (success) {
            if (returndata.length == 0) {
                // only check isContract if the call was successful and the return data is empty
                // otherwise we already know that it was a contract
                require(isContract(target), "Address: call to non-contract");
            }
            return returndata;
        } else {
            _revert(returndata, errorMessage);
        }
    }

    /**
     * @dev Tool to verify that a low level call was successful, and revert if it wasn't, either by bubbling the
     * revert reason or 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 {
            _revert(returndata, errorMessage);
        }
    }

    function _revert(bytes memory returndata, string memory errorMessage) private pure {
        // 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 14 of 14 : 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);
}

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

Contract Security Audit

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"inputs":[],"name":"CannotDelegatedATokenYouDontOwn","type":"error"},{"inputs":[],"name":"CannotDeleteValidDelegation","type":"error"},{"inputs":[],"name":"CannotRevokeAllForRegisterAdminHierarchy","type":"error"},{"inputs":[],"name":"HotAddressIsLockedAndCannotBeDelegatedTo","type":"error"},{"inputs":[{"internalType":"uint256","name":"requiredLevel","type":"uint256"}],"name":"IncorrectAdminLevel","type":"error"},{"inputs":[],"name":"IncorrectProxyRegisterFee","type":"error"},{"inputs":[],"name":"InvalidDelegation","type":"error"},{"inputs":[],"name":"InvalidERC20Payment","type":"error"},{"inputs":[],"name":"OnlyParticipantOrAuthorisedSubDelegate","type":"error"},{"inputs":[{"internalType":"uint256","name":"sent","type":"uint256"},{"internalType":"uint256","name":"required","type":"uint256"}],"name":"ToMuchETHForPendingPayments","type":"error"},{"inputs":[],"name":"UnknownAmount","type":"error"},{"inputs":[],"name":"UnrecognisedEPSAPIAmount","type":"error"},{"inputs":[{"internalType":"uint256","name":"usageType","type":"uint256"}],"name":"UsageTypeAlreadyDelegated","type":"error"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"cold","type":"address"}],"name":"AllDelegationsRevokedForCold","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hot","type":"address"}],"name":"AllDelegationsRevokedForHot","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":"targetAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"tokenId","type":"uint256"},{"indexed":false,"internalType":"bool","name":"tokenDelegation","type":"bool"},{"indexed":false,"internalType":"uint8[]","name":"usageTypes","type":"uint8[]"},{"indexed":false,"internalType":"uint40","name":"startDate","type":"uint40"},{"indexed":false,"internalType":"uint40","name":"endDate","type":"uint40"},{"indexed":false,"internalType":"uint16","name":"providerCode","type":"uint16"},{"indexed":false,"internalType":"enum IEPSDelegationRegister.DelegationClass","name":"delegationClass","type":"uint8"},{"indexed":false,"internalType":"uint96","name":"subDelegateKey","type":"uint96"},{"indexed":false,"internalType":"bytes","name":"data","type":"bytes"},{"indexed":false,"internalType":"enum IEPSDelegationRegister.DelegationStatus","name":"status","type":"uint8"}],"name":"DelegationMade","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"delegationKey","type":"address"}],"name":"DelegationPaid","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"hot","type":"address"},{"indexed":false,"internalType":"address","name":"cold","type":"address"},{"indexed":false,"internalType":"address","name":"delegationKey","type":"address"}],"name":"DelegationRevoked","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[{"internalType":"address","name":"bypassAddress_","type":"address"}],"name":"addLockBypassAddress","outputs":[],"stateMutability":"nonpayable","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"},{"internalType":"address","name":"contractAddress_","type":"address"},{"internalType":"uint256","name":"usageType_","type":"uint256"},{"internalType":"bool","name":"erc1155_","type":"bool"},{"internalType":"uint256","name":"id_","type":"uint256"},{"internalType":"bool","name":"includeSecondary_","type":"bool"},{"internalType":"bool","name":"includeRental_","type":"bool"}],"name":"beneficiaryBalanceOf","outputs":[{"internalType":"uint256","name":"balance_","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"collection_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"uint256","name":"usageType_","type":"uint256"},{"internalType":"bool","name":"includeSecondary_","type":"bool"},{"internalType":"bool","name":"includeRental_","type":"bool"}],"name":"beneficiaryOf","outputs":[{"internalType":"address","name":"primaryBeneficiary_","type":"address"},{"internalType":"address[]","name":"secondaryBeneficiaries_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address","name":"delegationKey_","type":"address"}],"name":"delegationFromColdExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"address","name":"delegationKey_","type":"address"}],"name":"delegationFromHotExists","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"delegationMetadata","outputs":[{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"bytes","name":"data","type":"bytes"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"delegationKey_","type":"address"}],"name":"deleteExpired","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"address","name":"collection_","type":"address"},{"internalType":"uint256","name":"usageType_","type":"uint256"},{"internalType":"bool","name":"includeSecondary_","type":"bool"},{"internalType":"bool","name":"includeRental_","type":"bool"}],"name":"getAddresses","outputs":[{"internalType":"address[]","name":"addresses_","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"}],"name":"getAllForCold","outputs":[{"components":[{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"enum IEPSDelegationRegister.DelegationScope","name":"scope","type":"uint8"},{"internalType":"enum IEPSDelegationRegister.DelegationClass","name":"class","type":"uint8"},{"internalType":"enum IEPSDelegationRegister.DelegationTimeLimit","name":"timeLimit","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint40","name":"startDate","type":"uint40"},{"internalType":"uint40","name":"endDate","type":"uint40"},{"internalType":"bool","name":"validByDate","type":"bool"},{"internalType":"bool","name":"validBilaterally","type":"bool"},{"internalType":"bool","name":"validTokenOwnership","type":"bool"},{"internalType":"bool[25]","name":"usageTypes","type":"bool[25]"},{"internalType":"address","name":"key","type":"address"},{"internalType":"uint96","name":"controlInteger","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum IEPSDelegationRegister.DelegationStatus","name":"status","type":"uint8"}],"internalType":"struct IEPSDelegationRegister.DelegationReport[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"}],"name":"getAllForHot","outputs":[{"components":[{"internalType":"address","name":"hot","type":"address"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"enum IEPSDelegationRegister.DelegationScope","name":"scope","type":"uint8"},{"internalType":"enum IEPSDelegationRegister.DelegationClass","name":"class","type":"uint8"},{"internalType":"enum IEPSDelegationRegister.DelegationTimeLimit","name":"timeLimit","type":"uint8"},{"internalType":"address","name":"collection","type":"address"},{"internalType":"uint256","name":"tokenId","type":"uint256"},{"internalType":"uint40","name":"startDate","type":"uint40"},{"internalType":"uint40","name":"endDate","type":"uint40"},{"internalType":"bool","name":"validByDate","type":"bool"},{"internalType":"bool","name":"validBilaterally","type":"bool"},{"internalType":"bool","name":"validTokenOwnership","type":"bool"},{"internalType":"bool[25]","name":"usageTypes","type":"bool[25]"},{"internalType":"address","name":"key","type":"address"},{"internalType":"uint96","name":"controlInteger","type":"uint96"},{"internalType":"bytes","name":"data","type":"bytes"},{"internalType":"enum IEPSDelegationRegister.DelegationStatus","name":"status","type":"uint8"}],"internalType":"struct IEPSDelegationRegister.DelegationReport[]","name":"","type":"tuple[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address","name":"targetAddress_","type":"address"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bool","name":"tokenDelegation_","type":"bool"},{"internalType":"uint96","name":"controlInteger_","type":"uint96"},{"internalType":"uint40","name":"startDate_","type":"uint40"},{"internalType":"uint40","name":"endDate_","type":"uint40"}],"name":"getDelegationKey","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"delegationKey_","type":"address"}],"name":"getDelegationRecord","outputs":[{"components":[{"internalType":"address","name":"hot","type":"address"},{"internalType":"uint96","name":"controlInteger","type":"uint96"},{"internalType":"address","name":"cold","type":"address"},{"internalType":"uint40","name":"startDate","type":"uint40"},{"internalType":"uint40","name":"endDate","type":"uint40"},{"internalType":"enum IEPSDelegationRegister.DelegationStatus","name":"status","type":"uint8"}],"internalType":"struct IEPSDelegationRegister.DelegationRecord","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"}],"name":"getHotAddressLockDetails","outputs":[{"components":[{"internalType":"uint40","name":"lockStart","type":"uint40"},{"internalType":"uint40","name":"lockEnd","type":"uint40"}],"internalType":"struct IEPSDelegationRegister.LockDetails","name":"","type":"tuple"},{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"includeLegacy","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"receivedAddress_","type":"address"},{"internalType":"uint256","name":"level_","type":"uint256"},{"internalType":"uint96","name":"key_","type":"uint96"}],"name":"isLevelAdmin","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":"collection_","type":"address"},{"internalType":"uint256","name":"usageType_","type":"uint256"},{"internalType":"bool","name":"includeSecondary_","type":"bool"},{"internalType":"bool","name":"includeRental_","type":"bool"}],"name":"isValidDelegation","outputs":[{"internalType":"bool","name":"isValid_","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"lockAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"unlockDate_","type":"uint40"}],"name":"lockAddressUntilDate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockRewardRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"hot_","type":"address"},{"internalType":"address","name":"cold_","type":"address"},{"internalType":"address[]","name":"targetAddresses_","type":"address[]"},{"internalType":"uint256","name":"tokenId_","type":"uint256"},{"internalType":"bool","name":"tokenDelegation_","type":"bool"},{"internalType":"uint8[]","name":"usageTypes_","type":"uint8[]"},{"internalType":"uint40","name":"startDate_","type":"uint40"},{"internalType":"uint40","name":"endDate_","type":"uint40"},{"internalType":"uint16","name":"providerCode_","type":"uint16"},{"internalType":"enum IEPSDelegationRegister.DelegationClass","name":"delegationClass_","type":"uint8"},{"internalType":"uint96","name":"subDelegateKey_","type":"uint96"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"makeDelegation","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[{"internalType":"address","name":"sender_","type":"address"},{"internalType":"uint256","name":"erc20Value_","type":"uint256"},{"internalType":"bytes","name":"data_","type":"bytes"}],"name":"onTokenTransfer","outputs":[],"stateMutability":"payable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"uint256","name":"","type":"uint256"}],"name":"pendingPayments","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"bypassAddress_","type":"address"}],"name":"removeLockBypassAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"cold_","type":"address"},{"internalType":"uint96","name":"subDelegateKey_","type":"uint96"}],"name":"revokeAllForCold","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"revokeAllForHot","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"delegationKey_","type":"address"},{"internalType":"uint96","name":"subDelegateKey_","type":"uint96"}],"name":"revokeRecord","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"participant2_","type":"address"}],"name":"revokeRecordOfGlobalScopeForAllUsages","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"rewardRate","outputs":[{"internalType":"uint88","name":"","type":"uint88"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardRateLocked","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"rewardToken","outputs":[{"internalType":"contract IOAT","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint8","name":"decimals_","type":"uint8"},{"internalType":"uint256","name":"balance_","type":"uint256"}],"name":"setDecimalsAndBalance","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"string","name":"ensName_","type":"string"}],"name":"setENSName","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"ensReverseRegistrar_","type":"address"}],"name":"setENSReverseRegistrar","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"setLegacyOff","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"registerFee_","type":"uint256"},{"internalType":"address","name":"erc20_","type":"address"},{"internalType":"uint256","name":"erc20Fee_","type":"uint256"}],"name":"setRegisterFees","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"rewardToken_","type":"address"},{"internalType":"uint88","name":"rewardRate_","type":"uint88"}],"name":"setRewardTokenAndRate","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"treasuryAddress_","type":"address"}],"name":"setTreasuryAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"pure","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"unlockAddress","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint40","name":"lockAtTime_","type":"uint40"}],"name":"unlockAddressUntilTime","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"contract IERC20","name":"token_","type":"address"},{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawERC20","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount_","type":"uint256"}],"name":"withdrawETH","outputs":[{"internalType":"bool","name":"success_","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"stateMutability":"payable","type":"receive"}]

60806040526000196000556003805461ffff19166103011790553480156200002657600080fd5b5062000033600e6200005d565b6200003f60196200005d565b6200004b60186200005d565b6200005760176200005d565b620017e5565b6040805160018082528183019092526000916020808301908036833701905050905081816000815181106200009657620000966200135d565b60ff92909216602092830291909101820152604080516101a081018252739f0773af2b1d3f7cc7030304548a823b4e6b13bb815230818401528151600180825281840184526200014a949293840192828101908036833701905050815260006020820181905260408201819052606082018590526080820181905260a0820181905260c082015260e0016001815260006020808301829052604080519182018152828252830152606090910152306200014e565b5050565b60005b8260400151518110156200058e57825160208401516101408501516200017a929190856200065e565b6000620001d18460200151856040015184815181106200019e576200019e6200135d565b6020026020010151866060015187608001518860a001518960c001518a60e001518b61012001516200069c60201b60201c565b90506000620002258560000151866020015187604001518681518110620001fc57620001fc6200135d565b602002602001015188606001518960800151878b60c001518c60e00151620009d860201b60201c565b90508460800151156200029a576200029881600860006200027689602001518a6040015189815181106200025d576200025d6200135d565b60200260200101518b6060015162000a6960201b60201c565b815260200190815260200160002062000ada60201b62001bb81790919060201c565b505b60006001600160a01b031685604001518481518110620002be57620002be6200135d565b60200260200101516001600160a01b0316141580620002e257506101608501515115155b1562000381576040518060600160405280866040015185815181106200030c576200030c6200135d565b6020908102919091018101516001600160a01b0390811683526060890151838301526101608901516040938401528481166000908152600a8352839020845181546001600160a01b03191692169190911781559083015160018201559082015160028201906200037d908262001409565b5050505b600185610180015160018111156200039d576200039d62001373565b03620003e8576020858101516001600160a01b039081166000908152600f835260408120805460018101825590825292902090910180546001600160a01b0319169183169190911790555b62000406816006600062000276896000015162000afa60201b60201c565b5062000425816007600062000276896020015162000b5460201b60201c565b506040518060c0016040528086600001516001600160a01b03168152602001836001600160601b0316815260200186602001516001600160a01b031681526020018660c0015164ffffffffff1681526020018660e0015164ffffffffff1681526020018661018001516001811115620004a257620004a262001373565b90526001600160a01b03828116600090815260096020908152604091829020845191850151918416600160a01b6001600160601b039093168302178155918401516001808401805460608801516080890151949097166001600160c81b03199091161764ffffffffff9687169094029390931764ffffffffff60c81b198116600160c81b9690931695909502918217835560a0860151939465ffffffffffff60c81b191660ff60f01b199092169190911790600160f01b9084908111156200056e576200056e62001373565b02179055506200058391508690508462000b96565b505060010162000151565b506002546001600160a01b0316156200014a5760008261018001516001811115620005bd57620005bd62001373565b036200014a576002546001600160a01b0316632e6f213633604085015151600254620005fa9190600160a01b90046001600160581b0316620014eb565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156200064157600080fd5b505af115801562000656573d6000803e3d6000fd5b505050505050565b6200066a848462000c50565b156200068957604051630da1844d60e01b815260040160405180910390fd5b6200069681848462000d03565b50505050565b6000806001600160a01b038916156200077857861562000766576040516331a9108f60e11b8152600481018990526001600160a01b03808c1691908b1690636352211e90602401602060405180830381865afa15801562000701573d6000803e3d6000fd5b505050506040513d601f19601f8201168201806040525081019062000727919062001505565b6001600160a01b0316146200074f5760405163400d9f5560e11b815260040160405180910390fd5b6b06765c793fa10079d00000008201915062000778565b6b033b2e3c9fd0803ce8000000820191505b60018360028111156200078f576200078f62001373565b03620007a6576a084595161401484a000000820191505b6002836002811115620007bd57620007bd62001373565b03620007d4576a108b2a2c28029094000000820191505b64ffffffffff8585011615620007f5576a52b7d2dcc80cd2e4000000820191505b60005b86518110156200091257600184600281111562000819576200081962001373565b14158015620008575750620008578b8b8a8c8b86815181106200084057620008406200135d565b602002602001015160ff1662000d3360201b60201c565b15620008a7578681815181106200087257620008726200135d565b6020026020010151604051630aab3ce760e41b81526004016200089e919060ff91909116815260200190565b60405180910390fd5b868181518110620008bc57620008bc6200135d565b602002602001015160ff16600103620008db5760018201915062000909565b6001878281518110620008f257620008f26200135d565b60200260200101510360ff16600a0a600102820191505b600101620007f8565b5060018360028111156200092a576200092a62001373565b14620009cb578060056000620009b38d8d8c8e6001600160a01b0384166000908152600c6020908152604091829020548251606097881b6001600160601b0319908116828501529690971b909516603487015292151560f81b60488601526049850191909152606980850193909352805180850390930183526089909301909252805191012090565b81526020810191909152604001600020805490910190555b0198975050505050505050565b604080516060998a1b6001600160601b0319908116602080840191909152998b1b811660348301529790991b9096166048890152605c88019490945291151560f81b607c87015260a01b6001600160a01b031916607d86015260d890811b6001600160d81b0319908116608987015291901b16608e8401528051607381850301815260939093019052815191012090565b6001600160a01b0383166000908152600c602090815260408083205490516001600160601b0319606088811b82169483019490945260348201929092529185901b166054820152606881018390526088016040516020818303038152906040528051906020012090505b9392505050565b600062000af1836001600160a01b03841662000dea565b90505b92915050565b6001600160a01b0381166000908152600b602090815260408083205490516001600160601b0319606086901b169281019290925260348201526054015b604051602081830303815290604052805190602001209050919050565b6001600160a01b0381166000908152600c602090815260408083205490516001600160601b0319606086901b1692810192909252603482015260540162000b37565b81602001516001600160a01b031682600001516001600160a01b03167f44d84a2c5d27e81636e3182f4601b82564c8086c61dd9a83e3b4586c4db96b2f8460400151848151811062000bec5762000bec6200135d565b6020026020010151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e610180015160405162000c449b9a99989796959493929190620015a2565b60405180910390a35050565b6001600160a01b0382166000908152600d6020908152604080832081518083019092525464ffffffffff808216835265010000000000909104169181018290529042118062000ca65750805164ffffffffff1642105b1562000cb757600091505062000af4565b6001600160a01b0384166000908152600e6020908152604090912062000ce891859062001bcd62000e3c821b17901c565b1562000cf957600091505062000af4565b5060019392505050565b62000d1083838362000e5f565b62000d2e5760405163fed82dc360e01b815260040160405180910390fd5b505050565b6001600160a01b0385166000908152600c602090815260408083205481516001600160601b031960608b811b8216838701528a901b16603482015287151560f81b60488201526049810187905260698082019290925282518082039092018252608901825280519083012083526005909152812054801580159062000dca5750826001148062000dca575062000dca838262000eef565b1562000ddb57600191505062000de1565b60009150505b95945050505050565b600081815260018301602052604081205462000e335750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915562000af4565b50600062000af4565b6001600160a01b0381166000908152600183016020526040812054151562000af1565b6000836001600160a01b0316836001600160a01b03160362000e845750600162000ad3565b60408051606080820183526001600160a01b0380881683528616602080840191909152600083850181905284519283018552600180845283830152828501819052845180860190955280855290840181905262000ee7938691600e918162000f2e565b949350505050565b6000600e831415801562000f0b575062000f0b6001836200115e565b1562000f1a5750600162000af4565b62000f2683836200115e565b905062000af4565b855160009015801562000f685750600162000f526001600160601b03881662001176565b600281111562000f665762000f6662001373565b145b8062000fa95750866020015115801562000fa95750600262000f936001600160601b03881662001176565b600281111562000fa75762000fa762001373565b145b8062000fc7575062000fc5856001600160601b03881662000eef565b155b1562000fd65750600062001153565b60006200100889600001518a602001518b60400151888c604001518c8a600001518b60200151620009d860201b60201c565b905062001020896020015182620011ba60201b60201c565b1580620010385750885162001036908262001208565b155b806200107e575060016001600160a01b0382166000908152600960205260409020600190810154600160f01b900460ff16908111156200107c576200107c62001373565b145b80620010c85750620010996001600160601b0388166200121d565b8015620010c857506040808a01516001600160a01b038381166000908152600a60205292909220548216911614155b806200110a5750620010e36001600160601b03881662001247565b80156200110a575083516020850151620011089164ffffffffff90811691166200126a565b155b806200113c57506001600160a01b038316158015906200113c5750806001600160a01b0316836001600160a01b031614155b156200114d57600091505062001153565b60019150505b979650505050505050565b60006200116c83836200127f565b6001149392505050565b600062001185601a836200127f565b6000036200119557506000919050565b620011a2601a836200127f565b600103620011b257506001919050565b506002919050565b6000620011f182600783620011cf8762000b54565b815260200190815260200160002062000e3c60201b62001bcd1790919060201c565b620011ff5750600062000af4565b50600192915050565b6000620011f182600683620011cf8762000afa565b600060016200122c83620012db565b600281111562001240576200124062001373565b1492915050565b60006001620012568362001320565b600181111562001240576200124062001373565b6000428310801562000af15750504210919050565b6000806200128f84600a6200177d565b9050600084600103620012a557506001620012c2565b620012b26001866200178b565b620012bf90600a6200177d565b90505b80620012cf8386620017b7565b62000de19190620017ce565b600080620012eb601c846200127f565b905080600003620012ff5750600092915050565b80600103620013115750600192915050565b50600292915050565b50919050565b60006200132f601b836200127f565b6000036200133f57506000919050565b506001919050565b634e487b7160e01b600052604160045260246000fd5b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052602160045260246000fd5b600181811c908216806200139e57607f821691505b6020821081036200131a57634e487b7160e01b600052602260045260246000fd5b601f82111562000d2e57600081815260208120601f850160051c81016020861015620013e85750805b601f850160051c820191505b818110156200065657828155600101620013f4565b81516001600160401b0381111562001425576200142562001347565b6200143d8162001436845462001389565b84620013bf565b602080601f8311600181146200147557600084156200145c5750858301515b600019600386901b1c1916600185901b17855562000656565b600085815260208120601f198616915b82811015620014a65788860151825594840194600190910190840162001485565b5085821015620014c55787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b634e487b7160e01b600052601160045260246000fd5b808202811582820484141762000af45762000af4620014d5565b6000602082840312156200151857600080fd5b81516001600160a01b038116811462000ad357600080fd5b6003811062001543576200154362001373565b9052565b6000815180845260005b818110156200156f5760208185018101518683018201520162001551565b506000602082860101526020601f19601f83011685010191505092915050565b6002811062001543576200154362001373565b6001600160a01b038c16815260208082018c90528a15156040830152610160606083018190528a519083018190526000916101808401918c82019190845b818110156200160157835160ff1685529382019392820192600101620015e0565b50505064ffffffffff8b1660808501525064ffffffffff891660a084015261ffff881660c08401526200163860e084018862001530565b6001600160601b0386166101008401528281036101208401526200165d818662001547565b915050620016706101408301846200158f565b9c9b505050505050505050505050565b600181815b80851115620016c1578160001904821115620016a557620016a5620014d5565b80851615620016b357918102915b93841c939080029062001685565b509250929050565b600082620016da5750600162000af4565b81620016e95750600062000af4565b81600181146200170257600281146200170d576200172d565b600191505062000af4565b60ff841115620017215762001721620014d5565b50506001821b62000af4565b5060208310610133831016604e8410600b841016171562001752575081810a62000af4565b6200175e838362001680565b8060001904821115620017755762001775620014d5565b029392505050565b600062000af18383620016c9565b8181038181111562000af45762000af4620014d5565b634e487b7160e01b600052601260045260246000fd5b600082620017c957620017c9620017a1565b500690565b600082620017e057620017e0620017a1565b500490565b615f5f80620017f56000396000f3fe60806040526004361061028c5760003560e01c80637be4c1771161015a578063b52d1c19116100c1578063f14210a61161007a578063f14210a614610863578063f228967e14610883578063f50ef9b4146108b0578063f7c618c1146108d0578063fc4a7db1146108f0578063fc662b1c1461091057600080fd5b8063b52d1c19146107a9578063b674d1d7146107c9578063c00206e1146107e3578063c2c97fa314610803578063d800321314610823578063df0003731461084357600080fd5b8063a1db978211610113578063a1db9782146106ef578063a4c0ed361461070f578063a5bc5b8414610722578063a659f29114610737578063a9059cbb14610757578063b30929cd1461077757600080fd5b80637be4c177146106655780637da3f6131461067a5780638546039e1461068f5780638ad2b02d146106af57806395d89b411461034157806397ec8346146106cf57600080fd5b80634a01e225116101fe5780636b33c1ef116101b75780636b33c1ef1461057657806370a082311461059657806371d55afe146105b857806377dd4ac3146105d857806379150d34146105f85780637b0a47ee1461062657600080fd5b80634a01e2251461048e5780634d0800b0146104bc57806354559dbb146104e95780635921920714610516578063652c12eb146105365780636605bfda1461055657600080fd5b806318160ddd1161025057806318160ddd146103b857806327eb8773146103d75780632a468529146103f7578063313ce5671461040c5780634144c028146104365780634815d31c1461045657600080fd5b80630186fce1146102eb5780630294bdab1461032157806306fdde0314610341578063147eb2601461037657806316ab93b11461038957600080fd5b366102e65760015461029e9034614cbf565b6000036102b1576102af3334610930565b005b6102c9335b60196a09195731e2ce35eb000000610aab565b6102af5760405163020ad41b60e11b815260040160405180910390fd5b600080fd5b3480156102f757600080fd5b5060025461030c90600160f81b900460ff1681565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b506102af61033c366004614cf3565b610b18565b34801561034d57600080fd5b50604080518082018252600681526545505341504960d01b602082015290516103189190614d56565b6102af610384366004614fba565b610b25565b34801561039557600080fd5b506103a96103a4366004614cf3565b610bfd565b604051610318939291906150e4565b3480156103c457600080fd5b506000545b604051908152602001610318565b3480156103e357600080fd5b506103c96103f236600461510b565b610cb2565b34801561040357600080fd5b506102af610e3e565b34801561041857600080fd5b50600354610100900460ff1660405160ff9091168152602001610318565b34801561044257600080fd5b5061030c61045136600461518f565b610aab565b34801561046257600080fd5b506104766104713660046151d1565b610e82565b6040516001600160a01b039091168152602001610318565b34801561049a57600080fd5b506104ae6104a93660046151fd565b610eba565b6040516103189291906152a0565b3480156104c857600080fd5b506104dc6104d7366004614cf3565b610f9d565b604051610318919061532c565b3480156104f557600080fd5b506105096105043660046154bd565b611145565b6040516103189190615507565b34801561052257600080fd5b506102af61053136600461551a565b611163565b34801561054257600080fd5b506102af610551366004614cf3565b6111ac565b34801561056257600080fd5b506102af610571366004614cf3565b6112ee565b34801561058257600080fd5b506102af610591366004615538565b611339565b3480156105a257600080fd5b506103c96105b1366004614cf3565b5060005490565b3480156105c457600080fd5b506102af6105d3366004615570565b611391565b3480156105e457600080fd5b506102af6105f33660046155a9565b61139c565b34801561060457600080fd5b50610618610613366004614cf3565b61143d565b6040516103189291906155f9565b34801561063257600080fd5b5060025461064d90600160a01b90046001600160581b031681565b6040516001600160581b039091168152602001610318565b34801561067157600080fd5b506102af6114ad565b34801561068657600080fd5b506102af6114b8565b34801561069b57600080fd5b5061030c6106aa366004615628565b6114c8565b3480156106bb57600080fd5b506102af6106ca366004615570565b61150d565b3480156106db57600080fd5b5061030c6106ea366004615656565b61154a565b3480156106fb57600080fd5b506102af61070a3660046151d1565b611566565b6102af61071d3660046156cf565b61160d565b34801561072e57600080fd5b506102af611660565b34801561074357600080fd5b506102af610752366004614cf3565b6116a0565b34801561076357600080fd5b5061030c6107723660046151d1565b6116b9565b34801561078357600080fd5b506102af336000908152600d60205260409020805469ffffffffffffffffffff19169055565b3480156107b557600080fd5b506102af6107c4366004614cf3565b611710565b3480156107d557600080fd5b5060035461030c9060ff1681565b3480156107ef57600080fd5b506102af6107fe366004614cf3565b611763565b34801561080f57600080fd5b506102af61081e366004615727565b61177c565b34801561082f57600080fd5b506102af61083e366004615761565b6117fe565b34801561084f57600080fd5b5061030c61085e366004615628565b61180e565b34801561086f57600080fd5b5061030c61087e36600461577e565b611821565b34801561088f57600080fd5b506108a361089e366004614cf3565b6118a7565b6040516103189190615797565b3480156108bc57600080fd5b506104dc6108cb366004614cf3565b61198d565b3480156108dc57600080fd5b50600254610476906001600160a01b031681565b3480156108fc57600080fd5b5061047661090b366004615808565b611b1c565b34801561091c57600080fd5b506102af61092b366004615761565b611bad565b6001600160a01b0382166000908152600f602052604081205460015490919061095990846158be565b90508181111561099957826001548361097291906158d2565b60405163ea626b3f60e01b8152600481019290925260248201526044015b60405180910390fd5b815b6000811180156109ab5750600082115b15610aa4576001600160a01b0385166000908152600f602052604081206109d36001846158e9565b815481106109e3576109e36158fc565b6000918252602080832091909101546001600160a01b031680835260098252604092839020600101805460ff60f01b1916905591518281529192507f851101b6327b058b27638fcf86d96eec48dca48ba23b1f29ed67139449f9407d910160405180910390a16001600160a01b0386166000908152600f60205260409020805480610a7057610a70615912565b600082815260209020810160001990810180546001600160a01b03191690559081019091559283019291909101905061099b565b5050505050565b60408051606080820183526001600160a01b038616825230602080840191909152600083850181905284519283018552600180845283830152828501819052845180860190955280855290840181905292610b0e92919085908790869081611bef565b90505b9392505050565b610b223382611deb565b50565b6001543414610b47576040516333b18e6b60e11b815260040160405180910390fd5b6000604051806101a001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c81526020018b81526020018a151581526020018981526020018864ffffffffff1681526020018764ffffffffff1681526020018661ffff168152602001856002811115610bc357610bc36152c4565b81526001600160601b038516602082015260408101849052606001600090529050610bee8133611e2a565b50505050505050505050505050565b600a602052600090815260409020805460018201546002830180546001600160a01b03909316939192610c2f90615928565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b90615928565b8015610ca85780601f10610c7d57610100808354040283529160200191610ca8565b820191906000526020600020905b815481529060010190602001808311610c8b57829003601f168201915b5050505050905083565b600080610cc28989898787611145565b905085610d7c5760005b8151811015610d7657886001600160a01b03166370a08231838381518110610cf657610cf66158fc565b60200260200101516040518263ffffffff1660e01b8152600401610d2991906001600160a01b0391909116815260200190565b602060405180830381865afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a919061595c565b90920191600101610ccc565b50610e31565b60005b8151811015610e2f57886001600160a01b031662fdd58e838381518110610da857610da86158fc565b6020026020010151886040518363ffffffff1660e01b8152600401610de29291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e23919061595c565b90920191600101610d7f565b505b505b979650505050505050565b610e56335b60176a0847b32ff4cb02fc400000610aab565b610e7657604051630894d7d160e41b815260036004820152602401610990565b6003805460ff19169055565b600f6020528160005260406000208181548110610e9e57600080fd5b6000918252602090912001546001600160a01b03169150829050565b600060606000876001600160a01b0316636352211e886040518263ffffffff1660e01b8152600401610eee91815260200190565b602060405180830381865afa158015610f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2f9190615975565b9050610f3f8189898989896122db565b90935091506001600160a01b038316610f8057610f7a81898860405180604001604052808a15151515815260200189151515158152506125c1565b90935091505b6001600160a01b038316610f92578092505b509550959350505050565b6060600060076000610fae8561288e565b815260200190815260200160002090506000610fc9826128e8565b90506000816001600160401b03811115610fe557610fe5614d69565b60405190808252806020026020018201604052801561101e57816020015b61100b614bad565b8152602001906001900390816110035790505b50905060005b8281101561113c57600061103885836128f2565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff16908111156110d2576110d26152c4565b60018111156110e3576110e36152c4565b90525080516020820151919250611115918a90611100838761180e565b85606001518660800151888860a001516128fe565b848481518110611127576111276158fc565b60209081029190910101525050600101611024565b50949350505050565b606061115686868686866000612c04565b5090505b95945050505050565b61116c33610e43565b61118c57604051630894d7d160e41b815260036004820152602401610990565b6003805460ff9093166101000261ff001990931692909217909155600055565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b8604166080840152929391929160a0840191600160f01b90910460ff1690811115611243576112436152c4565b6001811115611254576112546152c4565b90525080519091506001600160a01b03166112825760405163a9e649e960e01b815260040160405180910390fd5b61129881602001516001600160601b0316612f1a565b15806112bf57506112bf816060015164ffffffffff16826080015164ffffffffff16612f3f565b156112dc576040516287bfad60e21b815260040160405180910390fd5b80516112ea90836000612f53565b5050565b6112f733610e43565b61131757604051630894d7d160e41b815260036004820152602401610990565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611351335b60186a085ac218dbe29340800000610aab565b61137157604051630894d7d160e41b815260026004820152602401610990565b6001929092556001600160a01b0316600090815260106020526040902055565b6112ea338383612f53565b6113a5336102b6565b6113c557604051630894d7d160e41b815260016004820152602401610990565b60035460405163c47f002760e01b8152620100009091046001600160a01b03169063c47f0027906113fa908490600401614d56565b6020604051808303816000875af1158015611419573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ea919061595c565b604080518082018252600080825260208083018290526001600160a01b0385168252600d8152838220600e909152929020909160609161147c9061339c565b60408051808201909152915464ffffffffff8082168452650100000000009091041660208301529094909350915050565b6114b6336133a9565b565b6114b6334264ffffffffff613400565b60006114f782600760006114db8761288e565b8152602001908152602001600020611bcd90919063ffffffff16565b61150357506000611507565b5060015b92915050565b611518338383613463565b306001600160a01b038316036115415760405163e1bbc9d760e01b815260040160405180910390fd5b6112ea3361348b565b600061155a87868686868b612c04565b98975050505050505050565b61156f336102b6565b61158f57604051630894d7d160e41b815260016004820152602401610990565b6004805460405163a9059cbb60e01b81526001600160a01b03918216928101929092526024820183905283169063a9059cbb906044016020604051808303816000875af11580156115e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611608919061599d565b505050565b3360009081526010602052604090205480158061162a5750828114155b1561164857604051632ab209a560e11b815260040160405180910390fd5b61165a611654836134db565b85611e2a565b50505050565b61166933610e43565b61168957604051630894d7d160e41b815260036004820152602401610990565b600280546001600160f81b0316600160f81b179055565b336000908152600e602052604090206112ea9082611bb8565b60006116c633848461364a565b604051600081526001600160a01b0384169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350600192915050565b611719336102b6565b61173957604051630894d7d160e41b815260016004820152602401610990565b600380546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b336000908152600e602052604090206112ea90826137c6565b6117853361133e565b6117a557604051630894d7d160e41b815260026004820152602401610990565b600280546001600160a01b0319166001600160a01b0384161790819055600160f81b900460ff166112ea57600280546001600160581b038316600160a01b026affffffffffffffffffffff60a01b199091161790555050565b610b22338264ffffffffff613400565b60006114f782600660006114db876137db565b600061182c336102b6565b61184c57604051630894d7d160e41b815260016004820152602401610990565b6004546040516001600160a01b03909116908390600081818185875af1925050503d8060008114611899576040519150601f19603f3d011682016040523d82523d6000602084013e61189e565b606091505b50909392505050565b6118dd6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6001600160a01b03828116600090815260096020908152604091829020825160c08101845281548086168252600160a01b908190046001600160601b0316938201939093526001808301549586169482019490945291840464ffffffffff9081166060840152600160c81b85041660808301529092909160a0840191600160f01b900460ff1690811115611973576119736152c4565b6001811115611984576119846152c4565b90525092915050565b606060006006600061199e856137db565b8152602001908152602001600020905060006119b9826128e8565b90506000816001600160401b038111156119d5576119d5614d69565b604051908082528060200260200182016040528015611a0e57816020015b6119fb614bad565b8152602001906001900390816119f35790505b50905060005b8281101561113c576000611a2885836128f2565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff1690811115611ac257611ac26152c4565b6001811115611ad357611ad36152c4565b815250509050611af588826040015183602001516111008560400151876114c8565b848481518110611b0757611b076158fc565b60209081029190910101525050600101611a14565b604080516060998a1b6001600160601b0319908116602080840191909152998b1b811660348301529790991b9096166048890152605c88019490945291151560f81b607c87015260a01b6001600160a01b031916607d86015260d890811b6001600160d81b0319908116608987015291901b16608e8401528051607381850301815260939093019052815191012090565b610b22334283613400565b6000610b11836001600160a01b03841661381c565b6001600160a01b03811660009081526001830160205260408120541515610b11565b8551600090158015611c2357506001611c10876001600160601b031661386b565b6002811115611c2157611c216152c4565b145b80611c5d57508660200151158015611c5d57506002611c4a876001600160601b031661386b565b6002811115611c5b57611c5b6152c4565b145b80611c785750611c7685876001600160601b03166138ae565b155b15611c8557506000610e33565b6000611caf89600001518a602001518b60400151888c604001518c8a600001518b60200151611b1c565b9050611cbf8960200151826114c8565b1580611cd457508851611cd2908261180e565b155b80611d16575060016001600160a01b0382166000908152600960205260409020600190810154600160f01b900460ff1690811115611d1457611d146152c4565b145b80611d5c5750611d2e876001600160601b03166138e5565b8015611d5c57506040808a01516001600160a01b038381166000908152600a60205292909220548216911614155b80611d9d5750611d74876001600160601b0316612f1a565b8015611d9d5750611d9b846000015164ffffffffff16856020015164ffffffffff16612f3f565b155b80611dcd57506001600160a01b03831615801590611dcd5750806001600160a01b0316836001600160a01b031614155b15611ddc576000915050610e33565b50600198975050505050505050565b611df58282613903565b15611dfe575050565b611e088183613903565b15611e11575050565b60405163a9e649e960e01b815260040160405180910390fd5b60005b82604001515181101561221457611e5383600001518460200151856101400151856139fd565b6000611e9f846020015185604001518481518110611e7357611e736158fc565b6020026020010151866060015187608001518860a001518960c001518a60e001518b6101200151613a30565b90506000611ee88560000151866020015187604001518681518110611ec657611ec66158fc565b602002602001015188606001518960800151878b60c001518c60e00151611b1c565b9050846080015115611f4a57611f488160086000611f2c89602001518a604001518981518110611f1a57611f1a6158fc565b60200260200101518b60600151613cbf565b8152602001908152602001600020611bb890919063ffffffff16565b505b60006001600160a01b031685604001518481518110611f6b57611f6b6158fc565b60200260200101516001600160a01b0316141580611f8e57506101608501515115155b1561202757604051806060016040528086604001518581518110611fb457611fb46158fc565b6020908102919091018101516001600160a01b0390811683526060890151838301526101608901516040938401528481166000908152600a8352839020845181546001600160a01b03191692169190911781559083015160018201559082015160028201906120239082615a00565b5050505b60018561018001516001811115612040576120406152c4565b0361208a576020858101516001600160a01b039081166000908152600f835260408120805460018101825590825292902090910180546001600160a01b0319169183169190911790555b61209f8160066000611f2c89600001516137db565b506120b58160076000611f2c896020015161288e565b506040518060c0016040528086600001516001600160a01b03168152602001836001600160601b0316815260200186602001516001600160a01b031681526020018660c0015164ffffffffff1681526020018660e0015164ffffffffff168152602001866101800151600181111561212f5761212f6152c4565b90526001600160a01b03828116600090815260096020908152604091829020845191850151918416600160a01b6001600160601b039093168302178155918401516001808401805460608801516080890151949097166001600160c81b03199091161764ffffffffff9687169094029390931764ffffffffff60c81b198116600160c81b9690931695909502918217835560a0860151939465ffffffffffff60c81b191660ff60f01b199092169190911790600160f01b9084908111156121f8576121f86152c4565b021790555090505061220a8584613d29565b5050600101611e2d565b506002546001600160a01b0316156112ea576000826101800151600181111561223f5761223f6152c4565b036112ea576002546001600160a01b0316632e6f2136336040850151516002546122799190600160a01b90046001600160581b03166158d2565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156122bf57600080fd5b505af11580156122d3573d6000803e3d6000fd5b505050505050565b600060606000600860006122f08b8b8b613cbf565b81526020019081526020016000209050600061230b826128e8565b90506000816001600160401b0381111561232757612327614d69565b604051908082528060200260200182016040528015612350578160200160208202803683370190505b50935060005b8281101561259f57600060098161236d87856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff1690811115612401576124016152c4565b6001811115612412576124126152c4565b8152505090506124c1604051806060016040528083600001516001600160a01b031681526020018f6001600160a01b031681526020018e6001600160a01b031681525060405180606001604052808c151581526020018b151581526020016001151581525083602001518d8f6040518060400160405280886060015164ffffffffff168152602001886080015164ffffffffff168152506124bc898d6128f290919063ffffffff16565b611bef565b158061251357506001600960006124d888866128f2565b6001600160a01b031681526020810191909152604001600020600190810154600160f01b900460ff1690811115612511576125116152c4565b145b1561251e575061258d565b600161253682602001516001600160601b031661386b565b6002811115612547576125476152c4565b14612555578051965061258b565b806000015186848151811061256c5761256c6158fc565b6001600160a01b03909216602092830291909101909101526001909201915b505b8061259781615abf565b915050612356565b50808211156125b2578351818303900384525b5050505b965096945050505050565b600060606000600760006125d48961288e565b8152602001908152602001600020905060006125ef826128e8565b6001600160401b0381111561260657612606614d69565b60405190808252806020026020018201604052801561262f578160200160208202803683370190505b50925060005b61263e836128e8565b81101561288257600060098161265486856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156126e8576126e86152c4565b60018111156126f9576126f96152c4565b815250509050600061271782602001516001600160601b03166138e5565b1561271f5750885b604080516060808201835284516001600160a01b0390811683528e811660208085019190915290851683850152835180830185528c51151581528c82015115158183015260008186018190528288015186518088019097529388015164ffffffffff9081168752608089015116928601929092526127a6949092918e916124bc8c8b6128f2565b15806127f457506127c382602001516001600160601b03166138e5565b1580156127f457506127f489600560006127e08f8f600080613dde565b8152602001908152602001600020546138ae565b15612800575050612870565b600161281883602001516001600160601b031661386b565b6002811115612829576128296152c4565b14612837578151965061286d565b816000015186858151811061284e5761284e6158fc565b6001600160a01b03909216602092830291909101909101526001909301925b50505b8061287a81615abf565b915050612635565b50505094509492505050565b6001600160a01b0381166000908152600c602090815260408083205490516001600160601b0319606086901b169281019290925260348201526054015b604051602081830303815290604052805190602001209050919050565b6000611507825490565b6000610b118383613e53565b612906614bad565b6001600160a01b038084166000908152600a602090815260408083208151606081018352815490951685526001810154928501929092526002820180549394939184019161295390615928565b80601f016020809104026020016040519081016040528092919081815260200182805461297f90615928565b80156129cc5780601f106129a1576101008083540402835291602001916129cc565b820191906000526020600020905b8154815290600101906020018083116129af57829003601f168201915b50505050508152505090506040518061022001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001612a138a6001600160601b0316613e7d565b6002811115612a2457612a246152c4565b8152602001612a3b8a6001600160601b031661386b565b6002811115612a4c57612a4c6152c4565b8152602001612a638a6001600160601b0316613ebe565b6001811115612a7457612a746152c4565b815260200182600001516001600160a01b03168152602001826020015181526020018764ffffffffff1681526020018664ffffffffff168152602001612ac28a6001600160601b0316612f1a565b1580612ae15750612ae18864ffffffffff168864ffffffffff16612f3f565b1515815288151560208201526040016002612b048b6001600160601b0316613e7d565b6002811115612b1557612b156152c4565b141580612b9c5750825160208401516040516331a9108f60e11b815260048101919091526001600160a01b038d8116921690636352211e90602401602060405180830381865afa158015612b6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b919190615975565b6001600160a01b0316145b15158152602001612bb58a6001600160601b0316613ee2565b8152602001856001600160a01b03168152602001896001600160601b0316815260200182604001518152602001846001811115612bf457612bf46152c4565b90529a9950505050505050505050565b60606000612c1d86600560006127e08c8c600080613dde565b80612c4c57506001600160a01b03871615801590612c4c5750612c4c86600560006127e08c6000806000613dde565b15612c6e5784612c6e57505060408051600080825260208201909252906125b6565b600080612cb260405180606001604052808c6001600160a01b03168152602001876001600160a01b031681526020018b6001600160a01b0316815250898989613f2e565b929650919450925090508215612cc95750506125b6565b80821115612cdb578351818303900384525b60035460ff168015612cee575083516001145b15612f09576040516354559dbb60e01b81526001600160a01b03808c1660048301528a16602482015260448101899052871515606482015286151560848201526000907388888888888806458312bb6b7ae0f9a7ad30ea40906354559dbb9060a401600060405180830381865afa158015612d6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d959190810190615b3c565b9050600181511115612f0757612dca81600181518110612db757612db76158fc565b602002602001015160008060008d613f82565b80612df85750612df881600181518110612de657612de66158fc565b60200260200101518b6000808d613f82565b15612e0a5750600092506125b6915050565b856001600160a01b031681600181518110612e2757612e276158fc565b60200260200101516001600160a01b031603612e4a5750600192506125b6915050565b604080516002808252606082018352909160208301908036833701905050945080600081518110612e7d57612e7d6158fc565b602002602001015185600081518110612e9857612e986158fc565b60200260200101906001600160a01b031690816001600160a01b03168152505080600181518110612ecb57612ecb6158fc565b602002602001015185600181518110612ee657612ee66158fc565b60200260200101906001600160a01b031690816001600160a01b0316815250505b505b506000915050965096945050505050565b60006001612f2783613ebe565b6001811115612f3857612f386152c4565b1492915050565b60004283108015610b115750504210919050565b6001600160a01b038281166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b8604166080840152929391929160a0840191600160f01b90910460ff1690811115612fea57612fea6152c4565b6001811115612ffb57612ffb6152c4565b90525080519091506001600160a01b038581169116146130245761302484826040015184613463565b600261303c82602001516001600160601b0316613e7d565b600281111561304d5761304d6152c4565b036131e5576001600160a01b038084166000908152600a602090815260408083208151606081018352815490951685526001810154928501929092526002820180549394939184019161309f90615928565b80601f01602080910402602001604051908101604052809291908181526020018280546130cb90615928565b80156131185780601f106130ed57610100808354040283529160200191613118565b820191906000526020600020905b8154815290600101906020018083116130fb57829003601f168201915b5050505050815250509050600061313c836040015183600001518460200151613cbf565b60008181526008602052604090209091506131579086611bcd565b6131745760405163a9e649e960e01b815260040160405180910390fd5b600081815260086020526040902061318c90866137c6565b80156131bf575060016131ab84602001516001600160601b031661386b565b60028111156131bc576131bc6152c4565b14155b156131e2576131e283604001518360000151600185602001518760200151613fdf565b50505b61321683600660006131fa85600001516137db565b81526020019081526020016000206137c690919063ffffffff16565b5061322c83600760006131fa856040015161288e565b801561325f5750600161324b82602001516001600160601b031661386b565b600281111561325c5761325c6152c4565b14155b80156132925750600261327e82602001516001600160601b0316613e7d565b600281111561328f5761328f6152c4565b14155b156132e95760006132af82602001516001600160601b03166138e5565b156132d157506001600160a01b038084166000908152600a6020526040902054165b6132e78260400151826000808660200151613fdf565b505b6001600160a01b0383166000908152600960209081526040808320838155600190810180546001600160f81b0319169055600a909252822080546001600160a01b0319168155908101829055906133436002830182614c37565b5050805160408083015181516001600160a01b039384168152908316602082015291851682820152517f59ae3c34e9447e6c9676b72ba973ce1e412d1051a6da544ac93e2a07ef04259b9181900360600190a150505050565b60606000610b1183614044565b6001600160a01b0381166000818152600b60209081526040918290208054600101905590519182527f17847ea98d58f1bba43d4d7add9ace4b715eb6374a39c43445d322b747d6001991015b60405180910390a150565b60408051808201825264ffffffffff938416815291831660208084019182526001600160a01b039095166000908152600d90955293209051815493518316650100000000000269ffffffffffffffffffff19909416921691909117919091179055565b61346e8383836140a0565b6116085760405163fed82dc360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600c60209081526040918290208054600101905590519182527f150d16c5ed87101ded5915d2c85572217aa147e5f50f384305123e8c6c5680da91016133f5565b604080516101a08101825260008082526020820181905260609282018390528282018190526080820181905260a0820183905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082019290925261018081019190915260008060008060008060008060008060008c80602001905181019061356b9190615c0b565b9a509a509a509a509a509a509a509a509a509a509a50604051806101a001604052808c6001600160a01b031681526020018b6001600160a01b031681526020018a815260200189815260200188151581526020018781526020018664ffffffffff1681526020018564ffffffffff1681526020018461ffff1681526020018360028111156135fb576135fb6152c4565b8152602001826001600160601b0316815260200160405180602001604052806000815250815260200160006001811115613637576136376152c4565b90529d9c50505050505050505050505050565b606081901c816000600a6136606103e884615d04565b61366a9190615d2a565b6001600160601b0316905060018103613695576122d3858785856001600160601b0316600080614124565b600281036136c6576001600160a01b0383166136ba576136b58686611deb565b6122d3565b6122d386846000612f53565b600381036136d7576122d3866133a9565b600481036136e8576122d38661348b565b60058103613700576122d3864264ffffffffff613400565b60068103613739575050506001600160a01b039092166000908152600d60205260409020805469ffffffffffffffffffff191690555050565b6007810361375a576122d3858785856001600160601b031660016000614124565b60088103613786576122d38587856001600160601b03861660006137814262278d00615d50565b614124565b600981036137ad576122d38587856001600160601b0386166000613781426276a700615d50565b604051631ec9ca4160e21b815260040160405180910390fd5b6000610b11836001600160a01b038416614382565b6001600160a01b0381166000908152600b602090815260408083205490516001600160601b0319606086901b169281019290925260348201526054016128cb565b600081815260018301602052604081205461386357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611507565b506000611507565b6000613878601a83614475565b60000361388757506000919050565b613892601a83614475565b6001036138a157506001919050565b506002919050565b919050565b6000600e83141580156138c757506138c76001836144c5565b156138d457506001611507565b6138de83836144c5565b9050611507565b600060016138f283613e7d565b6002811115612f3857612f386152c4565b60008061391a848460008060006001600080611b1c565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff16908111156139b4576139b46152c4565b60018111156139c5576139c56152c4565b90525080519091506001600160a01b0316156139f2576139e785836000612f53565b600192505050611507565b506000949350505050565b613a0784846144db565b15613a2557604051630da1844d60e01b815260040160405180910390fd5b61165a818484613463565b6000806001600160a01b03891615613b05578615613af3576040516331a9108f60e11b8152600481018990526001600160a01b03808c1691908b1690636352211e90602401602060405180830381865afa158015613a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab69190615975565b6001600160a01b031614613add5760405163400d9f5560e11b815260040160405180910390fd5b6b06765c793fa10079d000000082019150613b05565b6b033b2e3c9fd0803ce8000000820191505b6001836002811115613b1957613b196152c4565b03613b2f576a084595161401484a000000820191505b6002836002811115613b4357613b436152c4565b03613b59576a108b2a2c28029094000000820191505b64ffffffffff8585011615613b79576a52b7d2dcc80cd2e4000000820191505b60005b8651811015613c6f576001846002811115613b9957613b996152c4565b14158015613bcb5750613bcb8b8b8a8c8b8681518110613bbb57613bbb6158fc565b602002602001015160ff16613f82565b15613c0d57868181518110613be257613be26158fc565b6020026020010151604051630aab3ce760e41b8152600401610990919060ff91909116815260200190565b868181518110613c1f57613c1f6158fc565b602002602001015160ff16600103613c3c57600182019150613c67565b6001878281518110613c5057613c506158fc565b60200260200101510360ff16600a0a600102820191505b600101613b7c565b506001836002811115613c8457613c846152c4565b14613cb2578060056000613c9a8d8d8c8e613dde565b81526020810191909152604001600020805490910190555b0198975050505050505050565b6001600160a01b0383166000908152600c60209081526040918290205482516001600160601b0319606097881b81168285015260348201929092529490951b9094166054840152606880840192909252805180840390920182526088909201909152805191012090565b81602001516001600160a01b031682600001516001600160a01b03167f44d84a2c5d27e81636e3182f4601b82564c8086c61dd9a83e3b4586c4db96b2f84604001518481518110613d7c57613d7c6158fc565b6020026020010151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e6101800151604051613dd29b9a99989796959493929190615d63565b60405180910390a35050565b6001600160a01b0384166000908152600c60209081526040918290205482516001600160601b0319606098891b8116828501529690971b909516603487015292151560f81b60488601526049850191909152606980850193909352805180850390930183526089909301909252805191012090565b6000826000018281548110613e6a57613e6a6158fc565b9060005260206000200154905092915050565b600080613e8b601c84614475565b905080600003613e9e5750600092915050565b80600103613eaf5750600192915050565b50600292915050565b50919050565b6000613ecb601b83614475565b600003613eda57506000919050565b506001919050565b613eea614c71565b60005b6019811015613eb857613f0a613f04826001615d50565b8461457a565b828260198110613f1c57613f1c6158fc565b91151560209092020152600101613eed565b60606000806000806001600160a01b031688604001516001600160a01b031603613f6b57613f5e88888888614586565b9350935093509350613f77565b613f5e88888888614868565b945094509450949050565b60008060056000613f9589898989613dde565b815260200190815260200160002054905080600014158015613fc657508260011480613fc65750613fc683826138ae565b15613fd557600191505061115a565b600091505061115a565b6000613fed86868686613dde565b9050613ffb6019601d6158e9565b61400690600a615f1d565b614019906001600160601b038416614cbf565b600082815260056020526040812080549091906140379084906158e9565b9091555050505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561409457602002820191906000526020600020905b815481526020019060010190808311614080575b50505050509050919050565b6000836001600160a01b0316836001600160a01b0316036140c357506001610b11565b60408051606080820183526001600160a01b03808816835286166020808401919091526000838501819052845192830185526001808452838301528285018190528451808601909552808552908401819052610b0e938691600e9181611bef565b6040805160018082528183019092526000916020808301908036833701905050905060006141546103e886614cbf565b9050858260008151811061416a5761416a6158fc565b6001600160a01b0390921660209283029190910190910152600061271061419e6c01431e0fae6d7217caa000000088614cbf565b6141a891906158be565b905060006001546000146141ba575060015b6060826000036142125760408051600180825281830190925290602080830190803683370190505090506001816000815181106141f9576141f96158fc565b602002602001019060ff16908160ff16815250506142b1565b6040805160198082526103408201909252600091602082016103208036833701905050915060005b601981101561429a57614257614251826001615d50565b8661457a565b1561429257614267816001615d50565b838381518110614279576142796158fc565b60ff909216602092830291909101909101526001909101905b60010161423a565b5080601911156142af57815181016018190182525b505b614375604051806101a001604052808d6001600160a01b031681526020018c6001600160a01b0316815260200187815260200160008152602001600015158152602001838152602001600064ffffffffff1681526020018864ffffffffff1681526020018661ffff168152602001896002811115614331576143316152c4565b815260200160006001600160601b0316815260200160405180602001604052806000815250815260200184600181111561436d5761436d6152c4565b90528b611e2a565b5050505050505050505050565b6000818152600183016020526040812054801561446b5760006143a66001836158e9565b85549091506000906143ba906001906158e9565b905081811461441f5760008660000182815481106143da576143da6158fc565b90600052602060002001549050808760000184815481106143fd576143fd6158fc565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061443057614430615912565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611507565b6000915050611507565b60008061448384600a615f1d565b9050600084600103614497575060016144b0565b6144a26001866158e9565b6144ad90600a615f1d565b90505b806144bb8386614cbf565b61115a91906158be565b60006144d18383614475565b6001149392505050565b6001600160a01b0382166000908152600d6020908152604080832081518083019092525464ffffffffff80821683526501000000000090910416918101829052904211806145305750805164ffffffffff1642105b1561453f576000915050611507565b6001600160a01b0384166000908152600e602052604090206145619084611bcd565b15614570576000915050611507565b5060019392505050565b6000610b1183836144c5565b60606000806000806006600061459f8b600001516137db565b815260200190815260200160002090506145b8816128e8565b6001019350836001600160401b038111156145d5576145d5614d69565b6040519080825280602002602001820160405280156145fe578160200160208202803683370190505b509450886000015185600081518110614619576146196158fc565b6001600160a01b039092166020928302919091019091015260019092019160005b6146456001866158e9565b81101561485757600060098161465b85856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156146ef576146ef6152c4565b6001811115614700576147006152c4565b81525050905061471c81602001516001600160601b03166138e5565b806147ce57506147cc60405180606001604052808d600001516001600160a01b0316815260200183604001516001600160a01b0316815260200160006001600160a01b031681525060405180606001604052808c151581526020018b151581526020016000151581525083602001518d60006040518060400160405280886060015164ffffffffff168152602001886080015164ffffffffff168152506124bc898b6128f290919063ffffffff16565b155b156147d95750614845565b8a602001516001600160a01b031681604001516001600160a01b03160361480e57506000945084935060019250613f77915050565b8060400151878681518110614825576148256158fc565b6001600160a01b0390921660209283029190910190910152506001909301925b8061484f81615abf565b91505061463a565b506000915050945094509450949050565b6060600080600080600660006148818b600001516137db565b8152602001908152602001600020905061489a816128e8565b6001019350836001600160401b038111156148b7576148b7614d69565b6040519080825280602002602001820160405280156148e0578160200160208202803683370190505b5094508860000151856000815181106148fb576148fb6158fc565b6001600160a01b039092166020928302919091019091015260019092019160005b6149276001866158e9565b81101561485757600060098161493d85856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156149d1576149d16152c4565b60018111156149e2576149e26152c4565b905250905060026149ff82602001516001600160601b0316613e7d565b6002811115614a1057614a106152c4565b03614a1b5750614b84565b6000614a3382602001516001600160601b03166138e5565b15614a43575060408b0151614a62565b614a5682604001518d604001518d614b96565b15614a62575050614b84565b614b0b60405180606001604052808e600001516001600160a01b0316815260200184604001516001600160a01b03168152602001836001600160a01b031681525060405180606001604052808d151581526020018c151581526020016000151581525084602001518e60006040518060400160405280896060015164ffffffffff168152602001896080015164ffffffffff168152506124bc8a8c6128f290919063ffffffff16565b614b16575050614b84565b8b602001516001600160a01b031682604001516001600160a01b031603614b4c57506000955085945060019350613f7792505050565b8160400151888781518110614b6357614b636158fc565b6001600160a01b039092166020928302919091019091015250506001909301925b80614b8e81615abf565b91505061491c565b6000610b0e82600560006127e08888600080613dde565b604080516102208101825260008082526020820181905290918201908152602001600081526020016000815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e082015261010001614c16614c71565b81526000602082018190526040820181905260608083015260809091015290565b508054614c4390615928565b6000825580601f10614c53575050565b601f016020900490600052602060002090810190610b229190614c90565b6040518061032001604052806019906020820280368337509192915050565b5b80821115614ca55760008155600101614c91565b5090565b634e487b7160e01b600052601260045260246000fd5b600082614cce57614cce614ca9565b500690565b6001600160a01b0381168114610b2257600080fd5b80356138a981614cd3565b600060208284031215614d0557600080fd5b8135610b1181614cd3565b6000815180845260005b81811015614d3657602081850181015186830182015201614d1a565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610b116020830184614d10565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614da757614da7614d69565b604052919050565b60006001600160401b03821115614dc857614dc8614d69565b5060051b60200190565b600082601f830112614de357600080fd5b81356020614df8614df383614daf565b614d7f565b82815260059290921b84018101918181019086841115614e1757600080fd5b8286015b84811015614e3b578035614e2e81614cd3565b8352918301918301614e1b565b509695505050505050565b8015158114610b2257600080fd5b80356138a981614e46565b60ff81168114610b2257600080fd5b600082601f830112614e7f57600080fd5b81356020614e8f614df383614daf565b82815260059290921b84018101918181019086841115614eae57600080fd5b8286015b84811015614e3b578035614ec581614e5f565b8352918301918301614eb2565b64ffffffffff81168114610b2257600080fd5b80356138a981614ed2565b61ffff81168114610b2257600080fd5b80356138a981614ef0565b60038110610b2257600080fd5b80356138a981614f0b565b6001600160601b0381168114610b2257600080fd5b80356138a981614f23565b60006001600160401b03831115614f5c57614f5c614d69565b614f6f601f8401601f1916602001614d7f565b9050828152838383011115614f8357600080fd5b828260208301376000602084830101529392505050565b600082601f830112614fab57600080fd5b610b1183833560208501614f43565b6000806000806000806000806000806000806101808d8f031215614fdd57600080fd5b614fe68d614ce8565b9b50614ff460208e01614ce8565b9a506001600160401b0360408e0135111561500e57600080fd5b61501e8e60408f01358f01614dd2565b995060608d0135985061503360808e01614e54565b97506001600160401b0360a08e0135111561504d57600080fd5b61505d8e60a08f01358f01614e6e565b965061506b60c08e01614ee5565b955061507960e08e01614ee5565b94506150886101008e01614f00565b93506150976101208e01614f18565b92506150a66101408e01614f38565b91506001600160401b036101608e013511156150c157600080fd5b6150d28e6101608f01358f01614f9a565b90509295989b509295989b509295989b565b60018060a01b038416815282602082015260606040820152600061115a6060830184614d10565b600080600080600080600060e0888a03121561512657600080fd5b873561513181614cd3565b9650602088013561514181614cd3565b955060408801359450606088013561515881614e46565b93506080880135925060a088013561516f81614e46565b915060c088013561517f81614e46565b8091505092959891949750929550565b6000806000606084860312156151a457600080fd5b83356151af81614cd3565b92506020840135915060408401356151c681614f23565b809150509250925092565b600080604083850312156151e457600080fd5b82356151ef81614cd3565b946020939093013593505050565b600080600080600060a0868803121561521557600080fd5b853561522081614cd3565b94506020860135935060408601359250606086013561523e81614e46565b9150608086013561524e81614e46565b809150509295509295909350565b600081518084526020808501945080840160005b838110156152955781516001600160a01b031687529582019590820190600101615270565b509495945050505050565b6001600160a01b0383168152604060208201819052600090610b0e9083018461525c565b634e487b7160e01b600052602160045260246000fd5b600381106152ea576152ea6152c4565b9052565b60028110610b2257610b226152c4565b6152ea816152ee565b8060005b601981101561165a578151151584526020938401939091019060010161530b565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156154af57888303603f19018552815180516001600160a01b03168452610520818901516001600160a01b038116868b01525087820151615399898701826152da565b506060808301516153ac828801826152da565b50506080808301516153c0828801826152fe565b505060a0828101516001600160a01b03169086015260c0808301519086015260e08083015164ffffffffff9081169187019190915261010080840151909116908601526101208083015115159086015261014080830151151590860152610160808301511515908601526101808083015161543d82880182615307565b50506101a08201516001600160a01b03166104a08601526101c08201516001600160601b03166104c08601526101e08201516104e0860182905261548382870182614d10565b915050610200820151915061549c6105008601836152fe565b9588019593505090860190600101615353565b509098975050505050505050565b600080600080600060a086880312156154d557600080fd5b85356154e081614cd3565b945060208601356154f081614cd3565b935060408601359250606086013561523e81614e46565b602081526000610b11602083018461525c565b6000806040838503121561552d57600080fd5b82356151ef81614e5f565b60008060006060848603121561554d57600080fd5b83359250602084013561555f81614cd3565b929592945050506040919091013590565b6000806040838503121561558357600080fd5b823561558e81614cd3565b9150602083013561559e81614f23565b809150509250929050565b6000602082840312156155bb57600080fd5b81356001600160401b038111156155d157600080fd5b8201601f810184136155e257600080fd5b6155f184823560208401614f43565b949350505050565b600064ffffffffff8085511683528060208601511660208401525060606040830152610b0e606083018461525c565b6000806040838503121561563b57600080fd5b823561564681614cd3565b9150602083013561559e81614cd3565b60008060008060008060c0878903121561566f57600080fd5b863561567a81614cd3565b9550602087013561568a81614cd3565b9450604087013561569a81614cd3565b93506060870135925060808701356156b181614e46565b915060a08701356156c181614e46565b809150509295509295509295565b6000806000606084860312156156e457600080fd5b83356156ef81614cd3565b92506020840135915060408401356001600160401b0381111561571157600080fd5b61571d86828701614f9a565b9150509250925092565b6000806040838503121561573a57600080fd5b823561574581614cd3565b915060208301356001600160581b038116811461559e57600080fd5b60006020828403121561577357600080fd5b8135610b1181614ed2565b60006020828403121561579057600080fd5b5035919050565b600060c08201905060018060a01b038084511683526001600160601b03602085015116602084015280604085015116604084015250606083015164ffffffffff8082166060850152806080860151166080850152505060a08301516157fb816152ee565b8060a08401525092915050565b600080600080600080600080610100898b03121561582557600080fd5b883561583081614cd3565b9750602089013561584081614cd3565b9650604089013561585081614cd3565b955060608901359450608089013561586781614e46565b935060a089013561587781614f23565b925060c089013561588781614ed2565b915060e089013561589781614ed2565b809150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b6000826158cd576158cd614ca9565b500490565b8082028115828204841417611507576115076158a8565b81810381811115611507576115076158a8565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600181811c9082168061593c57607f821691505b602082108103613eb857634e487b7160e01b600052602260045260246000fd5b60006020828403121561596e57600080fd5b5051919050565b60006020828403121561598757600080fd5b8151610b1181614cd3565b80516138a981614e46565b6000602082840312156159af57600080fd5b8151610b1181614e46565b601f82111561160857600081815260208120601f850160051c810160208610156159e15750805b601f850160051c820191505b818110156122d3578281556001016159ed565b81516001600160401b03811115615a1957615a19614d69565b615a2d81615a278454615928565b846159ba565b602080601f831160018114615a625760008415615a4a5750858301515b600019600386901b1c1916600185901b1785556122d3565b600085815260208120601f198616915b82811015615a9157888601518255948401946001909101908401615a72565b5085821015615aaf5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201615ad157615ad16158a8565b5060010190565b600082601f830112615ae957600080fd5b81516020615af9614df383614daf565b82815260059290921b84018101918181019086841115615b1857600080fd5b8286015b84811015614e3b578051615b2f81614cd3565b8352918301918301615b1c565b600060208284031215615b4e57600080fd5b81516001600160401b03811115615b6457600080fd5b6155f184828501615ad8565b80516138a981614cd3565b600082601f830112615b8c57600080fd5b81516020615b9c614df383614daf565b82815260059290921b84018101918181019086841115615bbb57600080fd5b8286015b84811015614e3b578051615bd281614e5f565b8352918301918301615bbf565b80516138a981614ed2565b80516138a981614ef0565b80516138a981614f0b565b80516138a981614f23565b60008060008060008060008060008060006101608c8e031215615c2d57600080fd5b615c368c615b70565b9a50615c4460208d01615b70565b995060408c01516001600160401b03811115615c5f57600080fd5b615c6b8e828f01615ad8565b99505060608c01519750615c8160808d01615992565b965060a08c01516001600160401b03811115615c9c57600080fd5b615ca88e828f01615b7b565b965050615cb760c08d01615bdf565b9450615cc560e08d01615bdf565b9350615cd46101008d01615bea565b9250615ce36101208d01615bf5565b9150615cf26101408d01615c00565b90509295989b509295989b9093969950565b60006001600160601b0380841680615d1e57615d1e614ca9565b92169190910492915050565b60006001600160601b0380841680615d4457615d44614ca9565b92169190910692915050565b80820180821115611507576115076158a8565b6001600160a01b038c16815260208082018c90528a15156040830152610160606083018190528a519083018190526000916101808401918c82019190845b81811015615dc057835160ff1685529382019392820192600101615da1565b50505064ffffffffff8b1660808501525064ffffffffff891660a084015261ffff881660c0840152615df560e08401886152da565b6001600160601b038616610100840152828103610120840152615e188186614d10565b915050615e296101408301846152fe565b9c9b505050505050505050505050565b600181815b80851115615e74578160001904821115615e5a57615e5a6158a8565b80851615615e6757918102915b93841c9390800290615e3e565b509250929050565b600082615e8b57506001611507565b81615e9857506000611507565b8160018114615eae5760028114615eb857615ed4565b6001915050611507565b60ff841115615ec957615ec96158a8565b50506001821b611507565b5060208310610133831016604e8410600b8410161715615ef7575081810a611507565b615f018383615e39565b8060001904821115615f1557615f156158a8565b029392505050565b6000610b118383615e7c56fea2646970667358221220ef44aa63d9541f34cd1b89cd7aa55beefd234f08a07d838c60de8aec85654dad64736f6c63430008110033

Deployed Bytecode

0x60806040526004361061028c5760003560e01c80637be4c1771161015a578063b52d1c19116100c1578063f14210a61161007a578063f14210a614610863578063f228967e14610883578063f50ef9b4146108b0578063f7c618c1146108d0578063fc4a7db1146108f0578063fc662b1c1461091057600080fd5b8063b52d1c19146107a9578063b674d1d7146107c9578063c00206e1146107e3578063c2c97fa314610803578063d800321314610823578063df0003731461084357600080fd5b8063a1db978211610113578063a1db9782146106ef578063a4c0ed361461070f578063a5bc5b8414610722578063a659f29114610737578063a9059cbb14610757578063b30929cd1461077757600080fd5b80637be4c177146106655780637da3f6131461067a5780638546039e1461068f5780638ad2b02d146106af57806395d89b411461034157806397ec8346146106cf57600080fd5b80634a01e225116101fe5780636b33c1ef116101b75780636b33c1ef1461057657806370a082311461059657806371d55afe146105b857806377dd4ac3146105d857806379150d34146105f85780637b0a47ee1461062657600080fd5b80634a01e2251461048e5780634d0800b0146104bc57806354559dbb146104e95780635921920714610516578063652c12eb146105365780636605bfda1461055657600080fd5b806318160ddd1161025057806318160ddd146103b857806327eb8773146103d75780632a468529146103f7578063313ce5671461040c5780634144c028146104365780634815d31c1461045657600080fd5b80630186fce1146102eb5780630294bdab1461032157806306fdde0314610341578063147eb2601461037657806316ab93b11461038957600080fd5b366102e65760015461029e9034614cbf565b6000036102b1576102af3334610930565b005b6102c9335b60196a09195731e2ce35eb000000610aab565b6102af5760405163020ad41b60e11b815260040160405180910390fd5b600080fd5b3480156102f757600080fd5b5060025461030c90600160f81b900460ff1681565b60405190151581526020015b60405180910390f35b34801561032d57600080fd5b506102af61033c366004614cf3565b610b18565b34801561034d57600080fd5b50604080518082018252600681526545505341504960d01b602082015290516103189190614d56565b6102af610384366004614fba565b610b25565b34801561039557600080fd5b506103a96103a4366004614cf3565b610bfd565b604051610318939291906150e4565b3480156103c457600080fd5b506000545b604051908152602001610318565b3480156103e357600080fd5b506103c96103f236600461510b565b610cb2565b34801561040357600080fd5b506102af610e3e565b34801561041857600080fd5b50600354610100900460ff1660405160ff9091168152602001610318565b34801561044257600080fd5b5061030c61045136600461518f565b610aab565b34801561046257600080fd5b506104766104713660046151d1565b610e82565b6040516001600160a01b039091168152602001610318565b34801561049a57600080fd5b506104ae6104a93660046151fd565b610eba565b6040516103189291906152a0565b3480156104c857600080fd5b506104dc6104d7366004614cf3565b610f9d565b604051610318919061532c565b3480156104f557600080fd5b506105096105043660046154bd565b611145565b6040516103189190615507565b34801561052257600080fd5b506102af61053136600461551a565b611163565b34801561054257600080fd5b506102af610551366004614cf3565b6111ac565b34801561056257600080fd5b506102af610571366004614cf3565b6112ee565b34801561058257600080fd5b506102af610591366004615538565b611339565b3480156105a257600080fd5b506103c96105b1366004614cf3565b5060005490565b3480156105c457600080fd5b506102af6105d3366004615570565b611391565b3480156105e457600080fd5b506102af6105f33660046155a9565b61139c565b34801561060457600080fd5b50610618610613366004614cf3565b61143d565b6040516103189291906155f9565b34801561063257600080fd5b5060025461064d90600160a01b90046001600160581b031681565b6040516001600160581b039091168152602001610318565b34801561067157600080fd5b506102af6114ad565b34801561068657600080fd5b506102af6114b8565b34801561069b57600080fd5b5061030c6106aa366004615628565b6114c8565b3480156106bb57600080fd5b506102af6106ca366004615570565b61150d565b3480156106db57600080fd5b5061030c6106ea366004615656565b61154a565b3480156106fb57600080fd5b506102af61070a3660046151d1565b611566565b6102af61071d3660046156cf565b61160d565b34801561072e57600080fd5b506102af611660565b34801561074357600080fd5b506102af610752366004614cf3565b6116a0565b34801561076357600080fd5b5061030c6107723660046151d1565b6116b9565b34801561078357600080fd5b506102af336000908152600d60205260409020805469ffffffffffffffffffff19169055565b3480156107b557600080fd5b506102af6107c4366004614cf3565b611710565b3480156107d557600080fd5b5060035461030c9060ff1681565b3480156107ef57600080fd5b506102af6107fe366004614cf3565b611763565b34801561080f57600080fd5b506102af61081e366004615727565b61177c565b34801561082f57600080fd5b506102af61083e366004615761565b6117fe565b34801561084f57600080fd5b5061030c61085e366004615628565b61180e565b34801561086f57600080fd5b5061030c61087e36600461577e565b611821565b34801561088f57600080fd5b506108a361089e366004614cf3565b6118a7565b6040516103189190615797565b3480156108bc57600080fd5b506104dc6108cb366004614cf3565b61198d565b3480156108dc57600080fd5b50600254610476906001600160a01b031681565b3480156108fc57600080fd5b5061047661090b366004615808565b611b1c565b34801561091c57600080fd5b506102af61092b366004615761565b611bad565b6001600160a01b0382166000908152600f602052604081205460015490919061095990846158be565b90508181111561099957826001548361097291906158d2565b60405163ea626b3f60e01b8152600481019290925260248201526044015b60405180910390fd5b815b6000811180156109ab5750600082115b15610aa4576001600160a01b0385166000908152600f602052604081206109d36001846158e9565b815481106109e3576109e36158fc565b6000918252602080832091909101546001600160a01b031680835260098252604092839020600101805460ff60f01b1916905591518281529192507f851101b6327b058b27638fcf86d96eec48dca48ba23b1f29ed67139449f9407d910160405180910390a16001600160a01b0386166000908152600f60205260409020805480610a7057610a70615912565b600082815260209020810160001990810180546001600160a01b03191690559081019091559283019291909101905061099b565b5050505050565b60408051606080820183526001600160a01b038616825230602080840191909152600083850181905284519283018552600180845283830152828501819052845180860190955280855290840181905292610b0e92919085908790869081611bef565b90505b9392505050565b610b223382611deb565b50565b6001543414610b47576040516333b18e6b60e11b815260040160405180910390fd5b6000604051806101a001604052808e6001600160a01b031681526020018d6001600160a01b031681526020018c81526020018b81526020018a151581526020018981526020018864ffffffffff1681526020018764ffffffffff1681526020018661ffff168152602001856002811115610bc357610bc36152c4565b81526001600160601b038516602082015260408101849052606001600090529050610bee8133611e2a565b50505050505050505050505050565b600a602052600090815260409020805460018201546002830180546001600160a01b03909316939192610c2f90615928565b80601f0160208091040260200160405190810160405280929190818152602001828054610c5b90615928565b8015610ca85780601f10610c7d57610100808354040283529160200191610ca8565b820191906000526020600020905b815481529060010190602001808311610c8b57829003601f168201915b5050505050905083565b600080610cc28989898787611145565b905085610d7c5760005b8151811015610d7657886001600160a01b03166370a08231838381518110610cf657610cf66158fc565b60200260200101516040518263ffffffff1660e01b8152600401610d2991906001600160a01b0391909116815260200190565b602060405180830381865afa158015610d46573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610d6a919061595c565b90920191600101610ccc565b50610e31565b60005b8151811015610e2f57886001600160a01b031662fdd58e838381518110610da857610da86158fc565b6020026020010151886040518363ffffffff1660e01b8152600401610de29291906001600160a01b03929092168252602082015260400190565b602060405180830381865afa158015610dff573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610e23919061595c565b90920191600101610d7f565b505b505b979650505050505050565b610e56335b60176a0847b32ff4cb02fc400000610aab565b610e7657604051630894d7d160e41b815260036004820152602401610990565b6003805460ff19169055565b600f6020528160005260406000208181548110610e9e57600080fd5b6000918252602090912001546001600160a01b03169150829050565b600060606000876001600160a01b0316636352211e886040518263ffffffff1660e01b8152600401610eee91815260200190565b602060405180830381865afa158015610f0b573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190610f2f9190615975565b9050610f3f8189898989896122db565b90935091506001600160a01b038316610f8057610f7a81898860405180604001604052808a15151515815260200189151515158152506125c1565b90935091505b6001600160a01b038316610f92578092505b509550959350505050565b6060600060076000610fae8561288e565b815260200190815260200160002090506000610fc9826128e8565b90506000816001600160401b03811115610fe557610fe5614d69565b60405190808252806020026020018201604052801561101e57816020015b61100b614bad565b8152602001906001900390816110035790505b50905060005b8281101561113c57600061103885836128f2565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff16908111156110d2576110d26152c4565b60018111156110e3576110e36152c4565b90525080516020820151919250611115918a90611100838761180e565b85606001518660800151888860a001516128fe565b848481518110611127576111276158fc565b60209081029190910101525050600101611024565b50949350505050565b606061115686868686866000612c04565b5090505b95945050505050565b61116c33610e43565b61118c57604051630894d7d160e41b815260036004820152602401610990565b6003805460ff9093166101000261ff001990931692909217909155600055565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b8604166080840152929391929160a0840191600160f01b90910460ff1690811115611243576112436152c4565b6001811115611254576112546152c4565b90525080519091506001600160a01b03166112825760405163a9e649e960e01b815260040160405180910390fd5b61129881602001516001600160601b0316612f1a565b15806112bf57506112bf816060015164ffffffffff16826080015164ffffffffff16612f3f565b156112dc576040516287bfad60e21b815260040160405180910390fd5b80516112ea90836000612f53565b5050565b6112f733610e43565b61131757604051630894d7d160e41b815260036004820152602401610990565b600480546001600160a01b0319166001600160a01b0392909216919091179055565b611351335b60186a085ac218dbe29340800000610aab565b61137157604051630894d7d160e41b815260026004820152602401610990565b6001929092556001600160a01b0316600090815260106020526040902055565b6112ea338383612f53565b6113a5336102b6565b6113c557604051630894d7d160e41b815260016004820152602401610990565b60035460405163c47f002760e01b8152620100009091046001600160a01b03169063c47f0027906113fa908490600401614d56565b6020604051808303816000875af1158015611419573d6000803e3d6000fd5b505050506040513d601f19601f820116820180604052508101906112ea919061595c565b604080518082018252600080825260208083018290526001600160a01b0385168252600d8152838220600e909152929020909160609161147c9061339c565b60408051808201909152915464ffffffffff8082168452650100000000009091041660208301529094909350915050565b6114b6336133a9565b565b6114b6334264ffffffffff613400565b60006114f782600760006114db8761288e565b8152602001908152602001600020611bcd90919063ffffffff16565b61150357506000611507565b5060015b92915050565b611518338383613463565b306001600160a01b038316036115415760405163e1bbc9d760e01b815260040160405180910390fd5b6112ea3361348b565b600061155a87868686868b612c04565b98975050505050505050565b61156f336102b6565b61158f57604051630894d7d160e41b815260016004820152602401610990565b6004805460405163a9059cbb60e01b81526001600160a01b03918216928101929092526024820183905283169063a9059cbb906044016020604051808303816000875af11580156115e4573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190611608919061599d565b505050565b3360009081526010602052604090205480158061162a5750828114155b1561164857604051632ab209a560e11b815260040160405180910390fd5b61165a611654836134db565b85611e2a565b50505050565b61166933610e43565b61168957604051630894d7d160e41b815260036004820152602401610990565b600280546001600160f81b0316600160f81b179055565b336000908152600e602052604090206112ea9082611bb8565b60006116c633848461364a565b604051600081526001600160a01b0384169033907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200160405180910390a350600192915050565b611719336102b6565b61173957604051630894d7d160e41b815260016004820152602401610990565b600380546001600160a01b03909216620100000262010000600160b01b0319909216919091179055565b336000908152600e602052604090206112ea90826137c6565b6117853361133e565b6117a557604051630894d7d160e41b815260026004820152602401610990565b600280546001600160a01b0319166001600160a01b0384161790819055600160f81b900460ff166112ea57600280546001600160581b038316600160a01b026affffffffffffffffffffff60a01b199091161790555050565b610b22338264ffffffffff613400565b60006114f782600660006114db876137db565b600061182c336102b6565b61184c57604051630894d7d160e41b815260016004820152602401610990565b6004546040516001600160a01b03909116908390600081818185875af1925050503d8060008114611899576040519150601f19603f3d011682016040523d82523d6000602084013e61189e565b606091505b50909392505050565b6118dd6040805160c08101825260008082526020820181905291810182905260608101829052608081018290529060a082015290565b6001600160a01b03828116600090815260096020908152604091829020825160c08101845281548086168252600160a01b908190046001600160601b0316938201939093526001808301549586169482019490945291840464ffffffffff9081166060840152600160c81b85041660808301529092909160a0840191600160f01b900460ff1690811115611973576119736152c4565b6001811115611984576119846152c4565b90525092915050565b606060006006600061199e856137db565b8152602001908152602001600020905060006119b9826128e8565b90506000816001600160401b038111156119d5576119d5614d69565b604051908082528060200260200182016040528015611a0e57816020015b6119fb614bad565b8152602001906001900390816119f35790505b50905060005b8281101561113c576000611a2885836128f2565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff1690811115611ac257611ac26152c4565b6001811115611ad357611ad36152c4565b815250509050611af588826040015183602001516111008560400151876114c8565b848481518110611b0757611b076158fc565b60209081029190910101525050600101611a14565b604080516060998a1b6001600160601b0319908116602080840191909152998b1b811660348301529790991b9096166048890152605c88019490945291151560f81b607c87015260a01b6001600160a01b031916607d86015260d890811b6001600160d81b0319908116608987015291901b16608e8401528051607381850301815260939093019052815191012090565b610b22334283613400565b6000610b11836001600160a01b03841661381c565b6001600160a01b03811660009081526001830160205260408120541515610b11565b8551600090158015611c2357506001611c10876001600160601b031661386b565b6002811115611c2157611c216152c4565b145b80611c5d57508660200151158015611c5d57506002611c4a876001600160601b031661386b565b6002811115611c5b57611c5b6152c4565b145b80611c785750611c7685876001600160601b03166138ae565b155b15611c8557506000610e33565b6000611caf89600001518a602001518b60400151888c604001518c8a600001518b60200151611b1c565b9050611cbf8960200151826114c8565b1580611cd457508851611cd2908261180e565b155b80611d16575060016001600160a01b0382166000908152600960205260409020600190810154600160f01b900460ff1690811115611d1457611d146152c4565b145b80611d5c5750611d2e876001600160601b03166138e5565b8015611d5c57506040808a01516001600160a01b038381166000908152600a60205292909220548216911614155b80611d9d5750611d74876001600160601b0316612f1a565b8015611d9d5750611d9b846000015164ffffffffff16856020015164ffffffffff16612f3f565b155b80611dcd57506001600160a01b03831615801590611dcd5750806001600160a01b0316836001600160a01b031614155b15611ddc576000915050610e33565b50600198975050505050505050565b611df58282613903565b15611dfe575050565b611e088183613903565b15611e11575050565b60405163a9e649e960e01b815260040160405180910390fd5b60005b82604001515181101561221457611e5383600001518460200151856101400151856139fd565b6000611e9f846020015185604001518481518110611e7357611e736158fc565b6020026020010151866060015187608001518860a001518960c001518a60e001518b6101200151613a30565b90506000611ee88560000151866020015187604001518681518110611ec657611ec66158fc565b602002602001015188606001518960800151878b60c001518c60e00151611b1c565b9050846080015115611f4a57611f488160086000611f2c89602001518a604001518981518110611f1a57611f1a6158fc565b60200260200101518b60600151613cbf565b8152602001908152602001600020611bb890919063ffffffff16565b505b60006001600160a01b031685604001518481518110611f6b57611f6b6158fc565b60200260200101516001600160a01b0316141580611f8e57506101608501515115155b1561202757604051806060016040528086604001518581518110611fb457611fb46158fc565b6020908102919091018101516001600160a01b0390811683526060890151838301526101608901516040938401528481166000908152600a8352839020845181546001600160a01b03191692169190911781559083015160018201559082015160028201906120239082615a00565b5050505b60018561018001516001811115612040576120406152c4565b0361208a576020858101516001600160a01b039081166000908152600f835260408120805460018101825590825292902090910180546001600160a01b0319169183169190911790555b61209f8160066000611f2c89600001516137db565b506120b58160076000611f2c896020015161288e565b506040518060c0016040528086600001516001600160a01b03168152602001836001600160601b0316815260200186602001516001600160a01b031681526020018660c0015164ffffffffff1681526020018660e0015164ffffffffff168152602001866101800151600181111561212f5761212f6152c4565b90526001600160a01b03828116600090815260096020908152604091829020845191850151918416600160a01b6001600160601b039093168302178155918401516001808401805460608801516080890151949097166001600160c81b03199091161764ffffffffff9687169094029390931764ffffffffff60c81b198116600160c81b9690931695909502918217835560a0860151939465ffffffffffff60c81b191660ff60f01b199092169190911790600160f01b9084908111156121f8576121f86152c4565b021790555090505061220a8584613d29565b5050600101611e2d565b506002546001600160a01b0316156112ea576000826101800151600181111561223f5761223f6152c4565b036112ea576002546001600160a01b0316632e6f2136336040850151516002546122799190600160a01b90046001600160581b03166158d2565b6040516001600160e01b031960e085901b1681526001600160a01b0390921660048301526024820152604401600060405180830381600087803b1580156122bf57600080fd5b505af11580156122d3573d6000803e3d6000fd5b505050505050565b600060606000600860006122f08b8b8b613cbf565b81526020019081526020016000209050600061230b826128e8565b90506000816001600160401b0381111561232757612327614d69565b604051908082528060200260200182016040528015612350578160200160208202803683370190505b50935060005b8281101561259f57600060098161236d87856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff1690811115612401576124016152c4565b6001811115612412576124126152c4565b8152505090506124c1604051806060016040528083600001516001600160a01b031681526020018f6001600160a01b031681526020018e6001600160a01b031681525060405180606001604052808c151581526020018b151581526020016001151581525083602001518d8f6040518060400160405280886060015164ffffffffff168152602001886080015164ffffffffff168152506124bc898d6128f290919063ffffffff16565b611bef565b158061251357506001600960006124d888866128f2565b6001600160a01b031681526020810191909152604001600020600190810154600160f01b900460ff1690811115612511576125116152c4565b145b1561251e575061258d565b600161253682602001516001600160601b031661386b565b6002811115612547576125476152c4565b14612555578051965061258b565b806000015186848151811061256c5761256c6158fc565b6001600160a01b03909216602092830291909101909101526001909201915b505b8061259781615abf565b915050612356565b50808211156125b2578351818303900384525b5050505b965096945050505050565b600060606000600760006125d48961288e565b8152602001908152602001600020905060006125ef826128e8565b6001600160401b0381111561260657612606614d69565b60405190808252806020026020018201604052801561262f578160200160208202803683370190505b50925060005b61263e836128e8565b81101561288257600060098161265486856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156126e8576126e86152c4565b60018111156126f9576126f96152c4565b815250509050600061271782602001516001600160601b03166138e5565b1561271f5750885b604080516060808201835284516001600160a01b0390811683528e811660208085019190915290851683850152835180830185528c51151581528c82015115158183015260008186018190528288015186518088019097529388015164ffffffffff9081168752608089015116928601929092526127a6949092918e916124bc8c8b6128f2565b15806127f457506127c382602001516001600160601b03166138e5565b1580156127f457506127f489600560006127e08f8f600080613dde565b8152602001908152602001600020546138ae565b15612800575050612870565b600161281883602001516001600160601b031661386b565b6002811115612829576128296152c4565b14612837578151965061286d565b816000015186858151811061284e5761284e6158fc565b6001600160a01b03909216602092830291909101909101526001909301925b50505b8061287a81615abf565b915050612635565b50505094509492505050565b6001600160a01b0381166000908152600c602090815260408083205490516001600160601b0319606086901b169281019290925260348201526054015b604051602081830303815290604052805190602001209050919050565b6000611507825490565b6000610b118383613e53565b612906614bad565b6001600160a01b038084166000908152600a602090815260408083208151606081018352815490951685526001810154928501929092526002820180549394939184019161295390615928565b80601f016020809104026020016040519081016040528092919081815260200182805461297f90615928565b80156129cc5780601f106129a1576101008083540402835291602001916129cc565b820191906000526020600020905b8154815290600101906020018083116129af57829003601f168201915b50505050508152505090506040518061022001604052808b6001600160a01b031681526020018a6001600160a01b03168152602001612a138a6001600160601b0316613e7d565b6002811115612a2457612a246152c4565b8152602001612a3b8a6001600160601b031661386b565b6002811115612a4c57612a4c6152c4565b8152602001612a638a6001600160601b0316613ebe565b6001811115612a7457612a746152c4565b815260200182600001516001600160a01b03168152602001826020015181526020018764ffffffffff1681526020018664ffffffffff168152602001612ac28a6001600160601b0316612f1a565b1580612ae15750612ae18864ffffffffff168864ffffffffff16612f3f565b1515815288151560208201526040016002612b048b6001600160601b0316613e7d565b6002811115612b1557612b156152c4565b141580612b9c5750825160208401516040516331a9108f60e11b815260048101919091526001600160a01b038d8116921690636352211e90602401602060405180830381865afa158015612b6d573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190612b919190615975565b6001600160a01b0316145b15158152602001612bb58a6001600160601b0316613ee2565b8152602001856001600160a01b03168152602001896001600160601b0316815260200182604001518152602001846001811115612bf457612bf46152c4565b90529a9950505050505050505050565b60606000612c1d86600560006127e08c8c600080613dde565b80612c4c57506001600160a01b03871615801590612c4c5750612c4c86600560006127e08c6000806000613dde565b15612c6e5784612c6e57505060408051600080825260208201909252906125b6565b600080612cb260405180606001604052808c6001600160a01b03168152602001876001600160a01b031681526020018b6001600160a01b0316815250898989613f2e565b929650919450925090508215612cc95750506125b6565b80821115612cdb578351818303900384525b60035460ff168015612cee575083516001145b15612f09576040516354559dbb60e01b81526001600160a01b03808c1660048301528a16602482015260448101899052871515606482015286151560848201526000907388888888888806458312bb6b7ae0f9a7ad30ea40906354559dbb9060a401600060405180830381865afa158015612d6d573d6000803e3d6000fd5b505050506040513d6000823e601f3d908101601f19168201604052612d959190810190615b3c565b9050600181511115612f0757612dca81600181518110612db757612db76158fc565b602002602001015160008060008d613f82565b80612df85750612df881600181518110612de657612de66158fc565b60200260200101518b6000808d613f82565b15612e0a5750600092506125b6915050565b856001600160a01b031681600181518110612e2757612e276158fc565b60200260200101516001600160a01b031603612e4a5750600192506125b6915050565b604080516002808252606082018352909160208301908036833701905050945080600081518110612e7d57612e7d6158fc565b602002602001015185600081518110612e9857612e986158fc565b60200260200101906001600160a01b031690816001600160a01b03168152505080600181518110612ecb57612ecb6158fc565b602002602001015185600181518110612ee657612ee66158fc565b60200260200101906001600160a01b031690816001600160a01b0316815250505b505b506000915050965096945050505050565b60006001612f2783613ebe565b6001811115612f3857612f386152c4565b1492915050565b60004283108015610b115750504210919050565b6001600160a01b038281166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b8604166080840152929391929160a0840191600160f01b90910460ff1690811115612fea57612fea6152c4565b6001811115612ffb57612ffb6152c4565b90525080519091506001600160a01b038581169116146130245761302484826040015184613463565b600261303c82602001516001600160601b0316613e7d565b600281111561304d5761304d6152c4565b036131e5576001600160a01b038084166000908152600a602090815260408083208151606081018352815490951685526001810154928501929092526002820180549394939184019161309f90615928565b80601f01602080910402602001604051908101604052809291908181526020018280546130cb90615928565b80156131185780601f106130ed57610100808354040283529160200191613118565b820191906000526020600020905b8154815290600101906020018083116130fb57829003601f168201915b5050505050815250509050600061313c836040015183600001518460200151613cbf565b60008181526008602052604090209091506131579086611bcd565b6131745760405163a9e649e960e01b815260040160405180910390fd5b600081815260086020526040902061318c90866137c6565b80156131bf575060016131ab84602001516001600160601b031661386b565b60028111156131bc576131bc6152c4565b14155b156131e2576131e283604001518360000151600185602001518760200151613fdf565b50505b61321683600660006131fa85600001516137db565b81526020019081526020016000206137c690919063ffffffff16565b5061322c83600760006131fa856040015161288e565b801561325f5750600161324b82602001516001600160601b031661386b565b600281111561325c5761325c6152c4565b14155b80156132925750600261327e82602001516001600160601b0316613e7d565b600281111561328f5761328f6152c4565b14155b156132e95760006132af82602001516001600160601b03166138e5565b156132d157506001600160a01b038084166000908152600a6020526040902054165b6132e78260400151826000808660200151613fdf565b505b6001600160a01b0383166000908152600960209081526040808320838155600190810180546001600160f81b0319169055600a909252822080546001600160a01b0319168155908101829055906133436002830182614c37565b5050805160408083015181516001600160a01b039384168152908316602082015291851682820152517f59ae3c34e9447e6c9676b72ba973ce1e412d1051a6da544ac93e2a07ef04259b9181900360600190a150505050565b60606000610b1183614044565b6001600160a01b0381166000818152600b60209081526040918290208054600101905590519182527f17847ea98d58f1bba43d4d7add9ace4b715eb6374a39c43445d322b747d6001991015b60405180910390a150565b60408051808201825264ffffffffff938416815291831660208084019182526001600160a01b039095166000908152600d90955293209051815493518316650100000000000269ffffffffffffffffffff19909416921691909117919091179055565b61346e8383836140a0565b6116085760405163fed82dc360e01b815260040160405180910390fd5b6001600160a01b0381166000818152600c60209081526040918290208054600101905590519182527f150d16c5ed87101ded5915d2c85572217aa147e5f50f384305123e8c6c5680da91016133f5565b604080516101a08101825260008082526020820181905260609282018390528282018190526080820181905260a0820183905260c0820181905260e0820181905261010082018190526101208201819052610140820181905261016082019290925261018081019190915260008060008060008060008060008060008c80602001905181019061356b9190615c0b565b9a509a509a509a509a509a509a509a509a509a509a50604051806101a001604052808c6001600160a01b031681526020018b6001600160a01b031681526020018a815260200189815260200188151581526020018781526020018664ffffffffff1681526020018564ffffffffff1681526020018461ffff1681526020018360028111156135fb576135fb6152c4565b8152602001826001600160601b0316815260200160405180602001604052806000815250815260200160006001811115613637576136376152c4565b90529d9c50505050505050505050505050565b606081901c816000600a6136606103e884615d04565b61366a9190615d2a565b6001600160601b0316905060018103613695576122d3858785856001600160601b0316600080614124565b600281036136c6576001600160a01b0383166136ba576136b58686611deb565b6122d3565b6122d386846000612f53565b600381036136d7576122d3866133a9565b600481036136e8576122d38661348b565b60058103613700576122d3864264ffffffffff613400565b60068103613739575050506001600160a01b039092166000908152600d60205260409020805469ffffffffffffffffffff191690555050565b6007810361375a576122d3858785856001600160601b031660016000614124565b60088103613786576122d38587856001600160601b03861660006137814262278d00615d50565b614124565b600981036137ad576122d38587856001600160601b0386166000613781426276a700615d50565b604051631ec9ca4160e21b815260040160405180910390fd5b6000610b11836001600160a01b038416614382565b6001600160a01b0381166000908152600b602090815260408083205490516001600160601b0319606086901b169281019290925260348201526054016128cb565b600081815260018301602052604081205461386357508154600181810184556000848152602080822090930184905584548482528286019093526040902091909155611507565b506000611507565b6000613878601a83614475565b60000361388757506000919050565b613892601a83614475565b6001036138a157506001919050565b506002919050565b919050565b6000600e83141580156138c757506138c76001836144c5565b156138d457506001611507565b6138de83836144c5565b9050611507565b600060016138f283613e7d565b6002811115612f3857612f386152c4565b60008061391a848460008060006001600080611b1c565b6001600160a01b038181166000908152600960209081526040808320815160c08101835281548087168252600160a01b908190046001600160601b0316948201949094526001808301549687169382019390935292850464ffffffffff9081166060850152600160c81b860416608084015294955091939092909160a0840191600160f01b900460ff16908111156139b4576139b46152c4565b60018111156139c5576139c56152c4565b90525080519091506001600160a01b0316156139f2576139e785836000612f53565b600192505050611507565b506000949350505050565b613a0784846144db565b15613a2557604051630da1844d60e01b815260040160405180910390fd5b61165a818484613463565b6000806001600160a01b03891615613b05578615613af3576040516331a9108f60e11b8152600481018990526001600160a01b03808c1691908b1690636352211e90602401602060405180830381865afa158015613a92573d6000803e3d6000fd5b505050506040513d601f19601f82011682018060405250810190613ab69190615975565b6001600160a01b031614613add5760405163400d9f5560e11b815260040160405180910390fd5b6b06765c793fa10079d000000082019150613b05565b6b033b2e3c9fd0803ce8000000820191505b6001836002811115613b1957613b196152c4565b03613b2f576a084595161401484a000000820191505b6002836002811115613b4357613b436152c4565b03613b59576a108b2a2c28029094000000820191505b64ffffffffff8585011615613b79576a52b7d2dcc80cd2e4000000820191505b60005b8651811015613c6f576001846002811115613b9957613b996152c4565b14158015613bcb5750613bcb8b8b8a8c8b8681518110613bbb57613bbb6158fc565b602002602001015160ff16613f82565b15613c0d57868181518110613be257613be26158fc565b6020026020010151604051630aab3ce760e41b8152600401610990919060ff91909116815260200190565b868181518110613c1f57613c1f6158fc565b602002602001015160ff16600103613c3c57600182019150613c67565b6001878281518110613c5057613c506158fc565b60200260200101510360ff16600a0a600102820191505b600101613b7c565b506001836002811115613c8457613c846152c4565b14613cb2578060056000613c9a8d8d8c8e613dde565b81526020810191909152604001600020805490910190555b0198975050505050505050565b6001600160a01b0383166000908152600c60209081526040918290205482516001600160601b0319606097881b81168285015260348201929092529490951b9094166054840152606880840192909252805180840390920182526088909201909152805191012090565b81602001516001600160a01b031682600001516001600160a01b03167f44d84a2c5d27e81636e3182f4601b82564c8086c61dd9a83e3b4586c4db96b2f84604001518481518110613d7c57613d7c6158fc565b6020026020010151856060015186608001518760a001518860c001518960e001518a61010001518b61012001518c61014001518d61016001518e6101800151604051613dd29b9a99989796959493929190615d63565b60405180910390a35050565b6001600160a01b0384166000908152600c60209081526040918290205482516001600160601b0319606098891b8116828501529690971b909516603487015292151560f81b60488601526049850191909152606980850193909352805180850390930183526089909301909252805191012090565b6000826000018281548110613e6a57613e6a6158fc565b9060005260206000200154905092915050565b600080613e8b601c84614475565b905080600003613e9e5750600092915050565b80600103613eaf5750600192915050565b50600292915050565b50919050565b6000613ecb601b83614475565b600003613eda57506000919050565b506001919050565b613eea614c71565b60005b6019811015613eb857613f0a613f04826001615d50565b8461457a565b828260198110613f1c57613f1c6158fc565b91151560209092020152600101613eed565b60606000806000806001600160a01b031688604001516001600160a01b031603613f6b57613f5e88888888614586565b9350935093509350613f77565b613f5e88888888614868565b945094509450949050565b60008060056000613f9589898989613dde565b815260200190815260200160002054905080600014158015613fc657508260011480613fc65750613fc683826138ae565b15613fd557600191505061115a565b600091505061115a565b6000613fed86868686613dde565b9050613ffb6019601d6158e9565b61400690600a615f1d565b614019906001600160601b038416614cbf565b600082815260056020526040812080549091906140379084906158e9565b9091555050505050505050565b60608160000180548060200260200160405190810160405280929190818152602001828054801561409457602002820191906000526020600020905b815481526020019060010190808311614080575b50505050509050919050565b6000836001600160a01b0316836001600160a01b0316036140c357506001610b11565b60408051606080820183526001600160a01b03808816835286166020808401919091526000838501819052845192830185526001808452838301528285018190528451808601909552808552908401819052610b0e938691600e9181611bef565b6040805160018082528183019092526000916020808301908036833701905050905060006141546103e886614cbf565b9050858260008151811061416a5761416a6158fc565b6001600160a01b0390921660209283029190910190910152600061271061419e6c01431e0fae6d7217caa000000088614cbf565b6141a891906158be565b905060006001546000146141ba575060015b6060826000036142125760408051600180825281830190925290602080830190803683370190505090506001816000815181106141f9576141f96158fc565b602002602001019060ff16908160ff16815250506142b1565b6040805160198082526103408201909252600091602082016103208036833701905050915060005b601981101561429a57614257614251826001615d50565b8661457a565b1561429257614267816001615d50565b838381518110614279576142796158fc565b60ff909216602092830291909101909101526001909101905b60010161423a565b5080601911156142af57815181016018190182525b505b614375604051806101a001604052808d6001600160a01b031681526020018c6001600160a01b0316815260200187815260200160008152602001600015158152602001838152602001600064ffffffffff1681526020018864ffffffffff1681526020018661ffff168152602001896002811115614331576143316152c4565b815260200160006001600160601b0316815260200160405180602001604052806000815250815260200184600181111561436d5761436d6152c4565b90528b611e2a565b5050505050505050505050565b6000818152600183016020526040812054801561446b5760006143a66001836158e9565b85549091506000906143ba906001906158e9565b905081811461441f5760008660000182815481106143da576143da6158fc565b90600052602060002001549050808760000184815481106143fd576143fd6158fc565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061443057614430615912565b600190038181906000526020600020016000905590558560010160008681526020019081526020016000206000905560019350505050611507565b6000915050611507565b60008061448384600a615f1d565b9050600084600103614497575060016144b0565b6144a26001866158e9565b6144ad90600a615f1d565b90505b806144bb8386614cbf565b61115a91906158be565b60006144d18383614475565b6001149392505050565b6001600160a01b0382166000908152600d6020908152604080832081518083019092525464ffffffffff80821683526501000000000090910416918101829052904211806145305750805164ffffffffff1642105b1561453f576000915050611507565b6001600160a01b0384166000908152600e602052604090206145619084611bcd565b15614570576000915050611507565b5060019392505050565b6000610b1183836144c5565b60606000806000806006600061459f8b600001516137db565b815260200190815260200160002090506145b8816128e8565b6001019350836001600160401b038111156145d5576145d5614d69565b6040519080825280602002602001820160405280156145fe578160200160208202803683370190505b509450886000015185600081518110614619576146196158fc565b6001600160a01b039092166020928302919091019091015260019092019160005b6146456001866158e9565b81101561485757600060098161465b85856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156146ef576146ef6152c4565b6001811115614700576147006152c4565b81525050905061471c81602001516001600160601b03166138e5565b806147ce57506147cc60405180606001604052808d600001516001600160a01b0316815260200183604001516001600160a01b0316815260200160006001600160a01b031681525060405180606001604052808c151581526020018b151581526020016000151581525083602001518d60006040518060400160405280886060015164ffffffffff168152602001886080015164ffffffffff168152506124bc898b6128f290919063ffffffff16565b155b156147d95750614845565b8a602001516001600160a01b031681604001516001600160a01b03160361480e57506000945084935060019250613f77915050565b8060400151878681518110614825576148256158fc565b6001600160a01b0390921660209283029190910190910152506001909301925b8061484f81615abf565b91505061463a565b506000915050945094509450949050565b6060600080600080600660006148818b600001516137db565b8152602001908152602001600020905061489a816128e8565b6001019350836001600160401b038111156148b7576148b7614d69565b6040519080825280602002602001820160405280156148e0578160200160208202803683370190505b5094508860000151856000815181106148fb576148fb6158fc565b6001600160a01b039092166020928302919091019091015260019092019160005b6149276001866158e9565b81101561485757600060098161493d85856128f2565b6001600160a01b0390811682526020808301939093526040918201600020825160c08101845281548084168252600160a01b908190046001600160601b0316958201959095526001808301549384169482019490945293820464ffffffffff9081166060860152600160c81b83041660808501529160a0840191600160f01b900460ff16908111156149d1576149d16152c4565b60018111156149e2576149e26152c4565b905250905060026149ff82602001516001600160601b0316613e7d565b6002811115614a1057614a106152c4565b03614a1b5750614b84565b6000614a3382602001516001600160601b03166138e5565b15614a43575060408b0151614a62565b614a5682604001518d604001518d614b96565b15614a62575050614b84565b614b0b60405180606001604052808e600001516001600160a01b0316815260200184604001516001600160a01b03168152602001836001600160a01b031681525060405180606001604052808d151581526020018c151581526020016000151581525084602001518e60006040518060400160405280896060015164ffffffffff168152602001896080015164ffffffffff168152506124bc8a8c6128f290919063ffffffff16565b614b16575050614b84565b8b602001516001600160a01b031682604001516001600160a01b031603614b4c57506000955085945060019350613f7792505050565b8160400151888781518110614b6357614b636158fc565b6001600160a01b039092166020928302919091019091015250506001909301925b80614b8e81615abf565b91505061491c565b6000610b0e82600560006127e08888600080613dde565b604080516102208101825260008082526020820181905290918201908152602001600081526020016000815260006020820181905260408201819052606082018190526080820181905260a0820181905260c0820181905260e082015261010001614c16614c71565b81526000602082018190526040820181905260608083015260809091015290565b508054614c4390615928565b6000825580601f10614c53575050565b601f016020900490600052602060002090810190610b229190614c90565b6040518061032001604052806019906020820280368337509192915050565b5b80821115614ca55760008155600101614c91565b5090565b634e487b7160e01b600052601260045260246000fd5b600082614cce57614cce614ca9565b500690565b6001600160a01b0381168114610b2257600080fd5b80356138a981614cd3565b600060208284031215614d0557600080fd5b8135610b1181614cd3565b6000815180845260005b81811015614d3657602081850181015186830182015201614d1a565b506000602082860101526020601f19601f83011685010191505092915050565b602081526000610b116020830184614d10565b634e487b7160e01b600052604160045260246000fd5b604051601f8201601f191681016001600160401b0381118282101715614da757614da7614d69565b604052919050565b60006001600160401b03821115614dc857614dc8614d69565b5060051b60200190565b600082601f830112614de357600080fd5b81356020614df8614df383614daf565b614d7f565b82815260059290921b84018101918181019086841115614e1757600080fd5b8286015b84811015614e3b578035614e2e81614cd3565b8352918301918301614e1b565b509695505050505050565b8015158114610b2257600080fd5b80356138a981614e46565b60ff81168114610b2257600080fd5b600082601f830112614e7f57600080fd5b81356020614e8f614df383614daf565b82815260059290921b84018101918181019086841115614eae57600080fd5b8286015b84811015614e3b578035614ec581614e5f565b8352918301918301614eb2565b64ffffffffff81168114610b2257600080fd5b80356138a981614ed2565b61ffff81168114610b2257600080fd5b80356138a981614ef0565b60038110610b2257600080fd5b80356138a981614f0b565b6001600160601b0381168114610b2257600080fd5b80356138a981614f23565b60006001600160401b03831115614f5c57614f5c614d69565b614f6f601f8401601f1916602001614d7f565b9050828152838383011115614f8357600080fd5b828260208301376000602084830101529392505050565b600082601f830112614fab57600080fd5b610b1183833560208501614f43565b6000806000806000806000806000806000806101808d8f031215614fdd57600080fd5b614fe68d614ce8565b9b50614ff460208e01614ce8565b9a506001600160401b0360408e0135111561500e57600080fd5b61501e8e60408f01358f01614dd2565b995060608d0135985061503360808e01614e54565b97506001600160401b0360a08e0135111561504d57600080fd5b61505d8e60a08f01358f01614e6e565b965061506b60c08e01614ee5565b955061507960e08e01614ee5565b94506150886101008e01614f00565b93506150976101208e01614f18565b92506150a66101408e01614f38565b91506001600160401b036101608e013511156150c157600080fd5b6150d28e6101608f01358f01614f9a565b90509295989b509295989b509295989b565b60018060a01b038416815282602082015260606040820152600061115a6060830184614d10565b600080600080600080600060e0888a03121561512657600080fd5b873561513181614cd3565b9650602088013561514181614cd3565b955060408801359450606088013561515881614e46565b93506080880135925060a088013561516f81614e46565b915060c088013561517f81614e46565b8091505092959891949750929550565b6000806000606084860312156151a457600080fd5b83356151af81614cd3565b92506020840135915060408401356151c681614f23565b809150509250925092565b600080604083850312156151e457600080fd5b82356151ef81614cd3565b946020939093013593505050565b600080600080600060a0868803121561521557600080fd5b853561522081614cd3565b94506020860135935060408601359250606086013561523e81614e46565b9150608086013561524e81614e46565b809150509295509295909350565b600081518084526020808501945080840160005b838110156152955781516001600160a01b031687529582019590820190600101615270565b509495945050505050565b6001600160a01b0383168152604060208201819052600090610b0e9083018461525c565b634e487b7160e01b600052602160045260246000fd5b600381106152ea576152ea6152c4565b9052565b60028110610b2257610b226152c4565b6152ea816152ee565b8060005b601981101561165a578151151584526020938401939091019060010161530b565b60006020808301818452808551808352604092508286019150828160051b87010184880160005b838110156154af57888303603f19018552815180516001600160a01b03168452610520818901516001600160a01b038116868b01525087820151615399898701826152da565b506060808301516153ac828801826152da565b50506080808301516153c0828801826152fe565b505060a0828101516001600160a01b03169086015260c0808301519086015260e08083015164ffffffffff9081169187019190915261010080840151909116908601526101208083015115159086015261014080830151151590860152610160808301511515908601526101808083015161543d82880182615307565b50506101a08201516001600160a01b03166104a08601526101c08201516001600160601b03166104c08601526101e08201516104e0860182905261548382870182614d10565b915050610200820151915061549c6105008601836152fe565b9588019593505090860190600101615353565b509098975050505050505050565b600080600080600060a086880312156154d557600080fd5b85356154e081614cd3565b945060208601356154f081614cd3565b935060408601359250606086013561523e81614e46565b602081526000610b11602083018461525c565b6000806040838503121561552d57600080fd5b82356151ef81614e5f565b60008060006060848603121561554d57600080fd5b83359250602084013561555f81614cd3565b929592945050506040919091013590565b6000806040838503121561558357600080fd5b823561558e81614cd3565b9150602083013561559e81614f23565b809150509250929050565b6000602082840312156155bb57600080fd5b81356001600160401b038111156155d157600080fd5b8201601f810184136155e257600080fd5b6155f184823560208401614f43565b949350505050565b600064ffffffffff8085511683528060208601511660208401525060606040830152610b0e606083018461525c565b6000806040838503121561563b57600080fd5b823561564681614cd3565b9150602083013561559e81614cd3565b60008060008060008060c0878903121561566f57600080fd5b863561567a81614cd3565b9550602087013561568a81614cd3565b9450604087013561569a81614cd3565b93506060870135925060808701356156b181614e46565b915060a08701356156c181614e46565b809150509295509295509295565b6000806000606084860312156156e457600080fd5b83356156ef81614cd3565b92506020840135915060408401356001600160401b0381111561571157600080fd5b61571d86828701614f9a565b9150509250925092565b6000806040838503121561573a57600080fd5b823561574581614cd3565b915060208301356001600160581b038116811461559e57600080fd5b60006020828403121561577357600080fd5b8135610b1181614ed2565b60006020828403121561579057600080fd5b5035919050565b600060c08201905060018060a01b038084511683526001600160601b03602085015116602084015280604085015116604084015250606083015164ffffffffff8082166060850152806080860151166080850152505060a08301516157fb816152ee565b8060a08401525092915050565b600080600080600080600080610100898b03121561582557600080fd5b883561583081614cd3565b9750602089013561584081614cd3565b9650604089013561585081614cd3565b955060608901359450608089013561586781614e46565b935060a089013561587781614f23565b925060c089013561588781614ed2565b915060e089013561589781614ed2565b809150509295985092959890939650565b634e487b7160e01b600052601160045260246000fd5b6000826158cd576158cd614ca9565b500490565b8082028115828204841417611507576115076158a8565b81810381811115611507576115076158a8565b634e487b7160e01b600052603260045260246000fd5b634e487b7160e01b600052603160045260246000fd5b600181811c9082168061593c57607f821691505b602082108103613eb857634e487b7160e01b600052602260045260246000fd5b60006020828403121561596e57600080fd5b5051919050565b60006020828403121561598757600080fd5b8151610b1181614cd3565b80516138a981614e46565b6000602082840312156159af57600080fd5b8151610b1181614e46565b601f82111561160857600081815260208120601f850160051c810160208610156159e15750805b601f850160051c820191505b818110156122d3578281556001016159ed565b81516001600160401b03811115615a1957615a19614d69565b615a2d81615a278454615928565b846159ba565b602080601f831160018114615a625760008415615a4a5750858301515b600019600386901b1c1916600185901b1785556122d3565b600085815260208120601f198616915b82811015615a9157888601518255948401946001909101908401615a72565b5085821015615aaf5787850151600019600388901b60f8161c191681555b5050505050600190811b01905550565b600060018201615ad157615ad16158a8565b5060010190565b600082601f830112615ae957600080fd5b81516020615af9614df383614daf565b82815260059290921b84018101918181019086841115615b1857600080fd5b8286015b84811015614e3b578051615b2f81614cd3565b8352918301918301615b1c565b600060208284031215615b4e57600080fd5b81516001600160401b03811115615b6457600080fd5b6155f184828501615ad8565b80516138a981614cd3565b600082601f830112615b8c57600080fd5b81516020615b9c614df383614daf565b82815260059290921b84018101918181019086841115615bbb57600080fd5b8286015b84811015614e3b578051615bd281614e5f565b8352918301918301615bbf565b80516138a981614ed2565b80516138a981614ef0565b80516138a981614f0b565b80516138a981614f23565b60008060008060008060008060008060006101608c8e031215615c2d57600080fd5b615c368c615b70565b9a50615c4460208d01615b70565b995060408c01516001600160401b03811115615c5f57600080fd5b615c6b8e828f01615ad8565b99505060608c01519750615c8160808d01615992565b965060a08c01516001600160401b03811115615c9c57600080fd5b615ca88e828f01615b7b565b965050615cb760c08d01615bdf565b9450615cc560e08d01615bdf565b9350615cd46101008d01615bea565b9250615ce36101208d01615bf5565b9150615cf26101408d01615c00565b90509295989b509295989b9093969950565b60006001600160601b0380841680615d1e57615d1e614ca9565b92169190910492915050565b60006001600160601b0380841680615d4457615d44614ca9565b92169190910692915050565b80820180821115611507576115076158a8565b6001600160a01b038c16815260208082018c90528a15156040830152610160606083018190528a519083018190526000916101808401918c82019190845b81811015615dc057835160ff1685529382019392820192600101615da1565b50505064ffffffffff8b1660808501525064ffffffffff891660a084015261ffff881660c0840152615df560e08401886152da565b6001600160601b038616610100840152828103610120840152615e188186614d10565b915050615e296101408301846152fe565b9c9b505050505050505050505050565b600181815b80851115615e74578160001904821115615e5a57615e5a6158a8565b80851615615e6757918102915b93841c9390800290615e3e565b509250929050565b600082615e8b57506001611507565b81615e9857506000611507565b8160018114615eae5760028114615eb857615ed4565b6001915050611507565b60ff841115615ec957615ec96158a8565b50506001821b611507565b5060208310610133831016604e8410600b8410161715615ef7575081810a611507565b615f018383615e39565b8060001904821115615f1557615f156158a8565b029392505050565b6000610b118383615e7c56fea2646970667358221220ef44aa63d9541f34cd1b89cd7aa55beefd234f08a07d838c60de8aec85654dad64736f6c63430008110033

Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

A token is a representation of an on-chain or off-chain asset. The token page shows information such as price, total supply, holders, transfers and social links. Learn more about this page in our Knowledge Base.