ETH Price: $3,425.11 (-2.58%)
Gas: 4 Gwei

Transaction Decoder

Block:
19642859 at Apr-12-2024 11:41:11 PM +UTC
Transaction Fee:
0.001370200039004797 ETH $4.69
Gas Used:
92,449 Gas / 14.821145053 Gwei

Emitted Events:

Account State Difference:

  Address   Before After State Difference Code
(Titan Builder)
8.448034929881218925 Eth8.448038262813460998 Eth0.000003332932242073
0xc42B14e4...af35e68a0
0xFeEd5CF7...C51B1Efde
1.246068033857853519 Eth
Nonce: 35592
1.244697833818848722 Eth
Nonce: 35593
0.001370200039004797

Execution Trace

0x52b8dc6816caf977d7728f0f235f40c6d1259f2f.2da03409( )
  • Forwarder.flushTokens( tokenContractAddress=0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd )
    • Forwarder.flushTokens( tokenContractAddress=0x056Fd409E1d7A124BD7017459dFEa2F387b6d5Cd )
      • ERC20Proxy.balanceOf( _owner=0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7 ) => ( balance=52592 )
        • ERC20Impl.balanceOf( _owner=0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7 ) => ( balance=52592 )
          • ERC20Store.balances( 0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7 ) => ( 52592 )
          • ERC20Proxy.transfer( _to=0x52B8dC6816caF977d7728F0F235f40C6d1259F2F, _value=52592 ) => ( success=True )
            • ERC20Impl.transferWithSender( _sender=0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7, _to=0x52B8dC6816caF977d7728F0F235f40C6d1259F2F, _value=52592 ) => ( success=True )
              • ERC20Store.balances( 0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7 ) => ( 52592 )
              • ERC20Store.setBalance( _owner=0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7, _newBalance=0 )
              • ERC20Store.addBalance( _owner=0x52B8dC6816caF977d7728F0F235f40C6d1259F2F, _balanceIncrease=52592 )
              • ERC20Proxy.emitTransfer( _from=0xeCc23Df58cEDc8a418C54bC4Dad41D6a1Db4a6D7, _to=0x52B8dC6816caF977d7728F0F235f40C6d1259F2F, _value=52592 )
                File 1 of 5: Forwarder
                pragma solidity 0.7.5;
                
                /*
                    The MIT License (MIT)
                    Copyright (c) 2018 Murray Software, LLC.
                    Permission is hereby granted, free of charge, to any person obtaining
                    a copy of this software and associated documentation files (the
                    "Software"), to deal in the Software without restriction, including
                    without limitation the rights to use, copy, modify, merge, publish,
                    distribute, sublicense, and/or sell copies of the Software, and to
                    permit persons to whom the Software is furnished to do so, subject to
                    the following conditions:
                    The above copyright notice and this permission notice shall be included
                    in all copies or substantial portions of the Software.
                    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
                    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
                    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
                    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                */
                //solhint-disable max-line-length
                //solhint-disable no-inline-assembly
                
                contract CloneFactory {
                  function createClone(address target, bytes32 salt)
                    internal
                    returns (address payable result)
                  {
                    bytes20 targetBytes = bytes20(target);
                    assembly {
                      // load the next free memory slot as a place to store the clone contract data
                      let clone := mload(0x40)
                
                      // The bytecode block below is responsible for contract initialization
                      // during deployment, it is worth noting the proxied contract constructor will not be called during
                      // the cloning procedure and that is why an initialization function needs to be called after the
                      // clone is created
                      mstore(
                        clone,
                        0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
                      )
                
                      // This stores the address location of the implementation contract
                      // so that the proxy knows where to delegate call logic to
                      mstore(add(clone, 0x14), targetBytes)
                
                      // The bytecode block is the actual code that is deployed for each clone created.
                      // It forwards all calls to the already deployed implementation via a delegatecall
                      mstore(
                        add(clone, 0x28),
                        0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
                      )
                
                      // deploy the contract using the CREATE2 opcode
                      // this deploys the minimal proxy defined above, which will proxy all
                      // calls to use the logic defined in the implementation contract `target`
                      result := create2(0, clone, 0x37, salt)
                    }
                  }
                
                  function isClone(address target, address query)
                    internal
                    view
                    returns (bool result)
                  {
                    bytes20 targetBytes = bytes20(target);
                    assembly {
                      // load the next free memory slot as a place to store the comparison clone
                      let clone := mload(0x40)
                
                      // The next three lines store the expected bytecode for a miniml proxy
                      // that targets `target` as its implementation contract
                      mstore(
                        clone,
                        0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
                      )
                      mstore(add(clone, 0xa), targetBytes)
                      mstore(
                        add(clone, 0x1e),
                        0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
                      )
                
                      // the next two lines store the bytecode of the contract that we are checking in memory
                      let other := add(clone, 0x40)
                      extcodecopy(query, other, 0, 0x2d)
                
                      // Check if the expected bytecode equals the actual bytecode and return the result
                      result := and(
                        eq(mload(clone), mload(other)),
                        eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
                      )
                    }
                  }
                }
                
                
                /**
                 * Contract that exposes the needed erc20 token functions
                 */
                
                abstract contract ERC20Interface {
                  // Send _value amount of tokens to address _to
                  function transfer(address _to, uint256 _value)
                    public
                    virtual
                    returns (bool success);
                
                  // Get the account balance of another account with address _owner
                  function balanceOf(address _owner)
                    public
                    virtual
                    view
                    returns (uint256 balance);
                }
                
                // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
                library TransferHelper {
                    function safeApprove(
                        address token,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('approve(address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::safeApprove: approve failed'
                        );
                    }
                
                    function safeTransfer(
                        address token,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('transfer(address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::safeTransfer: transfer failed'
                        );
                    }
                
                    function safeTransferFrom(
                        address token,
                        address from,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::transferFrom: transferFrom failed'
                        );
                    }
                
                    function safeTransferETH(address to, uint256 value) internal {
                        (bool success, ) = to.call{value: value}(new bytes(0));
                        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
                    }
                }
                
                
                /**
                 * Contract that will forward any incoming Ether to the creator of the contract
                 *
                 */
                contract Forwarder {
                  // Address to which any funds sent to this contract will be forwarded
                  address public parentAddress;
                  event ForwarderDeposited(address from, uint256 value, bytes data);
                
                  /**
                   * Initialize the contract, and sets the destination address to that of the creator
                   */
                  function init(address _parentAddress) external onlyUninitialized {
                    parentAddress = _parentAddress;
                    uint256 value = address(this).balance;
                
                    if (value == 0) {
                      return;
                    }
                
                    (bool success, ) = parentAddress.call{ value: value }('');
                    require(success, 'Flush failed');
                    // NOTE: since we are forwarding on initialization,
                    // we don't have the context of the original sender.
                    // We still emit an event about the forwarding but set
                    // the sender to the forwarder itself
                    emit ForwarderDeposited(address(this), value, msg.data);
                  }
                
                  /**
                   * Modifier that will execute internal code block only if the sender is the parent address
                   */
                  modifier onlyParent {
                    require(msg.sender == parentAddress, 'Only Parent');
                    _;
                  }
                
                  /**
                   * Modifier that will execute internal code block only if the contract has not been initialized yet
                   */
                  modifier onlyUninitialized {
                    require(parentAddress == address(0x0), 'Already initialized');
                    _;
                  }
                
                  /**
                   * Default function; Gets called when data is sent but does not match any other function
                   */
                  fallback() external payable {
                    flush();
                  }
                
                  /**
                   * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
                   */
                  receive() external payable {
                    flush();
                  }
                
                  /**
                   * Execute a token transfer of the full balance from the forwarder token to the parent address
                   * @param tokenContractAddress the address of the erc20 token contract
                   */
                  function flushTokens(address tokenContractAddress) external onlyParent {
                    ERC20Interface instance = ERC20Interface(tokenContractAddress);
                    address forwarderAddress = address(this);
                    uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
                    if (forwarderBalance == 0) {
                      return;
                    }
                
                    TransferHelper.safeTransfer(
                      tokenContractAddress,
                      parentAddress,
                      forwarderBalance
                    );
                  }
                
                  /**
                   * Flush the entire balance of the contract to the parent address.
                   */
                  function flush() public {
                    uint256 value = address(this).balance;
                
                    if (value == 0) {
                      return;
                    }
                
                    (bool success, ) = parentAddress.call{ value: value }('');
                    require(success, 'Flush failed');
                    emit ForwarderDeposited(msg.sender, value, msg.data);
                  }
                }
                
                contract ForwarderFactory is CloneFactory {
                  address public implementationAddress;
                
                  event ForwarderCreated(address newForwarderAddress, address parentAddress);
                
                  constructor(address _implementationAddress) {
                    implementationAddress = _implementationAddress;
                  }
                
                  function createForwarder(address parent, bytes32 salt) external {
                    // include the signers in the salt so any contract deployed to a given address must have the same signers
                    bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt));
                
                    address payable clone = createClone(implementationAddress, finalSalt);
                    Forwarder(clone).init(parent);
                    emit ForwarderCreated(clone, parent);
                  }
                }

                File 2 of 5: ERC20Proxy
                pragma solidity ^0.4.21;
                
                /** @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
                  */
                contract LockRequestable {
                
                    // MEMBERS
                    /// @notice  the count of all invocations of `generateLockId`.
                    uint256 public lockRequestCount;
                
                    // CONSTRUCTOR
                    function LockRequestable() public {
                        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 a 32-byte unique identifier.
                      */
                    function generateLockId() internal returns (bytes32 lockId) {
                        return keccak256(block.blockhash(block.number - 1), address(this), ++lockRequestCount);
                    }
                }
                
                
                /** @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
                  */
                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
                    function CustodianUpgradeable(
                        address _custodian
                    )
                      LockRequestable()
                      public
                    {
                        custodian = _custodian;
                    }
                
                    // MODIFIERS
                    modifier onlyCustodian {
                        require(msg.sender == custodian);
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedCustodian != address(0));
                
                        lockId = generateLockId();
                
                        custodianChangeReqs[lockId] = CustodianChangeRequest({
                            proposedNew: _proposedCustodian
                        });
                
                        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);
                    }
                
                    /** @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) public 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 != 0);
                
                        return changeRequest.proposedNew;
                    }
                
                    /// @dev  Emitted by successful `requestCustodianChange` calls.
                    event CustodianChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedCustodian
                    );
                
                    /// @dev Emitted by successful `confirmCustodianChange` calls.
                    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
                }
                
                
                /** @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
                  */
                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
                    function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
                        erc20Impl = ERC20Impl(0x0);
                    }
                
                    // MODIFIERS
                    modifier onlyImpl {
                        require(msg.sender == address(erc20Impl));
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedImpl != address(0));
                
                        lockId = generateLockId();
                
                        implChangeReqs[lockId] = ImplChangeRequest({
                            proposedNew: _proposedImpl
                        });
                
                        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
                    }
                
                    /** @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) public 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));
                
                        return ERC20Impl(changeRequest.proposedNew);
                    }
                
                    /// @dev  Emitted by successful `requestImplChange` calls.
                    event ImplChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedImpl
                    );
                
                    /// @dev Emitted by successful `confirmImplChange` calls.
                    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
                }
                
                
                contract 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() public view returns (uint256);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
                  function balanceOf(address _owner) public view returns (uint256 balance);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
                  function transfer(address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
                  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
                  function approve(address _spender, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
                  function allowance(address _owner, address _spender) public 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);
                }
                
                
                /** @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 {
                
                    // MEMBERS
                    /// @notice  Returns the name of the token.
                    string public name;
                
                    /// @notice  Returns the symbol of the token.
                    string public symbol;
                
                    /// @notice  Returns the number of decimals the token uses.
                    uint8 public decimals;
                
                    // CONSTRUCTOR
                    function ERC20Proxy(
                        string _name,
                        string _symbol,
                        uint8 _decimals,
                        address _custodian
                    )
                        ERC20ImplUpgradeable(_custodian)
                        public
                    {
                        name = _name;
                        symbol = _symbol;
                        decimals = _decimals;
                    }
                
                    // PUBLIC FUNCTIONS
                    // (ERC20Interface)
                    /** @notice  Returns the total token supply.
                      *
                      * @return  the total token supply.
                      */
                    function totalSupply() public 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) public view returns (uint256 balance) {
                        return erc20Impl.balanceOf(_owner);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitTransfer(address _from, address _to, uint256 _value) public 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) public 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) public returns (bool success) {
                        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitApproval(address _owner, address _spender, uint256 _value) public 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) public 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) public 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) public 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) public view returns (uint256 remaining) {
                        return erc20Impl.allowance(_owner, _spender);
                    }
                }
                
                
                /** @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;
                    }
                
                    // MEMBERS
                    /// @dev  The reference to the proxy.
                    ERC20Proxy public erc20Proxy;
                
                    /// @dev  The reference to the store.
                    ERC20Store public erc20Store;
                
                    /// @dev  The sole authorized caller of delegated transfer control ('sweeping').
                    address public sweeper;
                
                    /** @dev  The static message to be signed by an external account that
                      * signifies their permission to forward their balance to any arbitrary
                      * address. This is used to consolidate the control of all accounts
                      * backed by a shared keychain into the control of a single key.
                      * Initialized as the concatenation of the address of this contract
                      * and the word "sweep". This concatenation is done to prevent a replay
                      * attack in a subsequent contract, where the sweep message could
                      * potentially be replayed to re-enable sweeping ability.
                      */
                    bytes32 public sweepMsg;
                
                    /** @dev  The mapping that stores whether the address in question has
                      * enabled sweeping its contents to another account or not.
                      * If an address maps to "true", it has already enabled sweeping,
                      * and thus does not need to re-sign the `sweepMsg` to enact the sweep.
                      */
                    mapping (address => bool) public sweptSet;
                
                    /// @dev  The map of lock ids to pending token increases.
                    mapping (bytes32 => PendingPrint) public pendingPrintMap;
                
                    // CONSTRUCTOR
                    function ERC20Impl(
                          address _erc20Proxy,
                          address _erc20Store,
                          address _custodian,
                          address _sweeper
                    )
                        CustodianUpgradeable(_custodian)
                        public
                    {
                        require(_sweeper != 0);
                        erc20Proxy = ERC20Proxy(_erc20Proxy);
                        erc20Store = ERC20Store(_erc20Store);
                
                        sweeper = _sweeper;
                        sweepMsg = keccak256(address(this), "sweep");
                    }
                
                    // MODIFIERS
                    modifier onlyProxy {
                        require(msg.sender == address(erc20Proxy));
                        _;
                    }
                    modifier onlySweeper {
                        require(msg.sender == sweeper);
                        _;
                    }
                
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        erc20Store.setAllowance(_sender, _spender, _value);
                        erc20Proxy.emitApproval(_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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance + _addedValue;
                
                        require(newAllowance >= currentAllowance);
                
                        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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance - _subtractedValue;
                
                        require(newAllowance <= currentAllowance);
                
                        erc20Store.setAllowance(_sender, _spender, newAllowance);
                        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
                        return true;
                    }
                
                    /** @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) public returns (bytes32 lockId) {
                        require(_receiver != address(0));
                
                        lockId = generateLockId();
                
                        pendingPrintMap[lockId] = PendingPrint({
                            receiver: _receiver,
                            value: _value
                        });
                
                        emit PrintingLocked(lockId, _receiver, _value);
                    }
                
                    /** @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) public 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));
                        uint256 value = print.value;
                
                        delete pendingPrintMap[_lockId];
                
                        uint256 supply = erc20Store.totalSupply();
                        uint256 newSupply = supply + value;
                        if (newSupply >= supply) {
                          erc20Store.setTotalSupply(newSupply);
                          erc20Store.addBalance(receiver, value);
                
                          emit PrintingConfirmed(_lockId, receiver, value);
                          erc20Proxy.emitTransfer(address(0), receiver, value);
                        }
                    }
                
                    /** @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) public returns (bool success) {
                        uint256 balanceOfSender = erc20Store.balances(msg.sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(msg.sender, balanceOfSender - _value);
                        erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
                
                        erc20Proxy.emitTransfer(msg.sender, address(0), _value);
                
                        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[] _tos, uint256[] _values) public returns (bool success) {
                        require(_tos.length == _values.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));
                          uint256 v = _values[i];
                          require(senderBalance >= v);
                
                          if (msg.sender != to) {
                            senderBalance -= v;
                            erc20Store.addBalance(to, v);
                          }
                          erc20Proxy.emitTransfer(msg.sender, to, v);
                        }
                
                        erc20Store.setBalance(msg.sender, senderBalance);
                
                        return true;
                    }
                
                    /** @notice  Enables the delegation of transfer control for many
                      * accounts to the sweeper account, transferring any balances
                      * as well to the given destination.
                      *
                      * @dev  An account delegates transfer control by signing the
                      * value of `sweepMsg`. The sweeper account is the only authorized
                      * caller of this function, so it must relay signatures on behalf
                      * of accounts that delegate transfer control to it. Enabling
                      * delegation is idempotent and permanent. If the account has a
                      * balance at the time of enabling delegation, its balance is
                      * also transfered to the given destination account `_to`.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _vs  The array of recovery byte components of the ECDSA signatures.
                      * @param  _rs  The array of 'R' components of the ECDSA signatures.
                      * @param  _ss  The array of 'S' components of the ECDSA signatures.
                      * @param  _to  The destination for swept balances.
                      */
                    function enableSweep(uint8[] _vs, bytes32[] _rs, bytes32[] _ss, address _to) public onlySweeper {
                        require(_to != address(0));
                        require((_vs.length == _rs.length) && (_vs.length == _ss.length));
                
                        uint256 numSignatures = _vs.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<numSignatures; ++i) {
                          address from = ecrecover(sweepMsg, _vs[i], _rs[i], _ss[i]);
                
                          // ecrecover returns 0 on malformed input
                          if (from != address(0)) {
                            sweptSet[from] = true;
                
                            uint256 fromBalance = erc20Store.balances(from);
                
                            if (fromBalance > 0) {
                              sweptBalance += fromBalance;
                
                              erc20Store.setBalance(from, 0);
                
                              erc20Proxy.emitTransfer(from, _to, fromBalance);
                            }
                          }
                        }
                
                        if (sweptBalance > 0) {
                          erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @notice  For accounts that have delegated, transfer control
                      * to the sweeper, this function transfers their balances to the given
                      * destination.
                      *
                      * @dev The sweeper account is the only authorized caller of
                      * this function. This function accepts an array of addresses to have their
                      * balances transferred for gas efficiency purposes.
                      * NOTE: any address for an account that has not been previously enabled
                      * will be ignored.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _froms  The addresses to have their balances swept.
                      * @param  _to  The destination address of all these transfers.
                      */
                    function replaySweep(address[] _froms, address _to) public onlySweeper {
                        require(_to != address(0));
                        uint256 lenFroms = _froms.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<lenFroms; ++i) {
                            address from = _froms[i];
                
                            if (sweptSet[from]) {
                                uint256 fromBalance = erc20Store.balances(from);
                
                                if (fromBalance > 0) {
                                    sweptBalance += fromBalance;
                
                                    erc20Store.setBalance(from, 0);
                
                                    erc20Proxy.emitTransfer(from, _to, fromBalance);
                                }
                            }
                        }
                
                        if (sweptBalance > 0) {
                            erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfFrom = erc20Store.balances(_from);
                        require(_value <= balanceOfFrom);
                
                        uint256 senderAllowance = erc20Store.allowed(_from, _sender);
                        require(_value <= senderAllowance);
                
                        erc20Store.setBalance(_from, balanceOfFrom - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Store.setAllowance(_from, _sender, senderAllowance - _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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfSender = erc20Store.balances(_sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(_sender, balanceOfSender - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Proxy.emitTransfer(_sender, _to, _value);
                
                        return true;
                    }
                
                    // METHODS (ERC20 sub interface impl.)
                    /// @notice  Core logic of the ERC20 `totalSupply` function.
                    function totalSupply() public view returns (uint256) {
                        return erc20Store.totalSupply();
                    }
                
                    /// @notice  Core logic of the ERC20 `balanceOf` function.
                    function balanceOf(address _owner) public view returns (uint256 balance) {
                        return erc20Store.balances(_owner);
                    }
                
                    /// @notice  Core logic of the ERC20 `allowance` function.
                    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
                        return erc20Store.allowed(_owner, _spender);
                    }
                
                    // EVENTS
                    /// @dev  Emitted by successful `requestPrint` calls.
                    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value);
                    /// @dev Emitted by successful `confirmPrint` calls.
                    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);
                }
                
                
                /** @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;
                
                    // CONSTRUCTOR
                    function ERC20Store(address _custodian) ERC20ImplUpgradeable(_custodian) public {
                        totalSupply = 0;
                    }
                
                
                    // PUBLIC FUNCTIONS
                    // (ERC20 Ledger)
                
                    /** @notice  The function to set the total supply of tokens.
                      *
                      * @dev  Intended for use by token implementation functions
                      * that update the total supply. The only authorized caller
                      * is the active implementation.
                      *
                      * @param _newTotalSupply the value to set as the new total supply
                      */
                    function setTotalSupply(
                        uint256 _newTotalSupply
                    )
                        public
                        onlyImpl
                    {
                        totalSupply = _newTotalSupply;
                    }
                
                    /** @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
                    )
                        public
                        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
                    )
                        public
                        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
                    )
                        public
                        onlyImpl
                    {
                        balances[_owner] = balances[_owner] + _balanceIncrease;
                    }
                }

                File 3 of 5: Forwarder
                pragma solidity 0.7.5;
                
                /*
                    The MIT License (MIT)
                    Copyright (c) 2018 Murray Software, LLC.
                    Permission is hereby granted, free of charge, to any person obtaining
                    a copy of this software and associated documentation files (the
                    "Software"), to deal in the Software without restriction, including
                    without limitation the rights to use, copy, modify, merge, publish,
                    distribute, sublicense, and/or sell copies of the Software, and to
                    permit persons to whom the Software is furnished to do so, subject to
                    the following conditions:
                    The above copyright notice and this permission notice shall be included
                    in all copies or substantial portions of the Software.
                    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
                    OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
                    MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
                    IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
                    CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
                    TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
                    SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
                */
                //solhint-disable max-line-length
                //solhint-disable no-inline-assembly
                
                contract CloneFactory {
                  function createClone(address target, bytes32 salt)
                    internal
                    returns (address payable result)
                  {
                    bytes20 targetBytes = bytes20(target);
                    assembly {
                      // load the next free memory slot as a place to store the clone contract data
                      let clone := mload(0x40)
                
                      // The bytecode block below is responsible for contract initialization
                      // during deployment, it is worth noting the proxied contract constructor will not be called during
                      // the cloning procedure and that is why an initialization function needs to be called after the
                      // clone is created
                      mstore(
                        clone,
                        0x3d602d80600a3d3981f3363d3d373d3d3d363d73000000000000000000000000
                      )
                
                      // This stores the address location of the implementation contract
                      // so that the proxy knows where to delegate call logic to
                      mstore(add(clone, 0x14), targetBytes)
                
                      // The bytecode block is the actual code that is deployed for each clone created.
                      // It forwards all calls to the already deployed implementation via a delegatecall
                      mstore(
                        add(clone, 0x28),
                        0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
                      )
                
                      // deploy the contract using the CREATE2 opcode
                      // this deploys the minimal proxy defined above, which will proxy all
                      // calls to use the logic defined in the implementation contract `target`
                      result := create2(0, clone, 0x37, salt)
                    }
                  }
                
                  function isClone(address target, address query)
                    internal
                    view
                    returns (bool result)
                  {
                    bytes20 targetBytes = bytes20(target);
                    assembly {
                      // load the next free memory slot as a place to store the comparison clone
                      let clone := mload(0x40)
                
                      // The next three lines store the expected bytecode for a miniml proxy
                      // that targets `target` as its implementation contract
                      mstore(
                        clone,
                        0x363d3d373d3d3d363d7300000000000000000000000000000000000000000000
                      )
                      mstore(add(clone, 0xa), targetBytes)
                      mstore(
                        add(clone, 0x1e),
                        0x5af43d82803e903d91602b57fd5bf30000000000000000000000000000000000
                      )
                
                      // the next two lines store the bytecode of the contract that we are checking in memory
                      let other := add(clone, 0x40)
                      extcodecopy(query, other, 0, 0x2d)
                
                      // Check if the expected bytecode equals the actual bytecode and return the result
                      result := and(
                        eq(mload(clone), mload(other)),
                        eq(mload(add(clone, 0xd)), mload(add(other, 0xd)))
                      )
                    }
                  }
                }
                
                
                /**
                 * Contract that exposes the needed erc20 token functions
                 */
                
                abstract contract ERC20Interface {
                  // Send _value amount of tokens to address _to
                  function transfer(address _to, uint256 _value)
                    public
                    virtual
                    returns (bool success);
                
                  // Get the account balance of another account with address _owner
                  function balanceOf(address _owner)
                    public
                    virtual
                    view
                    returns (uint256 balance);
                }
                
                // helper methods for interacting with ERC20 tokens and sending ETH that do not consistently return true/false
                library TransferHelper {
                    function safeApprove(
                        address token,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('approve(address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x095ea7b3, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::safeApprove: approve failed'
                        );
                    }
                
                    function safeTransfer(
                        address token,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('transfer(address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0xa9059cbb, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::safeTransfer: transfer failed'
                        );
                    }
                
                    function safeTransferFrom(
                        address token,
                        address from,
                        address to,
                        uint256 value
                    ) internal {
                        // bytes4(keccak256(bytes('transferFrom(address,address,uint256)')));
                        (bool success, bytes memory data) = token.call(abi.encodeWithSelector(0x23b872dd, from, to, value));
                        require(
                            success && (data.length == 0 || abi.decode(data, (bool))),
                            'TransferHelper::transferFrom: transferFrom failed'
                        );
                    }
                
                    function safeTransferETH(address to, uint256 value) internal {
                        (bool success, ) = to.call{value: value}(new bytes(0));
                        require(success, 'TransferHelper::safeTransferETH: ETH transfer failed');
                    }
                }
                
                
                /**
                 * Contract that will forward any incoming Ether to the creator of the contract
                 *
                 */
                contract Forwarder {
                  // Address to which any funds sent to this contract will be forwarded
                  address public parentAddress;
                  event ForwarderDeposited(address from, uint256 value, bytes data);
                
                  /**
                   * Initialize the contract, and sets the destination address to that of the creator
                   */
                  function init(address _parentAddress) external onlyUninitialized {
                    parentAddress = _parentAddress;
                    uint256 value = address(this).balance;
                
                    if (value == 0) {
                      return;
                    }
                
                    (bool success, ) = parentAddress.call{ value: value }('');
                    require(success, 'Flush failed');
                    // NOTE: since we are forwarding on initialization,
                    // we don't have the context of the original sender.
                    // We still emit an event about the forwarding but set
                    // the sender to the forwarder itself
                    emit ForwarderDeposited(address(this), value, msg.data);
                  }
                
                  /**
                   * Modifier that will execute internal code block only if the sender is the parent address
                   */
                  modifier onlyParent {
                    require(msg.sender == parentAddress, 'Only Parent');
                    _;
                  }
                
                  /**
                   * Modifier that will execute internal code block only if the contract has not been initialized yet
                   */
                  modifier onlyUninitialized {
                    require(parentAddress == address(0x0), 'Already initialized');
                    _;
                  }
                
                  /**
                   * Default function; Gets called when data is sent but does not match any other function
                   */
                  fallback() external payable {
                    flush();
                  }
                
                  /**
                   * Default function; Gets called when Ether is deposited with no data, and forwards it to the parent address
                   */
                  receive() external payable {
                    flush();
                  }
                
                  /**
                   * Execute a token transfer of the full balance from the forwarder token to the parent address
                   * @param tokenContractAddress the address of the erc20 token contract
                   */
                  function flushTokens(address tokenContractAddress) external onlyParent {
                    ERC20Interface instance = ERC20Interface(tokenContractAddress);
                    address forwarderAddress = address(this);
                    uint256 forwarderBalance = instance.balanceOf(forwarderAddress);
                    if (forwarderBalance == 0) {
                      return;
                    }
                
                    TransferHelper.safeTransfer(
                      tokenContractAddress,
                      parentAddress,
                      forwarderBalance
                    );
                  }
                
                  /**
                   * Flush the entire balance of the contract to the parent address.
                   */
                  function flush() public {
                    uint256 value = address(this).balance;
                
                    if (value == 0) {
                      return;
                    }
                
                    (bool success, ) = parentAddress.call{ value: value }('');
                    require(success, 'Flush failed');
                    emit ForwarderDeposited(msg.sender, value, msg.data);
                  }
                }
                
                contract ForwarderFactory is CloneFactory {
                  address public implementationAddress;
                
                  event ForwarderCreated(address newForwarderAddress, address parentAddress);
                
                  constructor(address _implementationAddress) {
                    implementationAddress = _implementationAddress;
                  }
                
                  function createForwarder(address parent, bytes32 salt) external {
                    // include the signers in the salt so any contract deployed to a given address must have the same signers
                    bytes32 finalSalt = keccak256(abi.encodePacked(parent, salt));
                
                    address payable clone = createClone(implementationAddress, finalSalt);
                    Forwarder(clone).init(parent);
                    emit ForwarderCreated(clone, parent);
                  }
                }

                File 4 of 5: ERC20Impl
                pragma solidity ^0.4.21;
                
                /** @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
                  */
                contract LockRequestable {
                
                    // MEMBERS
                    /// @notice  the count of all invocations of `generateLockId`.
                    uint256 public lockRequestCount;
                
                    // CONSTRUCTOR
                    function LockRequestable() public {
                        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 a 32-byte unique identifier.
                      */
                    function generateLockId() internal returns (bytes32 lockId) {
                        return keccak256(block.blockhash(block.number - 1), address(this), ++lockRequestCount);
                    }
                }
                
                
                /** @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
                  */
                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
                    function CustodianUpgradeable(
                        address _custodian
                    )
                      LockRequestable()
                      public
                    {
                        custodian = _custodian;
                    }
                
                    // MODIFIERS
                    modifier onlyCustodian {
                        require(msg.sender == custodian);
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedCustodian != address(0));
                
                        lockId = generateLockId();
                
                        custodianChangeReqs[lockId] = CustodianChangeRequest({
                            proposedNew: _proposedCustodian
                        });
                
                        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);
                    }
                
                    /** @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) public 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 != 0);
                
                        return changeRequest.proposedNew;
                    }
                
                    /// @dev  Emitted by successful `requestCustodianChange` calls.
                    event CustodianChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedCustodian
                    );
                
                    /// @dev Emitted by successful `confirmCustodianChange` calls.
                    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
                }
                
                
                /** @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
                  */
                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
                    function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
                        erc20Impl = ERC20Impl(0x0);
                    }
                
                    // MODIFIERS
                    modifier onlyImpl {
                        require(msg.sender == address(erc20Impl));
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedImpl != address(0));
                
                        lockId = generateLockId();
                
                        implChangeReqs[lockId] = ImplChangeRequest({
                            proposedNew: _proposedImpl
                        });
                
                        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
                    }
                
                    /** @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) public 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));
                
                        return ERC20Impl(changeRequest.proposedNew);
                    }
                
                    /// @dev  Emitted by successful `requestImplChange` calls.
                    event ImplChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedImpl
                    );
                
                    /// @dev Emitted by successful `confirmImplChange` calls.
                    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
                }
                
                
                contract 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() public view returns (uint256);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
                  function balanceOf(address _owner) public view returns (uint256 balance);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
                  function transfer(address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
                  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
                  function approve(address _spender, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
                  function allowance(address _owner, address _spender) public 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);
                }
                
                
                /** @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 {
                
                    // MEMBERS
                    /// @notice  Returns the name of the token.
                    string public name;
                
                    /// @notice  Returns the symbol of the token.
                    string public symbol;
                
                    /// @notice  Returns the number of decimals the token uses.
                    uint8 public decimals;
                
                    // CONSTRUCTOR
                    function ERC20Proxy(
                        string _name,
                        string _symbol,
                        uint8 _decimals,
                        address _custodian
                    )
                        ERC20ImplUpgradeable(_custodian)
                        public
                    {
                        name = _name;
                        symbol = _symbol;
                        decimals = _decimals;
                    }
                
                    // PUBLIC FUNCTIONS
                    // (ERC20Interface)
                    /** @notice  Returns the total token supply.
                      *
                      * @return  the total token supply.
                      */
                    function totalSupply() public 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) public view returns (uint256 balance) {
                        return erc20Impl.balanceOf(_owner);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitTransfer(address _from, address _to, uint256 _value) public 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) public 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) public returns (bool success) {
                        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitApproval(address _owner, address _spender, uint256 _value) public 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) public 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) public 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) public 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) public view returns (uint256 remaining) {
                        return erc20Impl.allowance(_owner, _spender);
                    }
                }
                
                
                /** @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;
                    }
                
                    // MEMBERS
                    /// @dev  The reference to the proxy.
                    ERC20Proxy public erc20Proxy;
                
                    /// @dev  The reference to the store.
                    ERC20Store public erc20Store;
                
                    /// @dev  The sole authorized caller of delegated transfer control ('sweeping').
                    address public sweeper;
                
                    /** @dev  The static message to be signed by an external account that
                      * signifies their permission to forward their balance to any arbitrary
                      * address. This is used to consolidate the control of all accounts
                      * backed by a shared keychain into the control of a single key.
                      * Initialized as the concatenation of the address of this contract
                      * and the word "sweep". This concatenation is done to prevent a replay
                      * attack in a subsequent contract, where the sweep message could
                      * potentially be replayed to re-enable sweeping ability.
                      */
                    bytes32 public sweepMsg;
                
                    /** @dev  The mapping that stores whether the address in question has
                      * enabled sweeping its contents to another account or not.
                      * If an address maps to "true", it has already enabled sweeping,
                      * and thus does not need to re-sign the `sweepMsg` to enact the sweep.
                      */
                    mapping (address => bool) public sweptSet;
                
                    /// @dev  The map of lock ids to pending token increases.
                    mapping (bytes32 => PendingPrint) public pendingPrintMap;
                
                    // CONSTRUCTOR
                    function ERC20Impl(
                          address _erc20Proxy,
                          address _erc20Store,
                          address _custodian,
                          address _sweeper
                    )
                        CustodianUpgradeable(_custodian)
                        public
                    {
                        require(_sweeper != 0);
                        erc20Proxy = ERC20Proxy(_erc20Proxy);
                        erc20Store = ERC20Store(_erc20Store);
                
                        sweeper = _sweeper;
                        sweepMsg = keccak256(address(this), "sweep");
                    }
                
                    // MODIFIERS
                    modifier onlyProxy {
                        require(msg.sender == address(erc20Proxy));
                        _;
                    }
                    modifier onlySweeper {
                        require(msg.sender == sweeper);
                        _;
                    }
                
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        erc20Store.setAllowance(_sender, _spender, _value);
                        erc20Proxy.emitApproval(_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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance + _addedValue;
                
                        require(newAllowance >= currentAllowance);
                
                        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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance - _subtractedValue;
                
                        require(newAllowance <= currentAllowance);
                
                        erc20Store.setAllowance(_sender, _spender, newAllowance);
                        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
                        return true;
                    }
                
                    /** @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) public returns (bytes32 lockId) {
                        require(_receiver != address(0));
                
                        lockId = generateLockId();
                
                        pendingPrintMap[lockId] = PendingPrint({
                            receiver: _receiver,
                            value: _value
                        });
                
                        emit PrintingLocked(lockId, _receiver, _value);
                    }
                
                    /** @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) public 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));
                        uint256 value = print.value;
                
                        delete pendingPrintMap[_lockId];
                
                        uint256 supply = erc20Store.totalSupply();
                        uint256 newSupply = supply + value;
                        if (newSupply >= supply) {
                          erc20Store.setTotalSupply(newSupply);
                          erc20Store.addBalance(receiver, value);
                
                          emit PrintingConfirmed(_lockId, receiver, value);
                          erc20Proxy.emitTransfer(address(0), receiver, value);
                        }
                    }
                
                    /** @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) public returns (bool success) {
                        uint256 balanceOfSender = erc20Store.balances(msg.sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(msg.sender, balanceOfSender - _value);
                        erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
                
                        erc20Proxy.emitTransfer(msg.sender, address(0), _value);
                
                        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[] _tos, uint256[] _values) public returns (bool success) {
                        require(_tos.length == _values.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));
                          uint256 v = _values[i];
                          require(senderBalance >= v);
                
                          if (msg.sender != to) {
                            senderBalance -= v;
                            erc20Store.addBalance(to, v);
                          }
                          erc20Proxy.emitTransfer(msg.sender, to, v);
                        }
                
                        erc20Store.setBalance(msg.sender, senderBalance);
                
                        return true;
                    }
                
                    /** @notice  Enables the delegation of transfer control for many
                      * accounts to the sweeper account, transferring any balances
                      * as well to the given destination.
                      *
                      * @dev  An account delegates transfer control by signing the
                      * value of `sweepMsg`. The sweeper account is the only authorized
                      * caller of this function, so it must relay signatures on behalf
                      * of accounts that delegate transfer control to it. Enabling
                      * delegation is idempotent and permanent. If the account has a
                      * balance at the time of enabling delegation, its balance is
                      * also transfered to the given destination account `_to`.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _vs  The array of recovery byte components of the ECDSA signatures.
                      * @param  _rs  The array of 'R' components of the ECDSA signatures.
                      * @param  _ss  The array of 'S' components of the ECDSA signatures.
                      * @param  _to  The destination for swept balances.
                      */
                    function enableSweep(uint8[] _vs, bytes32[] _rs, bytes32[] _ss, address _to) public onlySweeper {
                        require(_to != address(0));
                        require((_vs.length == _rs.length) && (_vs.length == _ss.length));
                
                        uint256 numSignatures = _vs.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<numSignatures; ++i) {
                          address from = ecrecover(sweepMsg, _vs[i], _rs[i], _ss[i]);
                
                          // ecrecover returns 0 on malformed input
                          if (from != address(0)) {
                            sweptSet[from] = true;
                
                            uint256 fromBalance = erc20Store.balances(from);
                
                            if (fromBalance > 0) {
                              sweptBalance += fromBalance;
                
                              erc20Store.setBalance(from, 0);
                
                              erc20Proxy.emitTransfer(from, _to, fromBalance);
                            }
                          }
                        }
                
                        if (sweptBalance > 0) {
                          erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @notice  For accounts that have delegated, transfer control
                      * to the sweeper, this function transfers their balances to the given
                      * destination.
                      *
                      * @dev The sweeper account is the only authorized caller of
                      * this function. This function accepts an array of addresses to have their
                      * balances transferred for gas efficiency purposes.
                      * NOTE: any address for an account that has not been previously enabled
                      * will be ignored.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _froms  The addresses to have their balances swept.
                      * @param  _to  The destination address of all these transfers.
                      */
                    function replaySweep(address[] _froms, address _to) public onlySweeper {
                        require(_to != address(0));
                        uint256 lenFroms = _froms.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<lenFroms; ++i) {
                            address from = _froms[i];
                
                            if (sweptSet[from]) {
                                uint256 fromBalance = erc20Store.balances(from);
                
                                if (fromBalance > 0) {
                                    sweptBalance += fromBalance;
                
                                    erc20Store.setBalance(from, 0);
                
                                    erc20Proxy.emitTransfer(from, _to, fromBalance);
                                }
                            }
                        }
                
                        if (sweptBalance > 0) {
                            erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfFrom = erc20Store.balances(_from);
                        require(_value <= balanceOfFrom);
                
                        uint256 senderAllowance = erc20Store.allowed(_from, _sender);
                        require(_value <= senderAllowance);
                
                        erc20Store.setBalance(_from, balanceOfFrom - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Store.setAllowance(_from, _sender, senderAllowance - _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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfSender = erc20Store.balances(_sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(_sender, balanceOfSender - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Proxy.emitTransfer(_sender, _to, _value);
                
                        return true;
                    }
                
                    // METHODS (ERC20 sub interface impl.)
                    /// @notice  Core logic of the ERC20 `totalSupply` function.
                    function totalSupply() public view returns (uint256) {
                        return erc20Store.totalSupply();
                    }
                
                    /// @notice  Core logic of the ERC20 `balanceOf` function.
                    function balanceOf(address _owner) public view returns (uint256 balance) {
                        return erc20Store.balances(_owner);
                    }
                
                    /// @notice  Core logic of the ERC20 `allowance` function.
                    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
                        return erc20Store.allowed(_owner, _spender);
                    }
                
                    // EVENTS
                    /// @dev  Emitted by successful `requestPrint` calls.
                    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value);
                    /// @dev Emitted by successful `confirmPrint` calls.
                    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);
                }
                
                
                /** @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;
                
                    // CONSTRUCTOR
                    function ERC20Store(address _custodian) ERC20ImplUpgradeable(_custodian) public {
                        totalSupply = 0;
                    }
                
                
                    // PUBLIC FUNCTIONS
                    // (ERC20 Ledger)
                
                    /** @notice  The function to set the total supply of tokens.
                      *
                      * @dev  Intended for use by token implementation functions
                      * that update the total supply. The only authorized caller
                      * is the active implementation.
                      *
                      * @param _newTotalSupply the value to set as the new total supply
                      */
                    function setTotalSupply(
                        uint256 _newTotalSupply
                    )
                        public
                        onlyImpl
                    {
                        totalSupply = _newTotalSupply;
                    }
                
                    /** @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
                    )
                        public
                        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
                    )
                        public
                        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
                    )
                        public
                        onlyImpl
                    {
                        balances[_owner] = balances[_owner] + _balanceIncrease;
                    }
                }

                File 5 of 5: ERC20Store
                pragma solidity ^0.4.21;
                
                /** @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
                  */
                contract LockRequestable {
                
                    // MEMBERS
                    /// @notice  the count of all invocations of `generateLockId`.
                    uint256 public lockRequestCount;
                
                    // CONSTRUCTOR
                    function LockRequestable() public {
                        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 a 32-byte unique identifier.
                      */
                    function generateLockId() internal returns (bytes32 lockId) {
                        return keccak256(block.blockhash(block.number - 1), address(this), ++lockRequestCount);
                    }
                }
                
                
                /** @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
                  */
                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
                    function CustodianUpgradeable(
                        address _custodian
                    )
                      LockRequestable()
                      public
                    {
                        custodian = _custodian;
                    }
                
                    // MODIFIERS
                    modifier onlyCustodian {
                        require(msg.sender == custodian);
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedCustodian != address(0));
                
                        lockId = generateLockId();
                
                        custodianChangeReqs[lockId] = CustodianChangeRequest({
                            proposedNew: _proposedCustodian
                        });
                
                        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);
                    }
                
                    /** @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) public 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 != 0);
                
                        return changeRequest.proposedNew;
                    }
                
                    /// @dev  Emitted by successful `requestCustodianChange` calls.
                    event CustodianChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedCustodian
                    );
                
                    /// @dev Emitted by successful `confirmCustodianChange` calls.
                    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);
                }
                
                
                /** @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
                  */
                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
                    function ERC20ImplUpgradeable(address _custodian) CustodianUpgradeable(_custodian) public {
                        erc20Impl = ERC20Impl(0x0);
                    }
                
                    // MODIFIERS
                    modifier onlyImpl {
                        require(msg.sender == address(erc20Impl));
                        _;
                    }
                
                    // 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) public returns (bytes32 lockId) {
                        require(_proposedImpl != address(0));
                
                        lockId = generateLockId();
                
                        implChangeReqs[lockId] = ImplChangeRequest({
                            proposedNew: _proposedImpl
                        });
                
                        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);
                    }
                
                    /** @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) public 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));
                
                        return ERC20Impl(changeRequest.proposedNew);
                    }
                
                    /// @dev  Emitted by successful `requestImplChange` calls.
                    event ImplChangeRequested(
                        bytes32 _lockId,
                        address _msgSender,
                        address _proposedImpl
                    );
                
                    /// @dev Emitted by successful `confirmImplChange` calls.
                    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);
                }
                
                
                contract 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() public view returns (uint256);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof
                  function balanceOf(address _owner) public view returns (uint256 balance);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer
                  function transfer(address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom
                  function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve
                  function approve(address _spender, uint256 _value) public returns (bool success);
                
                  // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance
                  function allowance(address _owner, address _spender) public 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);
                }
                
                
                /** @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 {
                
                    // MEMBERS
                    /// @notice  Returns the name of the token.
                    string public name;
                
                    /// @notice  Returns the symbol of the token.
                    string public symbol;
                
                    /// @notice  Returns the number of decimals the token uses.
                    uint8 public decimals;
                
                    // CONSTRUCTOR
                    function ERC20Proxy(
                        string _name,
                        string _symbol,
                        uint8 _decimals,
                        address _custodian
                    )
                        ERC20ImplUpgradeable(_custodian)
                        public
                    {
                        name = _name;
                        symbol = _symbol;
                        decimals = _decimals;
                    }
                
                    // PUBLIC FUNCTIONS
                    // (ERC20Interface)
                    /** @notice  Returns the total token supply.
                      *
                      * @return  the total token supply.
                      */
                    function totalSupply() public 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) public view returns (uint256 balance) {
                        return erc20Impl.balanceOf(_owner);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitTransfer(address _from, address _to, uint256 _value) public 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) public 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) public returns (bool success) {
                        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);
                    }
                
                    /** @dev Internal use only.
                      */
                    function emitApproval(address _owner, address _spender, uint256 _value) public 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) public 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) public 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) public 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) public view returns (uint256 remaining) {
                        return erc20Impl.allowance(_owner, _spender);
                    }
                }
                
                
                /** @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;
                    }
                
                    // MEMBERS
                    /// @dev  The reference to the proxy.
                    ERC20Proxy public erc20Proxy;
                
                    /// @dev  The reference to the store.
                    ERC20Store public erc20Store;
                
                    /// @dev  The sole authorized caller of delegated transfer control ('sweeping').
                    address public sweeper;
                
                    /** @dev  The static message to be signed by an external account that
                      * signifies their permission to forward their balance to any arbitrary
                      * address. This is used to consolidate the control of all accounts
                      * backed by a shared keychain into the control of a single key.
                      * Initialized as the concatenation of the address of this contract
                      * and the word "sweep". This concatenation is done to prevent a replay
                      * attack in a subsequent contract, where the sweep message could
                      * potentially be replayed to re-enable sweeping ability.
                      */
                    bytes32 public sweepMsg;
                
                    /** @dev  The mapping that stores whether the address in question has
                      * enabled sweeping its contents to another account or not.
                      * If an address maps to "true", it has already enabled sweeping,
                      * and thus does not need to re-sign the `sweepMsg` to enact the sweep.
                      */
                    mapping (address => bool) public sweptSet;
                
                    /// @dev  The map of lock ids to pending token increases.
                    mapping (bytes32 => PendingPrint) public pendingPrintMap;
                
                    // CONSTRUCTOR
                    function ERC20Impl(
                          address _erc20Proxy,
                          address _erc20Store,
                          address _custodian,
                          address _sweeper
                    )
                        CustodianUpgradeable(_custodian)
                        public
                    {
                        require(_sweeper != 0);
                        erc20Proxy = ERC20Proxy(_erc20Proxy);
                        erc20Store = ERC20Store(_erc20Store);
                
                        sweeper = _sweeper;
                        sweepMsg = keccak256(address(this), "sweep");
                    }
                
                    // MODIFIERS
                    modifier onlyProxy {
                        require(msg.sender == address(erc20Proxy));
                        _;
                    }
                    modifier onlySweeper {
                        require(msg.sender == sweeper);
                        _;
                    }
                
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        erc20Store.setAllowance(_sender, _spender, _value);
                        erc20Proxy.emitApproval(_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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance + _addedValue;
                
                        require(newAllowance >= currentAllowance);
                
                        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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_spender != address(0)); // disallow unspendable approvals
                        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
                        uint256 newAllowance = currentAllowance - _subtractedValue;
                
                        require(newAllowance <= currentAllowance);
                
                        erc20Store.setAllowance(_sender, _spender, newAllowance);
                        erc20Proxy.emitApproval(_sender, _spender, newAllowance);
                        return true;
                    }
                
                    /** @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) public returns (bytes32 lockId) {
                        require(_receiver != address(0));
                
                        lockId = generateLockId();
                
                        pendingPrintMap[lockId] = PendingPrint({
                            receiver: _receiver,
                            value: _value
                        });
                
                        emit PrintingLocked(lockId, _receiver, _value);
                    }
                
                    /** @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) public 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));
                        uint256 value = print.value;
                
                        delete pendingPrintMap[_lockId];
                
                        uint256 supply = erc20Store.totalSupply();
                        uint256 newSupply = supply + value;
                        if (newSupply >= supply) {
                          erc20Store.setTotalSupply(newSupply);
                          erc20Store.addBalance(receiver, value);
                
                          emit PrintingConfirmed(_lockId, receiver, value);
                          erc20Proxy.emitTransfer(address(0), receiver, value);
                        }
                    }
                
                    /** @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) public returns (bool success) {
                        uint256 balanceOfSender = erc20Store.balances(msg.sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(msg.sender, balanceOfSender - _value);
                        erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
                
                        erc20Proxy.emitTransfer(msg.sender, address(0), _value);
                
                        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[] _tos, uint256[] _values) public returns (bool success) {
                        require(_tos.length == _values.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));
                          uint256 v = _values[i];
                          require(senderBalance >= v);
                
                          if (msg.sender != to) {
                            senderBalance -= v;
                            erc20Store.addBalance(to, v);
                          }
                          erc20Proxy.emitTransfer(msg.sender, to, v);
                        }
                
                        erc20Store.setBalance(msg.sender, senderBalance);
                
                        return true;
                    }
                
                    /** @notice  Enables the delegation of transfer control for many
                      * accounts to the sweeper account, transferring any balances
                      * as well to the given destination.
                      *
                      * @dev  An account delegates transfer control by signing the
                      * value of `sweepMsg`. The sweeper account is the only authorized
                      * caller of this function, so it must relay signatures on behalf
                      * of accounts that delegate transfer control to it. Enabling
                      * delegation is idempotent and permanent. If the account has a
                      * balance at the time of enabling delegation, its balance is
                      * also transfered to the given destination account `_to`.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _vs  The array of recovery byte components of the ECDSA signatures.
                      * @param  _rs  The array of 'R' components of the ECDSA signatures.
                      * @param  _ss  The array of 'S' components of the ECDSA signatures.
                      * @param  _to  The destination for swept balances.
                      */
                    function enableSweep(uint8[] _vs, bytes32[] _rs, bytes32[] _ss, address _to) public onlySweeper {
                        require(_to != address(0));
                        require((_vs.length == _rs.length) && (_vs.length == _ss.length));
                
                        uint256 numSignatures = _vs.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<numSignatures; ++i) {
                          address from = ecrecover(sweepMsg, _vs[i], _rs[i], _ss[i]);
                
                          // ecrecover returns 0 on malformed input
                          if (from != address(0)) {
                            sweptSet[from] = true;
                
                            uint256 fromBalance = erc20Store.balances(from);
                
                            if (fromBalance > 0) {
                              sweptBalance += fromBalance;
                
                              erc20Store.setBalance(from, 0);
                
                              erc20Proxy.emitTransfer(from, _to, fromBalance);
                            }
                          }
                        }
                
                        if (sweptBalance > 0) {
                          erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @notice  For accounts that have delegated, transfer control
                      * to the sweeper, this function transfers their balances to the given
                      * destination.
                      *
                      * @dev The sweeper account is the only authorized caller of
                      * this function. This function accepts an array of addresses to have their
                      * balances transferred for gas efficiency purposes.
                      * NOTE: any address for an account that has not been previously enabled
                      * will be ignored.
                      * NOTE: transfers to the zero address are disallowed.
                      *
                      * @param  _froms  The addresses to have their balances swept.
                      * @param  _to  The destination address of all these transfers.
                      */
                    function replaySweep(address[] _froms, address _to) public onlySweeper {
                        require(_to != address(0));
                        uint256 lenFroms = _froms.length;
                        uint256 sweptBalance = 0;
                
                        for (uint256 i=0; i<lenFroms; ++i) {
                            address from = _froms[i];
                
                            if (sweptSet[from]) {
                                uint256 fromBalance = erc20Store.balances(from);
                
                                if (fromBalance > 0) {
                                    sweptBalance += fromBalance;
                
                                    erc20Store.setBalance(from, 0);
                
                                    erc20Proxy.emitTransfer(from, _to, fromBalance);
                                }
                            }
                        }
                
                        if (sweptBalance > 0) {
                            erc20Store.addBalance(_to, sweptBalance);
                        }
                    }
                
                    /** @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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfFrom = erc20Store.balances(_from);
                        require(_value <= balanceOfFrom);
                
                        uint256 senderAllowance = erc20Store.allowed(_from, _sender);
                        require(_value <= senderAllowance);
                
                        erc20Store.setBalance(_from, balanceOfFrom - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Store.setAllowance(_from, _sender, senderAllowance - _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
                    )
                        public
                        onlyProxy
                        returns (bool success)
                    {
                        require(_to != address(0)); // ensure burn is the cannonical transfer to 0x0
                
                        uint256 balanceOfSender = erc20Store.balances(_sender);
                        require(_value <= balanceOfSender);
                
                        erc20Store.setBalance(_sender, balanceOfSender - _value);
                        erc20Store.addBalance(_to, _value);
                
                        erc20Proxy.emitTransfer(_sender, _to, _value);
                
                        return true;
                    }
                
                    // METHODS (ERC20 sub interface impl.)
                    /// @notice  Core logic of the ERC20 `totalSupply` function.
                    function totalSupply() public view returns (uint256) {
                        return erc20Store.totalSupply();
                    }
                
                    /// @notice  Core logic of the ERC20 `balanceOf` function.
                    function balanceOf(address _owner) public view returns (uint256 balance) {
                        return erc20Store.balances(_owner);
                    }
                
                    /// @notice  Core logic of the ERC20 `allowance` function.
                    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {
                        return erc20Store.allowed(_owner, _spender);
                    }
                
                    // EVENTS
                    /// @dev  Emitted by successful `requestPrint` calls.
                    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value);
                    /// @dev Emitted by successful `confirmPrint` calls.
                    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);
                }
                
                
                /** @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;
                
                    // CONSTRUCTOR
                    function ERC20Store(address _custodian) ERC20ImplUpgradeable(_custodian) public {
                        totalSupply = 0;
                    }
                
                
                    // PUBLIC FUNCTIONS
                    // (ERC20 Ledger)
                
                    /** @notice  The function to set the total supply of tokens.
                      *
                      * @dev  Intended for use by token implementation functions
                      * that update the total supply. The only authorized caller
                      * is the active implementation.
                      *
                      * @param _newTotalSupply the value to set as the new total supply
                      */
                    function setTotalSupply(
                        uint256 _newTotalSupply
                    )
                        public
                        onlyImpl
                    {
                        totalSupply = _newTotalSupply;
                    }
                
                    /** @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
                    )
                        public
                        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
                    )
                        public
                        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
                    )
                        public
                        onlyImpl
                    {
                        balances[_owner] = balances[_owner] + _balanceIncrease;
                    }
                }