ETH Price: $1,483.21 (-17.13%)
Gas: 4.17 Gwei

Contract

0x4B7ee45f30767F36f06F79B32BF1FCa6f726DEda
 

Overview

ETH Balance

0 ETH

Eth Value

$0.00

Token Holdings

Multichain Info

No addresses found
Transaction Hash
Method
Block
From
To
Transfer220157762025-03-10 10:08:2327 days ago1741601303IN
Gemini: eFIL Token
0 ETH0.000168632.85142126
Transfer213800082024-12-11 14:57:47116 days ago1733929067IN
Gemini: eFIL Token
0 ETH0.0015366925.95677854
Approve200430532024-06-07 22:52:59303 days ago1717800779IN
Gemini: eFIL Token
0 ETH0.00032478.98372298
Transfer197141532024-04-22 23:15:35349 days ago1713827735IN
Gemini: eFIL Token
0 ETH0.000404696.84
Transfer195610772024-04-01 12:48:23370 days ago1711975703IN
Gemini: eFIL Token
0 ETH0.0012000420.27032531
Transfer195084392024-03-25 2:06:59378 days ago1711332419IN
Gemini: eFIL Token
0 ETH0.0008472114.31355053
Approve195083592024-03-25 1:50:47378 days ago1711331447IN
Gemini: eFIL Token
0 ETH0.0009675716.65941964
Transfer194624342024-03-18 15:01:35384 days ago1710774095IN
Gemini: eFIL Token
0 ETH0.0036192661.15890553
Transfer194344732024-03-14 16:37:59388 days ago1710434279IN
Gemini: eFIL Token
0 ETH0.0036106461.01323725
Transfer194287372024-03-13 21:14:11389 days ago1710364451IN
Gemini: eFIL Token
0 ETH0.0025283260.03535841
Transfer194284752024-03-13 20:20:47389 days ago1710361247IN
Gemini: eFIL Token
0 ETH0.0038051459.48704745
Transfer190806542024-01-25 2:28:35438 days ago1706149715IN
Gemini: eFIL Token
0 ETH0.0006195710.46971601
Approve189412782024-01-05 13:09:59457 days ago1704460199IN
Gemini: eFIL Token
0 ETH0.0013597923.27307944
Transfer184021912023-10-22 0:14:11533 days ago1697933651IN
Gemini: eFIL Token
0 ETH0.000528628.93093507
Approve181972432023-09-23 8:11:23562 days ago1695456683IN
Gemini: eFIL Token
0 ETH0.000297827.80793315
Approve176987122023-07-15 12:14:11631 days ago1689423251IN
Gemini: eFIL Token
0 ETH0.0005309314.6894905
Approve174119732023-06-05 4:31:23672 days ago1685939483IN
Gemini: eFIL Token
0 ETH0.0007501720.75513202
Transfer172499652023-05-13 8:46:59695 days ago1683967619IN
Gemini: eFIL Token
0 ETH0.0025746843.48989738
Transfer172428222023-05-12 8:02:59696 days ago1683878579IN
Gemini: eFIL Token
0 ETH0.0035645855.72624789
Transfer171883122023-05-04 15:52:11703 days ago1683215531IN
Gemini: eFIL Token
0 ETH0.0052909389.40704787
Transfer171336852023-04-26 23:33:11711 days ago1682551991IN
Gemini: eFIL Token
0 ETH0.0023438339.59046432
Transfer168947402023-03-24 3:39:23745 days ago1679629163IN
Gemini: eFIL Token
0 ETH0.0008172313.80701312
Transfer166718272023-02-20 19:26:23776 days ago1676921183IN
Gemini: eFIL Token
0 ETH0.0024759441.83043859
Approve166690732023-02-20 10:09:59776 days ago1676887799IN
Gemini: eFIL Token
0 ETH0.0015350726.3
Approve166638392023-02-19 16:31:23777 days ago1676824283IN
Gemini: eFIL Token
0 ETH0.0019806333.8987796
View all transactions

View more zero value Internal Transactions in Advanced View mode

Advanced mode:
Loading...
Loading

Contract Source Code Verified (Exact Match)

Contract Name:
ERC20Proxy

Compiler Version
v0.7.4+commit.3f05b770

Optimization Enabled:
Yes with 1000 runs

Other Settings:
default evmVersion, None license
File 1 of 11 : ERC20Proxy.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./EIP2612Interface.sol";
import "./ERC20Interface.sol";
import "./ERC20ImplUpgradeable.sol";

/** @title  Public interface to ERC20 compliant token.
  *
  * @notice  This contract is a permanent entry point to an ERC20 compliant
  * system of contracts.
  *
  * @dev  This contract contains no business logic and instead
  * delegates to an instance of ERC20Impl. This contract also has no storage
  * that constitutes the operational state of the token. This contract is
  * upgradeable in the sense that the `custodian` can update the
  * `erc20Impl` address, thus redirecting the delegation of business logic.
  * The `custodian` is also authorized to pass custodianship.
  *
  * @author  Gemini Trust Company, LLC
  */
contract ERC20Proxy is ERC20Interface, ERC20ImplUpgradeable, EIP2612Interface {

    // MEMBERS
    /// @notice  Returns the name of the token.
    string public name; // TODO: use `constant` for mainnet

    /// @notice  Returns the symbol of the token.
    string public symbol; // TODO: use `constant` for mainnet

    /// @notice  Returns the number of decimals the token uses.
    uint8 immutable public decimals; // TODO: use `constant` (18) for mainnet

    // CONSTRUCTOR
    constructor(
        string memory _name,
        string memory _symbol,
        uint8 _decimals,
        address _custodian
    )
        ERC20ImplUpgradeable(_custodian)
    {
        name = _name;
        symbol = _symbol;
        decimals = _decimals;
    }

    // PUBLIC FUNCTIONS
    // (ERC20Interface)
    /** @notice  Returns the total token supply.
      *
      * @return  the total token supply.
      */
    function totalSupply() external override view returns (uint256) {
        return erc20Impl.totalSupply();
    }

    /** @notice  Returns the account balance of another account with address
      * `_owner`.
      *
      * @return  balance  the balance of account with address `_owner`.
      */
    function balanceOf(address _owner) external override view returns (uint256 balance) {
        return erc20Impl.balanceOf(_owner);
    }

    /** @dev Internal use only.
      */
    function emitTransfer(address _from, address _to, uint256 _value) external onlyImpl {
        emit Transfer(_from, _to, _value);
    }

    /** @notice  Transfers `_value` amount of tokens to address `_to`.
      *
      * @dev Will fire the `Transfer` event. Will revert if the `_from`
      * account balance does not have enough tokens to spend.
      *
      * @return  success  true if transfer completes.
      */
    function transfer(address _to, uint256 _value) external override returns (bool success) {
        return erc20Impl.transferWithSender(msg.sender, _to, _value);
    }

    /** @notice  Transfers `_value` amount of tokens from address `_from`
      * to address `_to`.
      *
      * @dev  Will fire the `Transfer` event. Will revert unless the `_from`
      * account has deliberately authorized the sender of the message
      * via some mechanism.
      *
      * @return  success  true if transfer completes.
      */
    function transferFrom(address _from, address _to, uint256 _value) external override returns (bool success) {
        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
    }

    /** @dev Internal use only.
      */
    function emitApproval(address _owner, address _spender, uint256 _value) external onlyImpl {
        emit Approval(_owner, _spender, _value);
    }

    /** @notice  Allows `_spender` to withdraw from your account multiple times,
      * up to the `_value` amount. If this function is called again it
      * overwrites the current allowance with _value.
      *
      * @dev  Will fire the `Approval` event.
      *
      * @return  success  true if approval completes.
      */
    function approve(address _spender, uint256 _value) external override returns (bool success) {
        return erc20Impl.approveWithSender(msg.sender, _spender, _value);
    }

    /** @notice Increases the amount `_spender` is allowed to withdraw from
      * your account.
      * This function is implemented to avoid the race condition in standard
      * ERC20 contracts surrounding the `approve` method.
      *
      * @dev  Will fire the `Approval` event. This function should be used instead of
      * `approve`.
      *
      * @return  success  true if approval completes.
      */
    function increaseApproval(address _spender, uint256 _addedValue) external returns (bool success) {
        return erc20Impl.increaseApprovalWithSender(msg.sender, _spender, _addedValue);
    }

    /** @notice  Decreases the amount `_spender` is allowed to withdraw from
      * your account. This function is implemented to avoid the race
      * condition in standard ERC20 contracts surrounding the `approve` method.
      *
      * @dev  Will fire the `Approval` event. This function should be used
      * instead of `approve`.
      *
      * @return  success  true if approval completes.
      */
    function decreaseApproval(address _spender, uint256 _subtractedValue) external returns (bool success) {
        return erc20Impl.decreaseApprovalWithSender(msg.sender, _spender, _subtractedValue);
    }

    /** @notice  Returns how much `_spender` is currently allowed to spend from
      * `_owner`'s balance.
      *
      * @return  remaining  the remaining allowance.
      */
    function allowance(address _owner, address _spender) external override view returns (uint256 remaining) {
        return erc20Impl.allowance(_owner, _spender);
    }

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external override {
      erc20Impl.permit(owner, spender, value, deadline, v, r, s);
    }
    function nonces(address owner) external override view returns (uint256) {
      return erc20Impl.nonces(owner);
    }
    function DOMAIN_SEPARATOR() external override view returns (bytes32) {
      return erc20Impl.DOMAIN_SEPARATOR();
    }

    function executeCallWithData(address contractAddress, bytes calldata callData) external {
        address implAddr = address(erc20Impl);
        require(msg.sender == implAddr, "unauthorized");
        require(contractAddress != implAddr, "disallowed");

        (bool success, bytes memory returnData) = contractAddress.call(callData);
        if (success) {
            emit CallWithDataSuccess(contractAddress, callData, returnData);
        } else {
            emit CallWithDataFailure(contractAddress, callData, returnData);
        }
    }

    event CallWithDataSuccess(address contractAddress, bytes callData, bytes returnData);
    event CallWithDataFailure(address contractAddress, bytes callData, bytes returnData);
}

File 2 of 11 : PrintLimiter.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./ERC20Impl.sol";
import "./LockRequestable.sol";

/** @title  A contact to govern hybrid control over increases to the token supply.
  *
  * @notice  A contract that acts as a custodian of the active token
  * implementation, and an intermediary between it and the ‘true’ custodian.
  * It preserves the functionality of direct custodianship as well as granting
  * limited control of token supply increases to an additional key.
  *
  * @dev  This contract is a layer of indirection between an instance of
  * ERC20Impl and a custodian. The functionality of the custodianship over
  * the token implementation is preserved (printing and custodian changes),
  * but this contract adds the ability for an additional key
  * (the 'limited printer') to increase the token supply up to a ceiling,
  * and this supply ceiling can only be raised by the custodian.
  *
  * @author  Gemini Trust Company, LLC
  */
contract PrintLimiter is LockRequestable {

    // TYPES
    /// @dev The struct type for pending ceiling raises.
    struct PendingCeilingRaise {
        uint256 raiseBy;
    }

    // MEMBERS
    /// @dev  The reference to the active token implementation.
    ERC20Impl immutable public erc20Impl;

    /// @dev  The address of the account or contract that acts as the custodian.
    address immutable public custodian;

    /** @dev  The sole authorized caller of limited printing.
      * This account is also authorized to lower the supply ceiling.
      */
    address immutable public limitedPrinter;

    /** @dev  The maximum that the token supply can be increased to
      * through use of the limited printing feature.
      * The difference between the current total supply and the supply
      * ceiling is what is available to the 'limited printer' account.
      * The value of the ceiling can only be increased by the custodian.
      */
    uint256 public totalSupplyCeiling;

    /// @dev  The map of lock ids to pending ceiling raises.
    mapping (bytes32 => PendingCeilingRaise) public pendingRaiseMap;

    // CONSTRUCTOR
    constructor(
        address _erc20Impl,
        address _custodian,
        address _limitedPrinter,
        uint256 _initialCeiling
    )
    {
        erc20Impl = ERC20Impl(_erc20Impl);
        custodian = _custodian;
        limitedPrinter = _limitedPrinter;
        totalSupplyCeiling = _initialCeiling;
    }

    // MODIFIERS
    modifier onlyCustodian {
        require(msg.sender == custodian, "unauthorized");
        _;
    }
    modifier onlyLimitedPrinter {
        require(msg.sender == limitedPrinter, "unauthorized");
        _;
    }

    /** @notice  Increases the token supply, with the newly created tokens
      * being added to the balance of the specified account.
      *
      * @dev  The function checks that the value to print does not
      * exceed the supply ceiling when added to the current total supply.
      * NOTE: printing to the zero address is disallowed.
      *
      * @param  _receiver  The receiving address of the print.
      * @param  _value  The number of tokens to add to the total supply and the
      * balance of the receiving address.
      */
    function limitedPrint(address _receiver, uint256 _value, bytes32 _merkleRoot) external onlyLimitedPrinter {
        uint256 totalSupply = erc20Impl.totalSupply();
        uint256 newTotalSupply = totalSupply + _value;

        require(newTotalSupply >= totalSupply, "overflow");
        require(newTotalSupply <= totalSupplyCeiling, "ceiling exceeded");
        erc20Impl.executePrint(_receiver, _value, _merkleRoot);
    }

    /** @notice  Requests an increase to the supply ceiling.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _raiseBy  The amount by which to raise the ceiling.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestCeilingRaise(uint256 _raiseBy) external returns (bytes32 lockId) {
        require(_raiseBy != 0, "zero");

        (bytes32 preLockId, uint256 lockRequestIdx) = generatePreLockId();
        lockId = keccak256(
            abi.encodePacked(
                preLockId,
                this.requestCeilingRaise.selector,
                _raiseBy
            )
        );

        pendingRaiseMap[lockId] = PendingCeilingRaise({
            raiseBy: _raiseBy
        });

        emit CeilingRaiseLocked(lockId, _raiseBy, lockRequestIdx);
    }

    /** @notice  Confirms a pending increase in the token supply.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending ceiling increase, the amount requested is added to the
      * current supply ceiling.
      * NOTE: this function will not execute any raise that would overflow the
      * supply ceiling, but it will not revert either.
      *
      * @param  _lockId  The identifier of a pending ceiling raise request.
      */
    function confirmCeilingRaise(bytes32 _lockId) external onlyCustodian {
        PendingCeilingRaise storage pendingRaise = pendingRaiseMap[_lockId];

        // copy locals of references to struct members
        uint256 raiseBy = pendingRaise.raiseBy;
        // accounts for a gibberish _lockId
        require(raiseBy != 0, "no such lockId");

        delete pendingRaiseMap[_lockId];

        uint256 newCeiling = totalSupplyCeiling + raiseBy;
        // overflow check
        if (newCeiling >= totalSupplyCeiling) {
            totalSupplyCeiling = newCeiling;

            emit CeilingRaiseConfirmed(_lockId, raiseBy, newCeiling);
        }
    }

    /** @notice  Lowers the supply ceiling, further constraining the bound of
      * what can be printed by the limited printer.
      *
      * @dev  The limited printer is the sole authorized caller of this function,
      * so it is the only account that can elect to lower its limit to increase
      * the token supply.
      *
      * @param  _lowerBy  The amount by which to lower the supply ceiling.
      */
    function lowerCeiling(uint256 _lowerBy) external onlyLimitedPrinter {
        uint256 newCeiling = totalSupplyCeiling - _lowerBy;
        // overflow check
        require(newCeiling <= totalSupplyCeiling, "overflow");
        totalSupplyCeiling = newCeiling;

        emit CeilingLowered(_lowerBy, newCeiling);
    }

    /** @notice  Pass-through control of print confirmation, allowing this
      * contract's custodian to act as the custodian of the associated
      * active token implementation.
      *
      * @dev  This contract is the direct custodian of the active token
      * implementation, but this function allows this contract's custodian
      * to act as though it were the direct custodian of the active
      * token implementation. Therefore the custodian retains control of
      * unlimited printing.
      *
      * @param  _lockId  The identifier of a pending print request in
      * the associated active token implementation.
      */
    function confirmPrintProxy(bytes32 _lockId) external onlyCustodian {
        erc20Impl.confirmPrint(_lockId);
    }

    /** @notice  Pass-through control of custodian change confirmation,
      * allowing this contract's custodian to act as the custodian of
      * the associated active token implementation.
      *
      * @dev  This contract is the direct custodian of the active token
      * implementation, but this function allows this contract's custodian
      * to act as though it were the direct custodian of the active
      * token implementation. Therefore the custodian retains control of
      * custodian changes.
      *
      * @param  _lockId  The identifier of a pending custodian change request
      * in the associated active token implementation.
      */
    function confirmCustodianChangeProxy(bytes32 _lockId) external onlyCustodian {
        erc20Impl.confirmCustodianChange(_lockId);
    }

    // EVENTS
    /// @dev  Emitted by successful `requestCeilingRaise` calls.
    event CeilingRaiseLocked(bytes32 _lockId, uint256 _raiseBy, uint256 _lockRequestIdx);
    /// @dev  Emitted by successful `confirmCeilingRaise` calls.
    event CeilingRaiseConfirmed(bytes32 _lockId, uint256 _raiseBy, uint256 _newCeiling);

    /// @dev  Emitted by successful `lowerCeiling` calls.
    event CeilingLowered(uint256 _lowerBy, uint256 _newCeiling);
}

File 3 of 11 : ERC20Impl.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./CustodianUpgradeable.sol";
import "./ERC20Proxy.sol";
import "./ERC20Store.sol";

/** @title  ERC20 compliant token intermediary contract holding core logic.
  *
  * @notice  This contract serves as an intermediary between the exposed ERC20
  * interface in ERC20Proxy and the store of balances in ERC20Store. This
  * contract contains core logic that the proxy can delegate to
  * and that the store is called by.
  *
  * @dev  This contract contains the core logic to implement the
  * ERC20 specification as well as several extensions.
  * 1. Changes to the token supply.
  * 2. Batched transfers.
  * 3. Relative changes to spending approvals.
  * 4. Delegated transfer control ('sweeping').
  *
  * @author  Gemini Trust Company, LLC
  */
contract ERC20Impl is CustodianUpgradeable {

    // TYPES
    /// @dev  The struct type for pending increases to the token supply (print).
    struct PendingPrint {
        address receiver;
        uint256 value;
        bytes32 merkleRoot;
    }

    // MEMBERS
    /// @dev  The reference to the proxy.
    ERC20Proxy immutable public erc20Proxy;

    /// @dev  The reference to the store.
    ERC20Store immutable public erc20Store;

    address immutable public implOwner;

    /// @dev  The map of lock ids to pending token increases.
    mapping (bytes32 => PendingPrint) public pendingPrintMap;

    // Cache the domain separator as an immutable value, but also store the chain id that it corresponds to, in order to
    // invalidate the cached domain separator if the chain id changes.
    bytes32 private immutable _CACHED_DOMAIN_SEPARATOR;
    uint256 private immutable _CACHED_CHAIN_ID;

    bytes32 private immutable _HASHED_NAME;
    bytes32 private immutable _HASHED_VERSION;
    bytes32 private immutable _TYPE_HASH;

    bytes32 private immutable _PERMIT_TYPEHASH;


    // CONSTRUCTOR
    constructor(
          address _erc20Proxy,
          address _erc20Store,
          address _custodian,
          address _implOwner
    )
        CustodianUpgradeable(_custodian)
    {
        erc20Proxy = ERC20Proxy(_erc20Proxy);
        erc20Store = ERC20Store(_erc20Store);
        implOwner = _implOwner;

        bytes32 hashedName = keccak256(bytes(ERC20Proxy(_erc20Proxy).name()));
        bytes32 hashedVersion = keccak256(bytes("1"));
        bytes32 typeHash = keccak256("EIP712Domain(string name,string version,uint256 chainId,address verifyingContract)"); 
        _HASHED_NAME = hashedName;
        _HASHED_VERSION = hashedVersion;
        _CACHED_CHAIN_ID = _getChainId();
        _CACHED_DOMAIN_SEPARATOR = _buildDomainSeparator(typeHash, hashedName, hashedVersion, _erc20Proxy);
        _TYPE_HASH = typeHash;

        _PERMIT_TYPEHASH = keccak256("Permit(address owner,address spender,uint256 value,uint256 nonce,uint256 deadline)");
    }

    // MODIFIERS
    modifier onlyProxy {
        require(msg.sender == address(erc20Proxy), "unauthorized");
        _;
    }

    modifier onlyImplOwner {
        require(msg.sender == implOwner, "unauthorized");
        _;
    }

    function _approve(
        address _owner,
        address _spender,
        uint256 _amount
    )
        private
    {
        require(_spender != address(0), "zero address"); // disallow unspendable approvals
        erc20Store.setAllowance(_owner, _spender, _amount);
        erc20Proxy.emitApproval(_owner, _spender, _amount);
    }

    /** @notice  Core logic of the ERC20 `approve` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has an `approve` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval in proxy.
      */
    function approveWithSender(
        address _sender,
        address _spender,
        uint256 _value
    )
        external
        onlyProxy
        returns (bool success)
    {
        _approve(_sender, _spender, _value);
        return true;
    }

    /** @notice  Core logic of the `increaseApproval` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has an `increaseApproval` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval.
      */
    function increaseApprovalWithSender(
        address _sender,
        address _spender,
        uint256 _addedValue
    )
        external
        onlyProxy
        returns (bool success)
    {
        require(_spender != address(0), "zero address"); // disallow unspendable approvals
        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
        uint256 newAllowance = currentAllowance + _addedValue;

        require(newAllowance >= currentAllowance, "overflow");

        erc20Store.setAllowance(_sender, _spender, newAllowance);
        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
        return true;
    }

    /** @notice  Core logic of the `decreaseApproval` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `decreaseApproval` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: approvals for the zero address (unspendable) are disallowed.
      *
      * @param  _sender  The address initiating the approval.
      */
    function decreaseApprovalWithSender(
        address _sender,
        address _spender,
        uint256 _subtractedValue
    )
        external
        onlyProxy
        returns (bool success)
    {
        require(_spender != address(0), "zero address"); // disallow unspendable approvals
        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
        uint256 newAllowance = currentAllowance - _subtractedValue;

        require(newAllowance <= currentAllowance, "overflow");

        erc20Store.setAllowance(_sender, _spender, newAllowance);
        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
        return true;
    }

    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
        require(owner != address(0x0), "zero address");
        require(block.timestamp <= deadline, "expired");

        bytes32 structHash = keccak256(
            abi.encode(
                _PERMIT_TYPEHASH,
                owner,
                spender,
                value,
                erc20Store.getNonceAndIncrement(owner),
                deadline
            )
        );

        bytes32 hash = keccak256(
            abi.encodePacked(
                "\x19\x01",
                _domainSeparatorV4(),
                structHash
            )
        );

        address signer = ecrecover(hash, v, r, s);
        require(signer == owner, "invalid signature");

        _approve(owner, spender, value);
    }
    function nonces(address owner) external view returns (uint256) {
      return erc20Store.nonces(owner);
    }
    function DOMAIN_SEPARATOR() external view returns (bytes32) {
      return _domainSeparatorV4();
    }

    /** @notice  Requests an increase in the token supply, with the newly created
      * tokens to be added to the balance of the specified account.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      * NOTE: printing to the zero address is disallowed.
      *
      * @param  _receiver  The receiving address of the print, if confirmed.
      * @param  _value  The number of tokens to add to the total supply and the
      * balance of the receiving address, if confirmed.
      *
      * @return  lockId  A unique identifier for this request.
      */
    function requestPrint(address _receiver, uint256 _value, bytes32 _merkleRoot) external returns (bytes32 lockId) {
        require(_receiver != address(0), "zero address");

        (bytes32 preLockId, uint256 lockRequestIdx) = generatePreLockId();
        lockId = keccak256(
            abi.encodePacked(
                preLockId,
                this.requestPrint.selector,
                _receiver,
                _value,
                _merkleRoot
            )
        );

        pendingPrintMap[lockId] = PendingPrint({
            receiver: _receiver,
            value: _value,
            merkleRoot: _merkleRoot
        });

        emit PrintingLocked(lockId, _receiver, _value, lockRequestIdx);
    }

    function _executePrint(address _receiver, uint256 _value, bytes32 _merkleRoot) private {
        uint256 supply = erc20Store.totalSupply();
        uint256 newSupply = supply + _value;
        if (newSupply >= supply) {
          erc20Store.setTotalSupplyAndAddBalance(newSupply, _receiver, _value);

          erc20Proxy.emitTransfer(address(0), _receiver, _value);
          emit AuditPrint(_merkleRoot);
        }
    }

    function executePrint(address _receiver, uint256 _value, bytes32 _merkleRoot) external onlyCustodian {
        _executePrint(_receiver, _value, _merkleRoot);
    }

    /** @notice  Confirms a pending increase in the token supply.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending increase, the amount requested to be printed in the print request
      * is printed to the receiving address specified in that same request.
      * NOTE: this function will not execute any print that would overflow the
      * total supply, but it will not revert either.
      *
      * @param  _lockId  The identifier of a pending print request.
      */
    function confirmPrint(bytes32 _lockId) external onlyCustodian {
        PendingPrint storage print = pendingPrintMap[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        address receiver = print.receiver;
        require (receiver != address(0), "no such lockId");
        uint256 value = print.value;
        bytes32 merkleRoot = print.merkleRoot;

        delete pendingPrintMap[_lockId];

        emit PrintingConfirmed(_lockId, receiver, value);
        _executePrint(receiver, value, merkleRoot);
    }

    /** @notice  Burns the specified value from the sender's balance.
      *
      * @dev  Sender's balanced is subtracted by the amount they wish to burn.
      *
      * @param  _value  The amount to burn.
      *
      * @return  success  true if the burn succeeded.
      */
    function burn(uint256 _value, bytes32 _merkleRoot) external returns (bool success) {
        uint256 balanceOfSender = erc20Store.balances(msg.sender);
        require(_value <= balanceOfSender, "insufficient balance");

        erc20Store.setBalanceAndDecreaseTotalSupply(
            msg.sender,
            balanceOfSender - _value,
            _value
        );

        erc20Proxy.emitTransfer(msg.sender, address(0), _value);
        emit AuditBurn(_merkleRoot);

        return true;
    }

    /** @notice  A function for a sender to issue multiple transfers to multiple
      * different addresses at once. This function is implemented for gas
      * considerations when someone wishes to transfer, as one transaction is
      * cheaper than issuing several distinct individual `transfer` transactions.
      *
      * @dev  By specifying a set of destination addresses and values, the
      * sender can issue one transaction to transfer multiple amounts to
      * distinct addresses, rather than issuing each as a separate
      * transaction. The `_tos` and `_values` arrays must be equal length, and
      * an index in one array corresponds to the same index in the other array
      * (e.g. `_tos[0]` will receive `_values[0]`, `_tos[1]` will receive
      * `_values[1]`, and so on.)
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _tos  The destination addresses to receive the transfers.
      * @param  _values  The values for each destination address.
      * @return  success  If transfers succeeded.
      */
    function batchTransfer(address[] calldata _tos, uint256[] calldata _values) external returns (bool success) {
        require(_tos.length == _values.length, "inconsistent length");

        uint256 numTransfers = _tos.length;
        uint256 senderBalance = erc20Store.balances(msg.sender);

        for (uint256 i = 0; i < numTransfers; i++) {
          address to = _tos[i];
          require(to != address(0), "zero address");
          uint256 v = _values[i];
          require(senderBalance >= v, "insufficient balance");

          if (msg.sender != to) {
            senderBalance -= v;
            erc20Store.addBalance(to, v);
          }
          erc20Proxy.emitTransfer(msg.sender, to, v);
        }

        erc20Store.setBalance(msg.sender, senderBalance);

        return true;
    }

    /** @notice  Core logic of the ERC20 `transferFrom` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `transferFrom` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _sender  The address initiating the transfer in proxy.
      */
    function transferFromWithSender(
        address _sender,
        address _from,
        address _to,
        uint256 _value
    )
        external
        onlyProxy
        returns (bool success)
    {
        require(_to != address(0), "zero address"); // ensure burn is the cannonical transfer to 0x0

        (uint256 balanceOfFrom, uint256 senderAllowance) = erc20Store.balanceAndAllowed(_from, _sender);
        require(_value <= balanceOfFrom, "insufficient balance");
        require(_value <= senderAllowance, "insufficient allowance");

        erc20Store.setBalanceAndAllowanceAndAddBalance(
            _from, balanceOfFrom - _value,
            _sender, senderAllowance - _value,
            _to, _value
        );

        erc20Proxy.emitTransfer(_from, _to, _value);

        return true;
    }

    /** @notice  Core logic of the ERC20 `transfer` function.
      *
      * @dev  This function can only be called by the referenced proxy,
      * which has a `transfer` function.
      * Every argument passed to that function as well as the original
      * `msg.sender` gets passed to this function.
      * NOTE: transfers to the zero address are disallowed.
      *
      * @param  _sender  The address initiating the transfer in proxy.
      */
    function transferWithSender(
        address _sender,
        address _to,
        uint256 _value
    )
        external
        onlyProxy
        returns (bool success)
    {
        require(_to != address(0), "zero address"); // ensure burn is the cannonical transfer to 0x0

        uint256 balanceOfSender = erc20Store.balances(_sender);
        require(_value <= balanceOfSender, "insufficient balance");

        erc20Store.setBalanceAndAddBalance(
            _sender, balanceOfSender - _value,
            _to, _value
        );

        erc20Proxy.emitTransfer(_sender, _to, _value);

        return true;
    }

    // METHODS (ERC20 sub interface impl.)
    /// @notice  Core logic of the ERC20 `totalSupply` function.
    function totalSupply() external view returns (uint256) {
        return erc20Store.totalSupply();
    }

    /// @notice  Core logic of the ERC20 `balanceOf` function.
    function balanceOf(address _owner) external view returns (uint256 balance) {
        return erc20Store.balances(_owner);
    }

    /// @notice  Core logic of the ERC20 `allowance` function.
    function allowance(address _owner, address _spender) external view returns (uint256 remaining) {
        return erc20Store.allowed(_owner, _spender);
    }

    function executeCallInProxy(
        address contractAddress,
        bytes calldata callData
    ) external onlyImplOwner {
        erc20Proxy.executeCallWithData(contractAddress, callData);
    }

    /**
     * @dev Returns the domain separator for the current chain.
     */
    function _domainSeparatorV4() private view returns (bytes32) {
        if (_getChainId() == _CACHED_CHAIN_ID) {
            return _CACHED_DOMAIN_SEPARATOR;
        } else {
            return _buildDomainSeparator(_TYPE_HASH, _HASHED_NAME, _HASHED_VERSION, address(erc20Proxy));
        }
    }

    function _buildDomainSeparator(bytes32 typeHash, bytes32 name, bytes32 version, address verifyingContract) private view returns (bytes32) {
        return keccak256(
            abi.encode(
                typeHash,
                name,
                version,
                _getChainId(),
                verifyingContract
            )
        );
    }

    function _getChainId() private view returns (uint256 chainId) {
        // SEE:
        //   - https://github.com/ethereum/solidity/issues/8854#issuecomment-629436203
        //   - https://github.com/ethereum/solidity/issues/10090
        // solhint-disable-next-line no-inline-assembly
        assembly {
            chainId := chainid()
        }
    }

    // EVENTS
    /// @dev  Emitted by successful `requestPrint` calls.
    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value, uint256 _lockRequestIdx);
    /// @dev Emitted by successful `confirmPrint` calls.
    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);

    event AuditBurn(bytes32 merkleRoot);
    event AuditPrint(bytes32 merkleRoot);
}

File 4 of 11 : CustodianUpgradeable.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./LockRequestable.sol";

/** @title  A contract to inherit upgradeable custodianship.
  *
  * @notice  A contract that provides re-usable code for upgradeable
  * custodianship. That custodian may be an account or another contract.
  *
  * @dev  This contract is intended to be inherited by any contract
  * requiring a custodian to control some aspect of its functionality.
  * This contract provides the mechanism for that custodianship to be
  * passed from one custodian to the next.
  *
  * @author  Gemini Trust Company, LLC
  */
abstract contract CustodianUpgradeable is LockRequestable {

    // TYPES
    /// @dev  The struct type for pending custodian changes.
    struct CustodianChangeRequest {
        address proposedNew;
    }

    // MEMBERS
    /// @dev  The address of the account or contract that acts as the custodian.
    address public custodian;

    /// @dev  The map of lock ids to pending custodian changes.
    mapping (bytes32 => CustodianChangeRequest) public custodianChangeReqs;

    // CONSTRUCTOR
    constructor(
        address _custodian
    )
      LockRequestable()
    {
        custodian = _custodian;
    }

    // MODIFIERS
    modifier onlyCustodian {
        require(msg.sender == custodian, "unauthorized");
        _;
    }

    // PUBLIC FUNCTIONS
    // (UPGRADE)

    /** @notice  Requests a change of the custodian associated with this contract.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _proposedCustodian  The address of the new custodian.
      * @return  lockId  A unique identifier for this request.
      */
    function requestCustodianChange(address _proposedCustodian) external returns (bytes32 lockId) {
        require(_proposedCustodian != address(0), "zero address");

        (bytes32 preLockId, uint256 lockRequestIdx) = generatePreLockId();
        lockId = keccak256(
            abi.encodePacked(
                preLockId,
                this.requestCustodianChange.selector,
                _proposedCustodian
            )
        );

        custodianChangeReqs[lockId] = CustodianChangeRequest({
            proposedNew: _proposedCustodian
        });

        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian, lockRequestIdx);
    }

    /** @notice  Confirms a pending change of the custodian associated with this contract.
      *
      * @dev  When called by the current custodian with a lock id associated with a
      * pending custodian change, the `address custodian` member will be updated with the
      * requested address.
      *
      * @param  _lockId  The identifier of a pending change request.
      */
    function confirmCustodianChange(bytes32 _lockId) external onlyCustodian {
        custodian = getCustodianChangeReq(_lockId);

        delete custodianChangeReqs[_lockId];

        emit CustodianChangeConfirmed(_lockId, custodian);
    }

    // PRIVATE FUNCTIONS
    function getCustodianChangeReq(bytes32 _lockId) private view returns (address _proposedNew) {
        CustodianChangeRequest storage changeRequest = custodianChangeReqs[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        require(changeRequest.proposedNew != address(0), "no such lockId");

        return changeRequest.proposedNew;
    }

    /// @dev  Emitted by successful `requestCustodianChange` calls.
    event CustodianChangeRequested(
        bytes32 _lockId,
        address _msgSender,
        address _proposedCustodian,
        uint256 _lockRequestIdx
    );

    /// @dev Emitted by successful `confirmCustodianChange` calls.
    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
}

File 5 of 11 : LockRequestable.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

/** @title  A contract for generating unique identifiers
  *
  * @notice  A contract that provides a identifier generation scheme,
  * guaranteeing uniqueness across all contracts that inherit from it,
  * as well as unpredictability of future identifiers.
  *
  * @dev  This contract is intended to be inherited by any contract that
  * implements the callback software pattern for cooperative custodianship.
  *
  * @author  Gemini Trust Company, LLC
  */
abstract contract LockRequestable {

    // MEMBERS
    /// @notice  the count of all invocations of `generatePreLockId`.
    uint256 public lockRequestCount;

    // CONSTRUCTOR
    constructor() {
        lockRequestCount = 0;
    }

    // FUNCTIONS
    /** @notice  Returns a fresh unique identifier.
      *
      * @dev the generation scheme uses three components.
      * First, the blockhash of the previous block.
      * Second, the deployed address.
      * Third, the next value of the counter.
      * This ensure that identifiers are unique across all contracts
      * following this scheme, and that future identifiers are
      * unpredictable.
      *
      * @return preLockId a 32-byte unique identifier.
      * @return lockRequestIdx index of lock request

      */
    function generatePreLockId() internal returns (bytes32 preLockId, uint256 lockRequestIdx) {
        lockRequestIdx = ++lockRequestCount;
        preLockId = keccak256(
          abi.encodePacked(
            blockhash(block.number - 1),
            address(this),
            lockRequestIdx
          )
        );
    }
}

File 6 of 11 : EIP2612Interface.sol
// SPDX-License-Identifier: MIT
// Adapted from
// https://github.com/OpenZeppelin/openzeppelin-contracts/blob/ceb7324657ed4e73df6cb6f853c60c8d3fb3a0e9/contracts/drafts/IERC20Permit.sol

pragma solidity >=0.6.0 <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 EIP2612Interface {
    /**
     * @dev Sets `value` as the allowance of `spender` over `owner`'s tokens,
     * given `owner`'s signed approval.
     *
     * IMPORTANT: The same issues {IERC20-approve} has related to transaction
     * ordering also apply here.
     *
     * Emits an {Approval} event.
     *
     * Requirements:
     *
     * - `spender` cannot be the zero address.
     * - `deadline` must be a timestamp in the future.
     * - `v`, `r` and `s` must be a valid `secp256k1` signature from `owner`
     * over the EIP712-formatted function arguments.
     * - the signature must use ``owner``'s current nonce (see {nonces}).
     *
     * For more information on the signature format, see the
     * https://eips.ethereum.org/EIPS/eip-2612#specification[relevant EIP
     * section].
     */
    function permit(address owner, address spender, uint256 value, uint256 deadline, uint8 v, bytes32 r, bytes32 s) external;

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

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

File 7 of 11 : ERC20Interface.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

interface ERC20Interface {
  // METHODS

  // NOTE:
  //   public getter functions are not currently recognised as an
  //   implementation of the matching abstract function by the compiler.

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#name
  // function name() public view returns (string);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#symbol
  // function symbol() public view returns (string);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply
  // function decimals() public view returns (uint8);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply
  function totalSupply() external view returns (uint256);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
  function balanceOf(address _owner) external view returns (uint256 balance);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
  function transfer(address _to, uint256 _value) external returns (bool success);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
  function transferFrom(address _from, address _to, uint256 _value) external returns (bool success);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
  function approve(address _spender, uint256 _value) external returns (bool success);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
  function allowance(address _owner, address _spender) external view returns (uint256 remaining);

  // EVENTS
  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1
  event Transfer(address indexed _from, address indexed _to, uint256 _value);

  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approval
  event Approval(address indexed _owner, address indexed _spender, uint256 _value);
}

File 8 of 11 : ERC20ImplUpgradeable.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./CustodianUpgradeable.sol";
import "./ERC20Impl.sol";

/** @title  A contract to inherit upgradeable token implementations.
  *
  * @notice  A contract that provides re-usable code for upgradeable
  * token implementations. It itself inherits from `CustodianUpgradable`
  * as the upgrade process is controlled by the custodian.
  *
  * @dev  This contract is intended to be inherited by any contract
  * requiring a reference to the active token implementation, either
  * to delegate calls to it, or authorize calls from it. This contract
  * provides the mechanism for that implementation to be be replaced,
  * which constitutes an implementation upgrade.
  *
  * @author Gemini Trust Company, LLC
  */
abstract contract ERC20ImplUpgradeable is CustodianUpgradeable {

    // TYPES
    /// @dev  The struct type for pending implementation changes.
    struct ImplChangeRequest {
        address proposedNew;
    }

    // MEMBERS
    // @dev  The reference to the active token implementation.
    ERC20Impl public erc20Impl;

    /// @dev  The map of lock ids to pending implementation changes.
    mapping (bytes32 => ImplChangeRequest) public implChangeReqs;

    // CONSTRUCTOR
    constructor(address _custodian) CustodianUpgradeable(_custodian) {
        erc20Impl = ERC20Impl(0x0);
    }

    // MODIFIERS
    modifier onlyImpl {
        require(msg.sender == address(erc20Impl), "unauthorized");
        _;
    }

    // PUBLIC FUNCTIONS
    // (UPGRADE)
    /** @notice  Requests a change of the active implementation associated
      * with this contract.
      *
      * @dev  Returns a unique lock id associated with the request.
      * Anyone can call this function, but confirming the request is authorized
      * by the custodian.
      *
      * @param  _proposedImpl  The address of the new active implementation.
      * @return  lockId  A unique identifier for this request.
      */
    function requestImplChange(address _proposedImpl) external returns (bytes32 lockId) {
        require(_proposedImpl != address(0), "zero address");

        (bytes32 preLockId, uint256 lockRequestIdx) = generatePreLockId();
        lockId = keccak256(
            abi.encodePacked(
                preLockId,
                this.requestImplChange.selector,
                _proposedImpl
            )
        );

        implChangeReqs[lockId] = ImplChangeRequest({
            proposedNew: _proposedImpl
        });

        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl, lockRequestIdx);
    }

    /** @notice  Confirms a pending change of the active implementation
      * associated with this contract.
      *
      * @dev  When called by the custodian with a lock id associated with a
      * pending change, the `ERC20Impl erc20Impl` member will be updated
      * with the requested address.
      *
      * @param  _lockId  The identifier of a pending change request.
      */
    function confirmImplChange(bytes32 _lockId) external onlyCustodian {
        erc20Impl = getImplChangeReq(_lockId);

        delete implChangeReqs[_lockId];

        emit ImplChangeConfirmed(_lockId, address(erc20Impl));
    }

    // PRIVATE FUNCTIONS
    function getImplChangeReq(bytes32 _lockId) private view returns (ERC20Impl _proposedNew) {
        ImplChangeRequest storage changeRequest = implChangeReqs[_lockId];

        // reject ‘null’ results from the map lookup
        // this can only be the case if an unknown `_lockId` is received
        require(changeRequest.proposedNew != address(0), "no such lockId");

        return ERC20Impl(changeRequest.proposedNew);
    }

    /// @dev  Emitted by successful `requestImplChange` calls.
    event ImplChangeRequested(
        bytes32 _lockId,
        address _msgSender,
        address _proposedImpl,
        uint256 _lockRequestIdx
    );

    /// @dev Emitted by successful `confirmImplChange` calls.
    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
}

File 9 of 11 : ERC20Store.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./ERC20ImplUpgradeable.sol";

/** @title  ERC20 compliant token balance store.
  *
  * @notice  This contract serves as the store of balances, allowances, and
  * supply for the ERC20 compliant token. No business logic exists here.
  *
  * @dev  This contract contains no business logic and instead
  * is the final destination for any change in balances, allowances, or token
  * supply. This contract is upgradeable in the sense that its custodian can
  * update the `erc20Impl` address, thus redirecting the source of logic that
  * determines how the balances will be updated.
  *
  * @author  Gemini Trust Company, LLC
  */
contract ERC20Store is ERC20ImplUpgradeable {

    // MEMBERS
    /// @dev  The total token supply.
    uint256 public totalSupply;

    /// @dev  The mapping of balances.
    mapping (address => uint256) public balances;

    /// @dev  The mapping of allowances.
    mapping (address => mapping (address => uint256)) public allowed;

    mapping (address => uint256) public nonces;

    // CONSTRUCTOR
    constructor(address _custodian) ERC20ImplUpgradeable(_custodian) {
        totalSupply = 0;
    }


    // PUBLIC FUNCTIONS
    // (ERC20 Ledger)

    /** @notice  Sets how much `_owner` allows `_spender` to transfer on behalf
      * of `_owner`.
      *
      * @dev  Intended for use by token implementation functions
      * that update spending allowances. The only authorized caller
      * is the active implementation.
      *
      * @param  _owner  The account that will allow an on-behalf-of spend.
      * @param  _spender  The account that will spend on behalf of the owner.
      * @param  _value  The limit of what can be spent.
      */
    function setAllowance(
        address _owner,
        address _spender,
        uint256 _value
    )
        external
        onlyImpl
    {
        allowed[_owner][_spender] = _value;
    }

    /** @notice  Sets the balance of `_owner` to `_newBalance`.
      *
      * @dev  Intended for use by token implementation functions
      * that update balances. The only authorized caller
      * is the active implementation.
      *
      * @param  _owner  The account that will hold a new balance.
      * @param  _newBalance  The balance to set.
      */
    function setBalance(
        address _owner,
        uint256 _newBalance
    )
        external
        onlyImpl
    {
        balances[_owner] = _newBalance;
    }

    /** @notice Adds `_balanceIncrease` to `_owner`'s balance.
      *
      * @dev  Intended for use by token implementation functions
      * that update balances. The only authorized caller
      * is the active implementation.
      * WARNING: the caller is responsible for preventing overflow.
      *
      * @param  _owner  The account that will hold a new balance.
      * @param  _balanceIncrease  The balance to add.
      */
    function addBalance(
        address _owner,
        uint256 _balanceIncrease
    )
        external
        onlyImpl
    {
        balances[_owner] = balances[_owner] + _balanceIncrease;
    }

    function setTotalSupplyAndAddBalance(
        uint256 _newTotalSupply,
        address _owner,
        uint256 _balanceIncrease
    )
        external
        onlyImpl
    {
        totalSupply = _newTotalSupply;
        balances[_owner] = balances[_owner] + _balanceIncrease;
    }

    function setBalanceAndDecreaseTotalSupply(
        address _owner,
        uint256 _newBalance,
        uint256 _supplyDecrease
    )
        external
        onlyImpl
    {
        balances[_owner] = _newBalance;
        totalSupply = totalSupply - _supplyDecrease;
    }

    function setBalanceAndAddBalance(
        address _ownerToSet,
        uint256 _newBalance,
        address _ownerToAdd,
        uint256 _balanceIncrease
    )
        external
        onlyImpl
    {
        balances[_ownerToSet] = _newBalance;
        balances[_ownerToAdd] = balances[_ownerToAdd] + _balanceIncrease;
    }

    function setBalanceAndAllowanceAndAddBalance(
        address _ownerToSet,
        uint256 _newBalance,
        address _spenderToSet,
        uint256 _newAllowance,
        address _ownerToAdd,
        uint256 _balanceIncrease
    )
        external
        onlyImpl
    {
        balances[_ownerToSet] = _newBalance;
        allowed[_ownerToSet][_spenderToSet] = _newAllowance;
        balances[_ownerToAdd] = balances[_ownerToAdd] + _balanceIncrease;
    }

    function balanceAndAllowed(
        address _owner,
        address _spender
    )
        external
        view
        returns (uint256 ownerBalance, uint256 spenderAllowance)
    {
        ownerBalance = balances[_owner];
        spenderAllowance = allowed[_owner][_spender];
    }

    function getNonceAndIncrement(
        address _owner
    )
        external
        onlyImpl
        returns (uint256 current)
    {
        current = nonces[_owner];
        nonces[_owner] = current + 1;
    }
}

File 10 of 11 : Initializer.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./ERC20Proxy.sol";
import "./ERC20Impl.sol";
import "./ERC20Store.sol";

contract Initializer {

  function initialize(
      ERC20Store _store,
      ERC20Proxy _proxy,
      ERC20Impl _impl,
      address _implChangeCustodian,
      address _printCustodian) external {

    // set impl as active implementation for store and proxy
    _store.confirmImplChange(_store.requestImplChange(address(_impl)));
    _proxy.confirmImplChange(_proxy.requestImplChange(address(_impl)));

    // pass custodianship of store and proxy to impl change custodian
    _store.confirmCustodianChange(_store.requestCustodianChange(_implChangeCustodian));
    _proxy.confirmCustodianChange(_proxy.requestCustodianChange(_implChangeCustodian));

    // pass custodianship of impl to print custodian
    _impl.confirmCustodianChange(_impl.requestCustodianChange(_printCustodian));
  }

}

File 11 of 11 : ERC20ImplPaused.sol
// SPDX-License-Identifier: UNLICENSED
// Copyright (c) 2020 Gemini Trust Company LLC. All Rights Reserved
pragma solidity ^0.7.0;

import "./ERC20Store.sol";

/** @title  ERC20 compliant token intermediary contract holding core logic.
  *
  * @notice  This contract serves as an intermediary between the exposed ERC20
  * interface in ERC20Proxy and the store of balances in ERC20Store. This
  * contract contains core logic that the proxy can delegate to
  * and that the store is called by.
  *
  * @dev  This version of ERC20Impl is intended to revert all ERC20 functions
  * that are state mutating; only view functions remain operational. Upgrading
  * to this contract places the system into a read-only paused state.
  *
  * @author  Gemini Trust Company, LLC
  */
contract ERC20ImplPaused {

    // MEMBERS

    /// @dev  The reference to the store.
    ERC20Store immutable public erc20Store;

    // CONSTRUCTOR
    constructor(
          address _erc20Store
    )
    {
        erc20Store = ERC20Store(_erc20Store);
    }

    // METHODS (ERC20 sub interface impl.)
    /// @notice  Core logic of the ERC20 `totalSupply` function.
    function totalSupply() external view returns (uint256) {
        return erc20Store.totalSupply();
    }

    /// @notice  Core logic of the ERC20 `balanceOf` function.
    function balanceOf(address _owner) external view returns (uint256 balance) {
        return erc20Store.balances(_owner);
    }

    /// @notice  Core logic of the ERC20 `allowance` function.
    function allowance(address _owner, address _spender) external view returns (uint256 remaining) {
        return erc20Store.allowed(_owner, _spender);
    }
}

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

Contract Security Audit

Contract ABI

API
[{"inputs":[{"internalType":"string","name":"_name","type":"string"},{"internalType":"string","name":"_symbol","type":"string"},{"internalType":"uint8","name":"_decimals","type":"uint8"},{"internalType":"address","name":"_custodian","type":"address"}],"stateMutability":"nonpayable","type":"constructor"},{"anonymous":false,"inputs":[{"indexed":true,"internalType":"address","name":"_owner","type":"address"},{"indexed":true,"internalType":"address","name":"_spender","type":"address"},{"indexed":false,"internalType":"uint256","name":"_value","type":"uint256"}],"name":"Approval","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"CallWithDataFailure","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"address","name":"contractAddress","type":"address"},{"indexed":false,"internalType":"bytes","name":"callData","type":"bytes"},{"indexed":false,"internalType":"bytes","name":"returnData","type":"bytes"}],"name":"CallWithDataSuccess","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_lockId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_newCustodian","type":"address"}],"name":"CustodianChangeConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_lockId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_msgSender","type":"address"},{"indexed":false,"internalType":"address","name":"_proposedCustodian","type":"address"},{"indexed":false,"internalType":"uint256","name":"_lockRequestIdx","type":"uint256"}],"name":"CustodianChangeRequested","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_lockId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_newImpl","type":"address"}],"name":"ImplChangeConfirmed","type":"event"},{"anonymous":false,"inputs":[{"indexed":false,"internalType":"bytes32","name":"_lockId","type":"bytes32"},{"indexed":false,"internalType":"address","name":"_msgSender","type":"address"},{"indexed":false,"internalType":"address","name":"_proposedImpl","type":"address"},{"indexed":false,"internalType":"uint256","name":"_lockRequestIdx","type":"uint256"}],"name":"ImplChangeRequested","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":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"}],"name":"allowance","outputs":[{"internalType":"uint256","name":"remaining","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"approve","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"}],"name":"balanceOf","outputs":[{"internalType":"uint256","name":"balance","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_lockId","type":"bytes32"}],"name":"confirmCustodianChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"_lockId","type":"bytes32"}],"name":"confirmImplChange","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"custodian","outputs":[{"internalType":"address","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"custodianChangeReqs","outputs":[{"internalType":"address","name":"proposedNew","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"decimals","outputs":[{"internalType":"uint8","name":"","type":"uint8"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_subtractedValue","type":"uint256"}],"name":"decreaseApproval","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_owner","type":"address"},{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"emitApproval","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"emitTransfer","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"erc20Impl","outputs":[{"internalType":"contract ERC20Impl","name":"","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"contractAddress","type":"address"},{"internalType":"bytes","name":"callData","type":"bytes"}],"name":"executeCallWithData","outputs":[],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"bytes32","name":"","type":"bytes32"}],"name":"implChangeReqs","outputs":[{"internalType":"address","name":"proposedNew","type":"address"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"_spender","type":"address"},{"internalType":"uint256","name":"_addedValue","type":"uint256"}],"name":"increaseApproval","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[],"name":"lockRequestCount","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"stateMutability":"view","type":"function"},{"inputs":[],"name":"name","outputs":[{"internalType":"string","name":"","type":"string"}],"stateMutability":"view","type":"function"},{"inputs":[{"internalType":"address","name":"owner","type":"address"}],"name":"nonces","outputs":[{"internalType":"uint256","name":"","type":"uint256"}],"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":"_proposedCustodian","type":"address"}],"name":"requestCustodianChange","outputs":[{"internalType":"bytes32","name":"lockId","type":"bytes32"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_proposedImpl","type":"address"}],"name":"requestImplChange","outputs":[{"internalType":"bytes32","name":"lockId","type":"bytes32"}],"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":"_value","type":"uint256"}],"name":"transfer","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"},{"inputs":[{"internalType":"address","name":"_from","type":"address"},{"internalType":"address","name":"_to","type":"address"},{"internalType":"uint256","name":"_value","type":"uint256"}],"name":"transferFrom","outputs":[{"internalType":"bool","name":"success","type":"bool"}],"stateMutability":"nonpayable","type":"function"}]

60a06040523480156200001157600080fd5b5060405162001a6038038062001a60833981810160405260808110156200003757600080fd5b81019080805160405193929190846401000000008211156200005857600080fd5b9083019060208201858111156200006e57600080fd5b82516401000000008111828201881017156200008957600080fd5b82525081516020918201929091019080838360005b83811015620000b85781810151838201526020016200009e565b50505050905090810190601f168015620000e65780820380516001836020036101000a031916815260200191505b50604052602001805160405193929190846401000000008211156200010a57600080fd5b9083019060208201858111156200012057600080fd5b82516401000000008111828201881017156200013b57600080fd5b82525081516020918201929091019080838360005b838110156200016a57818101518382015260200162000150565b50505050905090810190601f168015620001985780820380516001836020036101000a031916815260200191505b506040908152602082810151929091015160008055600180546001600160a01b0383166001600160a01b03199182161790915560038054909116905586519294509250620001ec9160059187019062000235565b5082516200020290600690602086019062000235565b505060f81b7fff000000000000000000000000000000000000000000000000000000000000001660805250620002e19050565b828054600181600116156101000203166002900490600052602060002090601f0160209004810192826200026d5760008555620002b8565b82601f106200028857805160ff1916838001178555620002b8565b82800160010185558215620002b8579182015b82811115620002b85782518255916020019190600101906200029b565b50620002c6929150620002ca565b5090565b5b80821115620002c65760008155600101620002cb565b60805160f81c611761620002ff60003980610a9152506117616000f3fe608060405234801561001057600080fd5b50600436106101ae5760003560e01c806366188463116100ee578063b508069b11610097578063d505accf11610071578063d505accf146104f4578063d73dd62314610545578063dd62ed3e14610571578063dfd1fb7a1461059f576101ae565b8063b508069b146104b2578063cb81fecf146104cf578063cf6e4488146104d7576101ae565b80638181b029116100c85780638181b0291461046157806395d89b411461047e578063a9059cbb14610486576101ae565b806366188463146103e957806370a08231146104155780637ecebe001461043b576101ae565b8063313ce5671161015b5780633a8343ee116101355780633a8343ee146103685780633c389cc41461038557806348f9e2461461038d5780635687f2b8146103b3576101ae565b8063313ce5671461031e5780633644e5151461033c578063375b74c314610344576101ae565b806318160ddd1161018c57806318160ddd146102a857806323b872dd146102b057806323de6651146102e6576101ae565b806306fdde03146101b3578063095ea7b31461023057806315b2108214610270575b600080fd5b6101bb61061f565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101f55781810151838201526020016101dd565b50505050905090810190601f1680156102225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61025c6004803603604081101561024657600080fd5b506001600160a01b0381351690602001356106ad565b604080519115158252519081900360200190f35b6102966004803603602081101561028657600080fd5b50356001600160a01b0316610758565b60408051918252519081900360200190f35b6102966108ae565b61025c600480360360608110156102c657600080fd5b506001600160a01b0381358116916020810135909116906040013561093d565b61031c600480360360608110156102fc57600080fd5b506001600160a01b038135811691602081013590911690604001356109f1565b005b610326610a8f565b6040805160ff9092168252519081900360200190f35b610296610ab3565b61034c610b11565b604080516001600160a01b039092168252519081900360200190f35b61031c6004803603602081101561037e57600080fd5b5035610b20565b61034c610bf8565b610296600480360360208110156103a357600080fd5b50356001600160a01b0316610c07565b61031c600480360360608110156103c957600080fd5b506001600160a01b03813581169160208101359091169060400135610d5d565b61025c600480360360408110156103ff57600080fd5b506001600160a01b038135169060200135610dfb565b6102966004803603602081101561042b57600080fd5b50356001600160a01b0316610e73565b6102966004803603602081101561045157600080fd5b50356001600160a01b0316610f0f565b61031c6004803603602081101561047757600080fd5b5035610f79565b6101bb611051565b61025c6004803603604081101561049c57600080fd5b506001600160a01b0381351690602001356110ac565b61034c600480360360208110156104c857600080fd5b5035611124565b61029661113f565b61034c600480360360208110156104ed57600080fd5b5035611145565b61031c600480360360e081101561050a57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611160565b61025c6004803603604081101561055b57600080fd5b506001600160a01b038135169060200135611215565b6102966004803603604081101561058757600080fd5b506001600160a01b038135811691602001351661128d565b61031c600480360360408110156105b557600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156105e057600080fd5b8201836020820111156105f257600080fd5b8035906020019184600183028401116401000000008311171561061457600080fd5b509092509050611313565b6005805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106a55780601f1061067a576101008083540402835291602001916106a5565b820191906000526020600020905b81548152906001019060200180831161068857829003601f168201915b505050505081565b600354604080517f89064fd20000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03858116602483015260448201859052915160009392909216916389064fd29160648082019260209290919082900301818787803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b505050506040513d602081101561074f57600080fd5b50519392505050565b60006001600160a01b0382166107a4576040805162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015290519081900360640190fd5b6000806107af6115ff565b6040805160208082018590527f15b210820000000000000000000000000000000000000000000000000000000082840152606089811b6bffffffffffffffffffffffff191660448401528351808403603801815260588401808652815191840191909120607890940185526001600160a01b03808c168083526000868152600286528790209251835473ffffffffffffffffffffffffffffffffffffffff19169216919091179091558451848152339381019390935282850152810184905291519096509294509092507f8286bbf6adfae598c227689d4e361af126e220106aaa15764538028b07f3a0d4916080918190039190910190a15050919050565b600354604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561090c57600080fd5b505afa158015610920573d6000803e3d6000fd5b505050506040513d602081101561093657600080fd5b5051905090565b600354604080517f5d5e22cd0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691635d5e22cd9160848082019260209290919082900301818787803b1580156109bd57600080fd5b505af11580156109d1573d6000803e3d6000fd5b505050506040513d60208110156109e757600080fd5b5051949350505050565b6003546001600160a01b03163314610a3f576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b7f000000000000000000000000000000000000000000000000000000000000000081565b600354604080517f3644e51500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691633644e515916004808301926020929190829003018186803b15801561090c57600080fd5b6001546001600160a01b031681565b6001546001600160a01b03163314610b6e576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b610b7781611647565b600180546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff1991821617825560008481526002602090815260409182902080549093169092559154825185815293169083015280517f9a99272c0f6b7a30ef9e76e684a7cd408bfd4f11a72f36a8e276253c920e442d9281900390910190a150565b6003546001600160a01b031681565b60006001600160a01b038216610c53576040805162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015290519081900360640190fd5b600080610c5e6115ff565b6040805160208082018590527f48f9e2460000000000000000000000000000000000000000000000000000000082840152606089811b6bffffffffffffffffffffffff191660448401528351808403603801815260588401808652815191840191909120607890940185526001600160a01b03808c168083526000868152600486528790209251835473ffffffffffffffffffffffffffffffffffffffff19169216919091179091558451848152339381019390935282850152810184905291519096509294509092507f5f00cc4c18a066865d0479be1a25e91493bafb7ddb7ae642e5b8718649855f0c916080918190039190910190a15050919050565b6003546001600160a01b03163314610dab576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600354604080517f61e1077d0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03858116602483015260448201859052915160009392909216916361e1077d9160648082019260209290919082900301818787803b15801561072557600080fd5b600354604080517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b158015610edd57600080fd5b505afa158015610ef1573d6000803e3d6000fd5b505050506040513d6020811015610f0757600080fd5b505192915050565b600354604080517f7ecebe000000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291516000939290921691637ecebe0091602480820192602092909190829003018186803b158015610edd57600080fd5b6001546001600160a01b03163314610fc7576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b610fd0816116c1565b600380546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff1991821617825560008481526004602090815260409182902080549093169092559154825185815293169083015280517f9d55b0349a0a4c5b511f72228170bb91d45c9ac78dba8ab5b4175d3ed42f06b39281900390910190a150565b6006805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106a55780601f1061067a576101008083540402835291602001916106a5565b600354604080517fdfe0f0ca0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b038581166024830152604482018590529151600093929092169163dfe0f0ca9160648082019260209290919082900301818787803b15801561072557600080fd5b6004602052600090815260409020546001600160a01b031681565b60005481565b6002602052600090815260409020546001600160a01b031681565b600354604080517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c482018590529151919092169163d505accf9160e480830192600092919082900301818387803b1580156111f457600080fd5b505af1158015611208573d6000803e3d6000fd5b5050505050505050505050565b600354604080517f2e0179b50000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0385811660248301526044820185905291516000939290921691632e0179b59160648082019260209290919082900301818787803b15801561072557600080fd5b600354604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b1580156112ff57600080fd5b505afa158015610739573d6000803e3d6000fd5b6003546001600160a01b0316338114611362576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b806001600160a01b0316846001600160a01b031614156113c9576040805162461bcd60e51b815260206004820152600a60248201527f646973616c6c6f77656400000000000000000000000000000000000000000000604482015290519081900360640190fd5b60006060856001600160a01b03168585604051808383808284376040519201945060009350909150508083038183865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b5091509150811561151a577f18e614c03fae7d4f0ad0790905bc76b8690e946c477b2b8970403bcad27a9b968686868460405180856001600160a01b03168152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b838110156114d75781810151838201526020016114bf565b50505050905090810190601f1680156115045780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a16115f7565b7faba0bbd4bfc61304155c867f51e2bc1c6f844c4d852c9bdb15c2cd9c3c8e62748686868460405180856001600160a01b03168152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b838110156115b85781810151838201526020016115a0565b50505050905090810190601f1680156115e55780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a15b505050505050565b6000805460010190819055604080516000194301406020808301919091523060601b828401526054808301859052835180840390910181526074909201909252805191012091565b600081815260026020526040812080546001600160a01b03166116b1576040805162461bcd60e51b815260206004820152600e60248201527f6e6f2073756368206c6f636b4964000000000000000000000000000000000000604482015290519081900360640190fd5b546001600160a01b031692915050565b600081815260046020526040812080546001600160a01b03166116b1576040805162461bcd60e51b815260206004820152600e60248201527f6e6f2073756368206c6f636b4964000000000000000000000000000000000000604482015290519081900360640190fdfea264697066735822122030b64a0e5ec6b3b880d8cf538043b2ee039773ec7b90b5d3363beb4a2e640f1a64736f6c63430007040033000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000120000000000000000000000001890bd6bb07bee625e3a2cc6ee3d83850da55c090000000000000000000000000000000000000000000000000000000000000019457468657265756d20577261707065642046696c65636f696e0000000000000000000000000000000000000000000000000000000000000000000000000000046546494c00000000000000000000000000000000000000000000000000000000

Deployed Bytecode

0x608060405234801561001057600080fd5b50600436106101ae5760003560e01c806366188463116100ee578063b508069b11610097578063d505accf11610071578063d505accf146104f4578063d73dd62314610545578063dd62ed3e14610571578063dfd1fb7a1461059f576101ae565b8063b508069b146104b2578063cb81fecf146104cf578063cf6e4488146104d7576101ae565b80638181b029116100c85780638181b0291461046157806395d89b411461047e578063a9059cbb14610486576101ae565b806366188463146103e957806370a08231146104155780637ecebe001461043b576101ae565b8063313ce5671161015b5780633a8343ee116101355780633a8343ee146103685780633c389cc41461038557806348f9e2461461038d5780635687f2b8146103b3576101ae565b8063313ce5671461031e5780633644e5151461033c578063375b74c314610344576101ae565b806318160ddd1161018c57806318160ddd146102a857806323b872dd146102b057806323de6651146102e6576101ae565b806306fdde03146101b3578063095ea7b31461023057806315b2108214610270575b600080fd5b6101bb61061f565b6040805160208082528351818301528351919283929083019185019080838360005b838110156101f55781810151838201526020016101dd565b50505050905090810190601f1680156102225780820380516001836020036101000a031916815260200191505b509250505060405180910390f35b61025c6004803603604081101561024657600080fd5b506001600160a01b0381351690602001356106ad565b604080519115158252519081900360200190f35b6102966004803603602081101561028657600080fd5b50356001600160a01b0316610758565b60408051918252519081900360200190f35b6102966108ae565b61025c600480360360608110156102c657600080fd5b506001600160a01b0381358116916020810135909116906040013561093d565b61031c600480360360608110156102fc57600080fd5b506001600160a01b038135811691602081013590911690604001356109f1565b005b610326610a8f565b6040805160ff9092168252519081900360200190f35b610296610ab3565b61034c610b11565b604080516001600160a01b039092168252519081900360200190f35b61031c6004803603602081101561037e57600080fd5b5035610b20565b61034c610bf8565b610296600480360360208110156103a357600080fd5b50356001600160a01b0316610c07565b61031c600480360360608110156103c957600080fd5b506001600160a01b03813581169160208101359091169060400135610d5d565b61025c600480360360408110156103ff57600080fd5b506001600160a01b038135169060200135610dfb565b6102966004803603602081101561042b57600080fd5b50356001600160a01b0316610e73565b6102966004803603602081101561045157600080fd5b50356001600160a01b0316610f0f565b61031c6004803603602081101561047757600080fd5b5035610f79565b6101bb611051565b61025c6004803603604081101561049c57600080fd5b506001600160a01b0381351690602001356110ac565b61034c600480360360208110156104c857600080fd5b5035611124565b61029661113f565b61034c600480360360208110156104ed57600080fd5b5035611145565b61031c600480360360e081101561050a57600080fd5b506001600160a01b03813581169160208101359091169060408101359060608101359060ff6080820135169060a08101359060c00135611160565b61025c6004803603604081101561055b57600080fd5b506001600160a01b038135169060200135611215565b6102966004803603604081101561058757600080fd5b506001600160a01b038135811691602001351661128d565b61031c600480360360408110156105b557600080fd5b6001600160a01b0382351691908101906040810160208201356401000000008111156105e057600080fd5b8201836020820111156105f257600080fd5b8035906020019184600183028401116401000000008311171561061457600080fd5b509092509050611313565b6005805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106a55780601f1061067a576101008083540402835291602001916106a5565b820191906000526020600020905b81548152906001019060200180831161068857829003601f168201915b505050505081565b600354604080517f89064fd20000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03858116602483015260448201859052915160009392909216916389064fd29160648082019260209290919082900301818787803b15801561072557600080fd5b505af1158015610739573d6000803e3d6000fd5b505050506040513d602081101561074f57600080fd5b50519392505050565b60006001600160a01b0382166107a4576040805162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015290519081900360640190fd5b6000806107af6115ff565b6040805160208082018590527f15b210820000000000000000000000000000000000000000000000000000000082840152606089811b6bffffffffffffffffffffffff191660448401528351808403603801815260588401808652815191840191909120607890940185526001600160a01b03808c168083526000868152600286528790209251835473ffffffffffffffffffffffffffffffffffffffff19169216919091179091558451848152339381019390935282850152810184905291519096509294509092507f8286bbf6adfae598c227689d4e361af126e220106aaa15764538028b07f3a0d4916080918190039190910190a15050919050565b600354604080517f18160ddd00000000000000000000000000000000000000000000000000000000815290516000926001600160a01b0316916318160ddd916004808301926020929190829003018186803b15801561090c57600080fd5b505afa158015610920573d6000803e3d6000fd5b505050506040513d602081101561093657600080fd5b5051905090565b600354604080517f5d5e22cd0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03868116602483015285811660448301526064820185905291516000939290921691635d5e22cd9160848082019260209290919082900301818787803b1580156109bd57600080fd5b505af11580156109d1573d6000803e3d6000fd5b505050506040513d60208110156109e757600080fd5b5051949350505050565b6003546001600160a01b03163314610a3f576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167fddf252ad1be2c89b69c2b068fc378daa952ba7f163c4a11628f55a4df523b3ef836040518082815260200191505060405180910390a3505050565b7f000000000000000000000000000000000000000000000000000000000000001281565b600354604080517f3644e51500000000000000000000000000000000000000000000000000000000815290516000926001600160a01b031691633644e515916004808301926020929190829003018186803b15801561090c57600080fd5b6001546001600160a01b031681565b6001546001600160a01b03163314610b6e576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b610b7781611647565b600180546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff1991821617825560008481526002602090815260409182902080549093169092559154825185815293169083015280517f9a99272c0f6b7a30ef9e76e684a7cd408bfd4f11a72f36a8e276253c920e442d9281900390910190a150565b6003546001600160a01b031681565b60006001600160a01b038216610c53576040805162461bcd60e51b815260206004820152600c60248201526b7a65726f206164647265737360a01b604482015290519081900360640190fd5b600080610c5e6115ff565b6040805160208082018590527f48f9e2460000000000000000000000000000000000000000000000000000000082840152606089811b6bffffffffffffffffffffffff191660448401528351808403603801815260588401808652815191840191909120607890940185526001600160a01b03808c168083526000868152600486528790209251835473ffffffffffffffffffffffffffffffffffffffff19169216919091179091558451848152339381019390935282850152810184905291519096509294509092507f5f00cc4c18a066865d0479be1a25e91493bafb7ddb7ae642e5b8718649855f0c916080918190039190910190a15050919050565b6003546001600160a01b03163314610dab576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b816001600160a01b0316836001600160a01b03167f8c5be1e5ebec7d5bd14f71427d1e84f3dd0314c0f7b2291e5b200ac8c7c3b925836040518082815260200191505060405180910390a3505050565b600354604080517f61e1077d0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b03858116602483015260448201859052915160009392909216916361e1077d9160648082019260209290919082900301818787803b15801561072557600080fd5b600354604080517f70a082310000000000000000000000000000000000000000000000000000000081526001600160a01b038481166004830152915160009392909216916370a0823191602480820192602092909190829003018186803b158015610edd57600080fd5b505afa158015610ef1573d6000803e3d6000fd5b505050506040513d6020811015610f0757600080fd5b505192915050565b600354604080517f7ecebe000000000000000000000000000000000000000000000000000000000081526001600160a01b03848116600483015291516000939290921691637ecebe0091602480820192602092909190829003018186803b158015610edd57600080fd5b6001546001600160a01b03163314610fc7576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b610fd0816116c1565b600380546001600160a01b0392831673ffffffffffffffffffffffffffffffffffffffff1991821617825560008481526004602090815260409182902080549093169092559154825185815293169083015280517f9d55b0349a0a4c5b511f72228170bb91d45c9ac78dba8ab5b4175d3ed42f06b39281900390910190a150565b6006805460408051602060026001851615610100026000190190941693909304601f810184900484028201840190925281815292918301828280156106a55780601f1061067a576101008083540402835291602001916106a5565b600354604080517fdfe0f0ca0000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b038581166024830152604482018590529151600093929092169163dfe0f0ca9160648082019260209290919082900301818787803b15801561072557600080fd5b6004602052600090815260409020546001600160a01b031681565b60005481565b6002602052600090815260409020546001600160a01b031681565b600354604080517fd505accf0000000000000000000000000000000000000000000000000000000081526001600160a01b038a811660048301528981166024830152604482018990526064820188905260ff8716608483015260a4820186905260c482018590529151919092169163d505accf9160e480830192600092919082900301818387803b1580156111f457600080fd5b505af1158015611208573d6000803e3d6000fd5b5050505050505050505050565b600354604080517f2e0179b50000000000000000000000000000000000000000000000000000000081523360048201526001600160a01b0385811660248301526044820185905291516000939290921691632e0179b59160648082019260209290919082900301818787803b15801561072557600080fd5b600354604080517fdd62ed3e0000000000000000000000000000000000000000000000000000000081526001600160a01b03858116600483015284811660248301529151600093929092169163dd62ed3e91604480820192602092909190829003018186803b1580156112ff57600080fd5b505afa158015610739573d6000803e3d6000fd5b6003546001600160a01b0316338114611362576040805162461bcd60e51b815260206004820152600c60248201526b1d5b985d5d1a1bdc9a5e995960a21b604482015290519081900360640190fd5b806001600160a01b0316846001600160a01b031614156113c9576040805162461bcd60e51b815260206004820152600a60248201527f646973616c6c6f77656400000000000000000000000000000000000000000000604482015290519081900360640190fd5b60006060856001600160a01b03168585604051808383808284376040519201945060009350909150508083038183865af19150503d8060008114611429576040519150601f19603f3d011682016040523d82523d6000602084013e61142e565b606091505b5091509150811561151a577f18e614c03fae7d4f0ad0790905bc76b8690e946c477b2b8970403bcad27a9b968686868460405180856001600160a01b03168152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b838110156114d75781810151838201526020016114bf565b50505050905090810190601f1680156115045780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a16115f7565b7faba0bbd4bfc61304155c867f51e2bc1c6f844c4d852c9bdb15c2cd9c3c8e62748686868460405180856001600160a01b03168152602001806020018060200183810383528686828181526020019250808284376000838201819052601f909101601f191690920185810384528651815286516020918201939188019250908190849084905b838110156115b85781810151838201526020016115a0565b50505050905090810190601f1680156115e55780820380516001836020036101000a031916815260200191505b50965050505050505060405180910390a15b505050505050565b6000805460010190819055604080516000194301406020808301919091523060601b828401526054808301859052835180840390910181526074909201909252805191012091565b600081815260026020526040812080546001600160a01b03166116b1576040805162461bcd60e51b815260206004820152600e60248201527f6e6f2073756368206c6f636b4964000000000000000000000000000000000000604482015290519081900360640190fd5b546001600160a01b031692915050565b600081815260046020526040812080546001600160a01b03166116b1576040805162461bcd60e51b815260206004820152600e60248201527f6e6f2073756368206c6f636b4964000000000000000000000000000000000000604482015290519081900360640190fdfea264697066735822122030b64a0e5ec6b3b880d8cf538043b2ee039773ec7b90b5d3363beb4a2e640f1a64736f6c63430007040033

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

000000000000000000000000000000000000000000000000000000000000008000000000000000000000000000000000000000000000000000000000000000c000000000000000000000000000000000000000000000000000000000000000120000000000000000000000001890bd6bb07bee625e3a2cc6ee3d83850da55c090000000000000000000000000000000000000000000000000000000000000019457468657265756d20577261707065642046696c65636f696e0000000000000000000000000000000000000000000000000000000000000000000000000000046546494c00000000000000000000000000000000000000000000000000000000

-----Decoded View---------------
Arg [0] : _name (string): Ethereum Wrapped Filecoin
Arg [1] : _symbol (string): eFIL
Arg [2] : _decimals (uint8): 18
Arg [3] : _custodian (address): 0x1890bD6bB07BEE625e3A2cC6eE3D83850Da55c09

-----Encoded View---------------
8 Constructor Arguments found :
Arg [0] : 0000000000000000000000000000000000000000000000000000000000000080
Arg [1] : 00000000000000000000000000000000000000000000000000000000000000c0
Arg [2] : 0000000000000000000000000000000000000000000000000000000000000012
Arg [3] : 0000000000000000000000001890bd6bb07bee625e3a2cc6ee3d83850da55c09
Arg [4] : 0000000000000000000000000000000000000000000000000000000000000019
Arg [5] : 457468657265756d20577261707065642046696c65636f696e00000000000000
Arg [6] : 0000000000000000000000000000000000000000000000000000000000000004
Arg [7] : 6546494c00000000000000000000000000000000000000000000000000000000


Deployed Bytecode Sourcemap

863:6008:6:-:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1011:18;;;:::i;:::-;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;3926:173;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3926:173:6;;;;;;;;:::i;:::-;;;;;;;;;;;;;;;;;;1872:659:0;;;;;;;;;;;;;;;;-1:-1:-1;1872:659:0;-1:-1:-1;;;;;1872:659:0;;:::i;:::-;;;;;;;;;;;;;;;;1769:111:6;;;:::i;3201:195::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3201:195:6;;;;;;;;;;;;;;;;;:::i;2252:134::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2252:134:6;;;;;;;;;;;;;;;;;:::i;:::-;;1249:31;;;:::i;:::-;;;;;;;;;;;;;;;;;;;6017:119;;;:::i;983:24:0:-;;;:::i;:::-;;;;-1:-1:-1;;;;;983:24:0;;;;;;;;;;;;;;2923:237;;;;;;;;;;;;;;;;-1:-1:-1;2923:237:0;;:::i;1142:26:4:-;;;:::i;2053:609::-;;;;;;;;;;;;;;;;-1:-1:-1;2053:609:4;-1:-1:-1;;;;;2053:609:4;;:::i;3443:146:6:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;3443:146:6;;;;;;;;;;;;;;;;;:::i;5130:202::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;5130:202:6;;;;;;;;:::i;2070:135::-;;;;;;;;;;;;;;;;-1:-1:-1;2070:135:6;-1:-1:-1;;;;;2070:135:6;;:::i;5895:117::-;;;;;;;;;;;;;;;;-1:-1:-1;5895:117:6;-1:-1:-1;;;;;5895:117:6;;:::i;3058:226:4:-;;;;;;;;;;;;;;;;-1:-1:-1;3058:226:4;;:::i;1122:20:6:-;;;:::i;2676:165::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;2676:165:6;;;;;;;;:::i;1244:60:4:-;;;;;;;;;;;;;;;;-1:-1:-1;1244:60:4;;:::i;716:31:9:-;;;:::i;1078:70:0:-;;;;;;;;;;;;;;;;-1:-1:-1;1078:70:0;;:::i;5687:203:6:-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;5687:203:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::i;4522:192::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;4522:192:6;;;;;;;;:::i;5516:165::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;;5516:165:6;;;;;;;;;;:::i;6142:546::-;;;;;;;;;;;;;;;;-1:-1:-1;;;;;6142:546:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6142:546:6;;-1:-1:-1;6142:546:6;-1:-1:-1;6142:546:6;:::i;1011:18::-;;;;;;;;;;;;;;;-1:-1:-1;;1011:18:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:::o;3926:173::-;4035:9;;:57;;;;;;4063:10;4035:57;;;;-1:-1:-1;;;;;4035:57:6;;;;;;;;;;;;;;;4004:12;;4035:9;;;;;:27;;:57;;;;;;;;;;;;;;;4004:12;4035:9;:57;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;4035:57:6;;3926:173;-1:-1:-1;;;3926:173:6:o;1872:659:0:-;1950:14;-1:-1:-1;;;;;1984:32:0;;1976:57;;;;;-1:-1:-1;;;1976:57:0;;;;;;;;;;;;-1:-1:-1;;;1976:57:0;;;;;;;;;;;;;;;2045:17;2064:22;2090:19;:17;:19::i;:::-;2151:147;;;;;;;;;;2212:36;2151:147;;;;;;;;-1:-1:-1;;2151:147:0;;;;;;;;;;;;;;;;;;;;2128:180;;;;;;;;;2349:79;;;;;;-1:-1:-1;;;;;2151:147:0;;;2349:79;;;-1:-1:-1;2319:27:0;;;:19;:27;;;;;:109;;;;-1:-1:-1;;2319:109:0;;;;;;;;;;2444:80;;;;;2477:10;2444:80;;;;;;;;;;;;;;;;;;2128:180;;-1:-1:-1;2151:147:0;;-1:-1:-1;2444:80:0;;-1:-1:-1;2444:80:0;;;;;;;;;;;;;1872:659;;;;;:::o;1769:111:6:-;1850:9;;:23;;;;;;;;1824:7;;-1:-1:-1;;;;;1850:9:6;;:21;;:23;;;;;;;;;;;;;;:9;:23;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;1850:23:6;;-1:-1:-1;1769:111:6;:::o;3201:195::-;3325:9;;:64;;;;;;3358:10;3325:64;;;;-1:-1:-1;;;;;3325:64:6;;;;;;;;;;;;;;;;;;;;;;3294:12;;3325:9;;;;;:32;;:64;;;;;;;;;;;;;;;3294:12;3325:9;:64;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;3325:64:6;;3201:195;-1:-1:-1;;;;3201:195:6:o;2252:134::-;1519:9:4;;-1:-1:-1;;;;;1519:9:4;1497:10;:32;1489:57;;;;;-1:-1:-1;;;1489:57:4;;;;;;;;;;;;-1:-1:-1;;;1489:57:4;;;;;;;;;;;;;;;2367:3:6::1;-1:-1:-1::0;;;;;2351:28:6::1;2360:5;-1:-1:-1::0;;;;;2351:28:6::1;;2372:6;2351:28;;;;;;;;;;;;;;;;;;2252:134:::0;;;:::o;1249:31::-;;;:::o;6017:119::-;6101:9;;:28;;;;;;;;6077:7;;-1:-1:-1;;;;;6101:9:6;;:26;;:28;;;;;;;;;;;;;;:9;:28;;;;;;;;;;983:24:0;;;-1:-1:-1;;;;;983:24:0;;:::o;2923:237::-;1365:9;;-1:-1:-1;;;;;1365:9:0;1351:10;:23;1343:48;;;;;-1:-1:-1;;;1343:48:0;;;;;;;;;;;;-1:-1:-1;;;1343:48:0;;;;;;;;;;;;;;;3017:30:::1;3039:7;3017:21;:30::i;:::-;3005:9;:42:::0;;-1:-1:-1;;;;;3005:42:0;;::::1;-1:-1:-1::0;;3005:42:0;;::::1;;::::0;;:9:::1;3065:28:::0;;;:19:::1;:28;::::0;;;;;;;;3058:35;;;;::::1;::::0;;;3143:9;;3109:44;;;;;3143:9;::::1;3109:44:::0;;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;2923:237:::0;:::o;1142:26:4:-;;;-1:-1:-1;;;;;1142:26:4;;:::o;2053:609::-;2121:14;-1:-1:-1;;;;;2155:27:4;;2147:52;;;;;-1:-1:-1;;;2147:52:4;;;;;;;;;;;;-1:-1:-1;;;2147:52:4;;;;;;;;;;;;;;;2211:17;2230:22;2256:19;:17;:19::i;:::-;2317:137;;;;;;;;;;2378:31;2317:137;;;;;;;;-1:-1:-1;;2317:137:4;;;;;;;;;;;;;;;;;;;;2294:170;;;;;;;;;2500:69;;;;;;-1:-1:-1;;;;;2317:137:4;;;2500:69;;;-1:-1:-1;2475:22:4;;;2317:137;2475:22;;;;;:94;;;;-1:-1:-1;;2475:94:4;;;;;;;;;;2585:70;;;;;2613:10;2585:70;;;;;;;;;;;;;;;;;;2294:170;;-1:-1:-1;2317:137:4;;-1:-1:-1;2585:70:4;;-1:-1:-1;2585:70:4;;;;;;;;;;;;;2053:609;;;;;:::o;3443:146:6:-;1519:9:4;;-1:-1:-1;;;;;1519:9:4;1497:10;:32;1489:57;;;;;-1:-1:-1;;;1489:57:4;;;;;;;;;;;;-1:-1:-1;;;1489:57:4;;;;;;;;;;;;;;;3565:8:6::1;-1:-1:-1::0;;;;;3548:34:6::1;3557:6;-1:-1:-1::0;;;;;3548:34:6::1;;3575:6;3548:34;;;;;;;;;;;;;;;;;;3443:146:::0;;;:::o;5130:202::-;5249:9;;:76;;;;;;5286:10;5249:76;;;;-1:-1:-1;;;;;5249:76:6;;;;;;;;;;;;;;;5218:12;;5249:9;;;;;:36;;:76;;;;;;;;;;;;;;;5218:12;5249:9;:76;;;;;;;;;;2070:135;2171:9;;:27;;;;;;-1:-1:-1;;;;;2171:27:6;;;;;;;;;2137:15;;2171:9;;;;;:19;;:27;;;;;;;;;;;;;;;:9;:27;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;2171:27:6;;2070:135;-1:-1:-1;;2070:135:6:o;5895:117::-;5982:9;;:23;;;;;;-1:-1:-1;;;;;5982:23:6;;;;;;;;;5958:7;;5982:9;;;;;:16;;:23;;;;;;;;;;;;;;;:9;:23;;;;;;;;;;3058:226:4;1365:9:0;;-1:-1:-1;;;;;1365:9:0;1351:10;:23;1343:48;;;;;-1:-1:-1;;;1343:48:0;;;;;;;;;;;;-1:-1:-1;;;1343:48:0;;;;;;;;;;;;;;;3147:25:4::1;3164:7;3147:16;:25::i;:::-;3135:9;:37:::0;;-1:-1:-1;;;;;3135:37:4;;::::1;-1:-1:-1::0;;3135:37:4;;::::1;;::::0;;:9:::1;3190:23:::0;;;:14:::1;:23;::::0;;;;;;;;3183:30;;;;::::1;::::0;;;3266:9;;3229:48;;;;;3266:9;::::1;3229:48:::0;;::::1;::::0;;;::::1;::::0;;;;;;;;::::1;3058:226:::0;:::o;1122:20:6:-;;;;;;;;;;;;;;;-1:-1:-1;;1122:20:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;2676:165;2781:9;;:53;;;;;;2810:10;2781:53;;;;-1:-1:-1;;;;;2781:53:6;;;;;;;;;;;;;;;2750:12;;2781:9;;;;;:28;;:53;;;;;;;;;;;;;;;2750:12;2781:9;:53;;;;;;;;;;1244:60:4;;;;;;;;;;;;-1:-1:-1;;;;;1244:60:4;;:::o;716:31:9:-;;;;:::o;1078:70:0:-;;;;;;;;;;;;-1:-1:-1;;;;;1078:70:0;;:::o;5687:203:6:-;5825:9;;:58;;;;;;-1:-1:-1;;;;;5825:58:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;:9;;;;;:16;;:58;;;;;:9;;:58;;;;;;;:9;;:58;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;5687:203;;;;;;;:::o;4522:192::-;4636:9;;:71;;;;;;4673:10;4636:71;;;;-1:-1:-1;;;;;4636:71:6;;;;;;;;;;;;;;;4605:12;;4636:9;;;;;:36;;:71;;;;;;;;;;;;;;;4605:12;4636:9;:71;;;;;;;;;;5516:165;5637:9;;:37;;;;;;-1:-1:-1;;;;;5637:37:6;;;;;;;;;;;;;;;;5601:17;;5637:9;;;;;:19;;:37;;;;;;;;;;;;;;;:9;:37;;;;;;;;;;;;;;;;;;;;;;;;;;6142:546;6267:9;;-1:-1:-1;;;;;6267:9:6;6295:10;:22;;6287:47;;;;;-1:-1:-1;;;6287:47:6;;;;;;;;;;;;-1:-1:-1;;;6287:47:6;;;;;;;;;;;;;;;6371:8;-1:-1:-1;;;;;6352:27:6;:15;-1:-1:-1;;;;;6352:27:6;;;6344:50;;;;;-1:-1:-1;;;6344:50:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;6406:12;6420:23;6447:15;-1:-1:-1;;;;;6447:20:6;6468:8;;6447:30;;;;;;;;;;;;;;-1:-1:-1;6447:30:6;;-1:-1:-1;6447:30:6;;-1:-1:-1;;6447:30:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6405:72;;;;6491:7;6487:195;;;6519:58;6539:15;6556:8;;6566:10;6519:58;;;;-1:-1:-1;;;;;6519:58:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6519:58:6;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6519:58:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6487:195;;;6613:58;6633:15;6650:8;;6660:10;6613:58;;;;-1:-1:-1;;;;;6613:58:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;;6613:58:6;;;;;;;;;;;;;;;;;;;;;;;;-1:-1:-1;6613:58:6;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;6487:195;6142:546;;;;;;:::o;1382:319:9:-;1429:17;1499:18;;;;;;;;1560:124;;;-1:-1:-1;;1600:12:9;:16;1590:27;1560:124;;;;;;;;1639:4;1560:124;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;1539:155;;;;;;1382:319::o;3191:434:0:-;3261:20;3340:28;;;:19;:28;;;;;3517:25;;-1:-1:-1;;;;;3517:25:0;3509:66;;;;;-1:-1:-1;;;3509:66:0;;;;;;;;;;;;;;;;;;;;;;;;;;;;3593:25;-1:-1:-1;;;;;3593:25:0;;3191:434;-1:-1:-1;;3191:434:0:o;3315:432:4:-;3380:22;3456:23;;;:14;:23;;;;;3628:25;;-1:-1:-1;;;;;3628:25:4;3620:66;;;;;-1:-1:-1;;;3620:66:4;;;;;;;;;;;;;;;;;;;;;;;;;;

Swarm Source

ipfs://30b64a0e5ec6b3b880d8cf538043b2ee039773ec7b90b5d3363beb4a2e640f1a

Block Transaction Difficulty Gas Used Reward
View All Blocks Produced

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

OVERVIEW

Gemini is a New York trust company regulated by the New York State Department of Financial Services (NYSDFS).

Validator Index Block Amount
View All Withdrawals

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

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