ETH Price: $2,271.27 (-7.00%)

Transaction Decoder

Block:
16355205 at Jan-07-2023 01:28:47 PM +UTC
Transaction Fee:
0.000950056852263558 ETH $2.16
Gas Used:
66,963 Gas / 14.187788066 Gwei

Emitted Events:

176 ERC20Proxy.Approval( _owner=[Sender] 0xc222f7d5c2cf5139d60e74ea69eff0e3bebcd471, _spender=0x11111112...90643097d, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 )

Account State Difference:

  Address   Before After State Difference Code
0x86c03684...3C9Be0B4a
0xC222f7D5...3bEBcd471
0.002856416604352624 Eth
Nonce: 2
0.001906359752089066 Eth
Nonce: 3
0.000950056852263558
(Flashbots: Builder)
1.235613492651155428 Eth1.235680455651155428 Eth0.000066963

Execution Trace

ERC20Proxy.approve( _spender=0x1111111254fb6c44bAC0beD2854e76F90643097d, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( success=True )
  • ERC20Impl.approveWithSender( _sender=0xC222f7D5c2cf5139D60E74Ea69eff0E3bEBcd471, _spender=0x1111111254fb6c44bAC0beD2854e76F90643097d, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 ) => ( success=True )
    • ERC20Store.setAllowance( _owner=0xC222f7D5c2cf5139D60E74Ea69eff0E3bEBcd471, _spender=0x1111111254fb6c44bAC0beD2854e76F90643097d, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
    • ERC20Proxy.emitApproval( _owner=0xC222f7D5c2cf5139D60E74Ea69eff0E3bEBcd471, _spender=0x1111111254fb6c44bAC0beD2854e76F90643097d, _value=115792089237316195423570985008687907853269984665640564039457584007913129639935 )
      File 1 of 3: ERC20Proxy
      {"callbackSelector.sol":{"content":"pragma solidity ^0.5.10;\n\n/**\n  * @title contract for generating HEX pointer\n  * for functions.\n  *\n  * @dev this contract is a tool meant to be used\n  * on local JavaScript VM.\n  *\n  */\ncontract callbackSelector {\n\n    /**\n      * @notice function which returns function HEX pointer (callbackSelector)\n      *\n      * @param _function function name with parameter types. Case and whitespace sensitive.\n      *\n      * @dev example: `function get(string memory _function)`\n      *    _function: `get(string)`\n      *       result: `0x693ec85e`\n      */\n    function get(string memory _function) public pure returns (bytes4) {\n        return bytes4(keccak256(abi.encodePacked(_function)));\n    }\n}"},"source.sol":{"content":"pragma solidity ^0.5.10;\n\n/** @title  A contract for generating unique identifiers\n  *\n  * @notice  A contract that provides an identifier generation scheme,\n  * guaranteeing uniqueness across all contracts that inherit from it,\n  * as well as the unpredictability of future identifiers.\n  *\n  * @dev  This contract is intended to be inherited by any contract that\n  * implements the callback software pattern for cooperative custodianship.\n  *\n*/\ncontract LockRequestable {\n\n    // MEMBERS\n    /// @notice  the count of all invocations of `generateLockId`.\n    uint256 public lockRequestCount;\n\n    // CONSTRUCTOR\n    constructor() public {\n        lockRequestCount = 0;\n    }\n\n    // FUNCTIONS\n    /** @notice  Returns a fresh unique identifier.\n      *\n      * @dev the generation scheme uses three components.\n      * First, the blockhash of the previous block.\n      * Second, the deployed address.\n      * Third, the next value of the counter.\n      * This ensures that identifiers are unique across all contracts\n      * following this scheme, and that future identifiers are\n      * unpredictable.\n      *\n      * @return a 32-byte unique identifier.\n    */\n    function generateLockId() internal returns (bytes32 lockId) {\n        return keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), ++lockRequestCount));\n    }\n}\n\ncontract ERC20Interface {\n\n    // METHODS\n\n    // NOTE:\n    //   public getter functions are not currently recognised as an\n    //   implementation of the matching abstract function by the compiler.\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#name\n    // function name() public view returns (string);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#symbol\n    // function symbol() public view returns (string);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply\n    // function decimals() public view returns (uint8);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#totalsupply\n    function totalSupply() public view returns (uint256);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#balanceof\n    function balanceOf(address _owner) public view returns (uint256 balance);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer\n    function transfer(address _to, uint256 _value) public returns (bool success);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transferfrom\n    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approve\n    function approve(address _spender, uint256 _value) public returns (bool success);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#allowance\n    function allowance(address _owner, address _spender) public view returns (uint256 remaining);\n\n    // EVENTS\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#transfer-1\n    event Transfer(address indexed _from, address indexed _to, uint256 _value);\n\n    // https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md#approval\n    event Approval(address indexed _owner, address indexed _spender, uint256 _value);\n}\n\n/** @title  A dual control contract.\n  *\n  * @notice  A general-purpose contract that implements dual control over\n  * co-operating contracts through a callback mechanism.\n  *\n  * @dev  This contract implements dual control through a 2-of-N\n  * threshold multi-signature scheme. The contract recognizes a set of N signers,\n  * and will unlock requests with signatures from any distinct pair of them.\n  * This contract signals the unlocking through a co-operative callback\n  * scheme.\n  * This contract also provides time lock and revocation features.\n  * Requests made by a \u0027primary\u0027 account have a default time lock applied.\n  * All other requests must pay a 1 ETH stake and have an extended time lock\n  * applied.\n  * A request that is completed will prevent all previous pending requests\n  * that share the same callback from being completed: this is the\n  * revocation feature.\n  *\n  */\ncontract Custodian {\n\n    // TYPES\n    /** @dev  The `Request` struct stores a pending unlocking.\n      * `callbackAddress` and `callbackSelector` are the data required to\n      * make a callback. The custodian completes the process by\n      * calling `callbackAddress.call(callbackSelector, lockId)`, which\n      * signals to the contract co-operating with the Custodian that\n      * the 2-of-N signatures have been provided and verified.\n      */\n    struct Request {\n        bytes32 lockId;\n        bytes4 callbackSelector;  // bytes4 and address can be packed into 1 word\n        address callbackAddress;\n        uint256 idx;\n        uint256 timestamp;\n        bool extended;\n    }\n\n    // EVENTS\n    /// @dev  Emitted by successful `requestUnlock` calls.\n    event Requested(\n        bytes32 _lockId,\n        address _callbackAddress,\n        bytes4 _callbackSelector,\n        uint256 _nonce,\n        address _whitelistedAddress,\n        bytes32 _requestMsgHash,\n        uint256 _timeLockExpiry\n    );\n\n    /// @dev  Emitted by `completeUnlock` calls on requests in the time-locked state.\n    event TimeLocked(\n        uint256 _timeLockExpiry,\n        bytes32 _requestMsgHash\n    );\n\n    /// @dev  Emitted by successful `completeUnlock` calls.\n    event Completed(\n        bytes32 _lockId,\n        bytes32 _requestMsgHash,\n        address _signer1,\n        address _signer2\n    );\n\n    /// @dev  Emitted by `completeUnlock` calls where the callback failed.\n    event Failed(\n        bytes32 _lockId,\n        bytes32 _requestMsgHash,\n        address _signer1,\n        address _signer2\n    );\n\n    /// @dev  Emitted by successful `extendRequestTimeLock` calls.\n    event TimeLockExtended(\n        uint256 _timeLockExpiry,\n        bytes32 _requestMsgHash\n    );\n\n     // MEMBERS\n    /** @dev  The count of all requests.\n      * This value is used as a nonce, incorporated into the request hash.\n      */\n    uint256 public requestCount;\n\n    /// @dev  The set of signers: signatures from two signers unlock a pending request.\n    mapping (address =\u003e bool) public signerSet;\n\n    /// @dev  The map of request hashes to pending requests.\n    mapping (bytes32 =\u003e Request) public requestMap;\n\n    /// @dev  The map of callback addresses to callback selectors to request indexes.\n    mapping (address =\u003e mapping (bytes4 =\u003e uint256)) public lastCompletedIdxs;\n\n    /** @dev  The default period (in seconds) to time-lock requests.\n      * All requests will be subject to this default time lock, and the duration\n      * is fixed at contract creation.\n      */\n    uint256 public defaultTimeLock;\n\n    /** @dev  The extended period (in seconds) to time-lock requests.\n      * Requests not from the primary account are subject to this time lock.\n      * The primary account may also elect to extend the time lock on requests\n      * that originally received the default.\n      */\n    uint256 public extendedTimeLock;\n\n    /// @dev  The primary account is the privileged account for making requests.\n    address public primary;\n\n    // CONSTRUCTOR\n    constructor(\n        address[] memory _signers,\n        uint256 _defaultTimeLock,\n        uint256 _extendedTimeLock,\n        address _primary\n    )\n        public\n    {\n        // check for at least two `_signers`\n        require(_signers.length \u003e= 2, \"at least two `_signers`\");\n\n         // validate time lock params\n        require(_defaultTimeLock \u003c= _extendedTimeLock, \"valid timelock params\");\n        defaultTimeLock = _defaultTimeLock;\n        extendedTimeLock = _extendedTimeLock;\n\n        primary = _primary;\n\n        // explicitly initialize `requestCount` to zero\n        requestCount = 0;\n        // turn the array into a set\n        for (uint i = 0; i \u003c _signers.length; i++) {\n            // no zero addresses or duplicates\n            require(_signers[i] != address(0) \u0026\u0026 !signerSet[_signers[i]], \"no zero addresses or duplicates\");\n            signerSet[_signers[i]] = true;\n        }\n    }\n\n    // MODIFIERS\n    modifier onlyPrimary {\n        require(msg.sender == primary, \"only primary\");\n        _;\n    }\n\n     modifier onlySigner {\n        require(signerSet[msg.sender], \"only signer\");\n        _;\n    }\n\n    // METHODS\n    /** @notice  Requests an unlocking with a lock identifier and a callback.\n      *\n      * @dev  If called by an account other than the primary a 1 ETH stake\n      * must be paid. When the request is unlocked stake will be transferred to the message sender.\n      * This is an anti-spam measure. As well as the callback\n      * and the lock identifier parameters a \u0027whitelisted address\u0027 is required\n      * for compatibility with existing signature schemes.\n      *\n      * @param  _lockId  The identifier of a pending request in a co-operating contract.\n      * @param  _callbackAddress  The address of a co-operating contract.\n      * @param  _callbackSelector  The function selector of a function within\n      * the co-operating contract at address `_callbackAddress`.\n      * @param  _whitelistedAddress  An address whitelisted in existing\n      * offline control protocols.\n      *\n      * @return  requestMsgHash  The hash of a request message to be signed.\n    */\n    function requestUnlock(\n        bytes32 _lockId,\n        address _callbackAddress,\n        bytes4 _callbackSelector,\n        address _whitelistedAddress\n    )\n        public\n        payable\n        returns (bytes32 requestMsgHash)\n    {\n        require(msg.sender == primary || msg.value \u003e= 1 ether, \"sender is primary or stake is paid\");\n\n        // disallow using a zero value for the callback address\n        require(_callbackAddress != address(0), \"no zero value for callback address\");\n\n        uint256 requestIdx = ++requestCount;\n        // compute a nonce value\n        // - the blockhash prevents prediction of future nonces\n        // - the address of this contract prevents conflicts with co-operating contracts using this scheme\n        // - the counter prevents conflicts arising from multiple txs within the same block\n        uint256 nonce = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), requestIdx)));\n\n        requestMsgHash = keccak256(\n            abi.encodePacked(\n                nonce,\n                _whitelistedAddress,\n                uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)\n            )\n        );\n        requestMap[requestMsgHash] = Request({\n            lockId: _lockId,\n            callbackSelector: _callbackSelector,\n            callbackAddress: _callbackAddress,\n            idx: requestIdx,\n            timestamp: block.timestamp,\n            extended: false\n        });\n\n        // compute the expiry time\n        uint256 timeLockExpiry = block.timestamp;\n        if (msg.sender == primary) {\n            timeLockExpiry += defaultTimeLock;\n        } else {\n            timeLockExpiry += extendedTimeLock;\n\n            // any sender that is not the creator will get the extended time lock\n            requestMap[requestMsgHash].extended = true;\n        }\n\n        emit Requested(_lockId, _callbackAddress, _callbackSelector, nonce, _whitelistedAddress, requestMsgHash, timeLockExpiry);\n    }\n\n    /** @notice  Completes a pending unlocking with two signatures.\n      *\n      * @dev  Given a request message hash as two signatures of it from\n      * two distinct signers in the signer set, this function completes the\n      * unlocking of the pending request by executing the callback.\n      *\n      * @param  _requestMsgHash  The request message hash of a pending request.\n      * @param  _recoveryByte1  The public key recovery byte (27 or 28)\n      * @param  _ecdsaR1  The R component of an ECDSA signature (R, S) pair\n      * @param  _ecdsaS1  The S component of an ECDSA signature (R, S) pair\n      * @param  _recoveryByte2  The public key recovery byte (27 or 28)\n      * @param  _ecdsaR2  The R component of an ECDSA signature (R, S) pair\n      * @param  _ecdsaS2  The S component of an ECDSA signature (R, S) pair\n      *\n      * @return  success  True if the callback successfully executed.\n    */\n    function completeUnlock(\n        bytes32 _requestMsgHash,\n        uint8 _recoveryByte1, bytes32 _ecdsaR1, bytes32 _ecdsaS1,\n        uint8 _recoveryByte2, bytes32 _ecdsaR2, bytes32 _ecdsaS2\n    )\n        public\n        onlySigner\n        returns (bool success)\n    {\n        Request storage request = requestMap[_requestMsgHash];\n\n        // copy storage to locals before `delete`\n        bytes32 lockId = request.lockId;\n        address callbackAddress = request.callbackAddress;\n        bytes4 callbackSelector = request.callbackSelector;\n\n        // failing case of the lookup if the callback address is zero\n        require(callbackAddress != address(0), \"no zero value for callback address\");\n\n        // reject confirms of earlier withdrawals buried under later confirmed withdrawals\n        require(request.idx \u003e lastCompletedIdxs[callbackAddress][callbackSelector],\n        \"reject confirms of earlier withdrawals buried under later confirmed withdrawals\");\n\n        address signer1 = ecrecover(\n            keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", _requestMsgHash)),\n            _recoveryByte1,\n            _ecdsaR1,\n            _ecdsaS1\n        );\n        require(signerSet[signer1], \"signer is set\");\n\n        address signer2 = ecrecover(\n            keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\", _requestMsgHash)),\n            _recoveryByte2,\n            _ecdsaR2,\n            _ecdsaS2\n        );\n        require(signerSet[signer2], \"signer is set\");\n        require(signer1 != signer2, \"signers are different\");\n\n        if (request.extended \u0026\u0026 ((block.timestamp - request.timestamp) \u003c extendedTimeLock)) {\n            emit TimeLocked(request.timestamp + extendedTimeLock, _requestMsgHash);\n            return false;\n        } else if ((block.timestamp - request.timestamp) \u003c defaultTimeLock) {\n            emit TimeLocked(request.timestamp + defaultTimeLock, _requestMsgHash);\n            return false;\n        } else {\n            if (address(this).balance \u003e 0) {\n                // reward sender with anti-spam payments\n                msg.sender.transfer(address(this).balance);\n            }\n\n            // raise the waterline for the last completed unlocking\n            lastCompletedIdxs[callbackAddress][callbackSelector] = request.idx;\n            // and delete the request\n            delete requestMap[_requestMsgHash];\n\n            // invoke callback\n            (success,) = callbackAddress.call(abi.encodeWithSelector(callbackSelector, lockId));\n\n            if (success) {\n                emit Completed(lockId, _requestMsgHash, signer1, signer2);\n            } else {\n                emit Failed(lockId, _requestMsgHash, signer1, signer2);\n            }\n        }\n    }\n\n    /** @notice  Reclaim the storage of a pending request that is uncompletable.\n      *\n      * @dev  If a pending request shares the callback (address and selector) of\n      * a later request has been completed, then the request can no longer\n      * be completed. This function will reclaim the contract storage of the\n      * pending request.\n      *\n      * @param  _requestMsgHash  The request message hash of a pending request.\n    */\n    function deleteUncompletableRequest(bytes32 _requestMsgHash) public {\n        Request storage request = requestMap[_requestMsgHash];\n\n        uint256 idx = request.idx;\n\n        require(0 \u003c idx \u0026\u0026 idx \u003c lastCompletedIdxs[request.callbackAddress][request.callbackSelector],\n        \"there must be a completed latter request with same callback\");\n\n        delete requestMap[_requestMsgHash];\n    }\n\n    /** @notice  Extend the time lock of a pending request.\n      *\n      * @dev  Requests made by the primary account receive the default time lock.\n      * This function allows the primary account to apply the extended time lock\n      * to one its own requests.\n      *\n      * @param  _requestMsgHash  The request message hash of a pending request.\n    */\n    function extendRequestTimeLock(bytes32 _requestMsgHash) public onlyPrimary {\n        Request storage request = requestMap[_requestMsgHash];\n\n        // reject ‘null’ results from the map lookup\n        // this can only be the case if an unknown `_requestMsgHash` is received\n        require(request.callbackAddress != address(0), \"reject ‘null’ results from the map lookup\");\n\n        // `extendRequestTimeLock` must be idempotent\n        require(request.extended != true, \"`extendRequestTimeLock` must be idempotent\");\n\n        // set the `extended` flag; note that this is never unset\n        request.extended = true;\n\n        emit TimeLockExtended(request.timestamp + extendedTimeLock, _requestMsgHash);\n    }\n}\n\n/** @title  A contract to inherit upgradeable custodianship.\n  *\n  * @notice  A contract that provides re-usable code for upgradeable\n  * custodianship. That custodian may be an account or another contract.\n  *\n  * @dev  This contract is intended to be inherited by any contract\n  * requiring a custodian to control some aspect of its functionality.\n  * This contract provides the mechanism for that custodianship to be\n  * passed from one custodian to the next.\n  *\n*/\ncontract CustodianUpgradeable is LockRequestable {\n\n    // TYPES\n    /// @dev  The struct type for pending custodian changes.\n    struct CustodianChangeRequest {\n        address proposedNew;\n    }\n\n    // MEMBERS\n    /// @dev  The address of the account or contract that acts as the custodian.\n    address public custodian;\n\n    /// @dev  The map of lock ids to pending custodian changes.\n    mapping (bytes32 =\u003e CustodianChangeRequest) public custodianChangeReqs;\n\n    // CONSTRUCTOR\n    constructor(\n        address _custodian\n    )\n      LockRequestable()\n      public\n    {\n        custodian = _custodian;\n    }\n\n    // MODIFIERS\n    modifier onlyCustodian {\n        require(msg.sender == custodian, \"only custodian\");\n        _;\n    }\n\n    // PUBLIC FUNCTIONS\n    // (UPGRADE)\n\n    /** @notice  Requests a change of the custodian associated with this contract.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Anyone can call this function, but confirming the request is authorized\n      * by the custodian.\n      *\n      * @param  _proposedCustodian  The address of the new custodian.\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestCustodianChange(address _proposedCustodian) public returns (bytes32 lockId) {\n        require(_proposedCustodian != address(0), \"no null value for `_proposedCustodian`\");\n\n        lockId = generateLockId();\n\n        custodianChangeReqs[lockId] = CustodianChangeRequest({\n            proposedNew: _proposedCustodian\n        });\n\n        emit CustodianChangeRequested(lockId, msg.sender, _proposedCustodian);\n    }\n\n    /** @notice  Confirms a pending change of the custodian associated with this contract.\n      *\n      * @dev  When called by the current custodian with a lock id associated with a\n      * pending custodian change, the `address custodian` member will be updated with the\n      * requested address.\n      *\n      * @param  _lockId  The identifier of a pending change request.\n      */\n    function confirmCustodianChange(bytes32 _lockId) public onlyCustodian {\n        custodian = getCustodianChangeReq(_lockId);\n\n        delete custodianChangeReqs[_lockId];\n\n        emit CustodianChangeConfirmed(_lockId, custodian);\n    }\n\n    // PRIVATE FUNCTIONS\n    function getCustodianChangeReq(bytes32 _lockId) private view returns (address _proposedNew) {\n        CustodianChangeRequest storage changeRequest = custodianChangeReqs[_lockId];\n\n        // reject ‘null’ results from the map lookup\n        // this can only be the case if an unknown `_lockId` is received\n        require(changeRequest.proposedNew != address(0), \"reject ‘null’ results from the map lookup\");\n\n        return changeRequest.proposedNew;\n    }\n\n    //EVENTS\n    /// @dev  Emitted by successful `requestCustodianChange` calls.\n    event CustodianChangeRequested(\n        bytes32 _lockId,\n        address _msgSender,\n        address _proposedCustodian\n    );\n\n    /// @dev Emitted by successful `confirmCustodianChange` calls.\n    event CustodianChangeConfirmed(bytes32 _lockId, address _newCustodian);\n}\n\n/** @title  A contract to inherit upgradeable token implementations.\n  *\n  * @notice  A contract that provides re-usable code for upgradeable\n  * token implementations. It itself inherits from `CustodianUpgradable`\n  * as the upgrade process is controlled by the custodian.\n  *\n  * @dev  This contract is intended to be inherited by any contract\n  * requiring a reference to the active token implementation, either\n  * to delegate calls to it, or authorize calls from it. This contract\n  * provides the mechanism for that implementation to be replaced,\n  * which constitutes an implementation upgrade.\n  *\n  */\ncontract ERC20ImplUpgradeable is CustodianUpgradeable  {\n\n    // TYPES\n    /// @dev  The struct type for pending implementation changes.\n    struct ImplChangeRequest {\n        address proposedNew;\n    }\n\n    // MEMBERS\n    // @dev  The reference to the active token implementation.\n    ERC20Impl public erc20Impl;\n\n    /// @dev  The map of lock ids to pending implementation changes.\n    mapping (bytes32 =\u003e ImplChangeRequest) public implChangeReqs;\n\n    // CONSTRUCTOR\n    constructor(address _custodian) CustodianUpgradeable(_custodian) public {\n        erc20Impl = ERC20Impl(0x0);\n    }\n\n    // MODIFIERS\n    modifier onlyImpl {\n        require(msg.sender == address(erc20Impl), \"only ERC20Impl\");\n        _;\n    }\n\n    // PUBLIC FUNCTIONS\n    // (UPGRADE)\n    /** @notice  Requests a change of the active implementation associated\n      * with this contract.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Anyone can call this function, but confirming the request is authorized\n      * by the custodian.\n      *\n      * @param  _proposedImpl  The address of the new active implementation.\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestImplChange(address _proposedImpl) public returns (bytes32 lockId) {\n        require(_proposedImpl != address(0), \"no null value for `_proposedImpl`\");\n\n        lockId = generateLockId();\n\n        implChangeReqs[lockId] = ImplChangeRequest({\n            proposedNew: _proposedImpl\n        });\n\n        emit ImplChangeRequested(lockId, msg.sender, _proposedImpl);\n    }\n\n    /** @notice  Confirms a pending change of the active implementation\n      * associated with this contract.\n      *\n      * @dev  When called by the custodian with a lock id associated with a\n      * pending change, the `ERC20Impl erc20Impl` member will be updated\n      * with the requested address.\n      *\n      * @param  _lockId  The identifier of a pending change request.\n      */\n    function confirmImplChange(bytes32 _lockId) public onlyCustodian {\n        erc20Impl = getImplChangeReq(_lockId);\n\n        delete implChangeReqs[_lockId];\n\n        emit ImplChangeConfirmed(_lockId, address(erc20Impl));\n    }\n\n    // PRIVATE FUNCTIONS\n    function getImplChangeReq(bytes32 _lockId) private view returns (ERC20Impl _proposedNew) {\n        ImplChangeRequest storage changeRequest = implChangeReqs[_lockId];\n\n        // reject ‘null’ results from the map lookup\n        // this can only be the case if an unknown `_lockId` is received\n        require(changeRequest.proposedNew != address(0), \"reject ‘null’ results from the map lookup\");\n\n        return ERC20Impl(changeRequest.proposedNew);\n    }\n\n    //EVENTS\n    /// @dev  Emitted by successful `requestImplChange` calls.\n    event ImplChangeRequested(\n        bytes32 _lockId,\n        address _msgSender,\n        address _proposedImpl\n    );\n\n    /// @dev Emitted by successful `confirmImplChange` calls.\n    event ImplChangeConfirmed(bytes32 _lockId, address _newImpl);\n}\n\n/** @title  Public interface to ERC20 compliant token.\n  *\n  * @notice  This contract is a permanent entry point to an ERC20 compliant\n  * system of contracts.\n  *\n  * @dev  This contract contains no business logic and instead\n  * delegates to an instance of ERC20Impl. This contract also has no storage\n  * that constitutes the operational state of the token. This contract is\n  * upgradeable in the sense that the `custodian` can update the\n  * `erc20Impl` address, thus redirecting the delegation of business logic.\n  * The `custodian` is also authorized to pass custodianship.\n  *\n*/\ncontract ERC20Proxy is ERC20Interface, ERC20ImplUpgradeable {\n\n    // MEMBERS\n    /// @notice  Returns the name of the token.\n    string public name;\n\n    /// @notice  Returns the symbol of the token.\n    string public symbol;\n\n    /// @notice  Returns the number of decimals the token uses.\n    uint8 public decimals;\n\n    // CONSTRUCTOR\n    constructor(\n        string memory _name,\n        string memory _symbol,\n        uint8 _decimals,\n        address _custodian\n    )\n        ERC20ImplUpgradeable(_custodian)\n        public\n    {\n        name = _name;\n        symbol = _symbol;\n        decimals = _decimals;\n    }\n\n    // PUBLIC FUNCTIONS\n    // (ERC20Interface)\n    /** @notice  Returns the total token supply.\n      *\n      * @return  the total token supply.\n      */\n    function totalSupply() public view returns (uint256) {\n        return erc20Impl.totalSupply();\n    }\n\n    /** @notice  Returns the account balance of another account with an address\n      * `_owner`.\n      *\n      * @return  balance  the balance of account with address `_owner`.\n      */\n    function balanceOf(address _owner) public view returns (uint256 balance) {\n        return erc20Impl.balanceOf(_owner);\n    }\n\n    /** @dev Internal use only.\n      */\n    function emitTransfer(address _from, address _to, uint256 _value) public onlyImpl {\n        emit Transfer(_from, _to, _value);\n    }\n\n    /** @notice  Transfers `_value` amount of tokens to address `_to`.\n      *\n      * @dev Will fire the `Transfer` event. Will revert if the `_from`\n      * account balance does not have enough tokens to spend.\n      *\n      * @return  success  true if transfer completes.\n      */\n    function transfer(address _to, uint256 _value) public returns (bool success) {\n        return erc20Impl.transferWithSender(msg.sender, _to, _value);\n    }\n\n    /** @notice  Transfers `_value` amount of tokens from address `_from`\n      * to address `_to`.\n      *\n      * @dev  Will fire the `Transfer` event. Will revert unless the `_from`\n      * account has deliberately authorized the sender of the message\n      * via some mechanism.\n      *\n      * @return  success  true if transfer completes.\n      */\n    function transferFrom(address _from, address _to, uint256 _value) public returns (bool success) {\n        return erc20Impl.transferFromWithSender(msg.sender, _from, _to, _value);\n    }\n\n    /** @dev Internal use only.\n      */\n    function emitApproval(address _owner, address _spender, uint256 _value) public onlyImpl {\n        emit Approval(_owner, _spender, _value);\n    }\n\n    /** @notice  Allows `_spender` to withdraw from your account multiple times,\n      * up to the `_value` amount. If this function is called again it\n      * overwrites the current allowance with _value.\n      *\n      * @dev  Will fire the `Approval` event.\n      *\n      * @return  success  true if approval completes.\n      */\n    function approve(address _spender, uint256 _value) public returns (bool success) {\n        return erc20Impl.approveWithSender(msg.sender, _spender, _value);\n    }\n\n    /** @notice Increases the amount `_spender` is allowed to withdraw from\n      * your account.\n      * This function is implemented to avoid the race condition in standard\n      * ERC20 contracts surrounding the `approve` method.\n      *\n      * @dev  Will fire the `Approval` event. This function should be used instead of\n      * `approve`.\n      *\n      * @return  success  true if approval completes.\n      */\n    function increaseApproval(address _spender, uint256 _addedValue) public returns (bool success) {\n        return erc20Impl.increaseApprovalWithSender(msg.sender, _spender, _addedValue);\n    }\n\n    /** @notice  Decreases the amount `_spender` is allowed to withdraw from\n      * your account. This function is implemented to avoid the race\n      * condition in standard ERC20 contracts surrounding the `approve` method.\n      *\n      * @dev  Will fire the `Approval` event. This function should be used\n      * instead of `approve`.\n      *\n      * @return  success  true if approval completes.\n      */\n    function decreaseApproval(address _spender, uint256 _subtractedValue) public returns (bool success) {\n        return erc20Impl.decreaseApprovalWithSender(msg.sender, _spender, _subtractedValue);\n    }\n\n    /** @notice  Returns how much `_spender` is currently allowed to spend from\n      * `_owner`\u0027s balance.\n      *\n      * @return  remaining  the remaining allowance.\n      */\n    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {\n        return erc20Impl.allowance(_owner, _spender);\n    }\n}\n\n/** @title  ERC20 compliant token balance store.\n  *\n  * @notice  This contract serves as the store of balances, allowances, and\n  * supply for the ERC20 compliant token. No business logic exists here.\n  *\n  * @dev  This contract contains no business logic and instead\n  * is the final destination for any change in balances, allowances, or token\n  * supply. This contract is upgradeable in the sense that its custodian can\n  * update the `erc20Impl` address, thus redirecting the source of logic that\n  * determines how the balances will be updated.\n  *\n  */\ncontract ERC20Store is ERC20ImplUpgradeable {\n\n    // MEMBERS\n    /// @dev  The total token supply.\n    uint256 public totalSupply;\n\n    /// @dev  The mapping of balances.\n    mapping (address =\u003e uint256) public balances;\n\n    /// @dev  The mapping of allowances.\n    mapping (address =\u003e mapping (address =\u003e uint256)) public allowed;\n\n    // CONSTRUCTOR\n    constructor(address _custodian) ERC20ImplUpgradeable(_custodian) public {\n        totalSupply = 0;\n    }\n\n    // PUBLIC FUNCTIONS\n    // (ERC20 Ledger)\n\n    /** @notice  The function to set the total supply of tokens.\n      *\n      * @dev  Intended for use by token implementation functions\n      * that update the total supply. The only authorized caller\n      * is the active implementation.\n      *\n      * @param _newTotalSupply the value to set as the new total supply\n      */\n    function setTotalSupply(\n        uint256 _newTotalSupply\n    )\n        public\n        onlyImpl\n    {\n        totalSupply = _newTotalSupply;\n    }\n\n    /** @notice  Sets how much `_owner` allows `_spender` to transfer on behalf\n      * of `_owner`.\n      *\n      * @dev  Intended for use by token implementation functions\n      * that update spending allowances. The only authorized caller\n      * is the active implementation.\n      *\n      * @param  _owner  The account that will allow an on-behalf-of spend.\n      * @param  _spender  The account that will spend on behalf of the owner.\n      * @param  _value  The limit of what can be spent.\n      */\n    function setAllowance(\n        address _owner,\n        address _spender,\n        uint256 _value\n    )\n        public\n        onlyImpl\n    {\n        allowed[_owner][_spender] = _value;\n    }\n\n    /** @notice  Sets the balance of `_owner` to `_newBalance`.\n      *\n      * @dev  Intended for use by token implementation functions\n      * that update balances. The only authorized caller\n      * is the active implementation.\n      *\n      * @param  _owner  The account that will hold a new balance.\n      * @param  _newBalance  The balance to set.\n      */\n    function setBalance(\n        address _owner,\n        uint256 _newBalance\n    )\n        public\n        onlyImpl\n    {\n        balances[_owner] = _newBalance;\n    }\n\n    /** @notice Adds `_balanceIncrease` to `_owner`\u0027s balance.\n      *\n      * @dev  Intended for use by token implementation functions\n      * that update balances. The only authorized caller\n      * is the active implementation.\n      * WARNING: the caller is responsible for preventing overflow.\n      *\n      * @param  _owner  The account that will hold a new balance.\n      * @param  _balanceIncrease  The balance to add.\n      */\n    function addBalance(\n        address _owner,\n        uint256 _balanceIncrease\n    )\n        public\n        onlyImpl\n    {\n        balances[_owner] = balances[_owner] + _balanceIncrease;\n    }\n}\n\n/** @title  ERC20 compliant token intermediary contract holding core logic.\n  *\n  * @notice  This contract serves as an intermediary between the exposed ERC20\n  * interface in ERC20Proxy and the store of balances in ERC20Store. This\n  * contract contains core logic that the proxy can delegate to\n  * and that the store is called by.\n  *\n  * @dev  This contract contains the core logic to implement the\n  * ERC20 specification as well as several extensions.\n  * 1. Changes to the token supply.\n  * 2. Batched transfers.\n  * 3. Relative changes to spending approvals.\n  * 4. Delegated transfer control (\u0027sweeping\u0027).\n  *\n  */\ncontract ERC20Impl is CustodianUpgradeable {\n\n    // TYPES\n    /// @dev  The struct type for pending increases to the token supply (print).\n    struct PendingPrint {\n        address receiver;\n        uint256 value;\n    }\n\n    // MEMBERS\n    /// @dev  The reference to the proxy.\n    ERC20Proxy public erc20Proxy;\n\n    /// @dev  The reference to the store.\n    ERC20Store public erc20Store;\n\n    /// @dev  The sole authorized caller of delegated transfer control (\u0027sweeping\u0027).\n    address public sweeper;\n\n    /** @dev  The static message to be signed by an external account that\n      * signifies their permission to forward their balance to any arbitrary\n      * address. This is used to consolidate the control of all accounts\n      * backed by a shared keychain into the control of a single key.\n      * Initialized as the concatenation of the address of this contract\n      * and the word \"sweep\". This concatenation is done to prevent a replay\n      * attack in a subsequent contract, where the sweeping message could\n      * potentially be replayed to re-enable sweeping ability.\n      */\n    bytes32 public sweepMsg;\n\n    /** @dev  The mapping that stores whether the address in question has\n      * enabled sweeping its contents to another account or not.\n      * If an address maps to \"true\", it has already enabled sweeping,\n      * and thus does not need to re-sign the `sweepMsg` to enact the sweep.\n      */\n    mapping (address =\u003e bool) public sweptSet;\n\n    /// @dev  The map of lock ids to pending token increases.\n    mapping (bytes32 =\u003e PendingPrint) public pendingPrintMap;\n\n    /// @dev The map of blocked addresses.\n    mapping (address =\u003e bool) public blocked;\n\n    // CONSTRUCTOR\n    constructor(\n          address _erc20Proxy,\n          address _erc20Store,\n          address _custodian,\n          address _sweeper\n    )\n        CustodianUpgradeable(_custodian)\n        public\n    {\n        require(_sweeper != address(0), \"no null value for `_sweeper`\");\n        erc20Proxy = ERC20Proxy(_erc20Proxy);\n        erc20Store = ERC20Store(_erc20Store);\n\n        sweeper = _sweeper;\n        sweepMsg = keccak256(abi.encodePacked(address(this), \"sweep\"));\n    }\n\n    // MODIFIERS\n    modifier onlyProxy {\n        require(msg.sender == address(erc20Proxy), \"only ERC20Proxy\");\n        _;\n    }\n    modifier onlySweeper {\n        require(msg.sender == sweeper, \"only sweeper\");\n        _;\n    }\n\n\n    /** @notice  Core logic of the ERC20 `approve` function.\n      *\n      * @dev  This function can only be called by the referenced proxy,\n      * which has an `approve` function.\n      * Every argument passed to that function as well as the original\n      * `msg.sender` gets passed to this function.\n      * NOTE: approvals for the zero address (unspendable) are disallowed.\n      *\n      * @param  _sender  The address initiating the approval in a proxy.\n      */\n    function approveWithSender(\n        address _sender,\n        address _spender,\n        uint256 _value\n    )\n        public\n        onlyProxy\n        returns (bool success)\n    {\n        require(_spender != address(0), \"no null value for `_spender`\");\n        require(blocked[_sender] != true, \"_sender must not be blocked\");\n        require(blocked[_spender] != true, \"_spender must not be blocked\");\n        erc20Store.setAllowance(_sender, _spender, _value);\n        erc20Proxy.emitApproval(_sender, _spender, _value);\n        return true;\n    }\n\n    /** @notice  Core logic of the `increaseApproval` function.\n      *\n      * @dev  This function can only be called by the referenced proxy,\n      * which has an `increaseApproval` function.\n      * Every argument passed to that function as well as the original\n      * `msg.sender` gets passed to this function.\n      * NOTE: approvals for the zero address (unspendable) are disallowed.\n      *\n      * @param  _sender  The address initiating the approval.\n      */\n    function increaseApprovalWithSender(\n        address _sender,\n        address _spender,\n        uint256 _addedValue\n    )\n        public\n        onlyProxy\n        returns (bool success)\n    {\n        require(_spender != address(0),\"no null value for_spender\");\n        require(blocked[_sender] != true, \"_sender must not be blocked\");\n        require(blocked[_spender] != true, \"_spender must not be blocked\");\n        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);\n        uint256 newAllowance = currentAllowance + _addedValue;\n\n        require(newAllowance \u003e= currentAllowance, \"new allowance must not be smaller than previous\");\n\n        erc20Store.setAllowance(_sender, _spender, newAllowance);\n        erc20Proxy.emitApproval(_sender, _spender, newAllowance);\n        return true;\n    }\n\n    /** @notice  Core logic of the `decreaseApproval` function.\n      *\n      * @dev  This function can only be called by the referenced proxy,\n      * which has a `decreaseApproval` function.\n      * Every argument passed to that function as well as the original\n      * `msg.sender` gets passed to this function.\n      * NOTE: approvals for the zero address (unspendable) are disallowed.\n      *\n      * @param  _sender  The address initiating the approval.\n      */\n    function decreaseApprovalWithSender(\n        address _sender,\n        address _spender,\n        uint256 _subtractedValue\n    )\n        public\n        onlyProxy\n        returns (bool success)\n    {\n        require(_spender != address(0), \"no unspendable approvals\"); // disallow unspendable approvals\n        require(blocked[_sender] != true, \"_sender must not be blocked\");\n        require(blocked[_spender] != true, \"_spender must not be blocked\");\n        uint256 currentAllowance = erc20Store.allowed(_sender, _spender);\n        uint256 newAllowance = currentAllowance - _subtractedValue;\n\n        require(newAllowance \u003c= currentAllowance, \"new allowance must not be smaller than previous\");\n\n        erc20Store.setAllowance(_sender, _spender, newAllowance);\n        erc20Proxy.emitApproval(_sender, _spender, newAllowance);\n        return true;\n    }\n\n    /** @notice  Requests an increase in the token supply, with the newly created\n      * tokens to be added to the balance of the specified account.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Anyone can call this function, but confirming the request is authorized\n      * by the custodian.\n      * NOTE: printing to the zero address is disallowed.\n      *\n      * @param  _receiver  The receiving address of the print, if confirmed.\n      * @param  _value  The number of tokens to add to the total supply and the\n      * balance of the receiving address, if confirmed.\n      *\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestPrint(address _receiver, uint256 _value) public returns (bytes32 lockId) {\n        require(_receiver != address(0), \"no null value for `_receiver`\");\n        require(blocked[msg.sender] != true, \"account blocked\");\n        require(blocked[_receiver] != true, \"_receiver must not be blocked\");\n        lockId = generateLockId();\n\n        pendingPrintMap[lockId] = PendingPrint({\n            receiver: _receiver,\n            value: _value\n        });\n\n        emit PrintingLocked(lockId, _receiver, _value);\n    }\n\n    /** @notice  Confirms a pending increase in the token supply.\n      *\n      * @dev  When called by the custodian with a lock id associated with a\n      * pending increase, the amount requested to be printed in the print request\n      * is printed to the receiving address specified in that same request.\n      * NOTE: this function will not execute any print that would overflow the\n      * total supply, but it will not revert either.\n      *\n      * @param  _lockId  The identifier of a pending print request.\n      */\n    function confirmPrint(bytes32 _lockId) public onlyCustodian {\n        PendingPrint storage print = pendingPrintMap[_lockId];\n\n        // reject ‘null’ results from the map lookup\n        // this can only be the case if an unknown `_lockId` is received\n        address receiver = print.receiver;\n        require (receiver != address(0), \"unknown `_lockId`\");\n        uint256 value = print.value;\n\n        delete pendingPrintMap[_lockId];\n\n        uint256 supply = erc20Store.totalSupply();\n        uint256 newSupply = supply + value;\n        if (newSupply \u003e= supply) {\n          erc20Store.setTotalSupply(newSupply);\n          erc20Store.addBalance(receiver, value);\n\n          emit PrintingConfirmed(_lockId, receiver, value);\n          erc20Proxy.emitTransfer(address(0), receiver, value);\n        }\n    }\n\n    /** @notice  Burns the specified value from the sender\u0027s balance.\n      *\n      * @dev  Sender\u0027s balanced is subtracted by the amount they wish to burn.\n      *\n      * @param  _value  The amount to burn.\n      *\n      * @return success true if the burn succeeded.\n      */\n    function burn(uint256 _value) public returns (bool success) {\n        require(blocked[msg.sender] != true, \"account blocked\");\n        uint256 balanceOfSender = erc20Store.balances(msg.sender);\n        require(_value \u003c= balanceOfSender, \"disallow burning more, than amount of the balance\");\n\n        erc20Store.setBalance(msg.sender, balanceOfSender - _value);\n        erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);\n\n        erc20Proxy.emitTransfer(msg.sender, address(0), _value);\n\n        return true;\n    }\n\n     /** @notice  Burns the specified value from the balance in question.\n      *\n      * @dev  Suspected balance is subtracted by the amount which will be burnt.\n      *\n      * @dev If the suspected balance has less than the amount requested, it will be set to 0.\n      *\n      * @param  _from  The address of suspected balance.\n      *\n      * @param  _value  The amount to burn.\n      *\n      * @return success true if the burn succeeded.\n      */\n    function burn(address _from, uint256 _value) public onlyCustodian returns (bool success) {\n        uint256 balance = erc20Store.balances(_from);\n        if(_value \u003c= balance){\n            erc20Store.setBalance(_from, balance - _value);\n            erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);\n            erc20Proxy.emitTransfer(_from, address(0), _value);\n            emit Wiped(_from, _value, _value, balance - _value);\n        }\n        else {\n            erc20Store.setBalance(_from,0);\n            erc20Store.setTotalSupply(erc20Store.totalSupply() - balance);\n            erc20Proxy.emitTransfer(_from, address(0), balance);\n            emit Wiped(_from, _value, balance, 0);\n        }\n        return true;\n    }\n\n    /** @notice  A function for a sender to issue multiple transfers to multiple\n      * different addresses at once. This function is implemented for gas\n      * considerations when someone wishes to transfer, as one transaction is\n      * cheaper than issuing several distinct individual `transfer` transactions.\n      *\n      * @dev  By specifying a set of destination addresses and values, the\n      * sender can issue one transaction to transfer multiple amounts to\n      * distinct addresses, rather than issuing each as a separate\n      * transaction. The `_tos` and `_values` arrays must be equal length, and\n      * an index in one array corresponds to the same index in the other array\n      * (e.g. `_tos[0]` will receive `_values[0]`, `_tos[1]` will receive\n      * `_values[1]`, and so on.)\n      * NOTE: transfers to the zero address are disallowed.\n      *\n      * @param  _tos  The destination addresses to receive the transfers.\n      * @param  _values  The values for each destination address.\n      * @return  success  If transfers succeeded.\n      */\n    function batchTransfer(address[] memory _tos, uint256[] memory _values) public returns (bool success) {\n        require(_tos.length == _values.length, \"_tos and _values must be the same length\");\n        require(blocked[msg.sender] != true, \"account blocked\");\n        uint256 numTransfers = _tos.length;\n        uint256 senderBalance = erc20Store.balances(msg.sender);\n\n        for (uint256 i = 0; i \u003c numTransfers; i++) {\n          address to = _tos[i];\n          require(to != address(0), \"no null values for _tos\");\n          require(blocked[to] != true, \"_tos must not be blocked\");\n          uint256 v = _values[i];\n          require(senderBalance \u003e= v, \"insufficient funds\");\n\n          if (msg.sender != to) {\n            senderBalance -= v;\n            erc20Store.addBalance(to, v);\n          }\n          erc20Proxy.emitTransfer(msg.sender, to, v);\n        }\n\n        erc20Store.setBalance(msg.sender, senderBalance);\n\n        return true;\n    }\n\n    /** @notice  Enables the delegation of transfer control for many\n      * accounts to the sweeper account, transferring any balances\n      * as well to the given destination.\n      *\n      * @dev  An account delegates transfer control by signing the\n      * value of `sweepMsg`. The sweeper account is the only authorized\n      * caller of this function, so it must relay signatures on behalf\n      * of accounts that delegate transfer control to it. Enabling\n      * delegation is idempotent and permanent. If the account has a\n      * balance at the time of enabling delegation, its balance is\n      * also transferred to the given destination account `_to`.\n      * NOTE: transfers to the zero address are disallowed.\n      *\n      * @param  _vs  The array of recovery byte components of the ECDSA signatures.\n      * @param  _rs  The array of \u0027R\u0027 components of the ECDSA signatures.\n      * @param  _ss  The array of \u0027S\u0027 components of the ECDSA signatures.\n      * @param  _to  The destination for swept balances.\n      */\n    function enableSweep(uint8[] memory _vs, bytes32[] memory _rs, bytes32[] memory _ss, address _to) public onlySweeper {\n        require(_to != address(0), \"no null value for `_to`\");\n        require(blocked[_to] != true, \"_to must not be blocked\");\n        require((_vs.length == _rs.length) \u0026\u0026 (_vs.length == _ss.length), \"_vs[], _rs[], _ss lengths are different\");\n\n        uint256 numSignatures = _vs.length;\n        uint256 sweptBalance = 0;\n\n        for (uint256 i = 0; i \u003c numSignatures; ++i) {\n            address from = ecrecover(keccak256(abi.encodePacked(\"\\x19Ethereum Signed Message:\\n32\",sweepMsg)), _vs[i], _rs[i], _ss[i]);\n            require(blocked[from] != true, \"_froms must not be blocked\");\n            // ecrecover returns 0 on malformed input\n            if (from != address(0)) {\n                sweptSet[from] = true;\n\n                uint256 fromBalance = erc20Store.balances(from);\n\n                if (fromBalance \u003e 0) {\n                    sweptBalance += fromBalance;\n\n                    erc20Store.setBalance(from, 0);\n\n                    erc20Proxy.emitTransfer(from, _to, fromBalance);\n                }\n            }\n        }\n\n        if (sweptBalance \u003e 0) {\n          erc20Store.addBalance(_to, sweptBalance);\n        }\n    }\n\n    /** @notice  For accounts that have delegated, transfer control\n      * to the sweeper, this function transfers their balances to the given\n      * destination.\n      *\n      * @dev The sweeper account is the only authorized caller of\n      * this function. This function accepts an array of addresses to have their\n      * balances transferred for gas efficiency purposes.\n      * NOTE: any address for an account that has not been previously enabled\n      * will be ignored.\n      * NOTE: transfers to the zero address are disallowed.\n      *\n      * @param  _froms  The addresses to have their balances swept.\n      * @param  _to  The destination address of all these transfers.\n      */\n    function replaySweep(address[] memory _froms, address _to) public onlySweeper {\n        require(_to != address(0), \"no null value for `_to`\");\n        require(blocked[_to] != true, \"_to must not be blocked\");\n        uint256 lenFroms = _froms.length;\n        uint256 sweptBalance = 0;\n\n        for (uint256 i = 0; i \u003c lenFroms; ++i) {\n            address from = _froms[i];\n            require(blocked[from] != true, \"_froms must not be blocked\");\n            if (sweptSet[from]) {\n                uint256 fromBalance = erc20Store.balances(from);\n\n                if (fromBalance \u003e 0) {\n                    sweptBalance += fromBalance;\n\n                    erc20Store.setBalance(from, 0);\n\n                    erc20Proxy.emitTransfer(from, _to, fromBalance);\n                }\n            }\n        }\n\n        if (sweptBalance \u003e 0) {\n            erc20Store.addBalance(_to, sweptBalance);\n        }\n    }\n\n    /** @notice  Core logic of the ERC20 `transferFrom` function.\n      *\n      * @dev  This function can only be called by the referenced proxy,\n      * which has a `transferFrom` function.\n      * Every argument passed to that function as well as the original\n      * `msg.sender` gets passed to this function.\n      * NOTE: transfers to the zero address are disallowed.\n      *\n      * @param  _sender  The address initiating the transfer in a proxy.\n      */\n    function transferFromWithSender(\n        address _sender,\n        address _from,\n        address _to,\n        uint256 _value\n    )\n        public\n        onlyProxy\n        returns (bool success)\n    {\n        require(_to != address(0), \"no null values for `_to`\");\n        require(blocked[_sender] != true, \"_sender must not be blocked\");\n        require(blocked[_from] != true, \"_from must not be blocked\");\n        require(blocked[_to] != true, \"_to must not be blocked\");\n\n        uint256 balanceOfFrom = erc20Store.balances(_from);\n        require(_value \u003c= balanceOfFrom, \"insufficient funds on `_from` balance\");\n\n        uint256 senderAllowance = erc20Store.allowed(_from, _sender);\n        require(_value \u003c= senderAllowance, \"insufficient allowance amount\");\n\n        erc20Store.setBalance(_from, balanceOfFrom - _value);\n        erc20Store.addBalance(_to, _value);\n\n        erc20Store.setAllowance(_from, _sender, senderAllowance - _value);\n\n        erc20Proxy.emitTransfer(_from, _to, _value);\n\n        return true;\n    }\n\n    /** @notice  Core logic of the ERC20 `transfer` function.\n      *\n      * @dev  This function can only be called by the referenced proxy,\n      * which has a `transfer` function.\n      * Every argument passed to that function as well as the original\n      * `msg.sender` gets passed to this function.\n      * NOTE: transfers to the zero address are disallowed.\n      *\n      * @param  _sender  The address initiating the transfer in a proxy.\n      */\n    function transferWithSender(\n        address _sender,\n        address _to,\n        uint256 _value\n    )\n        public\n        onlyProxy\n        returns (bool success)\n    {\n        require(_to != address(0), \"no null value for `_to`\");\n        require(blocked[_sender] != true, \"_sender must not be blocked\");\n        require(blocked[_to] != true, \"_to must not be blocked\");\n\n        uint256 balanceOfSender = erc20Store.balances(_sender);\n        require(_value \u003c= balanceOfSender, \"insufficient funds\");\n\n        erc20Store.setBalance(_sender, balanceOfSender - _value);\n        erc20Store.addBalance(_to, _value);\n\n        erc20Proxy.emitTransfer(_sender, _to, _value);\n\n        return true;\n    }\n\n    /** @notice  Transfers the specified value from the balance in question.\n      *\n      * @dev  Suspected balance is subtracted by the amount which will be transferred.\n      *\n      * @dev If the suspected balance has less than the amount requested, it will be set to 0.\n      *\n      * @param  _from  The address of suspected balance.\n      *\n      * @param  _value  The amount to transfer.\n      *\n      * @return success true if the transfer succeeded.\n      */\n    function forceTransfer(\n        address _from,\n        address _to,\n        uint256 _value\n    )\n        public\n        onlyCustodian\n        returns (bool success)\n    {\n        require(_to != address(0), \"no null value for `_to`\");\n        uint256 balanceOfSender = erc20Store.balances(_from);\n        if(_value \u003c= balanceOfSender) {\n            erc20Store.setBalance(_from, balanceOfSender - _value);\n            erc20Store.addBalance(_to, _value);\n\n            erc20Proxy.emitTransfer(_from, _to, _value);\n        } else {\n            erc20Store.setBalance(_from, 0);\n            erc20Store.addBalance(_to, balanceOfSender);\n\n            erc20Proxy.emitTransfer(_from, _to, balanceOfSender);\n        }\n\n        return true;\n    }\n\n    // METHODS (ERC20 sub interface impl.)\n    /// @notice  Core logic of the ERC20 `totalSupply` function.\n    function totalSupply() public view returns (uint256) {\n        return erc20Store.totalSupply();\n    }\n\n    /// @notice  Core logic of the ERC20 `balanceOf` function.\n    function balanceOf(address _owner) public view returns (uint256 balance) {\n        return erc20Store.balances(_owner);\n    }\n\n    /// @notice  Core logic of the ERC20 `allowance` function.\n    function allowance(address _owner, address _spender) public view returns (uint256 remaining) {\n        return erc20Store.allowed(_owner, _spender);\n    }\n\n    /// @dev internal use only.\n    function blockWallet(address wallet) public onlyCustodian returns (bool success) {\n        blocked[wallet] = true;\n        return true;\n    }\n\n    /// @dev internal use only.\n    function unblockWallet(address wallet) public onlyCustodian returns (bool success) {\n        blocked[wallet] = false;\n        return true;\n    }\n\n    // EVENTS\n    /// @dev  Emitted by successful `requestPrint` calls.\n    event PrintingLocked(bytes32 _lockId, address _receiver, uint256 _value);\n\n    /// @dev Emitted by successful `confirmPrint` calls.\n    event PrintingConfirmed(bytes32 _lockId, address _receiver, uint256 _value);\n\n    /** @dev Emitted by successful `confirmWipe` calls.\n      *\n      * @param _value Amount requested to be burned.\n      *\n      * @param _burned Amount which was burned.\n      *\n      * @param _balance Amount left on account after burn.\n      *\n      * @param _from Account which balance was burned.\n      */\n     event Wiped(address _from, uint256 _value, uint256 _burned, uint _balance);\n}\n\n/** @title  A contact to govern hybrid control over increases to the token supply and managing accounts.\n  *\n  * @notice  A contract that acts as a custodian of the active token\n  * implementation, and an intermediary between it and the ‘true’ custodian.\n  * It preserves the functionality of direct custodianship as well as granting\n  * limited control of token supply increases to an additional key.\n  *\n  * @dev  This contract is a layer of indirection between an instance of\n  * ERC20Impl and a custodian. The functionality of the custodianship over\n  * the token implementation is preserved (printing and custodian changes),\n  * but this contract adds the ability for an additional key\n  * (the \u0027controller\u0027) to increase the token supply up to a ceiling,\n  * and this supply ceiling can only be raised by the custodian.\n  *\n  */\ncontract Controller is LockRequestable {\n\n    // TYPES\n    /// @dev The struct type for pending ceiling raises.\n    struct PendingCeilingRaise {\n        uint256 raiseBy;\n    }\n\n    /// @dev The struct type for pending wipes.\n    struct wipeAddress {\n        uint256 value;\n        address from;\n    }\n\n    /// @dev The struct type for pending force transfer requests.\n    struct forceTransferRequest {\n        uint256 value;\n        address from;\n        address to;\n    }\n\n    // MEMBERS\n    /// @dev  The reference to the active token implementation.\n    ERC20Impl public erc20Impl;\n\n    /// @dev  The address of the account or contract that acts as the custodian.\n    Custodian public custodian;\n\n    /** @dev  The sole authorized caller of limited printing.\n      * This account is also authorized to lower the supply ceiling and\n      * wiping suspected accounts or force transferring funds from them.\n      */\n    address public controller;\n\n    /** @dev  The maximum that the token supply can be increased to\n      * through the use of the limited printing feature.\n      * The difference between the current total supply and the supply\n      * ceiling is what is available to the \u0027controller\u0027 account.\n      * The value of the ceiling can only be increased by the custodian.\n      */\n    uint256 public totalSupplyCeiling;\n\n    /// @dev  The map of lock ids to pending ceiling raises.\n    mapping (bytes32 =\u003e PendingCeilingRaise) public pendingRaiseMap;\n\n    /// @dev  The map of lock ids to pending wipes.\n    mapping (bytes32 =\u003e wipeAddress[]) public pendingWipeMap;\n\n    /// @dev  The map of lock ids to pending force transfer requests.\n    mapping (bytes32 =\u003e forceTransferRequest) public pendingForceTransferRequestMap;\n\n    // CONSTRUCTOR\n    constructor(\n        address _erc20Impl,\n        address _custodian,\n        address _controller,\n        uint256 _initialCeiling\n    )\n        public\n    {\n        erc20Impl = ERC20Impl(_erc20Impl);\n        custodian = Custodian(_custodian);\n        controller = _controller;\n        totalSupplyCeiling = _initialCeiling;\n    }\n\n    // MODIFIERS\n    modifier onlyCustodian {\n        require(msg.sender == address(custodian), \"only custodian\");\n        _;\n    }\n    modifier onlyController {\n        require(msg.sender == controller, \"only controller\");\n        _;\n    }\n\n    modifier onlySigner {\n        require(custodian.signerSet(msg.sender) == true, \"only signer\");\n        _;\n    }\n\n    /** @notice  Increases the token supply, with the newly created tokens\n      * being added to the balance of the specified account.\n      *\n      * @dev  The function checks that the value to print does not\n      * exceed the supply ceiling when added to the current total supply.\n      * NOTE: printing to the zero address is disallowed.\n      *\n      * @param  _receiver  The receiving address of the print.\n      * @param  _value  The number of tokens to add to the total supply and the\n      * balance of the receiving address.\n      */\n    function limitedPrint(address _receiver, uint256 _value) public onlyController {\n        uint256 totalSupply = erc20Impl.totalSupply();\n        uint256 newTotalSupply = totalSupply + _value;\n\n        require(newTotalSupply \u003e= totalSupply, \"new total supply overflow\");\n        require(newTotalSupply \u003c= totalSupplyCeiling, \"total supply ceiling overflow\");\n        erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));\n    }\n\n    /** @notice  Requests wipe of suspected accounts.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Only controller can call this function, and only the custodian\n      * can confirm the request.\n      *\n      * @param  _froms  The array of suspected accounts.\n      *\n      * @param  _values  array of amounts by which suspected accounts will be wiped.\n      *\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestWipe(address[] memory _froms, uint256[] memory _values) public onlyController returns (bytes32 lockId) {\n        require(_froms.length == _values.length, \"_froms[] and _values[] must be same length\");\n        lockId = generateLockId();\n        uint256 amount = _froms.length;\n\n        for(uint256 i = 0; i \u003c amount; i++) {\n            address from = _froms[i];\n            uint256 value = _values[i];\n            pendingWipeMap[lockId].push(wipeAddress(value, from));\n        }\n\n        emit WipeRequested(lockId);\n\n        return lockId;\n    }\n\n    /** @notice  Confirms a pending wipe of suspected accounts.\n      *\n      * @dev  When called by the custodian with a lock id associated with a\n      * pending wipe, the amount requested is burned from the suspected accounts.\n      *\n      * @param  _lockId  The identifier of a pending wipe request.\n      */\n    function confirmWipe(bytes32 _lockId) public onlyCustodian {\n        uint256 amount = pendingWipeMap[_lockId].length;\n        for(uint256 i = 0; i \u003c amount; i++) {\n            wipeAddress memory addr = pendingWipeMap[_lockId][i];\n            address from = addr.from;\n            uint256 value = addr.value;\n            erc20Impl.burn(from, value);\n        }\n\n        delete pendingWipeMap[_lockId];\n\n        emit WipeCompleted(_lockId);\n    }\n\n    /** @notice  Requests force transfer from the suspected account.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Only controller can call this function, and only the custodian\n      * can confirm the request.\n      *\n      * @param  _from  address of suspected account.\n      *\n      * @param  _to  address of reciever.\n      *\n      * @param  _value  amount which will be transferred.\n      *\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestForceTransfer(address _from, address _to, uint256 _value) public onlyController returns (bytes32 lockId) {\n        lockId = generateLockId();\n        require (_value != 0, \"no zero value transfers\");\n        pendingForceTransferRequestMap[lockId] = forceTransferRequest(_value, _from, _to);\n\n        emit ForceTransferRequested(lockId, _from, _to, _value);\n\n        return lockId;\n    }\n\n    /** @notice  Confirms a pending force transfer request.\n      *\n      * @dev  When called by the custodian with a lock id associated with a\n      * pending transfer request, the amount requested is transferred from the suspected account.\n      *\n      * @param  _lockId  The identifier of a pending transfer request.\n      */\n    function confirmForceTransfer(bytes32 _lockId) public onlyCustodian {\n        address from = pendingForceTransferRequestMap[_lockId].from;\n        address to = pendingForceTransferRequestMap[_lockId].to;\n        uint256 value = pendingForceTransferRequestMap[_lockId].value;\n\n        delete pendingForceTransferRequestMap[_lockId];\n\n        erc20Impl.forceTransfer(from, to, value);\n\n        emit ForceTransferCompleted(_lockId, from, to, value);\n    }\n\n    /** @notice  Requests an increase to the supply ceiling.\n      *\n      * @dev  Returns a unique lock id associated with the request.\n      * Anyone can call this function, but confirming the request is authorized\n      * by the custodian.\n      *\n      * @param  _raiseBy  The amount by which to raise the ceiling.\n      *\n      * @return  lockId  A unique identifier for this request.\n      */\n    function requestCeilingRaise(uint256 _raiseBy) public returns (bytes32 lockId) {\n        require(_raiseBy != 0, \"no zero ceiling raise\");\n\n        lockId = generateLockId();\n\n        pendingRaiseMap[lockId] = PendingCeilingRaise({\n            raiseBy: _raiseBy\n        });\n\n        emit CeilingRaiseLocked(lockId, _raiseBy);\n    }\n\n    /** @notice  Confirms a pending increase in the token supply.\n      *\n      * @dev  When called by the custodian with a lock id associated with a\n      * pending ceiling increase, the amount requested is added to the\n      * current supply ceiling.\n      * NOTE: this function will not execute any raise that would overflow the\n      * supply ceiling, but it will not revert either.\n      *\n      * @param  _lockId  The identifier of a pending ceiling raise request.\n      */\n    function confirmCeilingRaise(bytes32 _lockId) public onlyCustodian {\n        PendingCeilingRaise storage pendingRaise = pendingRaiseMap[_lockId];\n\n        // copy locals of references to struct members\n        uint256 raiseBy = pendingRaise.raiseBy;\n        // accounts for a gibberish _lockId\n        require(raiseBy != 0, \"no gibberish _lockId\");\n\n        delete pendingRaiseMap[_lockId];\n\n        uint256 newCeiling = totalSupplyCeiling + raiseBy;\n        // overflow check\n        if (newCeiling \u003e= totalSupplyCeiling) {\n            totalSupplyCeiling = newCeiling;\n\n            emit CeilingRaiseConfirmed(_lockId, raiseBy, newCeiling);\n        }\n    }\n\n    /** @notice  Lowers the supply ceiling, further constraining the bound of\n      * what can be printed by the controller.\n      *\n      * @dev  The controller is the sole authorized caller of this function,\n      * so it is the only account that can elect to lower its limit to increase\n      * the token supply.\n      *\n      * @param  _lowerBy  The amount by which to lower the supply ceiling.\n      */\n    function lowerCeiling(uint256 _lowerBy) public onlyController {\n        uint256 newCeiling = totalSupplyCeiling - _lowerBy;\n        // overflow check\n        require(newCeiling \u003c= totalSupplyCeiling, \"totalSupplyCeiling overflow\");\n        totalSupplyCeiling = newCeiling;\n\n        emit CeilingLowered(_lowerBy, newCeiling);\n    }\n\n    /** @notice  Pass-through control of print confirmation, allowing this\n      * contract\u0027s custodian to act as the custodian of the associated\n      * active token implementation.\n      *\n      * @dev  This contract is the direct custodian of the active token\n      * implementation, but this function allows this contract\u0027s custodian\n      * to act as though it were the direct custodian of the active\n      * token implementation. Therefore the custodian retains control of\n      * unlimited printing.\n      *\n      * @param  _lockId  The identifier of a pending print request in\n      * the associated active token implementation.\n      */\n    function confirmPrintProxy(bytes32 _lockId) public onlyCustodian {\n        erc20Impl.confirmPrint(_lockId);\n    }\n\n    /** @notice  Pass-through control of custodian change confirmation,\n      * allowing this contract\u0027s custodian to act as the custodian of\n      * the associated active token implementation.\n      *\n      * @dev  This contract is the direct custodian of the active token\n      * implementation, but this function allows this contract\u0027s custodian\n      * to act as though it were the direct custodian of the active\n      * token implementation. Therefore the custodian retains control of\n      * custodian changes.\n      *\n      * @param  _lockId  The identifier of a pending custodian change request\n      * in the associated active token implementation.\n      */\n    function confirmCustodianChangeProxy(bytes32 _lockId) public onlyCustodian {\n        erc20Impl.confirmCustodianChange(_lockId);\n    }\n\n    /** @notice  Blocks all transactions with a wallet.\n      *\n      * @dev Only signers from custodian are authorized to call this function\n      *\n      * @param  wallet account which will be blocked.\n      */\n    function blockWallet(address wallet) public onlySigner {\n        erc20Impl.blockWallet(wallet);\n        emit Blocked(wallet);\n    }\n\n    /** @notice Unblocks all transactions with a wallet.\n      *\n      * @dev Only signers from custodian are authorized to call this function\n      *\n      * @param  wallet account which will be unblocked.\n      */\n    function unblockWallet(address wallet) public onlySigner {\n        erc20Impl.unblockWallet(wallet);\n        emit Unblocked(wallet);\n    }\n\n    // EVENTS\n    /// @dev  Emitted by successful `requestCeilingRaise` calls.\n    event CeilingRaiseLocked(bytes32 _lockId, uint256 _raiseBy);\n\n    /// @dev  Emitted by successful `confirmCeilingRaise` calls.\n    event CeilingRaiseConfirmed(bytes32 _lockId, uint256 _raiseBy, uint256 _newCeiling);\n\n    /// @dev  Emitted by successful `lowerCeiling` calls.\n    event CeilingLowered(uint256 _lowerBy, uint256 _newCeiling);\n\n    /// @dev  Emitted by successful `blockWallet` calls.\n    event Blocked(address _wallet);\n\n    /// @dev  Emitted by successful `unblockWallet` calls.\n    event Unblocked(address _wallet);\n\n     /// @dev  Emitted by successful `requestForceTransfer` calls.\n    event ForceTransferRequested(bytes32 _lockId, address _from, address _to, uint256 _value);\n\n    /// @dev  Emitted by successful `confirmForceTransfer` calls.\n    event ForceTransferCompleted(bytes32 _lockId, address _from, address _to, uint256 _value);\n\n    /// @dev  Emitted by successful `requestWipe` calls.\n    event WipeRequested(bytes32 _lockId);\n\n    /// @dev  Emitted by successful `confirmWipe` calls.\n    event WipeCompleted(bytes32 _lockId);\n}"}}

      File 2 of 3: ERC20Impl
      pragma solidity ^0.5.10;
      
      /** @title  A contract for generating unique identifiers
        *
        * @notice  A contract that provides an identifier generation scheme,
        * guaranteeing uniqueness across all contracts that inherit from it,
        * as well as the unpredictability of future identifiers.
        *
        * @dev  This contract is intended to be inherited by any contract that
        * implements the callback software pattern for cooperative custodianship.
        *
      */
      contract LockRequestable {
      
          // MEMBERS
          /// @notice  the count of all invocations of `generateLockId`.
          uint256 public lockRequestCount;
      
          // CONSTRUCTOR
          constructor() 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 ensures 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(abi.encodePacked(blockhash(block.number - 1), address(this), ++lockRequestCount));
          }
      }
      
      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  A dual control contract.
        *
        * @notice  A general-purpose contract that implements dual control over
        * co-operating contracts through a callback mechanism.
        *
        * @dev  This contract implements dual control through a 2-of-N
        * threshold multi-signature scheme. The contract recognizes a set of N signers,
        * and will unlock requests with signatures from any distinct pair of them.
        * This contract signals the unlocking through a co-operative callback
        * scheme.
        * This contract also provides time lock and revocation features.
        * Requests made by a 'primary' account have a default time lock applied.
        * All other requests must pay a 1 ETH stake and have an extended time lock
        * applied.
        * A request that is completed will prevent all previous pending requests
        * that share the same callback from being completed: this is the
        * revocation feature.
        *
        */
      contract Custodian {
      
          // TYPES
          /** @dev  The `Request` struct stores a pending unlocking.
            * `callbackAddress` and `callbackSelector` are the data required to
            * make a callback. The custodian completes the process by
            * calling `callbackAddress.call(callbackSelector, lockId)`, which
            * signals to the contract co-operating with the Custodian that
            * the 2-of-N signatures have been provided and verified.
            */
          struct Request {
              bytes32 lockId;
              bytes4 callbackSelector;  // bytes4 and address can be packed into 1 word
              address callbackAddress;
              uint256 idx;
              uint256 timestamp;
              bool extended;
          }
      
          // EVENTS
          /// @dev  Emitted by successful `requestUnlock` calls.
          event Requested(
              bytes32 _lockId,
              address _callbackAddress,
              bytes4 _callbackSelector,
              uint256 _nonce,
              address _whitelistedAddress,
              bytes32 _requestMsgHash,
              uint256 _timeLockExpiry
          );
      
          /// @dev  Emitted by `completeUnlock` calls on requests in the time-locked state.
          event TimeLocked(
              uint256 _timeLockExpiry,
              bytes32 _requestMsgHash
          );
      
          /// @dev  Emitted by successful `completeUnlock` calls.
          event Completed(
              bytes32 _lockId,
              bytes32 _requestMsgHash,
              address _signer1,
              address _signer2
          );
      
          /// @dev  Emitted by `completeUnlock` calls where the callback failed.
          event Failed(
              bytes32 _lockId,
              bytes32 _requestMsgHash,
              address _signer1,
              address _signer2
          );
      
          /// @dev  Emitted by successful `extendRequestTimeLock` calls.
          event TimeLockExtended(
              uint256 _timeLockExpiry,
              bytes32 _requestMsgHash
          );
      
           // MEMBERS
          /** @dev  The count of all requests.
            * This value is used as a nonce, incorporated into the request hash.
            */
          uint256 public requestCount;
      
          /// @dev  The set of signers: signatures from two signers unlock a pending request.
          mapping (address => bool) public signerSet;
      
          /// @dev  The map of request hashes to pending requests.
          mapping (bytes32 => Request) public requestMap;
      
          /// @dev  The map of callback addresses to callback selectors to request indexes.
          mapping (address => mapping (bytes4 => uint256)) public lastCompletedIdxs;
      
          /** @dev  The default period (in seconds) to time-lock requests.
            * All requests will be subject to this default time lock, and the duration
            * is fixed at contract creation.
            */
          uint256 public defaultTimeLock;
      
          /** @dev  The extended period (in seconds) to time-lock requests.
            * Requests not from the primary account are subject to this time lock.
            * The primary account may also elect to extend the time lock on requests
            * that originally received the default.
            */
          uint256 public extendedTimeLock;
      
          /// @dev  The primary account is the privileged account for making requests.
          address public primary;
      
          // CONSTRUCTOR
          constructor(
              address[] memory _signers,
              uint256 _defaultTimeLock,
              uint256 _extendedTimeLock,
              address _primary
          )
              public
          {
              // check for at least two `_signers`
              require(_signers.length >= 2, "at least two `_signers`");
      
               // validate time lock params
              require(_defaultTimeLock <= _extendedTimeLock, "valid timelock params");
              defaultTimeLock = _defaultTimeLock;
              extendedTimeLock = _extendedTimeLock;
      
              primary = _primary;
      
              // explicitly initialize `requestCount` to zero
              requestCount = 0;
              // turn the array into a set
              for (uint i = 0; i < _signers.length; i++) {
                  // no zero addresses or duplicates
                  require(_signers[i] != address(0) && !signerSet[_signers[i]], "no zero addresses or duplicates");
                  signerSet[_signers[i]] = true;
              }
          }
      
          // MODIFIERS
          modifier onlyPrimary {
              require(msg.sender == primary, "only primary");
              _;
          }
      
           modifier onlySigner {
              require(signerSet[msg.sender], "only signer");
              _;
          }
      
          // METHODS
          /** @notice  Requests an unlocking with a lock identifier and a callback.
            *
            * @dev  If called by an account other than the primary a 1 ETH stake
            * must be paid. When the request is unlocked stake will be transferred to the message sender.
            * This is an anti-spam measure. As well as the callback
            * and the lock identifier parameters a 'whitelisted address' is required
            * for compatibility with existing signature schemes.
            *
            * @param  _lockId  The identifier of a pending request in a co-operating contract.
            * @param  _callbackAddress  The address of a co-operating contract.
            * @param  _callbackSelector  The function selector of a function within
            * the co-operating contract at address `_callbackAddress`.
            * @param  _whitelistedAddress  An address whitelisted in existing
            * offline control protocols.
            *
            * @return  requestMsgHash  The hash of a request message to be signed.
          */
          function requestUnlock(
              bytes32 _lockId,
              address _callbackAddress,
              bytes4 _callbackSelector,
              address _whitelistedAddress
          )
              public
              payable
              returns (bytes32 requestMsgHash)
          {
              require(msg.sender == primary || msg.value >= 1 ether, "sender is primary or stake is paid");
      
              // disallow using a zero value for the callback address
              require(_callbackAddress != address(0), "no zero value for callback address");
      
              uint256 requestIdx = ++requestCount;
              // compute a nonce value
              // - the blockhash prevents prediction of future nonces
              // - the address of this contract prevents conflicts with co-operating contracts using this scheme
              // - the counter prevents conflicts arising from multiple txs within the same block
              uint256 nonce = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), requestIdx)));
      
              requestMsgHash = keccak256(
                  abi.encodePacked(
                      nonce,
                      _whitelistedAddress,
                      uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
                  )
              );
              requestMap[requestMsgHash] = Request({
                  lockId: _lockId,
                  callbackSelector: _callbackSelector,
                  callbackAddress: _callbackAddress,
                  idx: requestIdx,
                  timestamp: block.timestamp,
                  extended: false
              });
      
              // compute the expiry time
              uint256 timeLockExpiry = block.timestamp;
              if (msg.sender == primary) {
                  timeLockExpiry += defaultTimeLock;
              } else {
                  timeLockExpiry += extendedTimeLock;
      
                  // any sender that is not the creator will get the extended time lock
                  requestMap[requestMsgHash].extended = true;
              }
      
              emit Requested(_lockId, _callbackAddress, _callbackSelector, nonce, _whitelistedAddress, requestMsgHash, timeLockExpiry);
          }
      
          /** @notice  Completes a pending unlocking with two signatures.
            *
            * @dev  Given a request message hash as two signatures of it from
            * two distinct signers in the signer set, this function completes the
            * unlocking of the pending request by executing the callback.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
            * @param  _recoveryByte1  The public key recovery byte (27 or 28)
            * @param  _ecdsaR1  The R component of an ECDSA signature (R, S) pair
            * @param  _ecdsaS1  The S component of an ECDSA signature (R, S) pair
            * @param  _recoveryByte2  The public key recovery byte (27 or 28)
            * @param  _ecdsaR2  The R component of an ECDSA signature (R, S) pair
            * @param  _ecdsaS2  The S component of an ECDSA signature (R, S) pair
            *
            * @return  success  True if the callback successfully executed.
          */
          function completeUnlock(
              bytes32 _requestMsgHash,
              uint8 _recoveryByte1, bytes32 _ecdsaR1, bytes32 _ecdsaS1,
              uint8 _recoveryByte2, bytes32 _ecdsaR2, bytes32 _ecdsaS2
          )
              public
              onlySigner
              returns (bool success)
          {
              Request storage request = requestMap[_requestMsgHash];
      
              // copy storage to locals before `delete`
              bytes32 lockId = request.lockId;
              address callbackAddress = request.callbackAddress;
              bytes4 callbackSelector = request.callbackSelector;
      
              // failing case of the lookup if the callback address is zero
              require(callbackAddress != address(0), "no zero value for callback address");
      
              // reject confirms of earlier withdrawals buried under later confirmed withdrawals
              require(request.idx > lastCompletedIdxs[callbackAddress][callbackSelector],
              "reject confirms of earlier withdrawals buried under later confirmed withdrawals");
      
              address signer1 = ecrecover(
                  keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
                  _recoveryByte1,
                  _ecdsaR1,
                  _ecdsaS1
              );
              require(signerSet[signer1], "signer is set");
      
              address signer2 = ecrecover(
                  keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
                  _recoveryByte2,
                  _ecdsaR2,
                  _ecdsaS2
              );
              require(signerSet[signer2], "signer is set");
              require(signer1 != signer2, "signers are different");
      
              if (request.extended && ((block.timestamp - request.timestamp) < extendedTimeLock)) {
                  emit TimeLocked(request.timestamp + extendedTimeLock, _requestMsgHash);
                  return false;
              } else if ((block.timestamp - request.timestamp) < defaultTimeLock) {
                  emit TimeLocked(request.timestamp + defaultTimeLock, _requestMsgHash);
                  return false;
              } else {
                  if (address(this).balance > 0) {
                      // reward sender with anti-spam payments
                      msg.sender.transfer(address(this).balance);
                  }
      
                  // raise the waterline for the last completed unlocking
                  lastCompletedIdxs[callbackAddress][callbackSelector] = request.idx;
                  // and delete the request
                  delete requestMap[_requestMsgHash];
      
                  // invoke callback
                  (success,) = callbackAddress.call(abi.encodeWithSelector(callbackSelector, lockId));
      
                  if (success) {
                      emit Completed(lockId, _requestMsgHash, signer1, signer2);
                  } else {
                      emit Failed(lockId, _requestMsgHash, signer1, signer2);
                  }
              }
          }
      
          /** @notice  Reclaim the storage of a pending request that is uncompletable.
            *
            * @dev  If a pending request shares the callback (address and selector) of
            * a later request has been completed, then the request can no longer
            * be completed. This function will reclaim the contract storage of the
            * pending request.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
          */
          function deleteUncompletableRequest(bytes32 _requestMsgHash) public {
              Request storage request = requestMap[_requestMsgHash];
      
              uint256 idx = request.idx;
      
              require(0 < idx && idx < lastCompletedIdxs[request.callbackAddress][request.callbackSelector],
              "there must be a completed latter request with same callback");
      
              delete requestMap[_requestMsgHash];
          }
      
          /** @notice  Extend the time lock of a pending request.
            *
            * @dev  Requests made by the primary account receive the default time lock.
            * This function allows the primary account to apply the extended time lock
            * to one its own requests.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
          */
          function extendRequestTimeLock(bytes32 _requestMsgHash) public onlyPrimary {
              Request storage request = requestMap[_requestMsgHash];
      
              // reject ‘null’ results from the map lookup
              // this can only be the case if an unknown `_requestMsgHash` is received
              require(request.callbackAddress != address(0), "reject ‘null’ results from the map lookup");
      
              // `extendRequestTimeLock` must be idempotent
              require(request.extended != true, "`extendRequestTimeLock` must be idempotent");
      
              // set the `extended` flag; note that this is never unset
              request.extended = true;
      
              emit TimeLockExtended(request.timestamp + extendedTimeLock, _requestMsgHash);
          }
      }
      
      /** @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.
        *
      */
      contract CustodianUpgradeable is LockRequestable {
      
          // TYPES
          /// @dev  The struct type for pending custodian changes.
          struct CustodianChangeRequest {
              address proposedNew;
          }
      
          // MEMBERS
          /// @dev  The address of the account or contract that acts as the custodian.
          address public custodian;
      
          /// @dev  The map of lock ids to pending custodian changes.
          mapping (bytes32 => CustodianChangeRequest) public custodianChangeReqs;
      
          // CONSTRUCTOR
          constructor(
              address _custodian
          )
            LockRequestable()
            public
          {
              custodian = _custodian;
          }
      
          // MODIFIERS
          modifier onlyCustodian {
              require(msg.sender == custodian, "only 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), "no null value for `_proposedCustodian`");
      
              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 != address(0), "reject ‘null’ results from the map lookup");
      
              return changeRequest.proposedNew;
          }
      
          //EVENTS
          /// @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 replaced,
        * which constitutes an implementation upgrade.
        *
        */
      contract ERC20ImplUpgradeable is CustodianUpgradeable  {
      
          // TYPES
          /// @dev  The struct type for pending implementation changes.
          struct ImplChangeRequest {
              address proposedNew;
          }
      
          // MEMBERS
          // @dev  The reference to the active token implementation.
          ERC20Impl public erc20Impl;
      
          /// @dev  The map of lock ids to pending implementation changes.
          mapping (bytes32 => ImplChangeRequest) public implChangeReqs;
      
          // CONSTRUCTOR
          constructor(address _custodian) CustodianUpgradeable(_custodian) public {
              erc20Impl = ERC20Impl(0x0);
          }
      
          // MODIFIERS
          modifier onlyImpl {
              require(msg.sender == address(erc20Impl), "only 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), "no null value for `_proposedImpl`");
      
              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), "reject ‘null’ results from the map lookup");
      
              return ERC20Impl(changeRequest.proposedNew);
          }
      
          //EVENTS
          /// @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);
      }
      
      /** @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.
        *
      */
      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
          constructor(
              string memory _name,
              string memory _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 an 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 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.
        *
        */
      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
          constructor(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;
          }
      }
      
      /** @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').
        *
        */
      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 sweeping 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;
      
          /// @dev The map of blocked addresses.
          mapping (address => bool) public blocked;
      
          // CONSTRUCTOR
          constructor(
                address _erc20Proxy,
                address _erc20Store,
                address _custodian,
                address _sweeper
          )
              CustodianUpgradeable(_custodian)
              public
          {
              require(_sweeper != address(0), "no null value for `_sweeper`");
              erc20Proxy = ERC20Proxy(_erc20Proxy);
              erc20Store = ERC20Store(_erc20Store);
      
              sweeper = _sweeper;
              sweepMsg = keccak256(abi.encodePacked(address(this), "sweep"));
          }
      
          // MODIFIERS
          modifier onlyProxy {
              require(msg.sender == address(erc20Proxy), "only ERC20Proxy");
              _;
          }
          modifier onlySweeper {
              require(msg.sender == sweeper, "only 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 a proxy.
            */
          function approveWithSender(
              address _sender,
              address _spender,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_spender != address(0), "no null value for `_spender`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              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),"no null value for_spender");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
              uint256 newAllowance = currentAllowance + _addedValue;
      
              require(newAllowance >= currentAllowance, "new allowance must not be smaller than previous");
      
              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), "no unspendable approvals"); // disallow unspendable approvals
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
              uint256 newAllowance = currentAllowance - _subtractedValue;
      
              require(newAllowance <= currentAllowance, "new allowance must not be smaller than previous");
      
              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), "no null value for `_receiver`");
              require(blocked[msg.sender] != true, "account blocked");
              require(blocked[_receiver] != true, "_receiver must not be blocked");
              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), "unknown `_lockId`");
              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) {
              require(blocked[msg.sender] != true, "account blocked");
              uint256 balanceOfSender = erc20Store.balances(msg.sender);
              require(_value <= balanceOfSender, "disallow burning more, than amount of the balance");
      
              erc20Store.setBalance(msg.sender, balanceOfSender - _value);
              erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
      
              erc20Proxy.emitTransfer(msg.sender, address(0), _value);
      
              return true;
          }
      
           /** @notice  Burns the specified value from the balance in question.
            *
            * @dev  Suspected balance is subtracted by the amount which will be burnt.
            *
            * @dev If the suspected balance has less than the amount requested, it will be set to 0.
            *
            * @param  _from  The address of suspected balance.
            *
            * @param  _value  The amount to burn.
            *
            * @return success true if the burn succeeded.
            */
          function burn(address _from, uint256 _value) public onlyCustodian returns (bool success) {
              uint256 balance = erc20Store.balances(_from);
              if(_value <= balance){
                  erc20Store.setBalance(_from, balance - _value);
                  erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
                  erc20Proxy.emitTransfer(_from, address(0), _value);
                  emit Wiped(_from, _value, _value, balance - _value);
              }
              else {
                  erc20Store.setBalance(_from,0);
                  erc20Store.setTotalSupply(erc20Store.totalSupply() - balance);
                  erc20Proxy.emitTransfer(_from, address(0), balance);
                  emit Wiped(_from, _value, balance, 0);
              }
              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[] memory _tos, uint256[] memory _values) public returns (bool success) {
              require(_tos.length == _values.length, "_tos and _values must be the same length");
              require(blocked[msg.sender] != true, "account blocked");
              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), "no null values for _tos");
                require(blocked[to] != true, "_tos must not be blocked");
                uint256 v = _values[i];
                require(senderBalance >= v, "insufficient funds");
      
                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 transferred 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[] memory _vs, bytes32[] memory _rs, bytes32[] memory _ss, address _to) public onlySweeper {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_to] != true, "_to must not be blocked");
              require((_vs.length == _rs.length) && (_vs.length == _ss.length), "_vs[], _rs[], _ss lengths are different");
      
              uint256 numSignatures = _vs.length;
              uint256 sweptBalance = 0;
      
              for (uint256 i = 0; i < numSignatures; ++i) {
                  address from = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",sweepMsg)), _vs[i], _rs[i], _ss[i]);
                  require(blocked[from] != true, "_froms must not be blocked");
                  // 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[] memory _froms, address _to) public onlySweeper {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_to] != true, "_to must not be blocked");
              uint256 lenFroms = _froms.length;
              uint256 sweptBalance = 0;
      
              for (uint256 i = 0; i < lenFroms; ++i) {
                  address from = _froms[i];
                  require(blocked[from] != true, "_froms must not be blocked");
                  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 a proxy.
            */
          function transferFromWithSender(
              address _sender,
              address _from,
              address _to,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_to != address(0), "no null values for `_to`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_from] != true, "_from must not be blocked");
              require(blocked[_to] != true, "_to must not be blocked");
      
              uint256 balanceOfFrom = erc20Store.balances(_from);
              require(_value <= balanceOfFrom, "insufficient funds on `_from` balance");
      
              uint256 senderAllowance = erc20Store.allowed(_from, _sender);
              require(_value <= senderAllowance, "insufficient allowance amount");
      
              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 a proxy.
            */
          function transferWithSender(
              address _sender,
              address _to,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_to] != true, "_to must not be blocked");
      
              uint256 balanceOfSender = erc20Store.balances(_sender);
              require(_value <= balanceOfSender, "insufficient funds");
      
              erc20Store.setBalance(_sender, balanceOfSender - _value);
              erc20Store.addBalance(_to, _value);
      
              erc20Proxy.emitTransfer(_sender, _to, _value);
      
              return true;
          }
      
          /** @notice  Transfers the specified value from the balance in question.
            *
            * @dev  Suspected balance is subtracted by the amount which will be transferred.
            *
            * @dev If the suspected balance has less than the amount requested, it will be set to 0.
            *
            * @param  _from  The address of suspected balance.
            *
            * @param  _value  The amount to transfer.
            *
            * @return success true if the transfer succeeded.
            */
          function forceTransfer(
              address _from,
              address _to,
              uint256 _value
          )
              public
              onlyCustodian
              returns (bool success)
          {
              require(_to != address(0), "no null value for `_to`");
              uint256 balanceOfSender = erc20Store.balances(_from);
              if(_value <= balanceOfSender) {
                  erc20Store.setBalance(_from, balanceOfSender - _value);
                  erc20Store.addBalance(_to, _value);
      
                  erc20Proxy.emitTransfer(_from, _to, _value);
              } else {
                  erc20Store.setBalance(_from, 0);
                  erc20Store.addBalance(_to, balanceOfSender);
      
                  erc20Proxy.emitTransfer(_from, _to, balanceOfSender);
              }
      
              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);
          }
      
          /// @dev internal use only.
          function blockWallet(address wallet) public onlyCustodian returns (bool success) {
              blocked[wallet] = true;
              return true;
          }
      
          /// @dev internal use only.
          function unblockWallet(address wallet) public onlyCustodian returns (bool success) {
              blocked[wallet] = false;
              return true;
          }
      
          // 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);
      
          /** @dev Emitted by successful `confirmWipe` calls.
            *
            * @param _value Amount requested to be burned.
            *
            * @param _burned Amount which was burned.
            *
            * @param _balance Amount left on account after burn.
            *
            * @param _from Account which balance was burned.
            */
           event Wiped(address _from, uint256 _value, uint256 _burned, uint _balance);
      }
      
      /** @title  A contact to govern hybrid control over increases to the token supply and managing accounts.
        *
        * @notice  A contract that acts as a custodian of the active token
        * implementation, and an intermediary between it and the ‘true’ custodian.
        * It preserves the functionality of direct custodianship as well as granting
        * limited control of token supply increases to an additional key.
        *
        * @dev  This contract is a layer of indirection between an instance of
        * ERC20Impl and a custodian. The functionality of the custodianship over
        * the token implementation is preserved (printing and custodian changes),
        * but this contract adds the ability for an additional key
        * (the 'controller') to increase the token supply up to a ceiling,
        * and this supply ceiling can only be raised by the custodian.
        *
        */
      contract Controller is LockRequestable {
      
          // TYPES
          /// @dev The struct type for pending ceiling raises.
          struct PendingCeilingRaise {
              uint256 raiseBy;
          }
      
          /// @dev The struct type for pending wipes.
          struct wipeAddress {
              uint256 value;
              address from;
          }
      
          /// @dev The struct type for pending force transfer requests.
          struct forceTransferRequest {
              uint256 value;
              address from;
              address to;
          }
      
          // MEMBERS
          /// @dev  The reference to the active token implementation.
          ERC20Impl public erc20Impl;
      
          /// @dev  The address of the account or contract that acts as the custodian.
          Custodian public custodian;
      
          /** @dev  The sole authorized caller of limited printing.
            * This account is also authorized to lower the supply ceiling and
            * wiping suspected accounts or force transferring funds from them.
            */
          address public controller;
      
          /** @dev  The maximum that the token supply can be increased to
            * through the use of the limited printing feature.
            * The difference between the current total supply and the supply
            * ceiling is what is available to the 'controller' account.
            * The value of the ceiling can only be increased by the custodian.
            */
          uint256 public totalSupplyCeiling;
      
          /// @dev  The map of lock ids to pending ceiling raises.
          mapping (bytes32 => PendingCeilingRaise) public pendingRaiseMap;
      
          /// @dev  The map of lock ids to pending wipes.
          mapping (bytes32 => wipeAddress[]) public pendingWipeMap;
      
          /// @dev  The map of lock ids to pending force transfer requests.
          mapping (bytes32 => forceTransferRequest) public pendingForceTransferRequestMap;
      
          // CONSTRUCTOR
          constructor(
              address _erc20Impl,
              address _custodian,
              address _controller,
              uint256 _initialCeiling
          )
              public
          {
              erc20Impl = ERC20Impl(_erc20Impl);
              custodian = Custodian(_custodian);
              controller = _controller;
              totalSupplyCeiling = _initialCeiling;
          }
      
          // MODIFIERS
          modifier onlyCustodian {
              require(msg.sender == address(custodian), "only custodian");
              _;
          }
          modifier onlyController {
              require(msg.sender == controller, "only controller");
              _;
          }
      
          modifier onlySigner {
              require(custodian.signerSet(msg.sender) == true, "only signer");
              _;
          }
      
          /** @notice  Increases the token supply, with the newly created tokens
            * being added to the balance of the specified account.
            *
            * @dev  The function checks that the value to print does not
            * exceed the supply ceiling when added to the current total supply.
            * NOTE: printing to the zero address is disallowed.
            *
            * @param  _receiver  The receiving address of the print.
            * @param  _value  The number of tokens to add to the total supply and the
            * balance of the receiving address.
            */
          function limitedPrint(address _receiver, uint256 _value) public onlyController {
              uint256 totalSupply = erc20Impl.totalSupply();
              uint256 newTotalSupply = totalSupply + _value;
      
              require(newTotalSupply >= totalSupply, "new total supply overflow");
              require(newTotalSupply <= totalSupplyCeiling, "total supply ceiling overflow");
              erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
          }
      
          /** @notice  Requests wipe of suspected accounts.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Only controller can call this function, and only the custodian
            * can confirm the request.
            *
            * @param  _froms  The array of suspected accounts.
            *
            * @param  _values  array of amounts by which suspected accounts will be wiped.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestWipe(address[] memory _froms, uint256[] memory _values) public onlyController returns (bytes32 lockId) {
              require(_froms.length == _values.length, "_froms[] and _values[] must be same length");
              lockId = generateLockId();
              uint256 amount = _froms.length;
      
              for(uint256 i = 0; i < amount; i++) {
                  address from = _froms[i];
                  uint256 value = _values[i];
                  pendingWipeMap[lockId].push(wipeAddress(value, from));
              }
      
              emit WipeRequested(lockId);
      
              return lockId;
          }
      
          /** @notice  Confirms a pending wipe of suspected accounts.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending wipe, the amount requested is burned from the suspected accounts.
            *
            * @param  _lockId  The identifier of a pending wipe request.
            */
          function confirmWipe(bytes32 _lockId) public onlyCustodian {
              uint256 amount = pendingWipeMap[_lockId].length;
              for(uint256 i = 0; i < amount; i++) {
                  wipeAddress memory addr = pendingWipeMap[_lockId][i];
                  address from = addr.from;
                  uint256 value = addr.value;
                  erc20Impl.burn(from, value);
              }
      
              delete pendingWipeMap[_lockId];
      
              emit WipeCompleted(_lockId);
          }
      
          /** @notice  Requests force transfer from the suspected account.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Only controller can call this function, and only the custodian
            * can confirm the request.
            *
            * @param  _from  address of suspected account.
            *
            * @param  _to  address of reciever.
            *
            * @param  _value  amount which will be transferred.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestForceTransfer(address _from, address _to, uint256 _value) public onlyController returns (bytes32 lockId) {
              lockId = generateLockId();
              require (_value != 0, "no zero value transfers");
              pendingForceTransferRequestMap[lockId] = forceTransferRequest(_value, _from, _to);
      
              emit ForceTransferRequested(lockId, _from, _to, _value);
      
              return lockId;
          }
      
          /** @notice  Confirms a pending force transfer request.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending transfer request, the amount requested is transferred from the suspected account.
            *
            * @param  _lockId  The identifier of a pending transfer request.
            */
          function confirmForceTransfer(bytes32 _lockId) public onlyCustodian {
              address from = pendingForceTransferRequestMap[_lockId].from;
              address to = pendingForceTransferRequestMap[_lockId].to;
              uint256 value = pendingForceTransferRequestMap[_lockId].value;
      
              delete pendingForceTransferRequestMap[_lockId];
      
              erc20Impl.forceTransfer(from, to, value);
      
              emit ForceTransferCompleted(_lockId, from, to, value);
          }
      
          /** @notice  Requests an increase to the supply ceiling.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Anyone can call this function, but confirming the request is authorized
            * by the custodian.
            *
            * @param  _raiseBy  The amount by which to raise the ceiling.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestCeilingRaise(uint256 _raiseBy) public returns (bytes32 lockId) {
              require(_raiseBy != 0, "no zero ceiling raise");
      
              lockId = generateLockId();
      
              pendingRaiseMap[lockId] = PendingCeilingRaise({
                  raiseBy: _raiseBy
              });
      
              emit CeilingRaiseLocked(lockId, _raiseBy);
          }
      
          /** @notice  Confirms a pending increase in the token supply.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending ceiling increase, the amount requested is added to the
            * current supply ceiling.
            * NOTE: this function will not execute any raise that would overflow the
            * supply ceiling, but it will not revert either.
            *
            * @param  _lockId  The identifier of a pending ceiling raise request.
            */
          function confirmCeilingRaise(bytes32 _lockId) public onlyCustodian {
              PendingCeilingRaise storage pendingRaise = pendingRaiseMap[_lockId];
      
              // copy locals of references to struct members
              uint256 raiseBy = pendingRaise.raiseBy;
              // accounts for a gibberish _lockId
              require(raiseBy != 0, "no gibberish _lockId");
      
              delete pendingRaiseMap[_lockId];
      
              uint256 newCeiling = totalSupplyCeiling + raiseBy;
              // overflow check
              if (newCeiling >= totalSupplyCeiling) {
                  totalSupplyCeiling = newCeiling;
      
                  emit CeilingRaiseConfirmed(_lockId, raiseBy, newCeiling);
              }
          }
      
          /** @notice  Lowers the supply ceiling, further constraining the bound of
            * what can be printed by the controller.
            *
            * @dev  The controller is the sole authorized caller of this function,
            * so it is the only account that can elect to lower its limit to increase
            * the token supply.
            *
            * @param  _lowerBy  The amount by which to lower the supply ceiling.
            */
          function lowerCeiling(uint256 _lowerBy) public onlyController {
              uint256 newCeiling = totalSupplyCeiling - _lowerBy;
              // overflow check
              require(newCeiling <= totalSupplyCeiling, "totalSupplyCeiling overflow");
              totalSupplyCeiling = newCeiling;
      
              emit CeilingLowered(_lowerBy, newCeiling);
          }
      
          /** @notice  Pass-through control of print confirmation, allowing this
            * contract's custodian to act as the custodian of the associated
            * active token implementation.
            *
            * @dev  This contract is the direct custodian of the active token
            * implementation, but this function allows this contract's custodian
            * to act as though it were the direct custodian of the active
            * token implementation. Therefore the custodian retains control of
            * unlimited printing.
            *
            * @param  _lockId  The identifier of a pending print request in
            * the associated active token implementation.
            */
          function confirmPrintProxy(bytes32 _lockId) public onlyCustodian {
              erc20Impl.confirmPrint(_lockId);
          }
      
          /** @notice  Pass-through control of custodian change confirmation,
            * allowing this contract's custodian to act as the custodian of
            * the associated active token implementation.
            *
            * @dev  This contract is the direct custodian of the active token
            * implementation, but this function allows this contract's custodian
            * to act as though it were the direct custodian of the active
            * token implementation. Therefore the custodian retains control of
            * custodian changes.
            *
            * @param  _lockId  The identifier of a pending custodian change request
            * in the associated active token implementation.
            */
          function confirmCustodianChangeProxy(bytes32 _lockId) public onlyCustodian {
              erc20Impl.confirmCustodianChange(_lockId);
          }
      
          /** @notice  Blocks all transactions with a wallet.
            *
            * @dev Only signers from custodian are authorized to call this function
            *
            * @param  wallet account which will be blocked.
            */
          function blockWallet(address wallet) public onlySigner {
              erc20Impl.blockWallet(wallet);
              emit Blocked(wallet);
          }
      
          /** @notice Unblocks all transactions with a wallet.
            *
            * @dev Only signers from custodian are authorized to call this function
            *
            * @param  wallet account which will be unblocked.
            */
          function unblockWallet(address wallet) public onlySigner {
              erc20Impl.unblockWallet(wallet);
              emit Unblocked(wallet);
          }
      
          // EVENTS
          /// @dev  Emitted by successful `requestCeilingRaise` calls.
          event CeilingRaiseLocked(bytes32 _lockId, uint256 _raiseBy);
      
          /// @dev  Emitted by successful `confirmCeilingRaise` calls.
          event CeilingRaiseConfirmed(bytes32 _lockId, uint256 _raiseBy, uint256 _newCeiling);
      
          /// @dev  Emitted by successful `lowerCeiling` calls.
          event CeilingLowered(uint256 _lowerBy, uint256 _newCeiling);
      
          /// @dev  Emitted by successful `blockWallet` calls.
          event Blocked(address _wallet);
      
          /// @dev  Emitted by successful `unblockWallet` calls.
          event Unblocked(address _wallet);
      
           /// @dev  Emitted by successful `requestForceTransfer` calls.
          event ForceTransferRequested(bytes32 _lockId, address _from, address _to, uint256 _value);
      
          /// @dev  Emitted by successful `confirmForceTransfer` calls.
          event ForceTransferCompleted(bytes32 _lockId, address _from, address _to, uint256 _value);
      
          /// @dev  Emitted by successful `requestWipe` calls.
          event WipeRequested(bytes32 _lockId);
      
          /// @dev  Emitted by successful `confirmWipe` calls.
          event WipeCompleted(bytes32 _lockId);
      }

      File 3 of 3: ERC20Store
      pragma solidity ^0.5.10;
      
      /** @title  A contract for generating unique identifiers
        *
        * @notice  A contract that provides an identifier generation scheme,
        * guaranteeing uniqueness across all contracts that inherit from it,
        * as well as the unpredictability of future identifiers.
        *
        * @dev  This contract is intended to be inherited by any contract that
        * implements the callback software pattern for cooperative custodianship.
        *
      */
      contract LockRequestable {
      
          // MEMBERS
          /// @notice  the count of all invocations of `generateLockId`.
          uint256 public lockRequestCount;
      
          // CONSTRUCTOR
          constructor() 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 ensures 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(abi.encodePacked(blockhash(block.number - 1), address(this), ++lockRequestCount));
          }
      }
      
      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  A dual control contract.
        *
        * @notice  A general-purpose contract that implements dual control over
        * co-operating contracts through a callback mechanism.
        *
        * @dev  This contract implements dual control through a 2-of-N
        * threshold multi-signature scheme. The contract recognizes a set of N signers,
        * and will unlock requests with signatures from any distinct pair of them.
        * This contract signals the unlocking through a co-operative callback
        * scheme.
        * This contract also provides time lock and revocation features.
        * Requests made by a 'primary' account have a default time lock applied.
        * All other requests must pay a 1 ETH stake and have an extended time lock
        * applied.
        * A request that is completed will prevent all previous pending requests
        * that share the same callback from being completed: this is the
        * revocation feature.
        *
        */
      contract Custodian {
      
          // TYPES
          /** @dev  The `Request` struct stores a pending unlocking.
            * `callbackAddress` and `callbackSelector` are the data required to
            * make a callback. The custodian completes the process by
            * calling `callbackAddress.call(callbackSelector, lockId)`, which
            * signals to the contract co-operating with the Custodian that
            * the 2-of-N signatures have been provided and verified.
            */
          struct Request {
              bytes32 lockId;
              bytes4 callbackSelector;  // bytes4 and address can be packed into 1 word
              address callbackAddress;
              uint256 idx;
              uint256 timestamp;
              bool extended;
          }
      
          // EVENTS
          /// @dev  Emitted by successful `requestUnlock` calls.
          event Requested(
              bytes32 _lockId,
              address _callbackAddress,
              bytes4 _callbackSelector,
              uint256 _nonce,
              address _whitelistedAddress,
              bytes32 _requestMsgHash,
              uint256 _timeLockExpiry
          );
      
          /// @dev  Emitted by `completeUnlock` calls on requests in the time-locked state.
          event TimeLocked(
              uint256 _timeLockExpiry,
              bytes32 _requestMsgHash
          );
      
          /// @dev  Emitted by successful `completeUnlock` calls.
          event Completed(
              bytes32 _lockId,
              bytes32 _requestMsgHash,
              address _signer1,
              address _signer2
          );
      
          /// @dev  Emitted by `completeUnlock` calls where the callback failed.
          event Failed(
              bytes32 _lockId,
              bytes32 _requestMsgHash,
              address _signer1,
              address _signer2
          );
      
          /// @dev  Emitted by successful `extendRequestTimeLock` calls.
          event TimeLockExtended(
              uint256 _timeLockExpiry,
              bytes32 _requestMsgHash
          );
      
           // MEMBERS
          /** @dev  The count of all requests.
            * This value is used as a nonce, incorporated into the request hash.
            */
          uint256 public requestCount;
      
          /// @dev  The set of signers: signatures from two signers unlock a pending request.
          mapping (address => bool) public signerSet;
      
          /// @dev  The map of request hashes to pending requests.
          mapping (bytes32 => Request) public requestMap;
      
          /// @dev  The map of callback addresses to callback selectors to request indexes.
          mapping (address => mapping (bytes4 => uint256)) public lastCompletedIdxs;
      
          /** @dev  The default period (in seconds) to time-lock requests.
            * All requests will be subject to this default time lock, and the duration
            * is fixed at contract creation.
            */
          uint256 public defaultTimeLock;
      
          /** @dev  The extended period (in seconds) to time-lock requests.
            * Requests not from the primary account are subject to this time lock.
            * The primary account may also elect to extend the time lock on requests
            * that originally received the default.
            */
          uint256 public extendedTimeLock;
      
          /// @dev  The primary account is the privileged account for making requests.
          address public primary;
      
          // CONSTRUCTOR
          constructor(
              address[] memory _signers,
              uint256 _defaultTimeLock,
              uint256 _extendedTimeLock,
              address _primary
          )
              public
          {
              // check for at least two `_signers`
              require(_signers.length >= 2, "at least two `_signers`");
      
               // validate time lock params
              require(_defaultTimeLock <= _extendedTimeLock, "valid timelock params");
              defaultTimeLock = _defaultTimeLock;
              extendedTimeLock = _extendedTimeLock;
      
              primary = _primary;
      
              // explicitly initialize `requestCount` to zero
              requestCount = 0;
              // turn the array into a set
              for (uint i = 0; i < _signers.length; i++) {
                  // no zero addresses or duplicates
                  require(_signers[i] != address(0) && !signerSet[_signers[i]], "no zero addresses or duplicates");
                  signerSet[_signers[i]] = true;
              }
          }
      
          // MODIFIERS
          modifier onlyPrimary {
              require(msg.sender == primary, "only primary");
              _;
          }
      
           modifier onlySigner {
              require(signerSet[msg.sender], "only signer");
              _;
          }
      
          // METHODS
          /** @notice  Requests an unlocking with a lock identifier and a callback.
            *
            * @dev  If called by an account other than the primary a 1 ETH stake
            * must be paid. When the request is unlocked stake will be transferred to the message sender.
            * This is an anti-spam measure. As well as the callback
            * and the lock identifier parameters a 'whitelisted address' is required
            * for compatibility with existing signature schemes.
            *
            * @param  _lockId  The identifier of a pending request in a co-operating contract.
            * @param  _callbackAddress  The address of a co-operating contract.
            * @param  _callbackSelector  The function selector of a function within
            * the co-operating contract at address `_callbackAddress`.
            * @param  _whitelistedAddress  An address whitelisted in existing
            * offline control protocols.
            *
            * @return  requestMsgHash  The hash of a request message to be signed.
          */
          function requestUnlock(
              bytes32 _lockId,
              address _callbackAddress,
              bytes4 _callbackSelector,
              address _whitelistedAddress
          )
              public
              payable
              returns (bytes32 requestMsgHash)
          {
              require(msg.sender == primary || msg.value >= 1 ether, "sender is primary or stake is paid");
      
              // disallow using a zero value for the callback address
              require(_callbackAddress != address(0), "no zero value for callback address");
      
              uint256 requestIdx = ++requestCount;
              // compute a nonce value
              // - the blockhash prevents prediction of future nonces
              // - the address of this contract prevents conflicts with co-operating contracts using this scheme
              // - the counter prevents conflicts arising from multiple txs within the same block
              uint256 nonce = uint256(keccak256(abi.encodePacked(blockhash(block.number - 1), address(this), requestIdx)));
      
              requestMsgHash = keccak256(
                  abi.encodePacked(
                      nonce,
                      _whitelistedAddress,
                      uint256(0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF)
                  )
              );
              requestMap[requestMsgHash] = Request({
                  lockId: _lockId,
                  callbackSelector: _callbackSelector,
                  callbackAddress: _callbackAddress,
                  idx: requestIdx,
                  timestamp: block.timestamp,
                  extended: false
              });
      
              // compute the expiry time
              uint256 timeLockExpiry = block.timestamp;
              if (msg.sender == primary) {
                  timeLockExpiry += defaultTimeLock;
              } else {
                  timeLockExpiry += extendedTimeLock;
      
                  // any sender that is not the creator will get the extended time lock
                  requestMap[requestMsgHash].extended = true;
              }
      
              emit Requested(_lockId, _callbackAddress, _callbackSelector, nonce, _whitelistedAddress, requestMsgHash, timeLockExpiry);
          }
      
          /** @notice  Completes a pending unlocking with two signatures.
            *
            * @dev  Given a request message hash as two signatures of it from
            * two distinct signers in the signer set, this function completes the
            * unlocking of the pending request by executing the callback.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
            * @param  _recoveryByte1  The public key recovery byte (27 or 28)
            * @param  _ecdsaR1  The R component of an ECDSA signature (R, S) pair
            * @param  _ecdsaS1  The S component of an ECDSA signature (R, S) pair
            * @param  _recoveryByte2  The public key recovery byte (27 or 28)
            * @param  _ecdsaR2  The R component of an ECDSA signature (R, S) pair
            * @param  _ecdsaS2  The S component of an ECDSA signature (R, S) pair
            *
            * @return  success  True if the callback successfully executed.
          */
          function completeUnlock(
              bytes32 _requestMsgHash,
              uint8 _recoveryByte1, bytes32 _ecdsaR1, bytes32 _ecdsaS1,
              uint8 _recoveryByte2, bytes32 _ecdsaR2, bytes32 _ecdsaS2
          )
              public
              onlySigner
              returns (bool success)
          {
              Request storage request = requestMap[_requestMsgHash];
      
              // copy storage to locals before `delete`
              bytes32 lockId = request.lockId;
              address callbackAddress = request.callbackAddress;
              bytes4 callbackSelector = request.callbackSelector;
      
              // failing case of the lookup if the callback address is zero
              require(callbackAddress != address(0), "no zero value for callback address");
      
              // reject confirms of earlier withdrawals buried under later confirmed withdrawals
              require(request.idx > lastCompletedIdxs[callbackAddress][callbackSelector],
              "reject confirms of earlier withdrawals buried under later confirmed withdrawals");
      
              address signer1 = ecrecover(
                  keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
                  _recoveryByte1,
                  _ecdsaR1,
                  _ecdsaS1
              );
              require(signerSet[signer1], "signer is set");
      
              address signer2 = ecrecover(
                  keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32", _requestMsgHash)),
                  _recoveryByte2,
                  _ecdsaR2,
                  _ecdsaS2
              );
              require(signerSet[signer2], "signer is set");
              require(signer1 != signer2, "signers are different");
      
              if (request.extended && ((block.timestamp - request.timestamp) < extendedTimeLock)) {
                  emit TimeLocked(request.timestamp + extendedTimeLock, _requestMsgHash);
                  return false;
              } else if ((block.timestamp - request.timestamp) < defaultTimeLock) {
                  emit TimeLocked(request.timestamp + defaultTimeLock, _requestMsgHash);
                  return false;
              } else {
                  if (address(this).balance > 0) {
                      // reward sender with anti-spam payments
                      msg.sender.transfer(address(this).balance);
                  }
      
                  // raise the waterline for the last completed unlocking
                  lastCompletedIdxs[callbackAddress][callbackSelector] = request.idx;
                  // and delete the request
                  delete requestMap[_requestMsgHash];
      
                  // invoke callback
                  (success,) = callbackAddress.call(abi.encodeWithSelector(callbackSelector, lockId));
      
                  if (success) {
                      emit Completed(lockId, _requestMsgHash, signer1, signer2);
                  } else {
                      emit Failed(lockId, _requestMsgHash, signer1, signer2);
                  }
              }
          }
      
          /** @notice  Reclaim the storage of a pending request that is uncompletable.
            *
            * @dev  If a pending request shares the callback (address and selector) of
            * a later request has been completed, then the request can no longer
            * be completed. This function will reclaim the contract storage of the
            * pending request.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
          */
          function deleteUncompletableRequest(bytes32 _requestMsgHash) public {
              Request storage request = requestMap[_requestMsgHash];
      
              uint256 idx = request.idx;
      
              require(0 < idx && idx < lastCompletedIdxs[request.callbackAddress][request.callbackSelector],
              "there must be a completed latter request with same callback");
      
              delete requestMap[_requestMsgHash];
          }
      
          /** @notice  Extend the time lock of a pending request.
            *
            * @dev  Requests made by the primary account receive the default time lock.
            * This function allows the primary account to apply the extended time lock
            * to one its own requests.
            *
            * @param  _requestMsgHash  The request message hash of a pending request.
          */
          function extendRequestTimeLock(bytes32 _requestMsgHash) public onlyPrimary {
              Request storage request = requestMap[_requestMsgHash];
      
              // reject ‘null’ results from the map lookup
              // this can only be the case if an unknown `_requestMsgHash` is received
              require(request.callbackAddress != address(0), "reject ‘null’ results from the map lookup");
      
              // `extendRequestTimeLock` must be idempotent
              require(request.extended != true, "`extendRequestTimeLock` must be idempotent");
      
              // set the `extended` flag; note that this is never unset
              request.extended = true;
      
              emit TimeLockExtended(request.timestamp + extendedTimeLock, _requestMsgHash);
          }
      }
      
      /** @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.
        *
      */
      contract CustodianUpgradeable is LockRequestable {
      
          // TYPES
          /// @dev  The struct type for pending custodian changes.
          struct CustodianChangeRequest {
              address proposedNew;
          }
      
          // MEMBERS
          /// @dev  The address of the account or contract that acts as the custodian.
          address public custodian;
      
          /// @dev  The map of lock ids to pending custodian changes.
          mapping (bytes32 => CustodianChangeRequest) public custodianChangeReqs;
      
          // CONSTRUCTOR
          constructor(
              address _custodian
          )
            LockRequestable()
            public
          {
              custodian = _custodian;
          }
      
          // MODIFIERS
          modifier onlyCustodian {
              require(msg.sender == custodian, "only 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), "no null value for `_proposedCustodian`");
      
              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 != address(0), "reject ‘null’ results from the map lookup");
      
              return changeRequest.proposedNew;
          }
      
          //EVENTS
          /// @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 replaced,
        * which constitutes an implementation upgrade.
        *
        */
      contract ERC20ImplUpgradeable is CustodianUpgradeable  {
      
          // TYPES
          /// @dev  The struct type for pending implementation changes.
          struct ImplChangeRequest {
              address proposedNew;
          }
      
          // MEMBERS
          // @dev  The reference to the active token implementation.
          ERC20Impl public erc20Impl;
      
          /// @dev  The map of lock ids to pending implementation changes.
          mapping (bytes32 => ImplChangeRequest) public implChangeReqs;
      
          // CONSTRUCTOR
          constructor(address _custodian) CustodianUpgradeable(_custodian) public {
              erc20Impl = ERC20Impl(0x0);
          }
      
          // MODIFIERS
          modifier onlyImpl {
              require(msg.sender == address(erc20Impl), "only 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), "no null value for `_proposedImpl`");
      
              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), "reject ‘null’ results from the map lookup");
      
              return ERC20Impl(changeRequest.proposedNew);
          }
      
          //EVENTS
          /// @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);
      }
      
      /** @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.
        *
      */
      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
          constructor(
              string memory _name,
              string memory _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 an 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 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.
        *
        */
      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
          constructor(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;
          }
      }
      
      /** @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').
        *
        */
      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 sweeping 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;
      
          /// @dev The map of blocked addresses.
          mapping (address => bool) public blocked;
      
          // CONSTRUCTOR
          constructor(
                address _erc20Proxy,
                address _erc20Store,
                address _custodian,
                address _sweeper
          )
              CustodianUpgradeable(_custodian)
              public
          {
              require(_sweeper != address(0), "no null value for `_sweeper`");
              erc20Proxy = ERC20Proxy(_erc20Proxy);
              erc20Store = ERC20Store(_erc20Store);
      
              sweeper = _sweeper;
              sweepMsg = keccak256(abi.encodePacked(address(this), "sweep"));
          }
      
          // MODIFIERS
          modifier onlyProxy {
              require(msg.sender == address(erc20Proxy), "only ERC20Proxy");
              _;
          }
          modifier onlySweeper {
              require(msg.sender == sweeper, "only 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 a proxy.
            */
          function approveWithSender(
              address _sender,
              address _spender,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_spender != address(0), "no null value for `_spender`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              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),"no null value for_spender");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
              uint256 newAllowance = currentAllowance + _addedValue;
      
              require(newAllowance >= currentAllowance, "new allowance must not be smaller than previous");
      
              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), "no unspendable approvals"); // disallow unspendable approvals
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_spender] != true, "_spender must not be blocked");
              uint256 currentAllowance = erc20Store.allowed(_sender, _spender);
              uint256 newAllowance = currentAllowance - _subtractedValue;
      
              require(newAllowance <= currentAllowance, "new allowance must not be smaller than previous");
      
              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), "no null value for `_receiver`");
              require(blocked[msg.sender] != true, "account blocked");
              require(blocked[_receiver] != true, "_receiver must not be blocked");
              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), "unknown `_lockId`");
              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) {
              require(blocked[msg.sender] != true, "account blocked");
              uint256 balanceOfSender = erc20Store.balances(msg.sender);
              require(_value <= balanceOfSender, "disallow burning more, than amount of the balance");
      
              erc20Store.setBalance(msg.sender, balanceOfSender - _value);
              erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
      
              erc20Proxy.emitTransfer(msg.sender, address(0), _value);
      
              return true;
          }
      
           /** @notice  Burns the specified value from the balance in question.
            *
            * @dev  Suspected balance is subtracted by the amount which will be burnt.
            *
            * @dev If the suspected balance has less than the amount requested, it will be set to 0.
            *
            * @param  _from  The address of suspected balance.
            *
            * @param  _value  The amount to burn.
            *
            * @return success true if the burn succeeded.
            */
          function burn(address _from, uint256 _value) public onlyCustodian returns (bool success) {
              uint256 balance = erc20Store.balances(_from);
              if(_value <= balance){
                  erc20Store.setBalance(_from, balance - _value);
                  erc20Store.setTotalSupply(erc20Store.totalSupply() - _value);
                  erc20Proxy.emitTransfer(_from, address(0), _value);
                  emit Wiped(_from, _value, _value, balance - _value);
              }
              else {
                  erc20Store.setBalance(_from,0);
                  erc20Store.setTotalSupply(erc20Store.totalSupply() - balance);
                  erc20Proxy.emitTransfer(_from, address(0), balance);
                  emit Wiped(_from, _value, balance, 0);
              }
              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[] memory _tos, uint256[] memory _values) public returns (bool success) {
              require(_tos.length == _values.length, "_tos and _values must be the same length");
              require(blocked[msg.sender] != true, "account blocked");
              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), "no null values for _tos");
                require(blocked[to] != true, "_tos must not be blocked");
                uint256 v = _values[i];
                require(senderBalance >= v, "insufficient funds");
      
                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 transferred 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[] memory _vs, bytes32[] memory _rs, bytes32[] memory _ss, address _to) public onlySweeper {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_to] != true, "_to must not be blocked");
              require((_vs.length == _rs.length) && (_vs.length == _ss.length), "_vs[], _rs[], _ss lengths are different");
      
              uint256 numSignatures = _vs.length;
              uint256 sweptBalance = 0;
      
              for (uint256 i = 0; i < numSignatures; ++i) {
                  address from = ecrecover(keccak256(abi.encodePacked("\x19Ethereum Signed Message:\n32",sweepMsg)), _vs[i], _rs[i], _ss[i]);
                  require(blocked[from] != true, "_froms must not be blocked");
                  // 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[] memory _froms, address _to) public onlySweeper {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_to] != true, "_to must not be blocked");
              uint256 lenFroms = _froms.length;
              uint256 sweptBalance = 0;
      
              for (uint256 i = 0; i < lenFroms; ++i) {
                  address from = _froms[i];
                  require(blocked[from] != true, "_froms must not be blocked");
                  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 a proxy.
            */
          function transferFromWithSender(
              address _sender,
              address _from,
              address _to,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_to != address(0), "no null values for `_to`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_from] != true, "_from must not be blocked");
              require(blocked[_to] != true, "_to must not be blocked");
      
              uint256 balanceOfFrom = erc20Store.balances(_from);
              require(_value <= balanceOfFrom, "insufficient funds on `_from` balance");
      
              uint256 senderAllowance = erc20Store.allowed(_from, _sender);
              require(_value <= senderAllowance, "insufficient allowance amount");
      
              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 a proxy.
            */
          function transferWithSender(
              address _sender,
              address _to,
              uint256 _value
          )
              public
              onlyProxy
              returns (bool success)
          {
              require(_to != address(0), "no null value for `_to`");
              require(blocked[_sender] != true, "_sender must not be blocked");
              require(blocked[_to] != true, "_to must not be blocked");
      
              uint256 balanceOfSender = erc20Store.balances(_sender);
              require(_value <= balanceOfSender, "insufficient funds");
      
              erc20Store.setBalance(_sender, balanceOfSender - _value);
              erc20Store.addBalance(_to, _value);
      
              erc20Proxy.emitTransfer(_sender, _to, _value);
      
              return true;
          }
      
          /** @notice  Transfers the specified value from the balance in question.
            *
            * @dev  Suspected balance is subtracted by the amount which will be transferred.
            *
            * @dev If the suspected balance has less than the amount requested, it will be set to 0.
            *
            * @param  _from  The address of suspected balance.
            *
            * @param  _value  The amount to transfer.
            *
            * @return success true if the transfer succeeded.
            */
          function forceTransfer(
              address _from,
              address _to,
              uint256 _value
          )
              public
              onlyCustodian
              returns (bool success)
          {
              require(_to != address(0), "no null value for `_to`");
              uint256 balanceOfSender = erc20Store.balances(_from);
              if(_value <= balanceOfSender) {
                  erc20Store.setBalance(_from, balanceOfSender - _value);
                  erc20Store.addBalance(_to, _value);
      
                  erc20Proxy.emitTransfer(_from, _to, _value);
              } else {
                  erc20Store.setBalance(_from, 0);
                  erc20Store.addBalance(_to, balanceOfSender);
      
                  erc20Proxy.emitTransfer(_from, _to, balanceOfSender);
              }
      
              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);
          }
      
          /// @dev internal use only.
          function blockWallet(address wallet) public onlyCustodian returns (bool success) {
              blocked[wallet] = true;
              return true;
          }
      
          /// @dev internal use only.
          function unblockWallet(address wallet) public onlyCustodian returns (bool success) {
              blocked[wallet] = false;
              return true;
          }
      
          // 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);
      
          /** @dev Emitted by successful `confirmWipe` calls.
            *
            * @param _value Amount requested to be burned.
            *
            * @param _burned Amount which was burned.
            *
            * @param _balance Amount left on account after burn.
            *
            * @param _from Account which balance was burned.
            */
           event Wiped(address _from, uint256 _value, uint256 _burned, uint _balance);
      }
      
      /** @title  A contact to govern hybrid control over increases to the token supply and managing accounts.
        *
        * @notice  A contract that acts as a custodian of the active token
        * implementation, and an intermediary between it and the ‘true’ custodian.
        * It preserves the functionality of direct custodianship as well as granting
        * limited control of token supply increases to an additional key.
        *
        * @dev  This contract is a layer of indirection between an instance of
        * ERC20Impl and a custodian. The functionality of the custodianship over
        * the token implementation is preserved (printing and custodian changes),
        * but this contract adds the ability for an additional key
        * (the 'controller') to increase the token supply up to a ceiling,
        * and this supply ceiling can only be raised by the custodian.
        *
        */
      contract Controller is LockRequestable {
      
          // TYPES
          /// @dev The struct type for pending ceiling raises.
          struct PendingCeilingRaise {
              uint256 raiseBy;
          }
      
          /// @dev The struct type for pending wipes.
          struct wipeAddress {
              uint256 value;
              address from;
          }
      
          /// @dev The struct type for pending force transfer requests.
          struct forceTransferRequest {
              uint256 value;
              address from;
              address to;
          }
      
          // MEMBERS
          /// @dev  The reference to the active token implementation.
          ERC20Impl public erc20Impl;
      
          /// @dev  The address of the account or contract that acts as the custodian.
          Custodian public custodian;
      
          /** @dev  The sole authorized caller of limited printing.
            * This account is also authorized to lower the supply ceiling and
            * wiping suspected accounts or force transferring funds from them.
            */
          address public controller;
      
          /** @dev  The maximum that the token supply can be increased to
            * through the use of the limited printing feature.
            * The difference between the current total supply and the supply
            * ceiling is what is available to the 'controller' account.
            * The value of the ceiling can only be increased by the custodian.
            */
          uint256 public totalSupplyCeiling;
      
          /// @dev  The map of lock ids to pending ceiling raises.
          mapping (bytes32 => PendingCeilingRaise) public pendingRaiseMap;
      
          /// @dev  The map of lock ids to pending wipes.
          mapping (bytes32 => wipeAddress[]) public pendingWipeMap;
      
          /// @dev  The map of lock ids to pending force transfer requests.
          mapping (bytes32 => forceTransferRequest) public pendingForceTransferRequestMap;
      
          // CONSTRUCTOR
          constructor(
              address _erc20Impl,
              address _custodian,
              address _controller,
              uint256 _initialCeiling
          )
              public
          {
              erc20Impl = ERC20Impl(_erc20Impl);
              custodian = Custodian(_custodian);
              controller = _controller;
              totalSupplyCeiling = _initialCeiling;
          }
      
          // MODIFIERS
          modifier onlyCustodian {
              require(msg.sender == address(custodian), "only custodian");
              _;
          }
          modifier onlyController {
              require(msg.sender == controller, "only controller");
              _;
          }
      
          modifier onlySigner {
              require(custodian.signerSet(msg.sender) == true, "only signer");
              _;
          }
      
          /** @notice  Increases the token supply, with the newly created tokens
            * being added to the balance of the specified account.
            *
            * @dev  The function checks that the value to print does not
            * exceed the supply ceiling when added to the current total supply.
            * NOTE: printing to the zero address is disallowed.
            *
            * @param  _receiver  The receiving address of the print.
            * @param  _value  The number of tokens to add to the total supply and the
            * balance of the receiving address.
            */
          function limitedPrint(address _receiver, uint256 _value) public onlyController {
              uint256 totalSupply = erc20Impl.totalSupply();
              uint256 newTotalSupply = totalSupply + _value;
      
              require(newTotalSupply >= totalSupply, "new total supply overflow");
              require(newTotalSupply <= totalSupplyCeiling, "total supply ceiling overflow");
              erc20Impl.confirmPrint(erc20Impl.requestPrint(_receiver, _value));
          }
      
          /** @notice  Requests wipe of suspected accounts.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Only controller can call this function, and only the custodian
            * can confirm the request.
            *
            * @param  _froms  The array of suspected accounts.
            *
            * @param  _values  array of amounts by which suspected accounts will be wiped.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestWipe(address[] memory _froms, uint256[] memory _values) public onlyController returns (bytes32 lockId) {
              require(_froms.length == _values.length, "_froms[] and _values[] must be same length");
              lockId = generateLockId();
              uint256 amount = _froms.length;
      
              for(uint256 i = 0; i < amount; i++) {
                  address from = _froms[i];
                  uint256 value = _values[i];
                  pendingWipeMap[lockId].push(wipeAddress(value, from));
              }
      
              emit WipeRequested(lockId);
      
              return lockId;
          }
      
          /** @notice  Confirms a pending wipe of suspected accounts.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending wipe, the amount requested is burned from the suspected accounts.
            *
            * @param  _lockId  The identifier of a pending wipe request.
            */
          function confirmWipe(bytes32 _lockId) public onlyCustodian {
              uint256 amount = pendingWipeMap[_lockId].length;
              for(uint256 i = 0; i < amount; i++) {
                  wipeAddress memory addr = pendingWipeMap[_lockId][i];
                  address from = addr.from;
                  uint256 value = addr.value;
                  erc20Impl.burn(from, value);
              }
      
              delete pendingWipeMap[_lockId];
      
              emit WipeCompleted(_lockId);
          }
      
          /** @notice  Requests force transfer from the suspected account.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Only controller can call this function, and only the custodian
            * can confirm the request.
            *
            * @param  _from  address of suspected account.
            *
            * @param  _to  address of reciever.
            *
            * @param  _value  amount which will be transferred.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestForceTransfer(address _from, address _to, uint256 _value) public onlyController returns (bytes32 lockId) {
              lockId = generateLockId();
              require (_value != 0, "no zero value transfers");
              pendingForceTransferRequestMap[lockId] = forceTransferRequest(_value, _from, _to);
      
              emit ForceTransferRequested(lockId, _from, _to, _value);
      
              return lockId;
          }
      
          /** @notice  Confirms a pending force transfer request.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending transfer request, the amount requested is transferred from the suspected account.
            *
            * @param  _lockId  The identifier of a pending transfer request.
            */
          function confirmForceTransfer(bytes32 _lockId) public onlyCustodian {
              address from = pendingForceTransferRequestMap[_lockId].from;
              address to = pendingForceTransferRequestMap[_lockId].to;
              uint256 value = pendingForceTransferRequestMap[_lockId].value;
      
              delete pendingForceTransferRequestMap[_lockId];
      
              erc20Impl.forceTransfer(from, to, value);
      
              emit ForceTransferCompleted(_lockId, from, to, value);
          }
      
          /** @notice  Requests an increase to the supply ceiling.
            *
            * @dev  Returns a unique lock id associated with the request.
            * Anyone can call this function, but confirming the request is authorized
            * by the custodian.
            *
            * @param  _raiseBy  The amount by which to raise the ceiling.
            *
            * @return  lockId  A unique identifier for this request.
            */
          function requestCeilingRaise(uint256 _raiseBy) public returns (bytes32 lockId) {
              require(_raiseBy != 0, "no zero ceiling raise");
      
              lockId = generateLockId();
      
              pendingRaiseMap[lockId] = PendingCeilingRaise({
                  raiseBy: _raiseBy
              });
      
              emit CeilingRaiseLocked(lockId, _raiseBy);
          }
      
          /** @notice  Confirms a pending increase in the token supply.
            *
            * @dev  When called by the custodian with a lock id associated with a
            * pending ceiling increase, the amount requested is added to the
            * current supply ceiling.
            * NOTE: this function will not execute any raise that would overflow the
            * supply ceiling, but it will not revert either.
            *
            * @param  _lockId  The identifier of a pending ceiling raise request.
            */
          function confirmCeilingRaise(bytes32 _lockId) public onlyCustodian {
              PendingCeilingRaise storage pendingRaise = pendingRaiseMap[_lockId];
      
              // copy locals of references to struct members
              uint256 raiseBy = pendingRaise.raiseBy;
              // accounts for a gibberish _lockId
              require(raiseBy != 0, "no gibberish _lockId");
      
              delete pendingRaiseMap[_lockId];
      
              uint256 newCeiling = totalSupplyCeiling + raiseBy;
              // overflow check
              if (newCeiling >= totalSupplyCeiling) {
                  totalSupplyCeiling = newCeiling;
      
                  emit CeilingRaiseConfirmed(_lockId, raiseBy, newCeiling);
              }
          }
      
          /** @notice  Lowers the supply ceiling, further constraining the bound of
            * what can be printed by the controller.
            *
            * @dev  The controller is the sole authorized caller of this function,
            * so it is the only account that can elect to lower its limit to increase
            * the token supply.
            *
            * @param  _lowerBy  The amount by which to lower the supply ceiling.
            */
          function lowerCeiling(uint256 _lowerBy) public onlyController {
              uint256 newCeiling = totalSupplyCeiling - _lowerBy;
              // overflow check
              require(newCeiling <= totalSupplyCeiling, "totalSupplyCeiling overflow");
              totalSupplyCeiling = newCeiling;
      
              emit CeilingLowered(_lowerBy, newCeiling);
          }
      
          /** @notice  Pass-through control of print confirmation, allowing this
            * contract's custodian to act as the custodian of the associated
            * active token implementation.
            *
            * @dev  This contract is the direct custodian of the active token
            * implementation, but this function allows this contract's custodian
            * to act as though it were the direct custodian of the active
            * token implementation. Therefore the custodian retains control of
            * unlimited printing.
            *
            * @param  _lockId  The identifier of a pending print request in
            * the associated active token implementation.
            */
          function confirmPrintProxy(bytes32 _lockId) public onlyCustodian {
              erc20Impl.confirmPrint(_lockId);
          }
      
          /** @notice  Pass-through control of custodian change confirmation,
            * allowing this contract's custodian to act as the custodian of
            * the associated active token implementation.
            *
            * @dev  This contract is the direct custodian of the active token
            * implementation, but this function allows this contract's custodian
            * to act as though it were the direct custodian of the active
            * token implementation. Therefore the custodian retains control of
            * custodian changes.
            *
            * @param  _lockId  The identifier of a pending custodian change request
            * in the associated active token implementation.
            */
          function confirmCustodianChangeProxy(bytes32 _lockId) public onlyCustodian {
              erc20Impl.confirmCustodianChange(_lockId);
          }
      
          /** @notice  Blocks all transactions with a wallet.
            *
            * @dev Only signers from custodian are authorized to call this function
            *
            * @param  wallet account which will be blocked.
            */
          function blockWallet(address wallet) public onlySigner {
              erc20Impl.blockWallet(wallet);
              emit Blocked(wallet);
          }
      
          /** @notice Unblocks all transactions with a wallet.
            *
            * @dev Only signers from custodian are authorized to call this function
            *
            * @param  wallet account which will be unblocked.
            */
          function unblockWallet(address wallet) public onlySigner {
              erc20Impl.unblockWallet(wallet);
              emit Unblocked(wallet);
          }
      
          // EVENTS
          /// @dev  Emitted by successful `requestCeilingRaise` calls.
          event CeilingRaiseLocked(bytes32 _lockId, uint256 _raiseBy);
      
          /// @dev  Emitted by successful `confirmCeilingRaise` calls.
          event CeilingRaiseConfirmed(bytes32 _lockId, uint256 _raiseBy, uint256 _newCeiling);
      
          /// @dev  Emitted by successful `lowerCeiling` calls.
          event CeilingLowered(uint256 _lowerBy, uint256 _newCeiling);
      
          /// @dev  Emitted by successful `blockWallet` calls.
          event Blocked(address _wallet);
      
          /// @dev  Emitted by successful `unblockWallet` calls.
          event Unblocked(address _wallet);
      
           /// @dev  Emitted by successful `requestForceTransfer` calls.
          event ForceTransferRequested(bytes32 _lockId, address _from, address _to, uint256 _value);
      
          /// @dev  Emitted by successful `confirmForceTransfer` calls.
          event ForceTransferCompleted(bytes32 _lockId, address _from, address _to, uint256 _value);
      
          /// @dev  Emitted by successful `requestWipe` calls.
          event WipeRequested(bytes32 _lockId);
      
          /// @dev  Emitted by successful `confirmWipe` calls.
          event WipeCompleted(bytes32 _lockId);
      }