ETH Price: $1,989.92 (+0.96%)

Transaction Decoder

Block:
8078796 at Jul-03-2019 01:50:33 PM +UTC
Transaction Fee:
0.00126645 ETH $2.52
Gas Used:
84,430 Gas / 15 Gwei

Account State Difference:

  Address   Before After State Difference Code
0x2Abf9f75...81Cc555ED
(Celsius Network: Deployer)
6.439924731855184498 Eth
Nonce: 46082
6.438658281855184498 Eth
Nonce: 46083
0.00126645
0x32A3256a...4d925a5CF
(Celsius Network: Contract)
(Spark Pool)
3,051.156694458479000598 Eth3,051.157960908479000598 Eth0.00126645
0xc42B14e4...af35e68a0

Execution Trace

Celsius Network: Contract.0dcd7a6c( )
  • Null: 0x000...001.075856f1( )
  • ERC20Proxy.transfer( _to=0x60A55F6709C30BabEf694396f11cC2c843D8B398, _value=119904 ) => ( success=True )
    • ERC20Impl.transferWithSender( _sender=0x32A3256a4b15BadD4a6e072A03d23404d925a5CF, _to=0x60A55F6709C30BabEf694396f11cC2c843D8B398, _value=119904 ) => ( success=True )
      • ERC20Store.balances( 0x32A3256a4b15BadD4a6e072A03d23404d925a5CF ) => ( 119904 )
      • ERC20Store.setBalance( _owner=0x32A3256a4b15BadD4a6e072A03d23404d925a5CF, _newBalance=0 )
      • ERC20Store.addBalance( _owner=0x60A55F6709C30BabEf694396f11cC2c843D8B398, _balanceIncrease=119904 )
      • ERC20Proxy.emitTransfer( _from=0x32A3256a4b15BadD4a6e072A03d23404d925a5CF, _to=0x60A55F6709C30BabEf694396f11cC2c843D8B398, _value=119904 )
        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;
            }
        }