ETH Price: $2,493.95 (+2.27%)

Transaction Decoder

Block:
12694823 at Jun-24-2021 04:45:19 AM +UTC
Transaction Fee:
0.000338892 ETH $0.85
Gas Used:
56,482 Gas / 6 Gwei

Account State Difference:

  Address   Before After State Difference Code
(zhizhu.top)
722.069927773344514756 Eth722.070266665344514756 Eth0.000338892
0x4629C3ac...5882d56Ed
0.112259343 Eth
Nonce: 9
0.111920451 Eth
Nonce: 10
0.000338892
0xc42B14e4...af35e68a0

Execution Trace

ERC20Proxy.transfer( _to=0x419CeDd4c1790B90887d135eA505a2104Ca76D3E, _value=507500 ) => ( success=True )
  • ERC20Impl.transferWithSender( _sender=0x4629C3acC568Be227D19dC767F48Bd05882d56Ed, _to=0x419CeDd4c1790B90887d135eA505a2104Ca76D3E, _value=507500 ) => ( success=True )
    • ERC20Store.balances( 0x4629C3acC568Be227D19dC767F48Bd05882d56Ed ) => ( 507500 )
    • ERC20Store.setBalance( _owner=0x4629C3acC568Be227D19dC767F48Bd05882d56Ed, _newBalance=0 )
    • ERC20Store.addBalance( _owner=0x419CeDd4c1790B90887d135eA505a2104Ca76D3E, _balanceIncrease=507500 )
    • ERC20Proxy.emitTransfer( _from=0x4629C3acC568Be227D19dC767F48Bd05882d56Ed, _to=0x419CeDd4c1790B90887d135eA505a2104Ca76D3E, _value=507500 )
      transfer[ERC20Proxy (ln:370)]
      File 1 of 3: 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 2 of 3: 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 3 of 3: 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;
          }
      }