Sepolia Testnet

Token

ERC-20: Gho Token (GHO)
ERC-20

Overview

Max Total Supply

999,999,999.999999974957553488 GHO

Holders

2,727

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Balance
31 GHO
0x68acf374f725be1bafc6b51a9a20e1886891278f
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:
GhoToken

Compiler Version
v0.8.10+commit.fc410830

Optimization Enabled:
Yes with 100000 runs

Other Settings:
default evmVersion, MIT license

Contract Source Code (Solidity Standard Json-Input format)

File 1 of 9 : GhoToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {EnumerableSet} from '@openzeppelin/contracts/utils/structs/EnumerableSet.sol';
import {Ownable} from '@openzeppelin/contracts/access/Ownable.sol';
import {ERC20} from './ERC20.sol';
import {IGhoToken} from './interfaces/IGhoToken.sol';

/**
 * @title GHO Token
 * @author Aave
 */
contract GhoToken is ERC20, Ownable, IGhoToken {
  using EnumerableSet for EnumerableSet.AddressSet;

  mapping(address => Facilitator) internal _facilitators;
  EnumerableSet.AddressSet internal _facilitatorsList;

  /**
   * @dev Constructor
   */
  constructor() ERC20('Gho Token', 'GHO', 18) {
    // Intentionally left blank
  }

  /**
   * @notice Mints the requested amount of tokens to the account address.
   * @dev Only facilitators with enough bucket capacity available can mint.
   * @dev The bucket level is increased upon minting.
   * @param account The address receiving the GHO tokens
   * @param amount The amount to mint
   */
  function mint(address account, uint256 amount) external override {
    Facilitator storage f = _facilitators[msg.sender];
    uint256 bucketCapacity = f.bucketCapacity;
    require(bucketCapacity > 0, 'INVALID_FACILITATOR');

    uint256 currentBucketLevel = f.bucketLevel;
    uint256 newBucketLevel = currentBucketLevel + amount;
    require(bucketCapacity >= newBucketLevel, 'FACILITATOR_BUCKET_CAPACITY_EXCEEDED');
    f.bucketLevel = uint128(newBucketLevel);

    _mint(account, amount);

    emit FacilitatorBucketLevelUpdated(msg.sender, currentBucketLevel, newBucketLevel);
  }

  /**
   * @notice Burns the requested amount of tokens from the account address.
   * @dev Only active facilitators (capacity > 0) can burn.
   * @dev The bucket level is decreased upon burning.
   * @param amount The amount to burn
   */
  function burn(uint256 amount) external override {
    require(amount != 0, 'INVALID_BURN_AMOUNT');

    Facilitator storage f = _facilitators[msg.sender];
    uint256 currentBucketLevel = f.bucketLevel;
    uint256 newBucketLevel = currentBucketLevel - amount;
    f.bucketLevel = uint128(newBucketLevel);

    _burn(msg.sender, amount);

    emit FacilitatorBucketLevelUpdated(msg.sender, currentBucketLevel, newBucketLevel);
  }

  /// @inheritdoc IGhoToken
  function addFacilitator(
    address facilitatorAddress,
    string calldata facilitatorLabel,
    uint128 bucketCapacity
  ) external onlyOwner {
    Facilitator storage facilitator = _facilitators[facilitatorAddress];
    require(bytes(facilitator.label).length == 0, 'FACILITATOR_ALREADY_EXISTS');
    require(bytes(facilitatorLabel).length > 0, 'INVALID_LABEL');

    facilitator.label = facilitatorLabel;
    facilitator.bucketCapacity = bucketCapacity;

    _facilitatorsList.add(facilitatorAddress);

    emit FacilitatorAdded(
      facilitatorAddress,
      keccak256(abi.encodePacked(facilitatorLabel)),
      bucketCapacity
    );
  }

  /// @inheritdoc IGhoToken
  function removeFacilitator(address facilitatorAddress) external onlyOwner {
    require(
      bytes(_facilitators[facilitatorAddress].label).length > 0,
      'FACILITATOR_DOES_NOT_EXIST'
    );
    require(
      _facilitators[facilitatorAddress].bucketLevel == 0,
      'FACILITATOR_BUCKET_LEVEL_NOT_ZERO'
    );

    delete _facilitators[facilitatorAddress];
    _facilitatorsList.remove(facilitatorAddress);

    emit FacilitatorRemoved(facilitatorAddress);
  }

  /// @inheritdoc IGhoToken
  function setFacilitatorBucketCapacity(
    address facilitator,
    uint128 newCapacity
  ) external onlyOwner {
    require(bytes(_facilitators[facilitator].label).length > 0, 'FACILITATOR_DOES_NOT_EXIST');

    uint256 oldCapacity = _facilitators[facilitator].bucketCapacity;
    _facilitators[facilitator].bucketCapacity = newCapacity;

    emit FacilitatorBucketCapacityUpdated(facilitator, oldCapacity, newCapacity);
  }

  /// @inheritdoc IGhoToken
  function getFacilitator(address facilitator) external view returns (Facilitator memory) {
    return _facilitators[facilitator];
  }

  /// @inheritdoc IGhoToken
  function getFacilitatorBucket(address facilitator) external view returns (uint256, uint256) {
    return (_facilitators[facilitator].bucketCapacity, _facilitators[facilitator].bucketLevel);
  }

  /// @inheritdoc IGhoToken
  function getFacilitatorsList() external view returns (address[] memory) {
    return _facilitatorsList.values();
  }
}

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

pragma solidity ^0.8.0;

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

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

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

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

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

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

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

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

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

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

File 3 of 9 : 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 4 of 9 : 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 5 of 9 : 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 6 of 9 : ERC20.sol
// SPDX-License-Identifier: MIT-only
pragma solidity ^0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';

/**
 * @title ERC20
 * @notice Gas Efficient ERC20 + EIP-2612 implementation
 * @dev Modified version of Solmate ERC20 (https://github.com/Rari-Capital/solmate/blob/main/src/tokens/ERC20.sol),
 * implementing the basic IERC20
 */
abstract contract ERC20 is IERC20 {
  /*///////////////////////////////////////////////////////////////
                             METADATA STORAGE
    //////////////////////////////////////////////////////////////*/

  string public name;

  string public symbol;

  uint8 public immutable decimals;

  /*///////////////////////////////////////////////////////////////
                              ERC20 STORAGE
    //////////////////////////////////////////////////////////////*/

  uint256 public totalSupply;

  mapping(address => uint256) public balanceOf;

  mapping(address => mapping(address => uint256)) public allowance;

  /*///////////////////////////////////////////////////////////////
                             EIP-2612 STORAGE
    //////////////////////////////////////////////////////////////*/

  bytes32 public constant PERMIT_TYPEHASH =
    keccak256('Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)');

  uint256 internal immutable INITIAL_CHAIN_ID;

  bytes32 internal immutable INITIAL_DOMAIN_SEPARATOR;

  mapping(address => uint256) public nonces;

  /*///////////////////////////////////////////////////////////////
                               CONSTRUCTOR
    //////////////////////////////////////////////////////////////*/

  constructor(string memory _name, string memory _symbol, uint8 _decimals) {
    name = _name;
    symbol = _symbol;
    decimals = _decimals;

    INITIAL_CHAIN_ID = block.chainid;
    INITIAL_DOMAIN_SEPARATOR = computeDomainSeparator();
  }

  /*///////////////////////////////////////////////////////////////
                              ERC20 LOGIC
    //////////////////////////////////////////////////////////////*/

  function approve(address spender, uint256 amount) public virtual returns (bool) {
    allowance[msg.sender][spender] = amount;

    emit Approval(msg.sender, spender, amount);

    return true;
  }

  function transfer(address to, uint256 amount) public virtual returns (bool) {
    balanceOf[msg.sender] -= amount;

    // Cannot overflow because the sum of all user
    // balances can't exceed the max uint256 value.
    unchecked {
      balanceOf[to] += amount;
    }

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

    return true;
  }

  function transferFrom(address from, address to, uint256 amount) public virtual returns (bool) {
    uint256 allowed = allowance[from][msg.sender]; // Saves gas for limited approvals.

    if (allowed != type(uint256).max) allowance[from][msg.sender] = allowed - amount;

    balanceOf[from] -= amount;

    // Cannot overflow because the sum of all user
    // balances can't exceed the max uint256 value.
    unchecked {
      balanceOf[to] += amount;
    }

    emit Transfer(from, to, amount);

    return true;
  }

  /*///////////////////////////////////////////////////////////////
                              EIP-2612 LOGIC
    //////////////////////////////////////////////////////////////*/

  function permit(
    address owner,
    address spender,
    uint256 value,
    uint256 deadline,
    uint8 v,
    bytes32 r,
    bytes32 s
  ) public virtual {
    require(deadline >= block.timestamp, 'PERMIT_DEADLINE_EXPIRED');

    // Unchecked because the only math done is incrementing
    // the owner's nonce which cannot realistically overflow.
    unchecked {
      bytes32 digest = keccak256(
        abi.encodePacked(
          '\x19\x01',
          DOMAIN_SEPARATOR(),
          keccak256(abi.encode(PERMIT_TYPEHASH, owner, spender, value, nonces[owner]++, deadline))
        )
      );

      address recoveredAddress = ecrecover(digest, v, r, s);

      require(recoveredAddress != address(0) && recoveredAddress == owner, 'INVALID_SIGNER');

      allowance[recoveredAddress][spender] = value;
    }

    emit Approval(owner, spender, value);
  }

  function DOMAIN_SEPARATOR() public view virtual returns (bytes32) {
    return block.chainid == INITIAL_CHAIN_ID ? INITIAL_DOMAIN_SEPARATOR : computeDomainSeparator();
  }

  function computeDomainSeparator() internal view virtual returns (bytes32) {
    return
      keccak256(
        abi.encode(
          keccak256(
            'EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)'
          ),
          keccak256(bytes(name)),
          keccak256('1'),
          block.chainid,
          address(this)
        )
      );
  }

  /*///////////////////////////////////////////////////////////////
                       INTERNAL MINT/BURN LOGIC
    //////////////////////////////////////////////////////////////*/

  function _mint(address to, uint256 amount) internal virtual {
    totalSupply += amount;

    // Cannot overflow because the sum of all user
    // balances can't exceed the max uint256 value.
    unchecked {
      balanceOf[to] += amount;
    }

    emit Transfer(address(0), to, amount);
  }

  function _burn(address from, uint256 amount) internal virtual {
    balanceOf[from] -= amount;

    // Cannot underflow because a user's balance
    // will never be larger than the total supply.
    unchecked {
      totalSupply -= amount;
    }

    emit Transfer(from, address(0), amount);
  }
}

File 7 of 9 : IERC20Burnable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @dev Interface of a burnable erc-20 token
 */
interface IERC20Burnable {
  /**
   * @dev Destroys `amount` tokens from caller
   * @param amount The amount of tokens to destroy
   */
  function burn(uint256 amount) external;
}

File 8 of 9 : IERC20Mintable.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

/**
 * @dev Interface of a mintable erc-20 token
 */
interface IERC20Mintable {
  /**
   * @dev Creates `amount` new tokens for `account`
   * @param account The address to create tokens for
   * @param amount The amount of tokens to create
   */
  function mint(address account, uint256 amount) external;
}

File 9 of 9 : IGhoToken.sol
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import {IERC20} from '@openzeppelin/contracts/token/ERC20/IERC20.sol';
import {IERC20Burnable} from './IERC20Burnable.sol';
import {IERC20Mintable} from './IERC20Mintable.sol';

/**
 * @title IGhoToken
 * @author Aave
 */
interface IGhoToken is IERC20Burnable, IERC20Mintable, IERC20 {
  struct Facilitator {
    uint128 bucketCapacity;
    uint128 bucketLevel;
    string label;
  }

  /**
   * @dev Emitted when a new facilitator is added
   * @param facilitatorAddress The address of the new facilitator
   * @param label A hashed human readable identifier for the facilitator
   * @param bucketCapacity The initial capacity of the facilitator's bucket
   */
  event FacilitatorAdded(
    address indexed facilitatorAddress,
    bytes32 indexed label,
    uint256 bucketCapacity
  );

  /**
   * @dev Emitted when a facilitator is removed
   * @param facilitatorAddress The address of the removed facilitator
   */
  event FacilitatorRemoved(address indexed facilitatorAddress);

  /**
   * @dev Emitted when the bucket capacity of a facilitator is updated
   * @param facilitatorAddress The address of the facilitator whose bucket capacity is being changed
   * @param oldCapacity The old capacity of the bucket
   * @param newCapacity The new capacity of the bucket
   */
  event FacilitatorBucketCapacityUpdated(
    address indexed facilitatorAddress,
    uint256 oldCapacity,
    uint256 newCapacity
  );

  /**
   * @dev Emitted when the bucket level changed
   * @param facilitatorAddress The address of the facilitator whose bucket level is being changed
   * @param oldLevel The old level of the bucket
   * @param newLevel The new level of the bucket
   */
  event FacilitatorBucketLevelUpdated(
    address indexed facilitatorAddress,
    uint256 oldLevel,
    uint256 newLevel
  );

  /**
   * @notice Add the facilitator passed with the parameters to the facilitators list.
   * @param facilitatorAddress The address of the facilitator to add
   * @param facilitatorLabel A human readable identifier for the facilitator
   * @param bucketCapacity The upward limit of GHO can be minted by the facilitator
   */
  function addFacilitator(
    address facilitatorAddress,
    string calldata facilitatorLabel,
    uint128 bucketCapacity
  ) external;

  /**
   * @notice Remove the facilitator from the facilitators list.
   * @param facilitatorAddress The address of the facilitator to remove
   */
  function removeFacilitator(address facilitatorAddress) external;

  /**
   * @notice Set the bucket capacity of the facilitator.
   * @param facilitator The address of the facilitator
   * @param newCapacity The new capacity of the bucket
   */
  function setFacilitatorBucketCapacity(address facilitator, uint128 newCapacity) external;

  /**
   * @notice Returns the facilitator data
   * @param facilitator The address of the facilitator
   * @return The facilitator configuration
   */
  function getFacilitator(address facilitator) external view returns (Facilitator memory);

  /**
   * @notice Returns the bucket configuration of the facilitator
   * @param facilitator The address of the facilitator
   * @return The capacity of the facilitator's bucket
   * @return The level of the facilitator's bucket
   */
  function getFacilitatorBucket(address facilitator) external view returns (uint256, uint256);

  /**
   * @notice Returns the list of the addresses of the active facilitator
   * @return The list of the facilitators addresses
   */
  function getFacilitatorsList() external view returns (address[] memory);
}

Settings
{
  "evmVersion": "london",
  "libraries": {},
  "metadata": {
    "bytecodeHash": "ipfs",
    "useLiteralContent": true
  },
  "optimizer": {
    "enabled": true,
    "runs": 100000
  },
  "remappings": [],
  "outputSelection": {
    "*": {
      "*": [
        "evm.bytecode",
        "evm.deployedBytecode",
        "devdoc",
        "userdoc",
        "metadata",
        "abi"
      ]
    }
  }
}

Contract ABI

[{"inputs":[],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"owner","type":"address"},{"indexed":true,"internalType":"address","name":"spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"facilitatorAddress","type":"address"},{"indexed":true,"internalType":"bytes32","name":"label","type":"bytes32"},{"indexed":false,"internalType":"uint256","name":"bucketCapacity","type":"uint256"}],"name":"FacilitatorAdded","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"facilitatorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldCapacity","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newCapacity","type":"uint256"}],"name":"FacilitatorBucketCapacityUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"facilitatorAddress","type":"address"},{"indexed":false,"internalType":"uint256","name":"oldLevel","type":"uint256"},{"indexed":false,"internalType":"uint256","name":"newLevel","type":"uint256"}],"name":"FacilitatorBucketLevelUpdated","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"facilitatorAddress","type":"address"}],"name":"FacilitatorRemoved","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"previousOwner","type":"address"},{"indexed":true,"internalType":"address","name":"newOwner","type":"address"}],"name":"OwnershipTransferred","type":"event"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"from","type":"address"},{"indexed":true,"internalType":"address","name":"to","type":"address"},{"indexed":false,"internalType":"uint256","name":"value","type":"uint256"}],"name":"Transfer","type":"event"},{"inputs":[],"name":"DOMAIN_SEPARATOR","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"PERMIT_TYPEHASH","outputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"facilitatorAddress","type":"address"},{"internalType":"string","name":"facilitatorLabel","type":"string"},{"internalType":"uint128","name":"bucketCapacity","type":"uint128"}],"name":"addFacilitator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"},{"internalType":"address","name":"","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"burn","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"}],"name":"getFacilitator","outputs":[{"components":[{"internalType":"uint128","name":"bucketCapacity","type":"uint128"},{"internalType":"uint128","name":"bucketLevel","type":"uint128"},{"internalType":"string","name":"label","type":"string"}],"internalType":"struct IGhoToken.Facilitator","name":"","type":"tuple"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"}],"name":"getFacilitatorBucket","outputs":[{"internalType":"uint256","name":"","type":"uint256"},{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"getFacilitatorsList","outputs":[{"internalType":"address[]","name":"","type":"address[]"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"account","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"mint","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"owner","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"},{"internalType":"address","name":"spender","type":"address"},{"internalType":"uint256","name":"value","type":"uint256"},{"internalType":"uint256","name":"deadline","type":"uint256"},{"internalType":"uint8","name":"v","type":"uint8"},{"internalType":"bytes32","name":"r","type":"bytes32"},{"internalType":"bytes32","name":"s","type":"bytes32"}],"name":"permit","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"facilitatorAddress","type":"address"}],"name":"removeFacilitator","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"renounceOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"facilitator","type":"address"},{"internalType":"uint128","name":"newCapacity","type":"uint128"}],"name":"setFacilitatorBucketCapacity","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"symbol","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"totalSupply","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"from","type":"address"},{"internalType":"address","name":"to","type":"address"},{"internalType":"uint256","name":"amount","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"newOwner","type":"address"}],"name":"transferOwnership","outputs":[],"stateMutability":"nonpayable","type":"function"}]

60e06040523480156200001157600080fd5b50604080518082018252600981526823b437902a37b5b2b760b91b60208083019182528351808501909452600384526247484f60e81b90840152815191929160129162000062916000919062000195565b5081516200007890600190602085019062000195565b5060ff81166080524660a0526200008e620000a7565b60c05250620000a1915033905062000143565b6200031c565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f6000604051620000db919062000278565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b600680546001600160a01b038381166001600160a01b0319831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b828054620001a3906200023b565b90600052602060002090601f016020900481019282620001c7576000855562000212565b82601f10620001e257805160ff191683800117855562000212565b8280016001018555821562000212579182015b8281111562000212578251825591602001919060010190620001f5565b506200022092915062000224565b5090565b5b8082111562000220576000815560010162000225565b600181811c908216806200025057607f821691505b602082108114156200027257634e487b7160e01b600052602260045260246000fd5b50919050565b600080835481600182811c9150808316806200029557607f831692505b6020808410821415620002b657634e487b7160e01b86526022600452602486fd5b818015620002cd5760018114620002df576200030e565b60ff198616895284890196506200030e565b60008a81526020902060005b86811015620003065781548b820152908501908301620002eb565b505084890196505b509498975050505050505050565b60805160a05160c0516120146200034c60003960006106e9015260006106b90152600061024901526120146000f3fe608060405234801561001057600080fd5b50600436106101985760003560e01c80637ecebe00116100e3578063aa02f94a1161008c578063d505accf11610066578063d505accf14610407578063dd62ed3e1461041a578063f2fde38b1461044557600080fd5b8063aa02f94a1461035e578063af93df57146103d4578063d46ec0ed146103e757600080fd5b806395d89b41116100bd57806395d89b4114610330578063a11812ba14610338578063a9059cbb1461034b57600080fd5b80637ecebe00146102d55780637fc24def146102f55780638da5cb5b1461030857600080fd5b8063313ce5671161014557806342966c681161011f57806342966c681461029a57806370a08231146102ad578063715018a6146102cd57600080fd5b8063313ce567146102445780633644e5151461027d57806340c10f191461028557600080fd5b80631ec90f2e116101765780631ec90f2e146101f557806323b872dd1461020a57806330adf81f1461021d57600080fd5b806306fdde031461019d578063095ea7b3146101bb57806318160ddd146101de575b600080fd5b6101a5610458565b6040516101b29190611aea565b60405180910390f35b6101ce6101c9366004611b26565b6104e6565b60405190151581526020016101b2565b6101e760025481565b6040519081526020016101b2565b6101fd610560565b6040516101b29190611b50565b6101ce610218366004611baa565b610571565b6101e77f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b61026b7f000000000000000000000000000000000000000000000000000000000000000081565b60405160ff90911681526020016101b2565b6101e76106b5565b610298610293366004611b26565b61070b565b005b6102986102a8366004611be6565b6108da565b6101e76102bb366004611bff565b60036020526000908152604090205481565b610298610a01565b6101e76102e3366004611bff565b60056020526000908152604090205481565b610298610303366004611c3a565b610a15565b60065460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b2565b6101a5610c20565b610298610346366004611bff565b610c2d565b6101ce610359366004611b26565b610e33565b6103bf61036c366004611bff565b73ffffffffffffffffffffffffffffffffffffffff166000908152600760205260409020546fffffffffffffffffffffffffffffffff808216927001000000000000000000000000000000009092041690565b604080519283526020830191909152016101b2565b6102986103e2366004611cce565b610eb8565b6103fa6103f5366004611bff565b611004565b6040516101b29190611d01565b610298610415366004611d4e565b611120565b6101e7610428366004611dc1565b600460209081526000928352604080842090915290825290205481565b610298610453366004611bff565b61144c565b6000805461046590611deb565b80601f016020809104026020016040519081016040528092919081815260200182805461049190611deb565b80156104de5780601f106104b3576101008083540402835291602001916104de565b820191906000526020600020905b8154815290600101906020018083116104c157829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061054e9086815260200190565b60405180910390a35060015b92915050565b606061056c6008611503565b905090565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610605576105d38382611e6e565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260408120805485929061063a908490611e6e565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906106a29087815260200190565b60405180910390a3506001949350505050565b60007f000000000000000000000000000000000000000000000000000000000000000046146106e65761056c611517565b507f000000000000000000000000000000000000000000000000000000000000000090565b33600090815260076020526040902080546fffffffffffffffffffffffffffffffff168061079a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f494e56414c49445f464143494c495441544f520000000000000000000000000060448201526064015b60405180910390fd5b815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1660006107ce8583611e85565b90508083101561085f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f464143494c495441544f525f4255434b45545f43415041434954595f4558434560448201527f45444544000000000000000000000000000000000000000000000000000000006064820152608401610791565b83546fffffffffffffffffffffffffffffffff80831670010000000000000000000000000000000002911617845561089786866115b1565b604080518381526020810183905233917facb6de9209e4f34974cb165eef5738f0cf0b4ea9819ef30d30f0f7d81272ab82910160405180910390a2505050505050565b80610941576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f494e56414c49445f4255524e5f414d4f554e54000000000000000000000000006044820152606401610791565b336000908152600760205260408120805490917001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff16906109868483611e6e565b83546fffffffffffffffffffffffffffffffff80831670010000000000000000000000000000000002911617845590506109c0338561162a565b604080518381526020810183905233917facb6de9209e4f34974cb165eef5738f0cf0b4ea9819ef30d30f0f7d81272ab82910160405180910390a250505050565b610a096116b8565b610a136000611739565b565b610a1d6116b8565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600760205260409020600181018054610a5190611deb565b159050610aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f414c52454144595f4558495354530000000000006044820152606401610791565b82610b21576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f4c4142454c000000000000000000000000000000000000006044820152606401610791565b610b2f600182018585611992565b5080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff8316178155610b756008866117b0565b508383604051602001610b89929190611e9d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020918201206fffffffffffffffffffffffffffffffff851683529173ffffffffffffffffffffffffffffffffffffffff8816917fdabd62626ada7b13e299389e94d768b294e5e24285ed2ffa1e5cd447c99c54ad910160405180910390a35050505050565b6001805461046590611deb565b610c356116b8565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604081206001018054610c6890611deb565b905011610cd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f444f45535f4e4f545f45584953540000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1615610daa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f464143494c495441544f525f4255434b45545f4c4556454c5f4e4f545f5a455260448201527f4f000000000000000000000000000000000000000000000000000000000000006064820152608401610791565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260076020526040812081815590610de06001830182611a34565b50610dee90506008826117d2565b5060405173ffffffffffffffffffffffffffffffffffffffff8216907fa8fe5b89f35f2ebd6f3f95a7ef215f4bd89179e10c101073ae76cffad14734cf90600090a250565b33600090815260036020526040812080548391908390610e54908490611e6e565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061054e9086815260200190565b610ec06116b8565b73ffffffffffffffffffffffffffffffffffffffff821660009081526007602052604081206001018054610ef390611deb565b905011610f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f444f45535f4e4f545f45584953540000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166fffffffffffffffffffffffffffffffff878116918217909355845192909116808352928201529092917fc795c0a4927c3b6645e4e49a5a519af936b3c1c0e4c323a3f7251063f3f4bb0e910160405180910390a2505050565b60408051606080820183526000808352602080840182905283850183905273ffffffffffffffffffffffffffffffffffffffff8616825260078152908490208451928301855280546fffffffffffffffffffffffffffffffff8082168552700100000000000000000000000000000000909104169183019190915260018101805493949293919284019161109790611deb565b80601f01602080910402602001604051908101604052809291908181526020018280546110c390611deb565b80156111105780601f106110e557610100808354040283529160200191611110565b820191906000526020600020905b8154815290600101906020018083116110f357829003601f168201915b5050505050815250509050919050565b4284101561118a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610791565b60006111946106b5565b73ffffffffffffffffffffffffffffffffffffffff89811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938c166060840152608083018b905260a083019390935260c08083018a90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156112f3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580159061136e57508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6113d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208b8516808552908352928190208a905551898152919350918a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6114546116b8565b73ffffffffffffffffffffffffffffffffffffffff81166114f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610791565b61150081611739565b50565b60606000611510836117f4565b9392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516115499190611ead565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546115c39190611e85565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061165f908490611e6e565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161161e565b60065473ffffffffffffffffffffffffffffffffffffffff163314610a13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610791565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006115108373ffffffffffffffffffffffffffffffffffffffff8416611850565b60006115108373ffffffffffffffffffffffffffffffffffffffff841661189f565b60608160000180548060200260200160405190810160405280929190818152602001828054801561184457602002820191906000526020600020905b815481526020019060010190808311611830575b50505050509050919050565b60008181526001830160205260408120546118975750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561055a565b50600061055a565b600081815260018301602052604081205480156119885760006118c3600183611e6e565b85549091506000906118d790600190611e6e565b905081811461193c5760008660000182815481106118f7576118f7611f80565b906000526020600020015490508087600001848154811061191a5761191a611f80565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061194d5761194d611faf565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061055a565b600091505061055a565b82805461199e90611deb565b90600052602060002090601f0160209004810192826119c05760008555611a24565b82601f106119f7578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555611a24565b82800160010185558215611a24579182015b82811115611a24578235825591602001919060010190611a09565b50611a30929150611a6a565b5090565b508054611a4090611deb565b6000825580601f10611a50575050565b601f01602090049060005260206000209081019061150091905b5b80821115611a305760008155600101611a6b565b6000815180845260005b81811015611aa557602081850181015186830182015201611a89565b81811115611ab7576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006115106020830184611a7f565b803573ffffffffffffffffffffffffffffffffffffffff81168114611b2157600080fd5b919050565b60008060408385031215611b3957600080fd5b611b4283611afd565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b81811015611b9e57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611b6c565b50909695505050505050565b600080600060608486031215611bbf57600080fd5b611bc884611afd565b9250611bd660208501611afd565b9150604084013590509250925092565b600060208284031215611bf857600080fd5b5035919050565b600060208284031215611c1157600080fd5b61151082611afd565b80356fffffffffffffffffffffffffffffffff81168114611b2157600080fd5b60008060008060608587031215611c5057600080fd5b611c5985611afd565b9350602085013567ffffffffffffffff80821115611c7657600080fd5b818701915087601f830112611c8a57600080fd5b813581811115611c9957600080fd5b886020828501011115611cab57600080fd5b602083019550809450505050611cc360408601611c1a565b905092959194509250565b60008060408385031215611ce157600080fd5b611cea83611afd565b9150611cf860208401611c1a565b90509250929050565b6020815260006fffffffffffffffffffffffffffffffff808451166020840152806020850151166040840152506040830151606080840152611d466080840182611a7f565b949350505050565b600080600080600080600060e0888a031215611d6957600080fd5b611d7288611afd565b9650611d8060208901611afd565b95506040880135945060608801359350608088013560ff81168114611da457600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611dd457600080fd5b611ddd83611afd565b9150611cf860208401611afd565b600181811c90821680611dff57607f821691505b60208210811415611e39577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611e8057611e80611e3f565b500390565b60008219821115611e9857611e98611e3f565b500190565b8183823760009101908152919050565b600080835481600182811c915080831680611ec957607f831692505b6020808410821415611f02577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015611f165760018114611f4557611f72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528489019650611f72565b60008a81526020902060005b86811015611f6a5781548b820152908501908301611f51565b505084890196505b509498975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a6dab2fc8078c8d8d8865a9fbd24b0c54c6ea3f77af90654d7588e777b91feb164736f6c634300080a0033

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101985760003560e01c80637ecebe00116100e3578063aa02f94a1161008c578063d505accf11610066578063d505accf14610407578063dd62ed3e1461041a578063f2fde38b1461044557600080fd5b8063aa02f94a1461035e578063af93df57146103d4578063d46ec0ed146103e757600080fd5b806395d89b41116100bd57806395d89b4114610330578063a11812ba14610338578063a9059cbb1461034b57600080fd5b80637ecebe00146102d55780637fc24def146102f55780638da5cb5b1461030857600080fd5b8063313ce5671161014557806342966c681161011f57806342966c681461029a57806370a08231146102ad578063715018a6146102cd57600080fd5b8063313ce567146102445780633644e5151461027d57806340c10f191461028557600080fd5b80631ec90f2e116101765780631ec90f2e146101f557806323b872dd1461020a57806330adf81f1461021d57600080fd5b806306fdde031461019d578063095ea7b3146101bb57806318160ddd146101de575b600080fd5b6101a5610458565b6040516101b29190611aea565b60405180910390f35b6101ce6101c9366004611b26565b6104e6565b60405190151581526020016101b2565b6101e760025481565b6040519081526020016101b2565b6101fd610560565b6040516101b29190611b50565b6101ce610218366004611baa565b610571565b6101e77f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c981565b61026b7f000000000000000000000000000000000000000000000000000000000000001281565b60405160ff90911681526020016101b2565b6101e76106b5565b610298610293366004611b26565b61070b565b005b6102986102a8366004611be6565b6108da565b6101e76102bb366004611bff565b60036020526000908152604090205481565b610298610a01565b6101e76102e3366004611bff565b60056020526000908152604090205481565b610298610303366004611c3a565b610a15565b60065460405173ffffffffffffffffffffffffffffffffffffffff90911681526020016101b2565b6101a5610c20565b610298610346366004611bff565b610c2d565b6101ce610359366004611b26565b610e33565b6103bf61036c366004611bff565b73ffffffffffffffffffffffffffffffffffffffff166000908152600760205260409020546fffffffffffffffffffffffffffffffff808216927001000000000000000000000000000000009092041690565b604080519283526020830191909152016101b2565b6102986103e2366004611cce565b610eb8565b6103fa6103f5366004611bff565b611004565b6040516101b29190611d01565b610298610415366004611d4e565b611120565b6101e7610428366004611dc1565b600460209081526000928352604080842090915290825290205481565b610298610453366004611bff565b61144c565b6000805461046590611deb565b80601f016020809104026020016040519081016040528092919081815260200182805461049190611deb565b80156104de5780601f106104b3576101008083540402835291602001916104de565b820191906000526020600020905b8154815290600101906020018083116104c157829003601f168201915b505050505081565b33600081815260046020908152604080832073ffffffffffffffffffffffffffffffffffffffff8716808552925280832085905551919290917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b9259061054e9086815260200190565b60405180910390a35060015b92915050565b606061056c6008611503565b905090565b73ffffffffffffffffffffffffffffffffffffffff831660009081526004602090815260408083203384529091528120547fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff8114610605576105d38382611e6e565b73ffffffffffffffffffffffffffffffffffffffff861660009081526004602090815260408083203384529091529020555b73ffffffffffffffffffffffffffffffffffffffff85166000908152600360205260408120805485929061063a908490611e6e565b909155505073ffffffffffffffffffffffffffffffffffffffff808516600081815260036020526040908190208054870190555190918716907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef906106a29087815260200190565b60405180910390a3506001949350505050565b60007f0000000000000000000000000000000000000000000000000000000000aa36a746146106e65761056c611517565b507f2927c890ba585bc839bc026585d825f6b4c6982855a47def0eadf870a7e7631390565b33600090815260076020526040902080546fffffffffffffffffffffffffffffffff168061079a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f494e56414c49445f464143494c495441544f520000000000000000000000000060448201526064015b60405180910390fd5b815470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1660006107ce8583611e85565b90508083101561085f576040517f08c379a0000000000000000000000000000000000000000000000000000000008152602060048201526024808201527f464143494c495441544f525f4255434b45545f43415041434954595f4558434560448201527f45444544000000000000000000000000000000000000000000000000000000006064820152608401610791565b83546fffffffffffffffffffffffffffffffff80831670010000000000000000000000000000000002911617845561089786866115b1565b604080518381526020810183905233917facb6de9209e4f34974cb165eef5738f0cf0b4ea9819ef30d30f0f7d81272ab82910160405180910390a2505050505050565b80610941576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601360248201527f494e56414c49445f4255524e5f414d4f554e54000000000000000000000000006044820152606401610791565b336000908152600760205260408120805490917001000000000000000000000000000000009091046fffffffffffffffffffffffffffffffff16906109868483611e6e565b83546fffffffffffffffffffffffffffffffff80831670010000000000000000000000000000000002911617845590506109c0338561162a565b604080518381526020810183905233917facb6de9209e4f34974cb165eef5738f0cf0b4ea9819ef30d30f0f7d81272ab82910160405180910390a250505050565b610a096116b8565b610a136000611739565b565b610a1d6116b8565b73ffffffffffffffffffffffffffffffffffffffff84166000908152600760205260409020600181018054610a5190611deb565b159050610aba576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f414c52454144595f4558495354530000000000006044820152606401610791565b82610b21576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600d60248201527f494e56414c49445f4c4142454c000000000000000000000000000000000000006044820152606401610791565b610b2f600182018585611992565b5080547fffffffffffffffffffffffffffffffff00000000000000000000000000000000166fffffffffffffffffffffffffffffffff8316178155610b756008866117b0565b508383604051602001610b89929190611e9d565b604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181529082905280516020918201206fffffffffffffffffffffffffffffffff851683529173ffffffffffffffffffffffffffffffffffffffff8816917fdabd62626ada7b13e299389e94d768b294e5e24285ed2ffa1e5cd447c99c54ad910160405180910390a35050505050565b6001805461046590611deb565b610c356116b8565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604081206001018054610c6890611deb565b905011610cd1576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f444f45535f4e4f545f45584953540000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff811660009081526007602052604090205470010000000000000000000000000000000090046fffffffffffffffffffffffffffffffff1615610daa576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602160248201527f464143494c495441544f525f4255434b45545f4c4556454c5f4e4f545f5a455260448201527f4f000000000000000000000000000000000000000000000000000000000000006064820152608401610791565b73ffffffffffffffffffffffffffffffffffffffff8116600090815260076020526040812081815590610de06001830182611a34565b50610dee90506008826117d2565b5060405173ffffffffffffffffffffffffffffffffffffffff8216907fa8fe5b89f35f2ebd6f3f95a7ef215f4bd89179e10c101073ae76cffad14734cf90600090a250565b33600090815260036020526040812080548391908390610e54908490611e6e565b909155505073ffffffffffffffffffffffffffffffffffffffff8316600081815260036020526040908190208054850190555133907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9061054e9086815260200190565b610ec06116b8565b73ffffffffffffffffffffffffffffffffffffffff821660009081526007602052604081206001018054610ef390611deb565b905011610f5c576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601a60248201527f464143494c495441544f525f444f45535f4e4f545f45584953540000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff821660008181526007602090815260409182902080547fffffffffffffffffffffffffffffffff0000000000000000000000000000000081166fffffffffffffffffffffffffffffffff878116918217909355845192909116808352928201529092917fc795c0a4927c3b6645e4e49a5a519af936b3c1c0e4c323a3f7251063f3f4bb0e910160405180910390a2505050565b60408051606080820183526000808352602080840182905283850183905273ffffffffffffffffffffffffffffffffffffffff8616825260078152908490208451928301855280546fffffffffffffffffffffffffffffffff8082168552700100000000000000000000000000000000909104169183019190915260018101805493949293919284019161109790611deb565b80601f01602080910402602001604051908101604052809291908181526020018280546110c390611deb565b80156111105780601f106110e557610100808354040283529160200191611110565b820191906000526020600020905b8154815290600101906020018083116110f357829003601f168201915b5050505050815250509050919050565b4284101561118a576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152601760248201527f5045524d49545f444541444c494e455f455850495245440000000000000000006044820152606401610791565b60006111946106b5565b73ffffffffffffffffffffffffffffffffffffffff89811660008181526005602090815260409182902080546001810190915582517f6e71edae12b1b97f4d1f60370fef10105fa2faae0126114a169c64845d6126c98184015280840194909452938c166060840152608083018b905260a083019390935260c08083018a90528151808403909101815260e0830190915280519201919091207f190100000000000000000000000000000000000000000000000000000000000061010083015261010282019290925261012281019190915261014201604080517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe08184030181528282528051602091820120600080855291840180845281905260ff88169284019290925260608301869052608083018590529092509060019060a0016020604051602081039080840390855afa1580156112f3573d6000803e3d6000fd5b50506040517fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0015191505073ffffffffffffffffffffffffffffffffffffffff81161580159061136e57508873ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff16145b6113d4576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152600e60248201527f494e56414c49445f5349474e45520000000000000000000000000000000000006044820152606401610791565b73ffffffffffffffffffffffffffffffffffffffff90811660009081526004602090815260408083208b8516808552908352928190208a905551898152919350918a16917f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925910160405180910390a350505050505050565b6114546116b8565b73ffffffffffffffffffffffffffffffffffffffff81166114f7576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820152602660248201527f4f776e61626c653a206e6577206f776e657220697320746865207a65726f206160448201527f64647265737300000000000000000000000000000000000000000000000000006064820152608401610791565b61150081611739565b50565b60606000611510836117f4565b9392505050565b60007f8b73c3c69bb8fe3d512ecc4cf759cc79239f7b179b0ffacaa9a75d522b39400f60006040516115499190611ead565b6040805191829003822060208301939093528101919091527fc89efdaa54c0f20c7adf612882df0950f5a951637e0307cdcb4c672f298b8bc660608201524660808201523060a082015260c00160405160208183030381529060405280519060200120905090565b80600260008282546115c39190611e85565b909155505073ffffffffffffffffffffffffffffffffffffffff82166000818152600360209081526040808320805486019055518481527fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef91015b60405180910390a35050565b73ffffffffffffffffffffffffffffffffffffffff82166000908152600360205260408120805483929061165f908490611e6e565b909155505060028054829003905560405181815260009073ffffffffffffffffffffffffffffffffffffffff8416907fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef9060200161161e565b60065473ffffffffffffffffffffffffffffffffffffffff163314610a13576040517f08c379a000000000000000000000000000000000000000000000000000000000815260206004820181905260248201527f4f776e61626c653a2063616c6c6572206973206e6f7420746865206f776e65726044820152606401610791565b6006805473ffffffffffffffffffffffffffffffffffffffff8381167fffffffffffffffffffffffff0000000000000000000000000000000000000000831681179093556040519116919082907f8be0079c531659141344cd1fd0a4f28419497f9722a3daafe3b4186f6b6457e090600090a35050565b60006115108373ffffffffffffffffffffffffffffffffffffffff8416611850565b60006115108373ffffffffffffffffffffffffffffffffffffffff841661189f565b60608160000180548060200260200160405190810160405280929190818152602001828054801561184457602002820191906000526020600020905b815481526020019060010190808311611830575b50505050509050919050565b60008181526001830160205260408120546118975750815460018181018455600084815260208082209093018490558454848252828601909352604090209190915561055a565b50600061055a565b600081815260018301602052604081205480156119885760006118c3600183611e6e565b85549091506000906118d790600190611e6e565b905081811461193c5760008660000182815481106118f7576118f7611f80565b906000526020600020015490508087600001848154811061191a5761191a611f80565b6000918252602080832090910192909255918252600188019052604090208390555b855486908061194d5761194d611faf565b60019003818190600052602060002001600090559055856001016000868152602001908152602001600020600090556001935050505061055a565b600091505061055a565b82805461199e90611deb565b90600052602060002090601f0160209004810192826119c05760008555611a24565b82601f106119f7578280017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00823516178555611a24565b82800160010185558215611a24579182015b82811115611a24578235825591602001919060010190611a09565b50611a30929150611a6a565b5090565b508054611a4090611deb565b6000825580601f10611a50575050565b601f01602090049060005260206000209081019061150091905b5b80821115611a305760008155600101611a6b565b6000815180845260005b81811015611aa557602081850181015186830182015201611a89565b81811115611ab7576000602083870101525b50601f017fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe0169290920160200192915050565b6020815260006115106020830184611a7f565b803573ffffffffffffffffffffffffffffffffffffffff81168114611b2157600080fd5b919050565b60008060408385031215611b3957600080fd5b611b4283611afd565b946020939093013593505050565b6020808252825182820181905260009190848201906040850190845b81811015611b9e57835173ffffffffffffffffffffffffffffffffffffffff1683529284019291840191600101611b6c565b50909695505050505050565b600080600060608486031215611bbf57600080fd5b611bc884611afd565b9250611bd660208501611afd565b9150604084013590509250925092565b600060208284031215611bf857600080fd5b5035919050565b600060208284031215611c1157600080fd5b61151082611afd565b80356fffffffffffffffffffffffffffffffff81168114611b2157600080fd5b60008060008060608587031215611c5057600080fd5b611c5985611afd565b9350602085013567ffffffffffffffff80821115611c7657600080fd5b818701915087601f830112611c8a57600080fd5b813581811115611c9957600080fd5b886020828501011115611cab57600080fd5b602083019550809450505050611cc360408601611c1a565b905092959194509250565b60008060408385031215611ce157600080fd5b611cea83611afd565b9150611cf860208401611c1a565b90509250929050565b6020815260006fffffffffffffffffffffffffffffffff808451166020840152806020850151166040840152506040830151606080840152611d466080840182611a7f565b949350505050565b600080600080600080600060e0888a031215611d6957600080fd5b611d7288611afd565b9650611d8060208901611afd565b95506040880135945060608801359350608088013560ff81168114611da457600080fd5b9699959850939692959460a0840135945060c09093013592915050565b60008060408385031215611dd457600080fd5b611ddd83611afd565b9150611cf860208401611afd565b600181811c90821680611dff57607f821691505b60208210811415611e39577f4e487b7100000000000000000000000000000000000000000000000000000000600052602260045260246000fd5b50919050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052601160045260246000fd5b600082821015611e8057611e80611e3f565b500390565b60008219821115611e9857611e98611e3f565b500190565b8183823760009101908152919050565b600080835481600182811c915080831680611ec957607f831692505b6020808410821415611f02577f4e487b710000000000000000000000000000000000000000000000000000000086526022600452602486fd5b818015611f165760018114611f4557611f72565b7fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff00861689528489019650611f72565b60008a81526020902060005b86811015611f6a5781548b820152908501908301611f51565b505084890196505b509498975050505050505050565b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603260045260246000fd5b7f4e487b7100000000000000000000000000000000000000000000000000000000600052603160045260246000fdfea2646970667358221220a6dab2fc8078c8d8d8865a9fbd24b0c54c6ea3f77af90654d7588e777b91feb164736f6c634300080a0033

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