ETH Price: $3,099.48 (+1.00%)
Gas: 9 Gwei

Token

Ethereum Wrapped Filecoin (eFIL)
 

Overview

Max Total Supply

44,924.147803 eFIL

Holders

134 (0.00%)

Market

Onchain Market Cap

$0.00

Circulating Supply Market Cap

-

Other Info

Token Contract (WITH 18 Decimals)

Filtered by Token Holder
bfgalvao.eth
Balance
1 eFIL

Value
$0.00
0x9DE39Be30B176C327Dd8824f4d7Ab5B6d2930Db7
Loading...
Loading
Loading...
Loading
Loading...
Loading

OVERVIEW

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

# Exchange Pair Price  24H Volume % Volume

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 : 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 2 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 3 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 4 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 5 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 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

[{"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
Loading...
Loading
Loading...
Loading
[ Download: CSV Export  ]
[ Download: CSV Export  ]

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