ETH Price: $1,894.43 (+1.84%)

Transaction Decoder

Block:
13018354 at Aug-13-2021 06:06:41 PM +UTC
Transaction Fee:
0.007556319894680518 ETH $14.31
Gas Used:
140,411 Gas / 53.815725938 Gwei

Emitted Events:

104 Dispatcher.0x262ab020cb638b76c90ba54ebb8ec0a4ff4412b8d6777f1edc4c23d6644a88cd( 0x262ab020cb638b76c90ba54ebb8ec0a4ff4412b8d6777f1edc4c23d6644a88cd, 0x00000000000000000000000096ce35a0c37dcfff15727ea68cab4b67393d61d4, 0x0000000000000000000000000000000000000000000000000000000000000a84, 000000000000000000000000000000000000000000000006db69ee746e336dd0 )
105 Dispatcher.0x6e826cfd4b2f0d3e70085110ff45fc6023aaa1ef2cd87f58f574aee310489ebc( 0x6e826cfd4b2f0d3e70085110ff45fc6023aaa1ef2cd87f58f574aee310489ebc, 0x00000000000000000000000096ce35a0c37dcfff15727ea68cab4b67393d61d4, 0x0000000000000000000000000000000000000000000000000000000000000a86, 000000000000000000000000000000000000000000000413b63231a24f0b263d )

Account State Difference:

  Address   Before After State Difference Code
(Spark Pool)
11.084007586574089453 Eth11.085171094547943341 Eth0.001163507973853888
0x67E4A942...2Dfa54D64
0x83E4B3BF...f9F47EaBD
0.036947036921847625 Eth
Nonce: 135
0.029390717027167107 Eth
Nonce: 136
0.007556319894680518
0xbbD3C0C7...6fcfCb2e2
(NuCypher: StakingEscrow)

Execution Trace

Dispatcher.CALL( )
  • StakingEscrow.DELEGATECALL( )
    • Dispatcher.b46ffb45( )
      • PolicyManager.ping( _node=0x96Ce35a0C37Dcfff15727EA68caB4B67393D61D4, _processedPeriod1=2692, _processedPeriod2=0, _periodToSetDefault=2694 )
        File 1 of 4: Dispatcher
        {"Address.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n        // for accounts without code, i.e. `keccak256(\u0027\u0027)`\n        bytes32 codehash;\n        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { codehash := extcodehash(account) }\n        return (codehash != accountHash \u0026\u0026 codehash != 0x0);\n    }\n\n    /**\n     * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     *\n     * _Available since v2.4.0._\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-call-value\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n}\n"},"Dispatcher.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"./Upgradeable.sol\";\nimport \"./Address.sol\";\n\n\n/**\n* @notice ERC897 - ERC DelegateProxy\n*/\ninterface ERCProxy {\n    function proxyType() external pure returns (uint256);\n    function implementation() external view returns (address);\n}\n\n\n/**\n* @notice Proxying requests to other contracts.\n* Client should use ABI of real contract and address of this contract\n*/\ncontract Dispatcher is Upgradeable, ERCProxy {\n    using Address for address;\n\n    event Upgraded(address indexed from, address indexed to, address owner);\n    event RolledBack(address indexed from, address indexed to, address owner);\n\n    /**\n    * @dev Set upgrading status before and after operations\n    */\n    modifier upgrading()\n    {\n        isUpgrade = UPGRADE_TRUE;\n        _;\n        isUpgrade = UPGRADE_FALSE;\n    }\n\n    /**\n    * @param _target Target contract address\n    */\n    constructor(address _target) upgrading {\n        require(_target.isContract());\n        // Checks that target contract inherits Dispatcher state\n        verifyState(_target);\n        // `verifyState` must work with its contract\n        verifyUpgradeableState(_target, _target);\n        target = _target;\n        finishUpgrade();\n        emit Upgraded(address(0), _target, msg.sender);\n    }\n\n    //------------------------ERC897------------------------\n    /**\n     * @notice ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy\n     */\n    function proxyType() external pure override returns (uint256) {\n        return 2;\n    }\n\n    /**\n     * @notice ERC897, gets the address of the implementation where every call will be delegated\n     */\n    function implementation() external view override returns (address) {\n        return target;\n    }\n    //------------------------------------------------------------\n\n    /**\n    * @notice Verify new contract storage and upgrade target\n    * @param _target New target contract address\n    */\n    function upgrade(address _target) public onlyOwner upgrading {\n        require(_target.isContract());\n        // Checks that target contract has \"correct\" (as much as possible) state layout\n        verifyState(_target);\n        //`verifyState` must work with its contract\n        verifyUpgradeableState(_target, _target);\n        if (target.isContract()) {\n            verifyUpgradeableState(target, _target);\n        }\n        previousTarget = target;\n        target = _target;\n        finishUpgrade();\n        emit Upgraded(previousTarget, _target, msg.sender);\n    }\n\n    /**\n    * @notice Rollback to previous target\n    * @dev Test storage carefully before upgrade again after rollback\n    */\n    function rollback() public onlyOwner upgrading {\n        require(previousTarget.isContract());\n        emit RolledBack(target, previousTarget, msg.sender);\n        // should be always true because layout previousTarget -\u003e target was already checked\n        // but `verifyState` is not 100% accurate so check again\n        verifyState(previousTarget);\n        if (target.isContract()) {\n            verifyUpgradeableState(previousTarget, target);\n        }\n        target = previousTarget;\n        previousTarget = address(0);\n        finishUpgrade();\n    }\n\n    /**\n    * @dev Call verifyState method for Upgradeable contract\n    */\n    function verifyUpgradeableState(address _from, address _to) private {\n        (bool callSuccess,) = _from.delegatecall(abi.encodeWithSelector(this.verifyState.selector, _to));\n        require(callSuccess);\n    }\n\n    /**\n    * @dev Call finishUpgrade method from the Upgradeable contract\n    */\n    function finishUpgrade() private {\n        (bool callSuccess,) = target.delegatecall(abi.encodeWithSelector(this.finishUpgrade.selector, target));\n        require(callSuccess);\n    }\n\n    function verifyState(address _testTarget) public override onlyWhileUpgrading {\n        //checks equivalence accessing state through new contract and current storage\n        require(address(uint160(delegateGet(_testTarget, this.owner.selector))) == owner());\n        require(address(uint160(delegateGet(_testTarget, this.target.selector))) == target);\n        require(address(uint160(delegateGet(_testTarget, this.previousTarget.selector))) == previousTarget);\n        require(uint8(delegateGet(_testTarget, this.isUpgrade.selector)) == isUpgrade);\n    }\n\n    /**\n    * @dev Override function using empty code because no reason to call this function in Dispatcher\n    */\n    function finishUpgrade(address) public override {}\n\n    /**\n    * @dev Receive function sends empty request to the target contract\n    */\n    receive() external payable {\n        assert(target.isContract());\n        // execute receive function from target contract using storage of the dispatcher\n        (bool callSuccess,) = target.delegatecall(\"\");\n        if (!callSuccess) {\n            revert();\n        }\n    }\n\n    /**\n    * @dev Fallback function sends all requests to the target contract\n    */\n    fallback() external payable {\n        assert(target.isContract());\n        // execute requested function from target contract using storage of the dispatcher\n        (bool callSuccess,) = target.delegatecall(msg.data);\n        if (callSuccess) {\n            // copy result of the request to the return data\n            // we can use the second return value from `delegatecall` (bytes memory)\n            // but it will consume a little more gas\n            assembly {\n                returndatacopy(0x0, 0x0, returndatasize())\n                return(0x0, returndatasize())\n            }\n        } else {\n            revert();\n        }\n    }\n\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\nabstract contract Ownable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n     * account.\n     */\n    constructor () {\n        _owner = msg.sender;\n        emit OwnershipTransferred(address(0), _owner);\n    }\n\n    /**\n     * @return the address of the owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner());\n        _;\n    }\n\n    /**\n     * @return true if `msg.sender` is the owner of the contract.\n     */\n    function isOwner() public view returns (bool) {\n        return msg.sender == _owner;\n    }\n\n    /**\n     * @dev Allows the current owner to relinquish control of the contract.\n     * @notice Renouncing to ownership will leave the contract without an owner.\n     * It will not be possible to call the functions with the `onlyOwner`\n     * modifier anymore.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Allows the current owner to transfer control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function transferOwnership(address newOwner) public onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0));\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"},"Upgradeable.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"./Ownable.sol\";\n\n\n/**\n* @notice Base contract for upgradeable contract\n* @dev Inherited contract should implement verifyState(address) method by checking storage variables\n* (see verifyState(address) in Dispatcher). Also contract should implement finishUpgrade(address)\n* if it is using constructor parameters by coping this parameters to the dispatcher storage\n*/\nabstract contract Upgradeable is Ownable {\n\n    event StateVerified(address indexed testTarget, address sender);\n    event UpgradeFinished(address indexed target, address sender);\n\n    /**\n    * @dev Contracts at the target must reserve the same location in storage for this address as in Dispatcher\n    * Stored data actually lives in the Dispatcher\n    * However the storage layout is specified here in the implementing contracts\n    */\n    address public target;\n\n    /**\n    * @dev Previous contract address (if available). Used for rollback\n    */\n    address public previousTarget;\n\n    /**\n    * @dev Upgrade status. Explicit `uint8` type is used instead of `bool` to save gas by excluding 0 value\n    */\n    uint8 public isUpgrade;\n\n    /**\n    * @dev Guarantees that next slot will be separated from the previous\n    */\n    uint256 stubSlot;\n\n    /**\n    * @dev Constants for `isUpgrade` field\n    */\n    uint8 constant UPGRADE_FALSE = 1;\n    uint8 constant UPGRADE_TRUE = 2;\n\n    /**\n    * @dev Checks that function executed while upgrading\n    * Recommended to add to `verifyState` and `finishUpgrade` methods\n    */\n    modifier onlyWhileUpgrading()\n    {\n        require(isUpgrade == UPGRADE_TRUE);\n        _;\n    }\n\n    /**\n    * @dev Method for verifying storage state.\n    * Should check that new target contract returns right storage value\n    */\n    function verifyState(address _testTarget) public virtual onlyWhileUpgrading {\n        emit StateVerified(_testTarget, msg.sender);\n    }\n\n    /**\n    * @dev Copy values from the new target to the current storage\n    * @param _target New target contract address\n    */\n    function finishUpgrade(address _target) public virtual onlyWhileUpgrading {\n        emit UpgradeFinished(_target, msg.sender);\n    }\n\n    /**\n    * @dev Base method to get data\n    * @param _target Target to call\n    * @param _selector Method selector\n    * @param _numberOfArguments Number of used arguments\n    * @param _argument1 First method argument\n    * @param _argument2 Second method argument\n    * @return memoryAddress Address in memory where the data is located\n    */\n    function delegateGetData(\n        address _target,\n        bytes4 _selector,\n        uint8 _numberOfArguments,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (bytes32 memoryAddress)\n    {\n        assembly {\n            memoryAddress := mload(0x40)\n            mstore(memoryAddress, _selector)\n            if gt(_numberOfArguments, 0) {\n                mstore(add(memoryAddress, 0x04), _argument1)\n            }\n            if gt(_numberOfArguments, 1) {\n                mstore(add(memoryAddress, 0x24), _argument2)\n            }\n            switch delegatecall(gas(), _target, memoryAddress, add(0x04, mul(0x20, _numberOfArguments)), 0, 0)\n                case 0 {\n                    revert(memoryAddress, 0)\n                }\n                default {\n                    returndatacopy(memoryAddress, 0x0, returndatasize())\n                }\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" without parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 0, 0, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with one parameter.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector, bytes32 _argument)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 1, _argument, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with two parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(\n        address _target,\n        bytes4 _selector,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 2, _argument1, _argument2);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n}\n"}}

        File 2 of 4: StakingEscrow
        {"AdditionalMath.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"SafeMath.sol\";\n\n\n/**\n* @notice Additional math operations\n*/\nlibrary AdditionalMath {\n    using SafeMath for uint256;\n\n    function max16(uint16 a, uint16 b) internal pure returns (uint16) {\n        return a \u003e= b ? a : b;\n    }\n\n    function min16(uint16 a, uint16 b) internal pure returns (uint16) {\n        return a \u003c b ? a : b;\n    }\n\n    /**\n    * @notice Division and ceil\n    */\n    function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n        return (a.add(b) - 1) / b;\n    }\n\n    /**\n    * @dev Adds signed value to unsigned value, throws on overflow.\n    */\n    function addSigned(uint256 a, int256 b) internal pure returns (uint256) {\n        if (b \u003e= 0) {\n            return a.add(uint256(b));\n        } else {\n            return a.sub(uint256(-b));\n        }\n    }\n\n    /**\n    * @dev Subtracts signed value from unsigned value, throws on overflow.\n    */\n    function subSigned(uint256 a, int256 b) internal pure returns (uint256) {\n        if (b \u003e= 0) {\n            return a.sub(uint256(b));\n        } else {\n            return a.add(uint256(-b));\n        }\n    }\n\n    /**\n    * @dev Multiplies two numbers, throws on overflow.\n    */\n    function mul32(uint32 a, uint32 b) internal pure returns (uint32) {\n        if (a == 0) {\n            return 0;\n        }\n        uint32 c = a * b;\n        assert(c / a == b);\n        return c;\n    }\n\n    /**\n    * @dev Adds two numbers, throws on overflow.\n    */\n    function add16(uint16 a, uint16 b) internal pure returns (uint16) {\n        uint16 c = a + b;\n        assert(c \u003e= a);\n        return c;\n    }\n\n    /**\n    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).\n    */\n    function sub16(uint16 a, uint16 b) internal pure returns (uint16) {\n        assert(b \u003c= a);\n        return a - b;\n    }\n\n    /**\n    * @dev Adds signed value to unsigned value, throws on overflow.\n    */\n    function addSigned16(uint16 a, int16 b) internal pure returns (uint16) {\n        if (b \u003e= 0) {\n            return add16(a, uint16(b));\n        } else {\n            return sub16(a, uint16(-b));\n        }\n    }\n\n    /**\n    * @dev Subtracts signed value from unsigned value, throws on overflow.\n    */\n    function subSigned16(uint16 a, int16 b) internal pure returns (uint16) {\n        if (b \u003e= 0) {\n            return sub16(a, uint16(b));\n        } else {\n            return add16(a, uint16(-b));\n        }\n    }\n}\n"},"Bits.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n/**\n* @dev Taken from https://github.com/ethereum/solidity-examples/blob/master/src/bits/Bits.sol\n*/\nlibrary Bits {\n\n    uint256 internal constant ONE = uint256(1);\n\n    /**\n    * @notice Sets the bit at the given \u0027index\u0027 in \u0027self\u0027 to:\n    *  \u00271\u0027 - if the bit is \u00270\u0027\n    *  \u00270\u0027 - if the bit is \u00271\u0027\n    * @return The modified value\n    */\n    function toggleBit(uint256 self, uint8 index) internal pure returns (uint256) {\n        return self ^ ONE \u003c\u003c index;\n    }\n\n    /**\n    * @notice Get the value of the bit at the given \u0027index\u0027 in \u0027self\u0027.\n    */\n    function bit(uint256 self, uint8 index) internal pure returns (uint8) {\n        return uint8(self \u003e\u003e index \u0026 1);\n    }\n\n    /**\n    * @notice Check if the bit at the given \u0027index\u0027 in \u0027self\u0027 is set.\n    * @return  \u0027true\u0027 - if the value of the bit is \u00271\u0027,\n    *          \u0027false\u0027 - if the value of the bit is \u00270\u0027\n    */\n    function bitSet(uint256 self, uint8 index) internal pure returns (bool) {\n        return self \u003e\u003e index \u0026 1 == 1;\n    }\n\n}\n"},"ERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\nimport \"SafeMath.sol\";\n\n\n/**\n * @title Standard ERC20 token\n *\n * @dev Implementation of the basic standard token.\n * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md\n * Originally based on code by FirstBlood:\n * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n *\n * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for\n * all accounts just by listening to said events. Note that this isn\u0027t required by the specification, and other\n * compliant implementations may not do it.\n */\ncontract ERC20 is IERC20 {\n    using SafeMath for uint256;\n\n    mapping (address =\u003e uint256) private _balances;\n\n    mapping (address =\u003e mapping (address =\u003e uint256)) private _allowed;\n\n    uint256 private _totalSupply;\n\n    /**\n     * @dev Total number of tokens in existence\n     */\n    function totalSupply() public view override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev Gets the balance of the specified address.\n     * @param owner The address to query the balance of.\n     * @return An uint256 representing the amount owned by the passed address.\n     */\n    function balanceOf(address owner) public view override returns (uint256) {\n        return _balances[owner];\n    }\n\n    /**\n     * @dev Function to check the amount of tokens that an owner allowed to a spender.\n     * @param owner address The address which owns the funds.\n     * @param spender address The address which will spend the funds.\n     * @return A uint256 specifying the amount of tokens still available for the spender.\n     */\n    function allowance(address owner, address spender) public view override returns (uint256) {\n        return _allowed[owner][spender];\n    }\n\n    /**\n     * @dev Transfer token for a specified address\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function transfer(address to, uint256 value) public override returns (bool) {\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.\n     * Beware that changing an allowance with this method brings the risk that someone may use both the old\n     * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this\n     * race condition is to first reduce the spender\u0027s allowance to 0 and set the desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     */\n    function approve(address spender, uint256 value) public override returns (bool) {\n\n        // To change the approve amount you first have to reduce the addresses`\n        //  allowance to zero by calling `approve(_spender, 0)` if it is not\n        //  already 0 to mitigate the race condition described here:\n        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n        require(value == 0 || _allowed[msg.sender][spender] == 0);\n\n        _approve(msg.sender, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev Transfer tokens from one address to another.\n     * Note that while this function emits an Approval event, this is not required as per the specification,\n     * and other compliant implementations may not emit the event.\n     * @param from address The address which you want to send tokens from\n     * @param to address The address which you want to transfer to\n     * @param value uint256 the amount of tokens to be transferred\n     */\n    function transferFrom(address from, address to, uint256 value) public override returns (bool) {\n        _transfer(from, to, value);\n        _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));\n        return true;\n    }\n\n    /**\n     * @dev Increase the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To increment\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * Emits an Approval event.\n     * @param spender The address which will spend the funds.\n     * @param addedValue The amount of tokens to increase the allowance by.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n        _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));\n        return true;\n    }\n\n    /**\n     * @dev Decrease the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To decrement\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * Emits an Approval event.\n     * @param spender The address which will spend the funds.\n     * @param subtractedValue The amount of tokens to decrease the allowance by.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n        _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));\n        return true;\n    }\n\n    /**\n     * @dev Transfer token for a specified addresses\n     * @param from The address to transfer from.\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        require(to != address(0));\n\n        _balances[from] = _balances[from].sub(value);\n        _balances[to] = _balances[to].add(value);\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Internal function that mints an amount of the token and assigns it to\n     * an account. This encapsulates the modification of balances such that the\n     * proper events are emitted.\n     * @param account The account that will receive the created tokens.\n     * @param value The amount that will be created.\n     */\n    function _mint(address account, uint256 value) internal {\n        require(account != address(0));\n\n        _totalSupply = _totalSupply.add(value);\n        _balances[account] = _balances[account].add(value);\n        emit Transfer(address(0), account, value);\n    }\n\n    /**\n     * @dev Internal function that burns an amount of the token of a given\n     * account.\n     * @param account The account whose tokens will be burnt.\n     * @param value The amount that will be burnt.\n     */\n    function _burn(address account, uint256 value) internal {\n        require(account != address(0));\n\n        _totalSupply = _totalSupply.sub(value);\n        _balances[account] = _balances[account].sub(value);\n        emit Transfer(account, address(0), value);\n    }\n\n    /**\n     * @dev Approve an address to spend another addresses\u0027 tokens.\n     * @param owner The address that owns the tokens.\n     * @param spender The address that will spend the tokens.\n     * @param value The number of tokens that can be spent.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        require(spender != address(0));\n        require(owner != address(0));\n\n        _allowed[owner][spender] = value;\n        emit Approval(owner, spender, value);\n    }\n\n    /**\n     * @dev Internal function that burns an amount of the token of a given\n     * account, deducting from the sender\u0027s allowance for said account. Uses the\n     * internal burn function.\n     * Emits an Approval event (reflecting the reduced allowance).\n     * @param account The account whose tokens will be burnt.\n     * @param value The amount that will be burnt.\n     */\n    function _burnFrom(address account, uint256 value) internal {\n        _burn(account, value);\n        _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));\n    }\n\n}\n"},"ERC20Detailed.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\n\n\n/**\n * @title ERC20Detailed token\n * @dev The decimals are only for visualization purposes.\n * All the operations are done using the smallest and indivisible token unit,\n * just as on Ethereum all the operations are done in wei.\n */\nabstract contract ERC20Detailed is IERC20 {\n    string private _name;\n    string private _symbol;\n    uint8 private _decimals;\n\n    constructor (string memory name, string memory symbol, uint8 decimals) {\n        _name = name;\n        _symbol = symbol;\n        _decimals = decimals;\n    }\n\n    /**\n     * @return the name of the token.\n     */\n    function name() public view returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @return the symbol of the token.\n     */\n    function symbol() public view returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @return the number of decimals of the token.\n     */\n    function decimals() public view returns (uint8) {\n        return _decimals;\n    }\n}\n"},"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/20\n */\ninterface IERC20 {\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address who) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"IERC900History.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\n// Minimum interface to interact with Aragon\u0027s Aggregator\ninterface IERC900History {\n    function totalStakedForAt(address addr, uint256 blockNumber) external view returns (uint256);\n    function totalStakedAt(uint256 blockNumber) external view returns (uint256);\n    function supportsHistory() external pure returns (bool);\n}\n"},"Issuer.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"NuCypherToken.sol\";\nimport \"Math.sol\";\nimport \"Upgradeable.sol\";\nimport \"AdditionalMath.sol\";\nimport \"SafeERC20.sol\";\n\n\n/**\n* @title Issuer\n* @notice Contract for calculation of issued tokens\n* @dev |v3.4.1|\n*/\nabstract contract Issuer is Upgradeable {\n    using SafeERC20 for NuCypherToken;\n    using AdditionalMath for uint32;\n\n    event Donated(address indexed sender, uint256 value);\n    /// Issuer is initialized with a reserved reward\n    event Initialized(uint256 reservedReward);\n\n    uint128 constant MAX_UINT128 = uint128(0) - 1;\n\n    NuCypherToken public immutable token;\n    uint128 public immutable totalSupply;\n\n    // d * k2\n    uint256 public immutable mintingCoefficient;\n    // k1\n    uint256 public immutable lockDurationCoefficient1;\n    // k2\n    uint256 public immutable lockDurationCoefficient2;\n\n    uint32 public immutable genesisSecondsPerPeriod;\n    uint32 public immutable secondsPerPeriod;\n\n    // kmax\n    uint16 public immutable maximumRewardedPeriods;\n\n    uint256 public immutable firstPhaseMaxIssuance;\n    uint256 public immutable firstPhaseTotalSupply;\n\n    /**\n    * Current supply is used in the minting formula and is stored to prevent different calculation\n    * for stakers which get reward in the same period. There are two values -\n    * supply for previous period (used in formula) and supply for current period which accumulates value\n    * before end of period.\n    */\n    uint128 public previousPeriodSupply;\n    uint128 public currentPeriodSupply;\n    uint16 public currentMintingPeriod;\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @dev Minting formula for one sub-stake in one period for the first phase\n    firstPhaseMaxIssuance * (lockedValue / totalLockedValue) * (k1 + min(allLockedPeriods, kmax)) / k2\n    * @dev Minting formula for one sub-stake in one period for the second phase\n    (totalSupply - currentSupply) / d * (lockedValue / totalLockedValue) * (k1 + min(allLockedPeriods, kmax)) / k2\n    if allLockedPeriods \u003e maximumRewardedPeriods then allLockedPeriods = maximumRewardedPeriods\n    * @param _token Token contract\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,\n    * only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.\n    * See Equation 10 in Staking Protocol \u0026 Economics paper\n    * @param _lockDurationCoefficient1 (k1) Numerator of the coefficient which modifies the extent \n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently. \n    * Applicable to Phase 1 and Phase 2. k1 = k2 * small_stake_multiplier where default small_stake_multiplier = 0.5.  \n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _lockDurationCoefficient2 (k2) Denominator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k2 = maximum_rewarded_periods / (1 - small_stake_multiplier)\n    * where default maximum_rewarded_periods = 365 and default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _maximumRewardedPeriods (kmax) Number of periods beyond which a stake\u0027s lock duration\n    * no longer increases the subsidy it receives. kmax = reward_saturation * 365 where default reward_saturation = 1.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _firstPhaseTotalSupply Total supply for the first phase\n    * @param _firstPhaseMaxIssuance (Imax) Maximum number of new tokens minted per period during Phase 1.\n    * See Equation 7 in Staking Protocol \u0026 Economics paper.\n    */\n    constructor(\n        NuCypherToken _token,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint256 _issuanceDecayCoefficient,\n        uint256 _lockDurationCoefficient1,\n        uint256 _lockDurationCoefficient2,\n        uint16 _maximumRewardedPeriods,\n        uint256 _firstPhaseTotalSupply,\n        uint256 _firstPhaseMaxIssuance\n    ) {\n        uint256 localTotalSupply = _token.totalSupply();\n        require(localTotalSupply \u003e 0 \u0026\u0026\n            _issuanceDecayCoefficient != 0 \u0026\u0026\n            _hoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod \u003c= _hoursPerPeriod \u0026\u0026\n            _lockDurationCoefficient1 != 0 \u0026\u0026\n            _lockDurationCoefficient2 != 0 \u0026\u0026\n            _maximumRewardedPeriods != 0);\n        require(localTotalSupply \u003c= uint256(MAX_UINT128), \"Token contract has supply more than supported\");\n\n        uint256 maxLockDurationCoefficient = _maximumRewardedPeriods + _lockDurationCoefficient1;\n        uint256 localMintingCoefficient = _issuanceDecayCoefficient * _lockDurationCoefficient2;\n        require(maxLockDurationCoefficient \u003e _maximumRewardedPeriods \u0026\u0026\n            localMintingCoefficient / _issuanceDecayCoefficient ==  _lockDurationCoefficient2 \u0026\u0026\n            // worst case for `totalLockedValue * d * k2`, when totalLockedValue == totalSupply\n            localTotalSupply * localMintingCoefficient / localTotalSupply == localMintingCoefficient \u0026\u0026\n            // worst case for `(totalSupply - currentSupply) * lockedValue * (k1 + min(allLockedPeriods, kmax))`,\n            // when currentSupply == 0, lockedValue == totalSupply\n            localTotalSupply * localTotalSupply * maxLockDurationCoefficient / localTotalSupply / localTotalSupply ==\n                maxLockDurationCoefficient,\n            \"Specified parameters cause overflow\");\n\n        require(maxLockDurationCoefficient \u003c= _lockDurationCoefficient2,\n            \"Resulting locking duration coefficient must be less than 1\");\n        require(_firstPhaseTotalSupply \u003c= localTotalSupply, \"Too many tokens for the first phase\");\n        require(_firstPhaseMaxIssuance \u003c= _firstPhaseTotalSupply, \"Reward for the first phase is too high\");\n\n        token = _token;\n        secondsPerPeriod = _hoursPerPeriod.mul32(1 hours);\n        genesisSecondsPerPeriod = _genesisHoursPerPeriod.mul32(1 hours);\n        lockDurationCoefficient1 = _lockDurationCoefficient1;\n        lockDurationCoefficient2 = _lockDurationCoefficient2;\n        maximumRewardedPeriods = _maximumRewardedPeriods;\n        firstPhaseTotalSupply = _firstPhaseTotalSupply;\n        firstPhaseMaxIssuance = _firstPhaseMaxIssuance;\n        totalSupply = uint128(localTotalSupply);\n        mintingCoefficient = localMintingCoefficient;\n    }\n\n    /**\n    * @dev Checks contract initialization\n    */\n    modifier isInitialized()\n    {\n        require(currentMintingPeriod != 0);\n        _;\n    }\n\n    /**\n    * @return Number of current period\n    */\n    function getCurrentPeriod() public view returns (uint16) {\n        return uint16(block.timestamp / secondsPerPeriod);\n    }\n\n    /**\n    * @return Recalculate period value using new basis\n    */\n    function recalculatePeriod(uint16 _period) internal view returns (uint16) {\n        return uint16(uint256(_period) * genesisSecondsPerPeriod / secondsPerPeriod);\n    }\n\n    /**\n    * @notice Initialize reserved tokens for reward\n    */\n    function initialize(uint256 _reservedReward, address _sourceOfFunds) external onlyOwner {\n        require(currentMintingPeriod == 0);\n        // Reserved reward must be sufficient for at least one period of the first phase\n        require(firstPhaseMaxIssuance \u003c= _reservedReward);\n        currentMintingPeriod = getCurrentPeriod();\n        currentPeriodSupply = totalSupply - uint128(_reservedReward);\n        previousPeriodSupply = currentPeriodSupply;\n        token.safeTransferFrom(_sourceOfFunds, address(this), _reservedReward);\n        emit Initialized(_reservedReward);\n    }\n\n    /**\n    * @notice Function to mint tokens for one period.\n    * @param _currentPeriod Current period number.\n    * @param _lockedValue The amount of tokens that were locked by user in specified period.\n    * @param _totalLockedValue The amount of tokens that were locked by all users in specified period.\n    * @param _allLockedPeriods The max amount of periods during which tokens will be locked after specified period.\n    * @return amount Amount of minted tokens.\n    */\n    function mint(\n        uint16 _currentPeriod,\n        uint256 _lockedValue,\n        uint256 _totalLockedValue,\n        uint16 _allLockedPeriods\n    )\n        internal returns (uint256 amount)\n    {\n        if (currentPeriodSupply == totalSupply) {\n            return 0;\n        }\n\n        if (_currentPeriod \u003e currentMintingPeriod) {\n            previousPeriodSupply = currentPeriodSupply;\n            currentMintingPeriod = _currentPeriod;\n        }\n\n        uint256 currentReward;\n        uint256 coefficient;\n\n        // first phase\n        // firstPhaseMaxIssuance * lockedValue * (k1 + min(allLockedPeriods, kmax)) / (totalLockedValue * k2)\n        if (previousPeriodSupply + firstPhaseMaxIssuance \u003c= firstPhaseTotalSupply) {\n            currentReward = firstPhaseMaxIssuance;\n            coefficient = lockDurationCoefficient2;\n        // second phase\n        // (totalSupply - currentSupply) * lockedValue * (k1 + min(allLockedPeriods, kmax)) / (totalLockedValue * d * k2)\n        } else {\n            currentReward = totalSupply - previousPeriodSupply;\n            coefficient = mintingCoefficient;\n        }\n\n        uint256 allLockedPeriods =\n            AdditionalMath.min16(_allLockedPeriods, maximumRewardedPeriods) + lockDurationCoefficient1;\n        amount = (uint256(currentReward) * _lockedValue * allLockedPeriods) /\n            (_totalLockedValue * coefficient);\n\n        // rounding the last reward\n        uint256 maxReward = getReservedReward();\n        if (amount == 0) {\n            amount = 1;\n        } else if (amount \u003e maxReward) {\n            amount = maxReward;\n        }\n\n        currentPeriodSupply += uint128(amount);\n    }\n\n    /**\n    * @notice Return tokens for future minting\n    * @param _amount Amount of tokens\n    */\n    function unMint(uint256 _amount) internal {\n        previousPeriodSupply -= uint128(_amount);\n        currentPeriodSupply -= uint128(_amount);\n    }\n\n    /**\n    * @notice Donate sender\u0027s tokens. Amount of tokens will be returned for future minting\n    * @param _value Amount to donate\n    */\n    function donate(uint256 _value) external isInitialized {\n        token.safeTransferFrom(msg.sender, address(this), _value);\n        unMint(_value);\n        emit Donated(msg.sender, _value);\n    }\n\n    /**\n    * @notice Returns the number of tokens that can be minted\n    */\n    function getReservedReward() public view returns (uint256) {\n        return totalSupply - currentPeriodSupply;\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n        require(uint16(delegateGet(_testTarget, this.currentMintingPeriod.selector)) == currentMintingPeriod);\n        require(uint128(delegateGet(_testTarget, this.previousPeriodSupply.selector)) == previousPeriodSupply);\n        require(uint128(delegateGet(_testTarget, this.currentPeriodSupply.selector)) == currentPeriodSupply);\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`\n    function finishUpgrade(address _target) public override virtual {\n        super.finishUpgrade(_target);\n        // recalculate currentMintingPeriod if needed\n        if (currentMintingPeriod \u003e getCurrentPeriod()) {\n            currentMintingPeriod = recalculatePeriod(currentMintingPeriod);\n        }\n    }\n\n}\n"},"Math.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Math\n * @dev Assorted math operations\n */\nlibrary Math {\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a \u003e= b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a \u003c b ? a : b;\n    }\n\n    /**\n     * @dev Calculates the average of two numbers. Since these are integers,\n     * averages of an even and odd number cannot be represented, and will be\n     * rounded down.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow, so we distribute\n        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);\n    }\n}\n"},"NuCypherToken.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"ERC20.sol\";\nimport \"ERC20Detailed.sol\";\n\n\n/**\n* @title NuCypher token\n* @notice ERC20 token\n* @dev Optional approveAndCall() functionality to notify a contract if an approve() has occurred.\n*/\ncontract NuCypherToken is ERC20, ERC20Detailed(\u0027NuCypher\u0027, \u0027NU\u0027, 18) {\n\n    /**\n    * @notice Set amount of tokens\n    * @param _totalSupplyOfTokens Total number of tokens\n    */\n    constructor (uint256 _totalSupplyOfTokens) {\n        _mint(msg.sender, _totalSupplyOfTokens);\n    }\n\n    /**\n    * @notice Approves and then calls the receiving contract\n    *\n    * @dev call the receiveApproval function on the contract you want to be notified.\n    * receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)\n    */\n    function approveAndCall(address _spender, uint256 _value, bytes calldata _extraData)\n        external returns (bool success)\n    {\n        approve(_spender, _value);\n        TokenRecipient(_spender).receiveApproval(msg.sender, _value, address(this), _extraData);\n        return true;\n    }\n\n}\n\n\n/**\n* @dev Interface to use the receiveApproval method\n*/\ninterface TokenRecipient {\n\n    /**\n    * @notice Receives a notification of approval of the transfer\n    * @param _from Sender of approval\n    * @param _value  The amount of tokens to be spent\n    * @param _tokenContract Address of the token contract\n    * @param _extraData Extra data\n    */\n    function receiveApproval(address _from, uint256 _value, address _tokenContract, bytes calldata _extraData) external;\n\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\nabstract contract Ownable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n     * account.\n     */\n    constructor () {\n        _owner = msg.sender;\n        emit OwnershipTransferred(address(0), _owner);\n    }\n\n    /**\n     * @return the address of the owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner());\n        _;\n    }\n\n    /**\n     * @return true if `msg.sender` is the owner of the contract.\n     */\n    function isOwner() public view returns (bool) {\n        return msg.sender == _owner;\n    }\n\n    /**\n     * @dev Allows the current owner to relinquish control of the contract.\n     * @notice Renouncing to ownership will leave the contract without an owner.\n     * It will not be possible to call the functions with the `onlyOwner`\n     * modifier anymore.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Allows the current owner to transfer control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0));\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"},"SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\nimport \"SafeMath.sol\";\n\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using SafeMath for uint256;\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        require(token.transfer(to, value));\n    }\n\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        require(token.transferFrom(from, to, value));\n    }\n\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // \u0027safeIncreaseAllowance\u0027 and \u0027safeDecreaseAllowance\u0027\n        require((value == 0) || (token.allowance(msg.sender, spender) == 0));\n        require(token.approve(spender, value));\n    }\n\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).add(value);\n        require(token.approve(spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).sub(value);\n        require(token.approve(spender, newAllowance));\n    }\n}\n"},"SafeMath.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title SafeMath\n * @dev Unsigned math operations with safety checks that revert on error\n */\nlibrary SafeMath {\n    /**\n     * @dev Multiplies two unsigned integers, reverts on overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Gas optimization: this is cheaper than requiring \u0027a\u0027 not being zero, but the\n        // benefit is lost if \u0027b\u0027 is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b);\n\n        return c;\n    }\n\n    /**\n     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Solidity only automatically asserts when dividing by 0\n        require(b \u003e 0);\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn\u0027t hold\n\n        return c;\n    }\n\n    /**\n     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b \u003c= a);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Adds two unsigned integers, reverts on overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c \u003e= a);\n\n        return c;\n    }\n\n    /**\n     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),\n     * reverts when dividing by zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b != 0);\n        return a % b;\n    }\n}\n"},"Snapshot.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Snapshot\n * @notice Manages snapshots of size 128 bits (32 bits for timestamp, 96 bits for value)\n * 96 bits is enough for storing NU token values, and 32 bits should be OK for block numbers\n * @dev Since each storage slot can hold two snapshots, new slots are allocated every other TX. Thus, gas cost of adding snapshots is 51400 and 36400 gas, alternately.\n * Based on Aragon\u0027s Checkpointing (https://https://github.com/aragonone/voting-connectors/blob/master/shared/contract-utils/contracts/Checkpointing.sol)\n * On average, adding snapshots spends ~6500 less gas than the 256-bit checkpoints of Aragon\u0027s Checkpointing\n */\nlibrary Snapshot {\n\n    function encodeSnapshot(uint32 _time, uint96 _value) internal pure returns(uint128) {\n        return uint128(uint256(_time) \u003c\u003c 96 | uint256(_value));\n    }\n\n    function decodeSnapshot(uint128 _snapshot) internal pure returns(uint32 time, uint96 value){\n        time = uint32(bytes4(bytes16(_snapshot)));\n        value = uint96(_snapshot);\n    }\n\n    function addSnapshot(uint128[] storage _self, uint256 _value) internal {\n        addSnapshot(_self, block.number, _value);\n    }\n\n    function addSnapshot(uint128[] storage _self, uint256 _time, uint256 _value) internal {\n        uint256 length = _self.length;\n        if (length != 0) {\n            (uint32 currentTime, ) = decodeSnapshot(_self[length - 1]);\n            if (uint32(_time) == currentTime) {\n                _self[length - 1] = encodeSnapshot(uint32(_time), uint96(_value));\n                return;\n            } else if (uint32(_time) \u003c currentTime){\n                revert();\n            }\n        }\n        _self.push(encodeSnapshot(uint32(_time), uint96(_value)));\n    }\n\n    function lastSnapshot(uint128[] storage _self) internal view returns (uint32, uint96) {\n        uint256 length = _self.length;\n        if (length \u003e 0) {\n            return decodeSnapshot(_self[length - 1]);\n        }\n\n        return (0, 0);\n    }\n\n    function lastValue(uint128[] storage _self) internal view returns (uint96) {\n        (, uint96 value) = lastSnapshot(_self);\n        return value;\n    }\n\n    function getValueAt(uint128[] storage _self, uint256 _time256) internal view returns (uint96) {\n        uint32 _time = uint32(_time256);\n        uint256 length = _self.length;\n\n        // Short circuit if there\u0027s no checkpoints yet\n        // Note that this also lets us avoid using SafeMath later on, as we\u0027ve established that\n        // there must be at least one checkpoint\n        if (length == 0) {\n            return 0;\n        }\n\n        // Check last checkpoint\n        uint256 lastIndex = length - 1;\n        (uint32 snapshotTime, uint96 snapshotValue) = decodeSnapshot(_self[length - 1]);\n        if (_time \u003e= snapshotTime) {\n            return snapshotValue;\n        }\n\n        // Check first checkpoint (if not already checked with the above check on last)\n        (snapshotTime, snapshotValue) = decodeSnapshot(_self[0]);\n        if (length == 1 || _time \u003c snapshotTime) {\n            return 0;\n        }\n\n        // Do binary search\n        // As we\u0027ve already checked both ends, we don\u0027t need to check the last checkpoint again\n        uint256 low = 0;\n        uint256 high = lastIndex - 1;\n        uint32 midTime;\n        uint96 midValue;\n\n        while (high \u003e low) {\n            uint256 mid = (high + low + 1) / 2; // average, ceil round\n            (midTime, midValue) = decodeSnapshot(_self[mid]);\n\n            if (_time \u003e midTime) {\n                low = mid;\n            } else if (_time \u003c midTime) {\n                // Note that we don\u0027t need SafeMath here because mid must always be greater than 0\n                // from the while condition\n                high = mid - 1;\n            } else {\n                // _time == midTime\n                return midValue;\n            }\n        }\n\n        (, snapshotValue) = decodeSnapshot(_self[low]);\n        return snapshotValue;\n    }\n}\n"},"StakingEscrow.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC900History.sol\";\nimport \"Issuer.sol\";\nimport \"Bits.sol\";\nimport \"Snapshot.sol\";\nimport \"SafeMath.sol\";\nimport \"SafeERC20.sol\";\n\n\n/**\n* @notice PolicyManager interface\n*/\ninterface PolicyManagerInterface {\n    function secondsPerPeriod() external view returns (uint32);\n    function register(address _node, uint16 _period) external;\n    function migrate(address _node) external;\n    function ping(\n        address _node,\n        uint16 _processedPeriod1,\n        uint16 _processedPeriod2,\n        uint16 _periodToSetDefault\n    ) external;\n}\n\n\n/**\n* @notice Adjudicator interface\n*/\ninterface AdjudicatorInterface {\n    function rewardCoefficient() external view returns (uint32);\n}\n\n\n/**\n* @notice WorkLock interface\n*/\ninterface WorkLockInterface {\n    function token() external view returns (NuCypherToken);\n}\n\n/**\n* @title StakingEscrowStub\n* @notice Stub is used to deploy main StakingEscrow after all other contract and make some variables immutable\n* @dev |v1.0.0|\n*/\ncontract StakingEscrowStub is Upgradeable {\n    using AdditionalMath for uint32;\n\n    NuCypherToken public immutable token;\n    uint32 public immutable genesisSecondsPerPeriod;\n    uint32 public immutable secondsPerPeriod;\n    uint16 public immutable minLockedPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n\n    /**\n    * @notice Predefines some variables for use when deploying other contracts\n    * @param _token Token contract\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _minLockedPeriods Min amount of periods during which tokens can be locked\n    * @param _minAllowableLockedTokens Min amount of tokens that can be locked\n    * @param _maxAllowableLockedTokens Max amount of tokens that can be locked\n    */\n    constructor(\n        NuCypherToken _token,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint16 _minLockedPeriods,\n        uint256 _minAllowableLockedTokens,\n        uint256 _maxAllowableLockedTokens\n    ) {\n        require(_token.totalSupply() \u003e 0 \u0026\u0026\n            _hoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod \u003c= _hoursPerPeriod \u0026\u0026\n            _minLockedPeriods \u003e 1 \u0026\u0026\n            _maxAllowableLockedTokens != 0);\n\n        token = _token;\n        secondsPerPeriod = _hoursPerPeriod.mul32(1 hours);\n        genesisSecondsPerPeriod = _genesisHoursPerPeriod.mul32(1 hours);\n        minLockedPeriods = _minLockedPeriods;\n        minAllowableLockedTokens = _minAllowableLockedTokens;\n        maxAllowableLockedTokens = _maxAllowableLockedTokens;\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n\n        // we have to use real values even though this is a stub\n        require(address(delegateGet(_testTarget, this.token.selector)) == address(token));\n        // TODO uncomment after merging this PR #2579\n//        require(uint32(delegateGet(_testTarget, this.genesisSecondsPerPeriod.selector)) == genesisSecondsPerPeriod);\n        require(uint32(delegateGet(_testTarget, this.secondsPerPeriod.selector)) == secondsPerPeriod);\n        require(uint16(delegateGet(_testTarget, this.minLockedPeriods.selector)) == minLockedPeriods);\n        require(delegateGet(_testTarget, this.minAllowableLockedTokens.selector) == minAllowableLockedTokens);\n        require(delegateGet(_testTarget, this.maxAllowableLockedTokens.selector) == maxAllowableLockedTokens);\n    }\n}\n\n\n/**\n* @title StakingEscrow\n* @notice Contract holds and locks stakers tokens.\n* Each staker that locks their tokens will receive some compensation\n* @dev |v5.7.1|\n*/\ncontract StakingEscrow is Issuer, IERC900History {\n\n    using AdditionalMath for uint256;\n    using AdditionalMath for uint16;\n    using Bits for uint256;\n    using SafeMath for uint256;\n    using Snapshot for uint128[];\n    using SafeERC20 for NuCypherToken;\n\n    /**\n    * @notice Signals that tokens were deposited\n    * @param staker Staker address\n    * @param value Amount deposited (in NuNits)\n    * @param periods Number of periods tokens will be locked\n    */\n    event Deposited(address indexed staker, uint256 value, uint16 periods);\n\n    /**\n    * @notice Signals that tokens were stake locked\n    * @param staker Staker address\n    * @param value Amount locked (in NuNits)\n    * @param firstPeriod Starting lock period\n    * @param periods Number of periods tokens will be locked\n    */\n    event Locked(address indexed staker, uint256 value, uint16 firstPeriod, uint16 periods);\n\n    /**\n    * @notice Signals that a sub-stake was divided\n    * @param staker Staker address\n    * @param oldValue Old sub-stake value (in NuNits)\n    * @param lastPeriod Final locked period of old sub-stake\n    * @param newValue New sub-stake value (in NuNits)\n    * @param periods Number of periods to extend sub-stake\n    */\n    event Divided(\n        address indexed staker,\n        uint256 oldValue,\n        uint16 lastPeriod,\n        uint256 newValue,\n        uint16 periods\n    );\n\n    /**\n    * @notice Signals that two sub-stakes were merged\n    * @param staker Staker address\n    * @param value1 Value of first sub-stake (in NuNits)\n    * @param value2 Value of second sub-stake (in NuNits)\n    * @param lastPeriod Final locked period of merged sub-stake\n    */\n    event Merged(address indexed staker, uint256 value1, uint256 value2, uint16 lastPeriod);\n\n    /**\n    * @notice Signals that a sub-stake was prolonged\n    * @param staker Staker address\n    * @param value Value of sub-stake\n    * @param lastPeriod Final locked period of old sub-stake\n    * @param periods Number of periods sub-stake was extended\n    */\n    event Prolonged(address indexed staker, uint256 value, uint16 lastPeriod, uint16 periods);\n\n    /**\n    * @notice Signals that tokens were withdrawn to the staker\n    * @param staker Staker address\n    * @param value Amount withdraws (in NuNits)\n    */\n    event Withdrawn(address indexed staker, uint256 value);\n\n    /**\n    * @notice Signals that the worker associated with the staker made a commitment to next period\n    * @param staker Staker address\n    * @param period Period committed to\n    * @param value Amount of tokens staked for the committed period\n    */\n    event CommitmentMade(address indexed staker, uint16 indexed period, uint256 value);\n\n    /**\n    * @notice Signals that tokens were minted for previous periods\n    * @param staker Staker address\n    * @param period Previous period tokens minted for\n    * @param value Amount minted (in NuNits)\n    */\n    event Minted(address indexed staker, uint16 indexed period, uint256 value);\n\n    /**\n    * @notice Signals that the staker was slashed\n    * @param staker Staker address\n    * @param penalty Slashing penalty\n    * @param investigator Investigator address\n    * @param reward Value of reward provided to investigator (in NuNits)\n    */\n    event Slashed(address indexed staker, uint256 penalty, address indexed investigator, uint256 reward);\n\n    /**\n    * @notice Signals that the restake parameter was activated/deactivated\n    * @param staker Staker address\n    * @param reStake Updated parameter value\n    */\n    event ReStakeSet(address indexed staker, bool reStake);\n\n    /**\n    * @notice Signals that a worker was bonded to the staker\n    * @param staker Staker address\n    * @param worker Worker address\n    * @param startPeriod Period bonding occurred\n    */\n    event WorkerBonded(address indexed staker, address indexed worker, uint16 indexed startPeriod);\n\n    /**\n    * @notice Signals that the winddown parameter was activated/deactivated\n    * @param staker Staker address\n    * @param windDown Updated parameter value\n    */\n    event WindDownSet(address indexed staker, bool windDown);\n\n    /**\n    * @notice Signals that the snapshot parameter was activated/deactivated\n    * @param staker Staker address\n    * @param snapshotsEnabled Updated parameter value\n    */\n    event SnapshotSet(address indexed staker, bool snapshotsEnabled);\n\n    /**\n    * @notice Signals that the staker migrated their stake to the new period length\n    * @param staker Staker address\n    * @param period Period when migration happened\n    */\n    event Migrated(address indexed staker, uint16 indexed period);\n\n    /// internal event\n    event WorkMeasurementSet(address indexed staker, bool measureWork);\n\n    struct SubStakeInfo {\n        uint16 firstPeriod;\n        uint16 lastPeriod;\n        uint16 unlockingDuration;\n        uint128 lockedValue;\n    }\n\n    struct Downtime {\n        uint16 startPeriod;\n        uint16 endPeriod;\n    }\n\n    struct StakerInfo {\n        uint256 value;\n        /*\n        * Stores periods that are committed but not yet rewarded.\n        * In order to optimize storage, only two values are used instead of an array.\n        * commitToNextPeriod() method invokes mint() method so there can only be two committed\n        * periods that are not yet rewarded: the current and the next periods.\n        */\n        uint16 currentCommittedPeriod;\n        uint16 nextCommittedPeriod;\n        uint16 lastCommittedPeriod;\n        uint16 stub1; // former slot for lockReStakeUntilPeriod\n        uint256 completedWork;\n        uint16 workerStartPeriod; // period when worker was bonded\n        address worker;\n        uint256 flags; // uint256 to acquire whole slot and minimize operations on it\n\n        uint256 reservedSlot1;\n        uint256 reservedSlot2;\n        uint256 reservedSlot3;\n        uint256 reservedSlot4;\n        uint256 reservedSlot5;\n\n        Downtime[] pastDowntime;\n        SubStakeInfo[] subStakes;\n        uint128[] history;\n\n    }\n\n    // used only for upgrading\n    uint16 internal constant RESERVED_PERIOD = 0;\n    uint16 internal constant MAX_CHECKED_VALUES = 5;\n    // to prevent high gas consumption in loops for slashing\n    uint16 public constant MAX_SUB_STAKES = 30;\n    uint16 internal constant MAX_UINT16 = 65535;\n\n    // indices for flags\n    uint8 internal constant RE_STAKE_DISABLED_INDEX = 0;\n    uint8 internal constant WIND_DOWN_INDEX = 1;\n    uint8 internal constant MEASURE_WORK_INDEX = 2;\n    uint8 internal constant SNAPSHOTS_DISABLED_INDEX = 3;\n    uint8 internal constant MIGRATED_INDEX = 4;\n\n    uint16 public immutable minLockedPeriods;\n    uint16 public immutable minWorkerPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n\n    PolicyManagerInterface public immutable policyManager;\n    AdjudicatorInterface public immutable adjudicator;\n    WorkLockInterface public immutable workLock;\n\n    mapping (address =\u003e StakerInfo) public stakerInfo;\n    address[] public stakers;\n    mapping (address =\u003e address) public stakerFromWorker;\n\n    mapping (uint16 =\u003e uint256) stub4; // former slot for lockedPerPeriod\n    uint128[] public balanceHistory;\n\n    address stub1; // former slot for PolicyManager\n    address stub2; // former slot for Adjudicator\n    address stub3; // former slot for WorkLock\n\n    mapping (uint16 =\u003e uint256) _lockedPerPeriod;\n    // only to make verifyState from previous version work, temporary\n    // TODO remove after upgrade #2579\n    function lockedPerPeriod(uint16 _period) public view returns (uint256) {\n        return _period != RESERVED_PERIOD ? _lockedPerPeriod[_period] : 111;\n    }\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @param _token Token contract\n    * @param _policyManager Policy Manager contract\n    * @param _adjudicator Adjudicator contract\n    * @param _workLock WorkLock contract. Zero address if there is no WorkLock\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,\n    * only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.\n    * See Equation 10 in Staking Protocol \u0026 Economics paper\n    * @param _lockDurationCoefficient1 (k1) Numerator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k1 = k2 * small_stake_multiplier where default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _lockDurationCoefficient2 (k2) Denominator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k2 = maximum_rewarded_periods / (1 - small_stake_multiplier)\n    * where default maximum_rewarded_periods = 365 and default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _maximumRewardedPeriods (kmax) Number of periods beyond which a stake\u0027s lock duration\n    * no longer increases the subsidy it receives. kmax = reward_saturation * 365 where default reward_saturation = 1.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _firstPhaseTotalSupply Total supply for the first phase\n    * @param _firstPhaseMaxIssuance (Imax) Maximum number of new tokens minted per period during Phase 1.\n    * See Equation 7 in Staking Protocol \u0026 Economics paper.\n    * @param _minLockedPeriods Min amount of periods during which tokens can be locked\n    * @param _minAllowableLockedTokens Min amount of tokens that can be locked\n    * @param _maxAllowableLockedTokens Max amount of tokens that can be locked\n    * @param _minWorkerPeriods Min amount of periods while a worker can\u0027t be changed\n    */\n    constructor(\n        NuCypherToken _token,\n        PolicyManagerInterface _policyManager,\n        AdjudicatorInterface _adjudicator,\n        WorkLockInterface _workLock,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint256 _issuanceDecayCoefficient,\n        uint256 _lockDurationCoefficient1,\n        uint256 _lockDurationCoefficient2,\n        uint16 _maximumRewardedPeriods,\n        uint256 _firstPhaseTotalSupply,\n        uint256 _firstPhaseMaxIssuance,\n        uint16 _minLockedPeriods,\n        uint256 _minAllowableLockedTokens,\n        uint256 _maxAllowableLockedTokens,\n        uint16 _minWorkerPeriods\n    )\n        Issuer(\n            _token,\n            _genesisHoursPerPeriod,\n            _hoursPerPeriod,\n            _issuanceDecayCoefficient,\n            _lockDurationCoefficient1,\n            _lockDurationCoefficient2,\n            _maximumRewardedPeriods,\n            _firstPhaseTotalSupply,\n            _firstPhaseMaxIssuance\n        )\n    {\n        // constant `1` in the expression `_minLockedPeriods \u003e 1` uses to simplify the `lock` method\n        require(_minLockedPeriods \u003e 1 \u0026\u0026 _maxAllowableLockedTokens != 0);\n        minLockedPeriods = _minLockedPeriods;\n        minAllowableLockedTokens = _minAllowableLockedTokens;\n        maxAllowableLockedTokens = _maxAllowableLockedTokens;\n        minWorkerPeriods = _minWorkerPeriods;\n\n        require((_policyManager.secondsPerPeriod() == _hoursPerPeriod * (1 hours) ||\n            _policyManager.secondsPerPeriod() == _genesisHoursPerPeriod * (1 hours)) \u0026\u0026\n            _adjudicator.rewardCoefficient() != 0 \u0026\u0026\n            (address(_workLock) == address(0) || _workLock.token() == _token));\n        policyManager = _policyManager;\n        adjudicator = _adjudicator;\n        workLock = _workLock;\n    }\n\n    /**\n    * @dev Checks the existence of a staker in the contract\n    */\n    modifier onlyStaker()\n    {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require((info.value \u003e 0 || info.nextCommittedPeriod != 0) \u0026\u0026\n            info.flags.bitSet(MIGRATED_INDEX));\n        _;\n    }\n\n    //------------------------Main getters------------------------\n    /**\n    * @notice Get all tokens belonging to the staker\n    */\n    function getAllTokens(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].value;\n    }\n\n    /**\n    * @notice Get all flags for the staker\n    */\n    function getFlags(address _staker)\n        external view returns (\n            bool windDown,\n            bool reStake,\n            bool measureWork,\n            bool snapshots,\n            bool migrated\n        )\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        windDown = info.flags.bitSet(WIND_DOWN_INDEX);\n        reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);\n        measureWork = info.flags.bitSet(MEASURE_WORK_INDEX);\n        snapshots = !info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX);\n        migrated = info.flags.bitSet(MIGRATED_INDEX);\n    }\n\n    /**\n    * @notice Get the start period. Use in the calculation of the last period of the sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    */\n    function getStartPeriod(StakerInfo storage _info, uint16 _currentPeriod)\n        internal view returns (uint16)\n    {\n        // if the next period (after current) is committed\n        if (_info.flags.bitSet(WIND_DOWN_INDEX) \u0026\u0026 _info.nextCommittedPeriod \u003e _currentPeriod) {\n            return _currentPeriod + 1;\n        }\n        return _currentPeriod;\n    }\n\n    /**\n    * @notice Get the last period of the sub stake\n    * @param _subStake Sub stake structure\n    * @param _startPeriod Pre-calculated start period\n    */\n    function getLastPeriodOfSubStake(SubStakeInfo storage _subStake, uint16 _startPeriod)\n        internal view returns (uint16)\n    {\n        if (_subStake.lastPeriod != 0) {\n            return _subStake.lastPeriod;\n        }\n        uint32 lastPeriod = uint32(_startPeriod) + _subStake.unlockingDuration;\n        if (lastPeriod \u003e uint32(MAX_UINT16)) {\n            return MAX_UINT16;\n        }\n        return uint16(lastPeriod);\n    }\n\n    /**\n    * @notice Get the last period of the sub stake\n    * @param _staker Staker\n    * @param _index Stake index\n    */\n    function getLastPeriodOfSubStake(address _staker, uint256 _index)\n        public view returns (uint16)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 startPeriod = getStartPeriod(info, getCurrentPeriod());\n        return getLastPeriodOfSubStake(subStake, startPeriod);\n    }\n\n\n    /**\n    * @notice Get the value of locked tokens for a staker in a specified period\n    * @dev Information may be incorrect for rewarded or not committed surpassed period\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _period Next period\n    */\n    function getLockedTokens(StakerInfo storage _info, uint16 _currentPeriod, uint16 _period)\n        internal view returns (uint256 lockedValue)\n    {\n        lockedValue = 0;\n        uint16 startPeriod = getStartPeriod(_info, _currentPeriod);\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.firstPeriod \u003c= _period \u0026\u0026\n                getLastPeriodOfSubStake(subStake, startPeriod) \u003e= _period) {\n                lockedValue += subStake.lockedValue;\n            }\n        }\n    }\n\n    /**\n    * @notice Get the value of locked tokens for a staker in a future period\n    * @dev This function is used by PreallocationEscrow so its signature can\u0027t be updated.\n    * @param _staker Staker\n    * @param _offsetPeriods Amount of periods that will be added to the current period\n    */\n    function getLockedTokens(address _staker, uint16 _offsetPeriods)\n        external view returns (uint256 lockedValue)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_offsetPeriods);\n        return getLockedTokens(info, currentPeriod, nextPeriod);\n    }\n\n    /**\n    * @notice Get the last committed staker\u0027s period\n    * @param _staker Staker\n    */\n    function getLastCommittedPeriod(address _staker) public view returns (uint16) {\n        StakerInfo storage info = stakerInfo[_staker];\n        return info.nextCommittedPeriod != 0 ? info.nextCommittedPeriod : info.lastCommittedPeriod;\n    }\n\n    /**\n    * @notice Get the value of locked tokens for active stakers in (getCurrentPeriod() + _offsetPeriods) period\n    * as well as stakers and their locked tokens\n    * @param _offsetPeriods Amount of periods for locked tokens calculation\n    * @param _startIndex Start index for looking in stakers array\n    * @param _maxStakers Max stakers for looking, if set 0 then all will be used\n    * @return allLockedTokens Sum of locked tokens for active stakers\n    * @return activeStakers Array of stakers and their locked tokens. Stakers addresses stored as uint256\n    * @dev Note that activeStakers[0] in an array of uint256, but you want addresses. Careful when used directly!\n    */\n    function getActiveStakers(uint16 _offsetPeriods, uint256 _startIndex, uint256 _maxStakers)\n        external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)\n    {\n        require(_offsetPeriods \u003e 0);\n\n        uint256 endIndex = stakers.length;\n        require(_startIndex \u003c endIndex);\n        if (_maxStakers != 0 \u0026\u0026 _startIndex + _maxStakers \u003c endIndex) {\n            endIndex = _startIndex + _maxStakers;\n        }\n        activeStakers = new uint256[2][](endIndex - _startIndex);\n        allLockedTokens = 0;\n\n        uint256 resultIndex = 0;\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_offsetPeriods);\n\n        for (uint256 i = _startIndex; i \u003c endIndex; i++) {\n            address staker = stakers[i];\n            StakerInfo storage info = stakerInfo[staker];\n            if (info.currentCommittedPeriod != currentPeriod \u0026\u0026\n                info.nextCommittedPeriod != currentPeriod) {\n                continue;\n            }\n            uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n            if (lockedTokens != 0) {\n                activeStakers[resultIndex][0] = uint256(staker);\n                activeStakers[resultIndex++][1] = lockedTokens;\n                allLockedTokens += lockedTokens;\n            }\n        }\n        assembly {\n            mstore(activeStakers, resultIndex)\n        }\n    }\n\n    /**\n    * @notice Get worker using staker\u0027s address\n    */\n    function getWorkerFromStaker(address _staker) external view returns (address) {\n        return stakerInfo[_staker].worker;\n    }\n\n    /**\n    * @notice Get work that completed by the staker\n    */\n    function getCompletedWork(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].completedWork;\n    }\n\n    /**\n    * @notice Find index of downtime structure that includes specified period\n    * @dev If specified period is outside all downtime periods, the length of the array will be returned\n    * @param _staker Staker\n    * @param _period Specified period number\n    */\n    function findIndexOfPastDowntime(address _staker, uint16 _period) external view returns (uint256 index) {\n        StakerInfo storage info = stakerInfo[_staker];\n        for (index = 0; index \u003c info.pastDowntime.length; index++) {\n            if (_period \u003c= info.pastDowntime[index].endPeriod) {\n                return index;\n            }\n        }\n    }\n\n    //------------------------Main methods------------------------\n    /**\n    * @notice Start or stop measuring the work of a staker\n    * @param _staker Staker\n    * @param _measureWork Value for `measureWork` parameter\n    * @return Work that was previously done\n    */\n    function setWorkMeasurement(address _staker, bool _measureWork) external returns (uint256) {\n        require(msg.sender == address(workLock));\n        StakerInfo storage info = stakerInfo[_staker];\n        if (info.flags.bitSet(MEASURE_WORK_INDEX) == _measureWork) {\n            return info.completedWork;\n        }\n        info.flags = info.flags.toggleBit(MEASURE_WORK_INDEX);\n        emit WorkMeasurementSet(_staker, _measureWork);\n        return info.completedWork;\n    }\n\n    /**\n    * @notice Bond worker\n    * @param _worker Worker address. Must be a real address, not a contract\n    */\n    function bondWorker(address _worker) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Specified worker is already bonded with this staker\n        require(_worker != info.worker);\n        uint16 currentPeriod = getCurrentPeriod();\n        if (info.worker != address(0)) { // If this staker had a worker ...\n            // Check that enough time has passed to change it\n            require(currentPeriod \u003e= info.workerStartPeriod.add16(minWorkerPeriods));\n            // Remove the old relation \"worker-\u003estaker\"\n            stakerFromWorker[info.worker] = address(0);\n        }\n\n        if (_worker != address(0)) {\n            // Specified worker is already in use\n            require(stakerFromWorker[_worker] == address(0));\n            // Specified worker is a staker\n            require(stakerInfo[_worker].subStakes.length == 0 || _worker == msg.sender);\n            // Set new worker-\u003estaker relation\n            stakerFromWorker[_worker] = msg.sender;\n        }\n\n        // Bond new worker (or unbond if _worker == address(0))\n        info.worker = _worker;\n        info.workerStartPeriod = currentPeriod;\n        emit WorkerBonded(msg.sender, _worker, currentPeriod);\n    }\n\n    /**\n    * @notice Set `reStake` parameter. If true then all staking rewards will be added to locked stake\n    * @param _reStake Value for parameter\n    */\n    function setReStake(bool _reStake) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(RE_STAKE_DISABLED_INDEX) == !_reStake) {\n            return;\n        }\n        info.flags = info.flags.toggleBit(RE_STAKE_DISABLED_INDEX);\n        emit ReStakeSet(msg.sender, _reStake);\n    }\n\n    /**\n    * @notice Deposit tokens from WorkLock contract\n    * @param _staker Staker address\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function depositFromWorkLock(\n        address _staker,\n        uint256 _value,\n        uint16 _unlockingDuration\n    )\n        external\n    {\n        require(msg.sender == address(workLock));\n        StakerInfo storage info = stakerInfo[_staker];\n        if (!info.flags.bitSet(WIND_DOWN_INDEX) \u0026\u0026 info.subStakes.length == 0) {\n            info.flags = info.flags.toggleBit(WIND_DOWN_INDEX);\n            emit WindDownSet(_staker, true);\n        }\n        // WorkLock still uses the genesis period length (24h)\n        _unlockingDuration = recalculatePeriod(_unlockingDuration);\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Set `windDown` parameter.\n    * If true then stake\u0027s duration will be decreasing in each period with `commitToNextPeriod()`\n    * @param _windDown Value for parameter\n    */\n    function setWindDown(bool _windDown) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(WIND_DOWN_INDEX) == _windDown) {\n            return;\n        }\n        info.flags = info.flags.toggleBit(WIND_DOWN_INDEX);\n        emit WindDownSet(msg.sender, _windDown);\n\n        // duration adjustment if next period is committed\n        uint16 nextPeriod = getCurrentPeriod() + 1;\n        if (info.nextCommittedPeriod != nextPeriod) {\n           return;\n        }\n\n        // adjust sub-stakes duration for the new value of winding down parameter\n        for (uint256 index = 0; index \u003c info.subStakes.length; index++) {\n            SubStakeInfo storage subStake = info.subStakes[index];\n            // sub-stake does not have fixed last period when winding down is disabled\n            if (!_windDown \u0026\u0026 subStake.lastPeriod == nextPeriod) {\n                subStake.lastPeriod = 0;\n                subStake.unlockingDuration = 1;\n                continue;\n            }\n            // this sub-stake is no longer affected by winding down parameter\n            if (subStake.lastPeriod != 0 || subStake.unlockingDuration == 0) {\n                continue;\n            }\n\n            subStake.unlockingDuration = _windDown ? subStake.unlockingDuration - 1 : subStake.unlockingDuration + 1;\n            if (subStake.unlockingDuration == 0) {\n                subStake.lastPeriod = nextPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Activate/deactivate taking snapshots of balances\n    * @param _enableSnapshots True to activate snapshots, False to deactivate\n    */\n    function setSnapshots(bool _enableSnapshots) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX) == !_enableSnapshots) {\n            return;\n        }\n\n        uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n        if(_enableSnapshots){\n            info.history.addSnapshot(info.value);\n            balanceHistory.addSnapshot(lastGlobalBalance + info.value);\n        } else {\n            info.history.addSnapshot(0);\n            balanceHistory.addSnapshot(lastGlobalBalance - info.value);\n        }\n        info.flags = info.flags.toggleBit(SNAPSHOTS_DISABLED_INDEX);\n\n        emit SnapshotSet(msg.sender, _enableSnapshots);\n    }\n\n    /**\n    * @notice Adds a new snapshot to both the staker and global balance histories,\n    * assuming the staker\u0027s balance was already changed\n    * @param _info Reference to affected staker\u0027s struct\n    * @param _addition Variance in balance. It can be positive or negative.\n    */\n    function addSnapshot(StakerInfo storage _info, int256 _addition) internal {\n        if(!_info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX)){\n            _info.history.addSnapshot(_info.value);\n            uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n            balanceHistory.addSnapshot(lastGlobalBalance.addSigned(_addition));\n        }\n    }\n\n    /**\n    * @notice Implementation of the receiveApproval(address,uint256,address,bytes) method\n    * (see NuCypherToken contract). Deposit all tokens that were approved to transfer\n    * @param _from Staker\n    * @param _value Amount of tokens to deposit\n    * @param _tokenContract Token contract address\n    * @notice (param _extraData) Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function receiveApproval(\n        address _from,\n        uint256 _value,\n        address _tokenContract,\n        bytes calldata /* _extraData */\n    )\n        external\n    {\n        require(_tokenContract == address(token) \u0026\u0026 msg.sender == address(token));\n\n        // Copy first 32 bytes from _extraData, according to calldata memory layout:\n        //\n        // 0x00: method signature      4 bytes\n        // 0x04: _from                 32 bytes after encoding\n        // 0x24: _value                32 bytes after encoding\n        // 0x44: _tokenContract        32 bytes after encoding\n        // 0x64: _extraData pointer    32 bytes. Value must be 0x80 (offset of _extraData wrt to 1st parameter)\n        // 0x84: _extraData length     32 bytes\n        // 0xA4: _extraData data       Length determined by previous variable\n        //\n        // See https://solidity.readthedocs.io/en/latest/abi-spec.html#examples\n\n        uint256 payloadSize;\n        uint256 payload;\n        assembly {\n            payloadSize := calldataload(0x84)\n            payload := calldataload(0xA4)\n        }\n        payload = payload \u003e\u003e 8*(32 - payloadSize);\n        deposit(_from, _from, MAX_SUB_STAKES, _value, uint16(payload));\n    }\n\n    /**\n    * @notice Deposit tokens and create new sub-stake. Use this method to become a staker\n    * @param _staker Staker\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function deposit(address _staker, uint256 _value, uint16 _unlockingDuration) external {\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Deposit tokens and increase lock amount of an existing sub-stake\n    * @dev This is preferable way to stake tokens because will be fewer active sub-stakes in the result\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function depositAndIncrease(uint256 _index, uint256 _value) external onlyStaker {\n        require(_index \u003c MAX_SUB_STAKES);\n        deposit(msg.sender, msg.sender, _index, _value, 0);\n    }\n\n    /**\n    * @notice Deposit tokens\n    * @dev Specify either index and zero periods (for an existing sub-stake)\n    * or index \u003e= MAX_SUB_STAKES and real value for periods (for a new sub-stake), not both\n    * @param _staker Staker\n    * @param _payer Owner of tokens\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function deposit(address _staker, address _payer, uint256 _index, uint256 _value, uint16 _unlockingDuration) internal {\n        require(_value != 0);\n        StakerInfo storage info = stakerInfo[_staker];\n        // A staker can\u0027t be a worker for another staker\n        require(stakerFromWorker[_staker] == address(0) || stakerFromWorker[_staker] == info.worker);\n        // initial stake of the staker\n        if (info.subStakes.length == 0 \u0026\u0026 info.lastCommittedPeriod == 0) {\n            stakers.push(_staker);\n            policyManager.register(_staker, getCurrentPeriod() - 1);\n            info.flags = info.flags.toggleBit(MIGRATED_INDEX);\n        }\n        require(info.flags.bitSet(MIGRATED_INDEX));\n        token.safeTransferFrom(_payer, address(this), _value);\n        info.value += _value;\n        lock(_staker, _index, _value, _unlockingDuration);\n\n        addSnapshot(info, int256(_value));\n        if (_index \u003e= MAX_SUB_STAKES) {\n            emit Deposited(_staker, _value, _unlockingDuration);\n        } else {\n            uint16 lastPeriod = getLastPeriodOfSubStake(_staker, _index);\n            emit Deposited(_staker, _value, lastPeriod - getCurrentPeriod());\n        }\n    }\n\n    /**\n    * @notice Lock some tokens as a new sub-stake\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lockAndCreate(uint256 _value, uint16 _unlockingDuration) external onlyStaker {\n        lock(msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Increase lock amount of an existing sub-stake\n    * @param _index Index of the sub-stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function lockAndIncrease(uint256 _index, uint256 _value) external onlyStaker {\n        require(_index \u003c MAX_SUB_STAKES);\n        lock(msg.sender, _index, _value, 0);\n    }\n\n    /**\n    * @notice Lock some tokens as a stake\n    * @dev Specify either index and zero periods (for an existing sub-stake)\n    * or index \u003e= MAX_SUB_STAKES and real value for periods (for a new sub-stake), not both\n    * @param _staker Staker\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lock(address _staker, uint256 _index, uint256 _value, uint16 _unlockingDuration) internal {\n        if (_index \u003c MAX_SUB_STAKES) {\n            require(_value \u003e 0);\n        } else {\n            require(_value \u003e= minAllowableLockedTokens \u0026\u0026 _unlockingDuration \u003e= minLockedPeriods);\n        }\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        StakerInfo storage info = stakerInfo[_staker];\n        uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n        uint256 requestedLockedTokens = _value.add(lockedTokens);\n        require(requestedLockedTokens \u003c= info.value \u0026\u0026 requestedLockedTokens \u003c= maxAllowableLockedTokens);\n\n        // next period is committed\n        if (info.nextCommittedPeriod == nextPeriod) {\n            _lockedPerPeriod[nextPeriod] += _value;\n            emit CommitmentMade(_staker, nextPeriod, _value);\n        }\n\n        // if index was provided then increase existing sub-stake\n        if (_index \u003c MAX_SUB_STAKES) {\n            lockAndIncrease(info, currentPeriod, nextPeriod, _staker, _index, _value);\n        // otherwise create new\n        } else {\n            lockAndCreate(info, nextPeriod, _staker, _value, _unlockingDuration);\n        }\n    }\n\n    /**\n    * @notice Lock some tokens as a new sub-stake\n    * @param _info Staker structure\n    * @param _nextPeriod Next period\n    * @param _staker Staker\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lockAndCreate(\n        StakerInfo storage _info,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _value,\n        uint16 _unlockingDuration\n    )\n        internal\n    {\n        uint16 duration = _unlockingDuration;\n        // if winding down is enabled and next period is committed\n        // then sub-stakes duration were decreased\n        if (_info.nextCommittedPeriod == _nextPeriod \u0026\u0026 _info.flags.bitSet(WIND_DOWN_INDEX)) {\n            duration -= 1;\n        }\n        saveSubStake(_info, _nextPeriod, 0, duration, _value);\n\n        emit Locked(_staker, _value, _nextPeriod, _unlockingDuration);\n    }\n\n    /**\n    * @notice Increase lock amount of an existing sub-stake\n    * @dev Probably will be created a new sub-stake but it will be active only one period\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _nextPeriod Next period\n    * @param _staker Staker\n    * @param _index Index of the sub-stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function lockAndIncrease(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _index,\n        uint256 _value\n    )\n        internal\n    {\n        SubStakeInfo storage subStake = _info.subStakes[_index];\n        (, uint16 lastPeriod) = checkLastPeriodOfSubStake(_info, subStake, _currentPeriod);\n\n        // create temporary sub-stake for current or previous committed periods\n        // to leave locked amount in this period unchanged\n        if (_info.currentCommittedPeriod != 0 \u0026\u0026\n            _info.currentCommittedPeriod \u003c= _currentPeriod ||\n            _info.nextCommittedPeriod != 0 \u0026\u0026\n            _info.nextCommittedPeriod \u003c= _currentPeriod)\n        {\n            saveSubStake(_info, subStake.firstPeriod, _currentPeriod, 0, subStake.lockedValue);\n        }\n\n        subStake.lockedValue += uint128(_value);\n        // all new locks should start from the next period\n        subStake.firstPeriod = _nextPeriod;\n\n        emit Locked(_staker, _value, _nextPeriod, lastPeriod - _currentPeriod);\n    }\n\n    /**\n    * @notice Checks that last period of sub-stake is greater than the current period\n    * @param _info Staker structure\n    * @param _subStake Sub-stake structure\n    * @param _currentPeriod Current period\n    * @return startPeriod Start period. Use in the calculation of the last period of the sub stake\n    * @return lastPeriod Last period of the sub stake\n    */\n    function checkLastPeriodOfSubStake(\n        StakerInfo storage _info,\n        SubStakeInfo storage _subStake,\n        uint16 _currentPeriod\n    )\n        internal view returns (uint16 startPeriod, uint16 lastPeriod)\n    {\n        startPeriod = getStartPeriod(_info, _currentPeriod);\n        lastPeriod = getLastPeriodOfSubStake(_subStake, startPeriod);\n        // The sub stake must be active at least in the next period\n        require(lastPeriod \u003e _currentPeriod);\n    }\n\n    /**\n    * @notice Save sub stake. First tries to override inactive sub stake\n    * @dev Inactive sub stake means that last period of sub stake has been surpassed and already rewarded\n    * @param _info Staker structure\n    * @param _firstPeriod First period of the sub stake\n    * @param _lastPeriod Last period of the sub stake\n    * @param _unlockingDuration Duration of the sub stake in periods\n    * @param _lockedValue Amount of locked tokens\n    */\n    function saveSubStake(\n        StakerInfo storage _info,\n        uint16 _firstPeriod,\n        uint16 _lastPeriod,\n        uint16 _unlockingDuration,\n        uint256 _lockedValue\n    )\n        internal\n    {\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.lastPeriod != 0 \u0026\u0026\n                (_info.currentCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c _info.currentCommittedPeriod) \u0026\u0026\n                (_info.nextCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c _info.nextCommittedPeriod))\n            {\n                subStake.firstPeriod = _firstPeriod;\n                subStake.lastPeriod = _lastPeriod;\n                subStake.unlockingDuration = _unlockingDuration;\n                subStake.lockedValue = uint128(_lockedValue);\n                return;\n            }\n        }\n        require(_info.subStakes.length \u003c MAX_SUB_STAKES);\n        _info.subStakes.push(SubStakeInfo(_firstPeriod, _lastPeriod, _unlockingDuration, uint128(_lockedValue)));\n    }\n\n    /**\n    * @notice Divide sub stake into two parts\n    * @param _index Index of the sub stake\n    * @param _newValue New sub stake value\n    * @param _additionalDuration Amount of periods for extending sub stake\n    */\n    function divideStake(uint256 _index, uint256 _newValue, uint16 _additionalDuration) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require(_newValue \u003e= minAllowableLockedTokens \u0026\u0026 _additionalDuration \u003e 0);\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 currentPeriod = getCurrentPeriod();\n        (, uint16 lastPeriod) = checkLastPeriodOfSubStake(info, subStake, currentPeriod);\n\n        uint256 oldValue = subStake.lockedValue;\n        subStake.lockedValue = uint128(oldValue.sub(_newValue));\n        require(subStake.lockedValue \u003e= minAllowableLockedTokens);\n        uint16 requestedPeriods = subStake.unlockingDuration.add16(_additionalDuration);\n        saveSubStake(info, subStake.firstPeriod, 0, requestedPeriods, _newValue);\n        emit Divided(msg.sender, oldValue, lastPeriod, _newValue, _additionalDuration);\n        emit Locked(msg.sender, _newValue, subStake.firstPeriod, requestedPeriods);\n    }\n\n    /**\n    * @notice Prolong active sub stake\n    * @param _index Index of the sub stake\n    * @param _additionalDuration Amount of periods for extending sub stake\n    */\n    function prolongStake(uint256 _index, uint16 _additionalDuration) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Incorrect parameters\n        require(_additionalDuration \u003e 0);\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 currentPeriod = getCurrentPeriod();\n        (uint16 startPeriod, uint16 lastPeriod) = checkLastPeriodOfSubStake(info, subStake, currentPeriod);\n\n        subStake.unlockingDuration = subStake.unlockingDuration.add16(_additionalDuration);\n        // if the sub stake ends in the next committed period then reset the `lastPeriod` field\n        if (lastPeriod == startPeriod) {\n            subStake.lastPeriod = 0;\n        }\n        // The extended sub stake must not be less than the minimum value\n        require(uint32(lastPeriod - currentPeriod) + _additionalDuration \u003e= minLockedPeriods);\n        emit Locked(msg.sender, subStake.lockedValue, lastPeriod + 1, _additionalDuration);\n        emit Prolonged(msg.sender, subStake.lockedValue, lastPeriod, _additionalDuration);\n    }\n\n    /**\n    * @notice Merge two sub-stakes into one if their last periods are equal\n    * @dev It\u0027s possible that both sub-stakes will be active after this transaction.\n    * But only one of them will be active until next call `commitToNextPeriod` (in the next period)\n    * @param _index1 Index of the first sub-stake\n    * @param _index2 Index of the second sub-stake\n    */\n    function mergeStake(uint256 _index1, uint256 _index2) external onlyStaker {\n        require(_index1 != _index2); // must be different sub-stakes\n\n        StakerInfo storage info = stakerInfo[msg.sender];\n        SubStakeInfo storage subStake1 = info.subStakes[_index1];\n        SubStakeInfo storage subStake2 = info.subStakes[_index2];\n        uint16 currentPeriod = getCurrentPeriod();\n\n        (, uint16 lastPeriod1) = checkLastPeriodOfSubStake(info, subStake1, currentPeriod);\n        (, uint16 lastPeriod2) = checkLastPeriodOfSubStake(info, subStake2, currentPeriod);\n        // both sub-stakes must have equal last period to be mergeable\n        require(lastPeriod1 == lastPeriod2);\n        emit Merged(msg.sender, subStake1.lockedValue, subStake2.lockedValue, lastPeriod1);\n\n        if (subStake1.firstPeriod == subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = 1;\n            subStake2.unlockingDuration = 0;\n        } else if (subStake1.firstPeriod \u003e subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = subStake1.firstPeriod - 1;\n            subStake2.unlockingDuration = 0;\n        } else {\n            subStake2.lockedValue += subStake1.lockedValue;\n            subStake1.lastPeriod = subStake2.firstPeriod - 1;\n            subStake1.unlockingDuration = 0;\n        }\n    }\n\n    /**\n    * @notice Remove unused sub-stake to decrease gas cost for several methods\n    */\n    function removeUnusedSubStake(uint16 _index) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n\n        uint256 lastIndex = info.subStakes.length - 1;\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        require(subStake.lastPeriod != 0 \u0026\u0026\n                (info.currentCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c info.currentCommittedPeriod) \u0026\u0026\n                (info.nextCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c info.nextCommittedPeriod));\n\n        if (_index != lastIndex) {\n            SubStakeInfo storage lastSubStake = info.subStakes[lastIndex];\n            subStake.firstPeriod = lastSubStake.firstPeriod;\n            subStake.lastPeriod = lastSubStake.lastPeriod;\n            subStake.unlockingDuration = lastSubStake.unlockingDuration;\n            subStake.lockedValue = lastSubStake.lockedValue;\n        }\n        info.subStakes.pop();\n    }\n\n    /**\n    * @notice Withdraw available amount of tokens to staker\n    * @param _value Amount of tokens to withdraw\n    */\n    function withdraw(uint256 _value) external onlyStaker {\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // the max locked tokens in most cases will be in the current period\n        // but when the staker locks more then we should use the next period\n        uint256 lockedTokens = Math.max(getLockedTokens(info, currentPeriod, nextPeriod),\n            getLockedTokens(info, currentPeriod, currentPeriod));\n        require(_value \u003c= info.value.sub(lockedTokens));\n        info.value -= _value;\n\n        addSnapshot(info, - int256(_value));\n        token.safeTransfer(msg.sender, _value);\n        emit Withdrawn(msg.sender, _value);\n\n        // unbond worker if staker withdraws last portion of NU\n        if (info.value == 0 \u0026\u0026\n            info.nextCommittedPeriod == 0 \u0026\u0026\n            info.worker != address(0))\n        {\n            stakerFromWorker[info.worker] = address(0);\n            info.worker = address(0);\n            emit WorkerBonded(msg.sender, address(0), currentPeriod);\n        }\n    }\n\n    /**\n    * @notice Make a commitment to the next period and mint for the previous period\n    */\n    function commitToNextPeriod() external isInitialized {\n        address staker = stakerFromWorker[msg.sender];\n        StakerInfo storage info = stakerInfo[staker];\n        // Staker must have a stake to make a commitment\n        require(info.value \u003e 0);\n        // Only worker with real address can make a commitment\n        require(msg.sender == tx.origin);\n\n        migrate(staker);\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        // the period has already been committed\n        require(info.nextCommittedPeriod != nextPeriod);\n\n        uint16 lastCommittedPeriod = getLastCommittedPeriod(staker);\n        (uint16 processedPeriod1, uint16 processedPeriod2) = mint(staker);\n\n        uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n        require(lockedTokens \u003e 0);\n        _lockedPerPeriod[nextPeriod] += lockedTokens;\n\n        info.currentCommittedPeriod = info.nextCommittedPeriod;\n        info.nextCommittedPeriod = nextPeriod;\n\n        decreaseSubStakesDuration(info, nextPeriod);\n\n        // staker was inactive for several periods\n        if (lastCommittedPeriod \u003c currentPeriod) {\n            info.pastDowntime.push(Downtime(lastCommittedPeriod + 1, currentPeriod));\n        }\n\n        policyManager.ping(staker, processedPeriod1, processedPeriod2, nextPeriod);\n        emit CommitmentMade(staker, nextPeriod, lockedTokens);\n    }\n\n    /**\n    * @notice Migrate from the old period length to the new one. Can be done only once\n    * @param _staker Staker\n    */\n    function migrate(address _staker) public {\n        StakerInfo storage info = stakerInfo[_staker];\n        // check that provided address is/was a staker\n        require(info.subStakes.length != 0 || info.lastCommittedPeriod != 0);\n        if (info.flags.bitSet(MIGRATED_INDEX)) {\n            return;\n        }\n\n        // reset state\n        info.currentCommittedPeriod = 0;\n        info.nextCommittedPeriod = 0;\n        // maintain case when no more sub-stakes and need to avoid re-registering this staker during deposit\n        info.lastCommittedPeriod = 1;\n        info.workerStartPeriod = recalculatePeriod(info.workerStartPeriod);\n        delete info.pastDowntime;\n\n        // recalculate all sub-stakes\n        uint16 currentPeriod = getCurrentPeriod();\n        for (uint256 i = 0; i \u003c info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = info.subStakes[i];\n            subStake.firstPeriod = recalculatePeriod(subStake.firstPeriod);\n            // sub-stake has fixed last period\n            if (subStake.lastPeriod != 0) {\n                subStake.lastPeriod = recalculatePeriod(subStake.lastPeriod);\n                if (subStake.lastPeriod == 0) {\n                    subStake.lastPeriod = 1;\n                }\n                subStake.unlockingDuration = 0;\n            // sub-stake has no fixed ending but possible that with new period length will have\n            } else {\n                uint16 oldCurrentPeriod = uint16(block.timestamp / genesisSecondsPerPeriod);\n                uint16 lastPeriod = recalculatePeriod(oldCurrentPeriod + subStake.unlockingDuration);\n                subStake.unlockingDuration = lastPeriod - currentPeriod;\n                if (subStake.unlockingDuration == 0) {\n                    subStake.lastPeriod = lastPeriod;\n                }\n            }\n        }\n\n        policyManager.migrate(_staker);\n        info.flags = info.flags.toggleBit(MIGRATED_INDEX);\n        emit Migrated(_staker, currentPeriod);\n    }\n\n    /**\n    * @notice Decrease sub-stakes duration if `windDown` is enabled\n    */\n    function decreaseSubStakesDuration(StakerInfo storage _info, uint16 _nextPeriod) internal {\n        if (!_info.flags.bitSet(WIND_DOWN_INDEX)) {\n            return;\n        }\n        for (uint256 index = 0; index \u003c _info.subStakes.length; index++) {\n            SubStakeInfo storage subStake = _info.subStakes[index];\n            if (subStake.lastPeriod != 0 || subStake.unlockingDuration == 0) {\n                continue;\n            }\n            subStake.unlockingDuration--;\n            if (subStake.unlockingDuration == 0) {\n                subStake.lastPeriod = _nextPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Mint tokens for previous periods if staker locked their tokens and made a commitment\n    */\n    function mint() external onlyStaker {\n        // save last committed period to the storage if both periods will be empty after minting\n        // because we won\u0027t be able to calculate last committed period\n        // see getLastCommittedPeriod(address)\n        StakerInfo storage info = stakerInfo[msg.sender];\n        uint16 previousPeriod = getCurrentPeriod() - 1;\n        if (info.nextCommittedPeriod \u003c= previousPeriod \u0026\u0026 info.nextCommittedPeriod != 0) {\n            info.lastCommittedPeriod = info.nextCommittedPeriod;\n        }\n        (uint16 processedPeriod1, uint16 processedPeriod2) = mint(msg.sender);\n\n        if (processedPeriod1 != 0 || processedPeriod2 != 0) {\n            policyManager.ping(msg.sender, processedPeriod1, processedPeriod2, 0);\n        }\n    }\n\n    /**\n    * @notice Mint tokens for previous periods if staker locked their tokens and made a commitment\n    * @param _staker Staker\n    * @return processedPeriod1 Processed period: currentCommittedPeriod or zero\n    * @return processedPeriod2 Processed period: nextCommittedPeriod or zero\n    */\n    function mint(address _staker) internal returns (uint16 processedPeriod1, uint16 processedPeriod2) {\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 previousPeriod = currentPeriod - 1;\n        StakerInfo storage info = stakerInfo[_staker];\n\n        if (info.nextCommittedPeriod == 0 ||\n            info.currentCommittedPeriod == 0 \u0026\u0026\n            info.nextCommittedPeriod \u003e previousPeriod ||\n            info.currentCommittedPeriod \u003e previousPeriod) {\n            return (0, 0);\n        }\n\n        uint16 startPeriod = getStartPeriod(info, currentPeriod);\n        uint256 reward = 0;\n        bool reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);\n\n        if (info.currentCommittedPeriod != 0) {\n            reward = mint(info, info.currentCommittedPeriod, currentPeriod, startPeriod, reStake);\n            processedPeriod1 = info.currentCommittedPeriod;\n            info.currentCommittedPeriod = 0;\n            if (reStake) {\n                _lockedPerPeriod[info.nextCommittedPeriod] += reward;\n            }\n        }\n        if (info.nextCommittedPeriod \u003c= previousPeriod) {\n            reward += mint(info, info.nextCommittedPeriod, currentPeriod, startPeriod, reStake);\n            processedPeriod2 = info.nextCommittedPeriod;\n            info.nextCommittedPeriod = 0;\n        }\n\n        info.value += reward;\n        if (info.flags.bitSet(MEASURE_WORK_INDEX)) {\n            info.completedWork += reward;\n        }\n\n        addSnapshot(info, int256(reward));\n        emit Minted(_staker, previousPeriod, reward);\n    }\n\n    /**\n    * @notice Calculate reward for one period\n    * @param _info Staker structure\n    * @param _mintingPeriod Period for minting calculation\n    * @param _currentPeriod Current period\n    * @param _startPeriod Pre-calculated start period\n    */\n    function mint(\n        StakerInfo storage _info,\n        uint16 _mintingPeriod,\n        uint16 _currentPeriod,\n        uint16 _startPeriod,\n        bool _reStake\n    )\n        internal returns (uint256 reward)\n    {\n        reward = 0;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake =  _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (subStake.firstPeriod \u003c= _mintingPeriod \u0026\u0026 lastPeriod \u003e= _mintingPeriod) {\n                uint256 subStakeReward = mint(\n                    _currentPeriod,\n                    subStake.lockedValue,\n                    _lockedPerPeriod[_mintingPeriod],\n                    lastPeriod.sub16(_mintingPeriod));\n                reward += subStakeReward;\n                if (_reStake) {\n                    subStake.lockedValue += uint128(subStakeReward);\n                }\n            }\n        }\n        return reward;\n    }\n\n    //-------------------------Slashing-------------------------\n    /**\n    * @notice Slash the staker\u0027s stake and reward the investigator\n    * @param _staker Staker\u0027s address\n    * @param _penalty Penalty\n    * @param _investigator Investigator\n    * @param _reward Reward for the investigator\n    */\n    function slashStaker(\n        address _staker,\n        uint256 _penalty,\n        address _investigator,\n        uint256 _reward\n    )\n        public isInitialized\n    {\n        require(msg.sender == address(adjudicator));\n        require(_penalty \u003e 0);\n        StakerInfo storage info = stakerInfo[_staker];\n        require(info.flags.bitSet(MIGRATED_INDEX));\n        if (info.value \u003c= _penalty) {\n            _penalty = info.value;\n        }\n        info.value -= _penalty;\n        if (_reward \u003e _penalty) {\n            _reward = _penalty;\n        }\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        uint16 startPeriod = getStartPeriod(info, currentPeriod);\n\n        (uint256 currentLock, uint256 nextLock, uint256 currentAndNextLock, uint256 shortestSubStakeIndex) =\n            getLockedTokensAndShortestSubStake(info, currentPeriod, nextPeriod, startPeriod);\n\n        // Decrease the stake if amount of locked tokens in the current period more than staker has\n        uint256 lockedTokens = currentLock + currentAndNextLock;\n        if (info.value \u003c lockedTokens) {\n           decreaseSubStakes(info, lockedTokens - info.value, currentPeriod, startPeriod, shortestSubStakeIndex);\n        }\n        // Decrease the stake if amount of locked tokens in the next period more than staker has\n        if (nextLock \u003e 0) {\n            lockedTokens = nextLock + currentAndNextLock -\n                (currentAndNextLock \u003e info.value ? currentAndNextLock - info.value : 0);\n            if (info.value \u003c lockedTokens) {\n               decreaseSubStakes(info, lockedTokens - info.value, nextPeriod, startPeriod, MAX_SUB_STAKES);\n            }\n        }\n\n        emit Slashed(_staker, _penalty, _investigator, _reward);\n        if (_penalty \u003e _reward) {\n            unMint(_penalty - _reward);\n        }\n        // TODO change to withdrawal pattern (#1499)\n        if (_reward \u003e 0) {\n            token.safeTransfer(_investigator, _reward);\n        }\n\n        addSnapshot(info, - int256(_penalty));\n\n    }\n\n    /**\n    * @notice Get the value of locked tokens for a staker in the current and the next period\n    * and find the shortest sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _nextPeriod Next period\n    * @param _startPeriod Pre-calculated start period\n    * @return currentLock Amount of tokens that locked in the current period and unlocked in the next period\n    * @return nextLock Amount of tokens that locked in the next period and not locked in the current period\n    * @return currentAndNextLock Amount of tokens that locked in the current period and in the next period\n    * @return shortestSubStakeIndex Index of the shortest sub stake\n    */\n    function getLockedTokensAndShortestSubStake(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _nextPeriod,\n        uint16 _startPeriod\n    )\n        internal view returns (\n            uint256 currentLock,\n            uint256 nextLock,\n            uint256 currentAndNextLock,\n            uint256 shortestSubStakeIndex\n        )\n    {\n        uint16 minDuration = MAX_UINT16;\n        uint16 minLastPeriod = MAX_UINT16;\n        shortestSubStakeIndex = MAX_SUB_STAKES;\n        currentLock = 0;\n        nextLock = 0;\n        currentAndNextLock = 0;\n\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (lastPeriod \u003c subStake.firstPeriod) {\n                continue;\n            }\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _nextPeriod) {\n                currentAndNextLock += subStake.lockedValue;\n            } else if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod) {\n                currentLock += subStake.lockedValue;\n            } else if (subStake.firstPeriod \u003c= _nextPeriod \u0026\u0026\n                lastPeriod \u003e= _nextPeriod) {\n                nextLock += subStake.lockedValue;\n            }\n            uint16 duration = lastPeriod - subStake.firstPeriod;\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod \u0026\u0026\n                (lastPeriod \u003c minLastPeriod ||\n                lastPeriod == minLastPeriod \u0026\u0026 duration \u003c minDuration))\n            {\n                shortestSubStakeIndex = i;\n                minDuration = duration;\n                minLastPeriod = lastPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Decrease short sub stakes\n    * @param _info Staker structure\n    * @param _penalty Penalty rate\n    * @param _decreasePeriod The period when the decrease begins\n    * @param _startPeriod Pre-calculated start period\n    * @param _shortestSubStakeIndex Index of the shortest period\n    */\n    function decreaseSubStakes(\n        StakerInfo storage _info,\n        uint256 _penalty,\n        uint16 _decreasePeriod,\n        uint16 _startPeriod,\n        uint256 _shortestSubStakeIndex\n    )\n        internal\n    {\n        SubStakeInfo storage shortestSubStake = _info.subStakes[0];\n        uint16 minSubStakeLastPeriod = MAX_UINT16;\n        uint16 minSubStakeDuration = MAX_UINT16;\n        while(_penalty \u003e 0) {\n            if (_shortestSubStakeIndex \u003c MAX_SUB_STAKES) {\n                shortestSubStake = _info.subStakes[_shortestSubStakeIndex];\n                minSubStakeLastPeriod = getLastPeriodOfSubStake(shortestSubStake, _startPeriod);\n                minSubStakeDuration = minSubStakeLastPeriod - shortestSubStake.firstPeriod;\n                _shortestSubStakeIndex = MAX_SUB_STAKES;\n            } else {\n                (shortestSubStake, minSubStakeDuration, minSubStakeLastPeriod) =\n                    getShortestSubStake(_info, _decreasePeriod, _startPeriod);\n            }\n            if (minSubStakeDuration == MAX_UINT16) {\n                break;\n            }\n            uint256 appliedPenalty = _penalty;\n            if (_penalty \u003c shortestSubStake.lockedValue) {\n                shortestSubStake.lockedValue -= uint128(_penalty);\n                saveOldSubStake(_info, shortestSubStake.firstPeriod, _penalty, _decreasePeriod);\n                _penalty = 0;\n            } else {\n                shortestSubStake.lastPeriod = _decreasePeriod - 1;\n                _penalty -= shortestSubStake.lockedValue;\n                appliedPenalty = shortestSubStake.lockedValue;\n            }\n            if (_info.currentCommittedPeriod \u003e= _decreasePeriod \u0026\u0026\n                _info.currentCommittedPeriod \u003c= minSubStakeLastPeriod)\n            {\n                _lockedPerPeriod[_info.currentCommittedPeriod] -= appliedPenalty;\n            }\n            if (_info.nextCommittedPeriod \u003e= _decreasePeriod \u0026\u0026\n                _info.nextCommittedPeriod \u003c= minSubStakeLastPeriod)\n            {\n                _lockedPerPeriod[_info.nextCommittedPeriod] -= appliedPenalty;\n            }\n        }\n    }\n\n    /**\n    * @notice Get the shortest sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _startPeriod Pre-calculated start period\n    * @return shortestSubStake The shortest sub stake\n    * @return minSubStakeDuration Duration of the shortest sub stake\n    * @return minSubStakeLastPeriod Last period of the shortest sub stake\n    */\n    function getShortestSubStake(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _startPeriod\n    )\n        internal view returns (\n            SubStakeInfo storage shortestSubStake,\n            uint16 minSubStakeDuration,\n            uint16 minSubStakeLastPeriod\n        )\n    {\n        shortestSubStake = shortestSubStake;\n        minSubStakeDuration = MAX_UINT16;\n        minSubStakeLastPeriod = MAX_UINT16;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (lastPeriod \u003c subStake.firstPeriod) {\n                continue;\n            }\n            uint16 duration = lastPeriod - subStake.firstPeriod;\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod \u0026\u0026\n                (lastPeriod \u003c minSubStakeLastPeriod ||\n                lastPeriod == minSubStakeLastPeriod \u0026\u0026 duration \u003c minSubStakeDuration))\n            {\n                shortestSubStake = subStake;\n                minSubStakeDuration = duration;\n                minSubStakeLastPeriod = lastPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Save the old sub stake values to prevent decreasing reward for the previous period\n    * @dev Saving happens only if the previous period is committed\n    * @param _info Staker structure\n    * @param _firstPeriod First period of the old sub stake\n    * @param _lockedValue Locked value of the old sub stake\n    * @param _currentPeriod Current period, when the old sub stake is already unlocked\n    */\n    function saveOldSubStake(\n        StakerInfo storage _info,\n        uint16 _firstPeriod,\n        uint256 _lockedValue,\n        uint16 _currentPeriod\n    )\n        internal\n    {\n        // Check that the old sub stake should be saved\n        bool oldCurrentCommittedPeriod = _info.currentCommittedPeriod != 0 \u0026\u0026\n            _info.currentCommittedPeriod \u003c _currentPeriod;\n        bool oldnextCommittedPeriod = _info.nextCommittedPeriod != 0 \u0026\u0026\n            _info.nextCommittedPeriod \u003c _currentPeriod;\n        bool crosscurrentCommittedPeriod = oldCurrentCommittedPeriod \u0026\u0026 _info.currentCommittedPeriod \u003e= _firstPeriod;\n        bool crossnextCommittedPeriod = oldnextCommittedPeriod \u0026\u0026 _info.nextCommittedPeriod \u003e= _firstPeriod;\n        if (!crosscurrentCommittedPeriod \u0026\u0026 !crossnextCommittedPeriod) {\n            return;\n        }\n        // Try to find already existent proper old sub stake\n        uint16 previousPeriod = _currentPeriod - 1;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.lastPeriod == previousPeriod \u0026\u0026\n                ((crosscurrentCommittedPeriod ==\n                (oldCurrentCommittedPeriod \u0026\u0026 _info.currentCommittedPeriod \u003e= subStake.firstPeriod)) \u0026\u0026\n                (crossnextCommittedPeriod ==\n                (oldnextCommittedPeriod \u0026\u0026 _info.nextCommittedPeriod \u003e= subStake.firstPeriod))))\n            {\n                subStake.lockedValue += uint128(_lockedValue);\n                return;\n            }\n        }\n        saveSubStake(_info, _firstPeriod, previousPeriod, 0, _lockedValue);\n    }\n\n    //-------------Additional getters for stakers info-------------\n    /**\n    * @notice Return the length of the array of stakers\n    */\n    function getStakersLength() external view returns (uint256) {\n        return stakers.length;\n    }\n\n    /**\n    * @notice Return the length of the array of sub stakes\n    */\n    function getSubStakesLength(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].subStakes.length;\n    }\n\n    /**\n    * @notice Return the information about sub stake\n    */\n    function getSubStakeInfo(address _staker, uint256 _index)\n    // TODO change to structure when ABIEncoderV2 is released (#1501)\n//        public view returns (SubStakeInfo)\n        // TODO \"virtual\" only for tests, probably will be removed after #1512\n        external view virtual returns (\n            uint16 firstPeriod,\n            uint16 lastPeriod,\n            uint16 unlockingDuration,\n            uint128 lockedValue\n        )\n    {\n        SubStakeInfo storage info = stakerInfo[_staker].subStakes[_index];\n        firstPeriod = info.firstPeriod;\n        lastPeriod = info.lastPeriod;\n        unlockingDuration = info.unlockingDuration;\n        lockedValue = info.lockedValue;\n    }\n\n    /**\n    * @notice Return the length of the array of past downtime\n    */\n    function getPastDowntimeLength(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].pastDowntime.length;\n    }\n\n    /**\n    * @notice Return the information about past downtime\n    */\n    function  getPastDowntime(address _staker, uint256 _index)\n    // TODO change to structure when ABIEncoderV2 is released (#1501)\n//        public view returns (Downtime)\n        external view returns (uint16 startPeriod, uint16 endPeriod)\n    {\n        Downtime storage downtime = stakerInfo[_staker].pastDowntime[_index];\n        startPeriod = downtime.startPeriod;\n        endPeriod = downtime.endPeriod;\n    }\n\n    //------------------ ERC900 connectors ----------------------\n\n    function totalStakedForAt(address _owner, uint256 _blockNumber) public view override returns (uint256){\n        return stakerInfo[_owner].history.getValueAt(_blockNumber);\n    }\n\n    function totalStakedAt(uint256 _blockNumber) public view override returns (uint256){\n        return balanceHistory.getValueAt(_blockNumber);\n    }\n\n    function supportsHistory() external pure override returns (bool){\n        return true;\n    }\n\n    //------------------------Upgradeable------------------------\n    /**\n    * @dev Get StakerInfo structure by delegatecall\n    */\n    function delegateGetStakerInfo(address _target, bytes32 _staker)\n        internal returns (StakerInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, this.stakerInfo.selector, 1, _staker, 0);\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get SubStakeInfo structure by delegatecall\n    */\n    function delegateGetSubStakeInfo(address _target, bytes32 _staker, uint256 _index)\n        internal returns (SubStakeInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(\n            _target, this.getSubStakeInfo.selector, 2, _staker, bytes32(_index));\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get Downtime structure by delegatecall\n    */\n    function delegateGetPastDowntime(address _target, bytes32 _staker, uint256 _index)\n        internal returns (Downtime memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(\n            _target, this.getPastDowntime.selector, 2, _staker, bytes32(_index));\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n        require(delegateGet(_testTarget, this.lockedPerPeriod.selector,\n            bytes32(bytes2(RESERVED_PERIOD))) == lockedPerPeriod(RESERVED_PERIOD));\n        require(address(delegateGet(_testTarget, this.stakerFromWorker.selector, bytes32(0))) ==\n            stakerFromWorker[address(0)]);\n\n        require(delegateGet(_testTarget, this.getStakersLength.selector) == stakers.length);\n        if (stakers.length == 0) {\n            return;\n        }\n        address stakerAddress = stakers[0];\n        require(address(uint160(delegateGet(_testTarget, this.stakers.selector, 0))) == stakerAddress);\n        StakerInfo storage info = stakerInfo[stakerAddress];\n        bytes32 staker = bytes32(uint256(stakerAddress));\n        StakerInfo memory infoToCheck = delegateGetStakerInfo(_testTarget, staker);\n        require(infoToCheck.value == info.value \u0026\u0026\n            infoToCheck.currentCommittedPeriod == info.currentCommittedPeriod \u0026\u0026\n            infoToCheck.nextCommittedPeriod == info.nextCommittedPeriod \u0026\u0026\n            infoToCheck.flags == info.flags \u0026\u0026\n            infoToCheck.lastCommittedPeriod == info.lastCommittedPeriod \u0026\u0026\n            infoToCheck.completedWork == info.completedWork \u0026\u0026\n            infoToCheck.worker == info.worker \u0026\u0026\n            infoToCheck.workerStartPeriod == info.workerStartPeriod);\n\n        require(delegateGet(_testTarget, this.getPastDowntimeLength.selector, staker) ==\n            info.pastDowntime.length);\n        for (uint256 i = 0; i \u003c info.pastDowntime.length \u0026\u0026 i \u003c MAX_CHECKED_VALUES; i++) {\n            Downtime storage downtime = info.pastDowntime[i];\n            Downtime memory downtimeToCheck = delegateGetPastDowntime(_testTarget, staker, i);\n            require(downtimeToCheck.startPeriod == downtime.startPeriod \u0026\u0026\n                downtimeToCheck.endPeriod == downtime.endPeriod);\n        }\n\n        require(delegateGet(_testTarget, this.getSubStakesLength.selector, staker) == info.subStakes.length);\n        for (uint256 i = 0; i \u003c info.subStakes.length \u0026\u0026 i \u003c MAX_CHECKED_VALUES; i++) {\n            SubStakeInfo storage subStakeInfo = info.subStakes[i];\n            SubStakeInfo memory subStakeInfoToCheck = delegateGetSubStakeInfo(_testTarget, staker, i);\n            require(subStakeInfoToCheck.firstPeriod == subStakeInfo.firstPeriod \u0026\u0026\n                subStakeInfoToCheck.lastPeriod == subStakeInfo.lastPeriod \u0026\u0026\n                subStakeInfoToCheck.unlockingDuration == subStakeInfo.unlockingDuration \u0026\u0026\n                subStakeInfoToCheck.lockedValue == subStakeInfo.lockedValue);\n        }\n\n        // it\u0027s not perfect because checks not only slot value but also decoding\n        // at least without additional functions\n        require(delegateGet(_testTarget, this.totalStakedForAt.selector, staker, bytes32(block.number)) ==\n            totalStakedForAt(stakerAddress, block.number));\n        require(delegateGet(_testTarget, this.totalStakedAt.selector, bytes32(block.number)) ==\n            totalStakedAt(block.number));\n\n        if (info.worker != address(0)) {\n            require(address(delegateGet(_testTarget, this.stakerFromWorker.selector, bytes32(uint256(info.worker)))) ==\n                stakerFromWorker[info.worker]);\n        }\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`\n    function finishUpgrade(address _target) public override virtual {\n        super.finishUpgrade(_target);\n        // Create fake period\n        _lockedPerPeriod[RESERVED_PERIOD] = 111;\n\n        // Create fake worker\n        stakerFromWorker[address(0)] = address(this);\n    }\n}\n"},"Upgradeable.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"Ownable.sol\";\n\n\n/**\n* @notice Base contract for upgradeable contract\n* @dev Inherited contract should implement verifyState(address) method by checking storage variables\n* (see verifyState(address) in Dispatcher). Also contract should implement finishUpgrade(address)\n* if it is using constructor parameters by coping this parameters to the dispatcher storage\n*/\nabstract contract Upgradeable is Ownable {\n\n    event StateVerified(address indexed testTarget, address sender);\n    event UpgradeFinished(address indexed target, address sender);\n\n    /**\n    * @dev Contracts at the target must reserve the same location in storage for this address as in Dispatcher\n    * Stored data actually lives in the Dispatcher\n    * However the storage layout is specified here in the implementing contracts\n    */\n    address public target;\n\n    /**\n    * @dev Previous contract address (if available). Used for rollback\n    */\n    address public previousTarget;\n\n    /**\n    * @dev Upgrade status. Explicit `uint8` type is used instead of `bool` to save gas by excluding 0 value\n    */\n    uint8 public isUpgrade;\n\n    /**\n    * @dev Guarantees that next slot will be separated from the previous\n    */\n    uint256 stubSlot;\n\n    /**\n    * @dev Constants for `isUpgrade` field\n    */\n    uint8 constant UPGRADE_FALSE = 1;\n    uint8 constant UPGRADE_TRUE = 2;\n\n    /**\n    * @dev Checks that function executed while upgrading\n    * Recommended to add to `verifyState` and `finishUpgrade` methods\n    */\n    modifier onlyWhileUpgrading()\n    {\n        require(isUpgrade == UPGRADE_TRUE);\n        _;\n    }\n\n    /**\n    * @dev Method for verifying storage state.\n    * Should check that new target contract returns right storage value\n    */\n    function verifyState(address _testTarget) public virtual onlyWhileUpgrading {\n        emit StateVerified(_testTarget, msg.sender);\n    }\n\n    /**\n    * @dev Copy values from the new target to the current storage\n    * @param _target New target contract address\n    */\n    function finishUpgrade(address _target) public virtual onlyWhileUpgrading {\n        emit UpgradeFinished(_target, msg.sender);\n    }\n\n    /**\n    * @dev Base method to get data\n    * @param _target Target to call\n    * @param _selector Method selector\n    * @param _numberOfArguments Number of used arguments\n    * @param _argument1 First method argument\n    * @param _argument2 Second method argument\n    * @return memoryAddress Address in memory where the data is located\n    */\n    function delegateGetData(\n        address _target,\n        bytes4 _selector,\n        uint8 _numberOfArguments,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (bytes32 memoryAddress)\n    {\n        assembly {\n            memoryAddress := mload(0x40)\n            mstore(memoryAddress, _selector)\n            if gt(_numberOfArguments, 0) {\n                mstore(add(memoryAddress, 0x04), _argument1)\n            }\n            if gt(_numberOfArguments, 1) {\n                mstore(add(memoryAddress, 0x24), _argument2)\n            }\n            switch delegatecall(gas(), _target, memoryAddress, add(0x04, mul(0x20, _numberOfArguments)), 0, 0)\n                case 0 {\n                    revert(memoryAddress, 0)\n                }\n                default {\n                    returndatacopy(memoryAddress, 0x0, returndatasize())\n                }\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" without parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 0, 0, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with one parameter.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector, bytes32 _argument)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 1, _argument, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with two parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(\n        address _target,\n        bytes4 _selector,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 2, _argument1, _argument2);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n}\n"}}

        File 3 of 4: Dispatcher
        {"Address.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n        // for accounts without code, i.e. `keccak256(\u0027\u0027)`\n        bytes32 codehash;\n        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { codehash := extcodehash(account) }\n        return (codehash != accountHash \u0026\u0026 codehash != 0x0);\n    }\n\n    /**\n     * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     *\n     * _Available since v2.4.0._\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-call-value\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n}\n"},"Dispatcher.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"./Upgradeable.sol\";\nimport \"./Address.sol\";\n\n\n/**\n* @notice ERC897 - ERC DelegateProxy\n*/\ninterface ERCProxy {\n    function proxyType() external pure returns (uint256);\n    function implementation() external view returns (address);\n}\n\n\n/**\n* @notice Proxying requests to other contracts.\n* Client should use ABI of real contract and address of this contract\n*/\ncontract Dispatcher is Upgradeable, ERCProxy {\n    using Address for address;\n\n    event Upgraded(address indexed from, address indexed to, address owner);\n    event RolledBack(address indexed from, address indexed to, address owner);\n\n    /**\n    * @dev Set upgrading status before and after operations\n    */\n    modifier upgrading()\n    {\n        isUpgrade = UPGRADE_TRUE;\n        _;\n        isUpgrade = UPGRADE_FALSE;\n    }\n\n    /**\n    * @param _target Target contract address\n    */\n    constructor(address _target) upgrading {\n        require(_target.isContract());\n        // Checks that target contract inherits Dispatcher state\n        verifyState(_target);\n        // `verifyState` must work with its contract\n        verifyUpgradeableState(_target, _target);\n        target = _target;\n        finishUpgrade();\n        emit Upgraded(address(0), _target, msg.sender);\n    }\n\n    //------------------------ERC897------------------------\n    /**\n     * @notice ERC897, whether it is a forwarding (1) or an upgradeable (2) proxy\n     */\n    function proxyType() external pure override returns (uint256) {\n        return 2;\n    }\n\n    /**\n     * @notice ERC897, gets the address of the implementation where every call will be delegated\n     */\n    function implementation() external view override returns (address) {\n        return target;\n    }\n    //------------------------------------------------------------\n\n    /**\n    * @notice Verify new contract storage and upgrade target\n    * @param _target New target contract address\n    */\n    function upgrade(address _target) public onlyOwner upgrading {\n        require(_target.isContract());\n        // Checks that target contract has \"correct\" (as much as possible) state layout\n        verifyState(_target);\n        //`verifyState` must work with its contract\n        verifyUpgradeableState(_target, _target);\n        if (target.isContract()) {\n            verifyUpgradeableState(target, _target);\n        }\n        previousTarget = target;\n        target = _target;\n        finishUpgrade();\n        emit Upgraded(previousTarget, _target, msg.sender);\n    }\n\n    /**\n    * @notice Rollback to previous target\n    * @dev Test storage carefully before upgrade again after rollback\n    */\n    function rollback() public onlyOwner upgrading {\n        require(previousTarget.isContract());\n        emit RolledBack(target, previousTarget, msg.sender);\n        // should be always true because layout previousTarget -\u003e target was already checked\n        // but `verifyState` is not 100% accurate so check again\n        verifyState(previousTarget);\n        if (target.isContract()) {\n            verifyUpgradeableState(previousTarget, target);\n        }\n        target = previousTarget;\n        previousTarget = address(0);\n        finishUpgrade();\n    }\n\n    /**\n    * @dev Call verifyState method for Upgradeable contract\n    */\n    function verifyUpgradeableState(address _from, address _to) private {\n        (bool callSuccess,) = _from.delegatecall(abi.encodeWithSelector(this.verifyState.selector, _to));\n        require(callSuccess);\n    }\n\n    /**\n    * @dev Call finishUpgrade method from the Upgradeable contract\n    */\n    function finishUpgrade() private {\n        (bool callSuccess,) = target.delegatecall(abi.encodeWithSelector(this.finishUpgrade.selector, target));\n        require(callSuccess);\n    }\n\n    function verifyState(address _testTarget) public override onlyWhileUpgrading {\n        //checks equivalence accessing state through new contract and current storage\n        require(address(uint160(delegateGet(_testTarget, this.owner.selector))) == owner());\n        require(address(uint160(delegateGet(_testTarget, this.target.selector))) == target);\n        require(address(uint160(delegateGet(_testTarget, this.previousTarget.selector))) == previousTarget);\n        require(uint8(delegateGet(_testTarget, this.isUpgrade.selector)) == isUpgrade);\n    }\n\n    /**\n    * @dev Override function using empty code because no reason to call this function in Dispatcher\n    */\n    function finishUpgrade(address) public override {}\n\n    /**\n    * @dev Receive function sends empty request to the target contract\n    */\n    receive() external payable {\n        assert(target.isContract());\n        // execute receive function from target contract using storage of the dispatcher\n        (bool callSuccess,) = target.delegatecall(\"\");\n        if (!callSuccess) {\n            revert();\n        }\n    }\n\n    /**\n    * @dev Fallback function sends all requests to the target contract\n    */\n    fallback() external payable {\n        assert(target.isContract());\n        // execute requested function from target contract using storage of the dispatcher\n        (bool callSuccess,) = target.delegatecall(msg.data);\n        if (callSuccess) {\n            // copy result of the request to the return data\n            // we can use the second return value from `delegatecall` (bytes memory)\n            // but it will consume a little more gas\n            assembly {\n                returndatacopy(0x0, 0x0, returndatasize())\n                return(0x0, returndatasize())\n            }\n        } else {\n            revert();\n        }\n    }\n\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\nabstract contract Ownable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n     * account.\n     */\n    constructor () {\n        _owner = msg.sender;\n        emit OwnershipTransferred(address(0), _owner);\n    }\n\n    /**\n     * @return the address of the owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner());\n        _;\n    }\n\n    /**\n     * @return true if `msg.sender` is the owner of the contract.\n     */\n    function isOwner() public view returns (bool) {\n        return msg.sender == _owner;\n    }\n\n    /**\n     * @dev Allows the current owner to relinquish control of the contract.\n     * @notice Renouncing to ownership will leave the contract without an owner.\n     * It will not be possible to call the functions with the `onlyOwner`\n     * modifier anymore.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Allows the current owner to transfer control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function transferOwnership(address newOwner) public onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0));\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"},"Upgradeable.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"./Ownable.sol\";\n\n\n/**\n* @notice Base contract for upgradeable contract\n* @dev Inherited contract should implement verifyState(address) method by checking storage variables\n* (see verifyState(address) in Dispatcher). Also contract should implement finishUpgrade(address)\n* if it is using constructor parameters by coping this parameters to the dispatcher storage\n*/\nabstract contract Upgradeable is Ownable {\n\n    event StateVerified(address indexed testTarget, address sender);\n    event UpgradeFinished(address indexed target, address sender);\n\n    /**\n    * @dev Contracts at the target must reserve the same location in storage for this address as in Dispatcher\n    * Stored data actually lives in the Dispatcher\n    * However the storage layout is specified here in the implementing contracts\n    */\n    address public target;\n\n    /**\n    * @dev Previous contract address (if available). Used for rollback\n    */\n    address public previousTarget;\n\n    /**\n    * @dev Upgrade status. Explicit `uint8` type is used instead of `bool` to save gas by excluding 0 value\n    */\n    uint8 public isUpgrade;\n\n    /**\n    * @dev Guarantees that next slot will be separated from the previous\n    */\n    uint256 stubSlot;\n\n    /**\n    * @dev Constants for `isUpgrade` field\n    */\n    uint8 constant UPGRADE_FALSE = 1;\n    uint8 constant UPGRADE_TRUE = 2;\n\n    /**\n    * @dev Checks that function executed while upgrading\n    * Recommended to add to `verifyState` and `finishUpgrade` methods\n    */\n    modifier onlyWhileUpgrading()\n    {\n        require(isUpgrade == UPGRADE_TRUE);\n        _;\n    }\n\n    /**\n    * @dev Method for verifying storage state.\n    * Should check that new target contract returns right storage value\n    */\n    function verifyState(address _testTarget) public virtual onlyWhileUpgrading {\n        emit StateVerified(_testTarget, msg.sender);\n    }\n\n    /**\n    * @dev Copy values from the new target to the current storage\n    * @param _target New target contract address\n    */\n    function finishUpgrade(address _target) public virtual onlyWhileUpgrading {\n        emit UpgradeFinished(_target, msg.sender);\n    }\n\n    /**\n    * @dev Base method to get data\n    * @param _target Target to call\n    * @param _selector Method selector\n    * @param _numberOfArguments Number of used arguments\n    * @param _argument1 First method argument\n    * @param _argument2 Second method argument\n    * @return memoryAddress Address in memory where the data is located\n    */\n    function delegateGetData(\n        address _target,\n        bytes4 _selector,\n        uint8 _numberOfArguments,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (bytes32 memoryAddress)\n    {\n        assembly {\n            memoryAddress := mload(0x40)\n            mstore(memoryAddress, _selector)\n            if gt(_numberOfArguments, 0) {\n                mstore(add(memoryAddress, 0x04), _argument1)\n            }\n            if gt(_numberOfArguments, 1) {\n                mstore(add(memoryAddress, 0x24), _argument2)\n            }\n            switch delegatecall(gas(), _target, memoryAddress, add(0x04, mul(0x20, _numberOfArguments)), 0, 0)\n                case 0 {\n                    revert(memoryAddress, 0)\n                }\n                default {\n                    returndatacopy(memoryAddress, 0x0, returndatasize())\n                }\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" without parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 0, 0, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with one parameter.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector, bytes32 _argument)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 1, _argument, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with two parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(\n        address _target,\n        bytes4 _selector,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 2, _argument1, _argument2);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n}\n"}}

        File 4 of 4: PolicyManager
        {"AdditionalMath.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"SafeMath.sol\";\n\n\n/**\n* @notice Additional math operations\n*/\nlibrary AdditionalMath {\n    using SafeMath for uint256;\n\n    function max16(uint16 a, uint16 b) internal pure returns (uint16) {\n        return a \u003e= b ? a : b;\n    }\n\n    function min16(uint16 a, uint16 b) internal pure returns (uint16) {\n        return a \u003c b ? a : b;\n    }\n\n    /**\n    * @notice Division and ceil\n    */\n    function divCeil(uint256 a, uint256 b) internal pure returns (uint256) {\n        return (a.add(b) - 1) / b;\n    }\n\n    /**\n    * @dev Adds signed value to unsigned value, throws on overflow.\n    */\n    function addSigned(uint256 a, int256 b) internal pure returns (uint256) {\n        if (b \u003e= 0) {\n            return a.add(uint256(b));\n        } else {\n            return a.sub(uint256(-b));\n        }\n    }\n\n    /**\n    * @dev Subtracts signed value from unsigned value, throws on overflow.\n    */\n    function subSigned(uint256 a, int256 b) internal pure returns (uint256) {\n        if (b \u003e= 0) {\n            return a.sub(uint256(b));\n        } else {\n            return a.add(uint256(-b));\n        }\n    }\n\n    /**\n    * @dev Multiplies two numbers, throws on overflow.\n    */\n    function mul32(uint32 a, uint32 b) internal pure returns (uint32) {\n        if (a == 0) {\n            return 0;\n        }\n        uint32 c = a * b;\n        assert(c / a == b);\n        return c;\n    }\n\n    /**\n    * @dev Adds two numbers, throws on overflow.\n    */\n    function add16(uint16 a, uint16 b) internal pure returns (uint16) {\n        uint16 c = a + b;\n        assert(c \u003e= a);\n        return c;\n    }\n\n    /**\n    * @dev Subtracts two numbers, throws on overflow (i.e. if subtrahend is greater than minuend).\n    */\n    function sub16(uint16 a, uint16 b) internal pure returns (uint16) {\n        assert(b \u003c= a);\n        return a - b;\n    }\n\n    /**\n    * @dev Adds signed value to unsigned value, throws on overflow.\n    */\n    function addSigned16(uint16 a, int16 b) internal pure returns (uint16) {\n        if (b \u003e= 0) {\n            return add16(a, uint16(b));\n        } else {\n            return sub16(a, uint16(-b));\n        }\n    }\n\n    /**\n    * @dev Subtracts signed value from unsigned value, throws on overflow.\n    */\n    function subSigned16(uint16 a, int16 b) internal pure returns (uint16) {\n        if (b \u003e= 0) {\n            return sub16(a, uint16(b));\n        } else {\n            return add16(a, uint16(-b));\n        }\n    }\n}\n"},"Address.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n/**\n * @dev Collection of functions related to the address type\n */\nlibrary Address {\n    /**\n     * @dev Returns true if `account` is a contract.\n     *\n     * [IMPORTANT]\n     * ====\n     * It is unsafe to assume that an address for which this function returns\n     * false is an externally-owned account (EOA) and not a contract.\n     *\n     * Among others, `isContract` will return false for the following\n     * types of addresses:\n     *\n     *  - an externally-owned account\n     *  - a contract in construction\n     *  - an address where a contract will be created\n     *  - an address where a contract lived, but was destroyed\n     * ====\n     */\n    function isContract(address account) internal view returns (bool) {\n        // According to EIP-1052, 0x0 is the value returned for not-yet created accounts\n        // and 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470 is returned\n        // for accounts without code, i.e. `keccak256(\u0027\u0027)`\n        bytes32 codehash;\n        bytes32 accountHash = 0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470;\n        // solhint-disable-next-line no-inline-assembly\n        assembly { codehash := extcodehash(account) }\n        return (codehash != accountHash \u0026\u0026 codehash != 0x0);\n    }\n\n    /**\n     * @dev Replacement for Solidity\u0027s `transfer`: sends `amount` wei to\n     * `recipient`, forwarding all available gas and reverting on errors.\n     *\n     * https://eips.ethereum.org/EIPS/eip-1884[EIP1884] increases the gas cost\n     * of certain opcodes, possibly making contracts go over the 2300 gas limit\n     * imposed by `transfer`, making them unable to receive funds via\n     * `transfer`. {sendValue} removes this limitation.\n     *\n     * https://diligence.consensys.net/posts/2019/09/stop-using-soliditys-transfer-now/[Learn more].\n     *\n     * IMPORTANT: because control is transferred to `recipient`, care must be\n     * taken to not create reentrancy vulnerabilities. Consider using\n     * {ReentrancyGuard} or the\n     * https://solidity.readthedocs.io/en/v0.5.11/security-considerations.html#use-the-checks-effects-interactions-pattern[checks-effects-interactions pattern].\n     *\n     * _Available since v2.4.0._\n     */\n    function sendValue(address payable recipient, uint256 amount) internal {\n        require(address(this).balance \u003e= amount, \"Address: insufficient balance\");\n\n        // solhint-disable-next-line avoid-call-value\n        (bool success, ) = recipient.call{value: amount}(\"\");\n        require(success, \"Address: unable to send value, recipient may have reverted\");\n    }\n}\n"},"Bits.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n/**\n* @dev Taken from https://github.com/ethereum/solidity-examples/blob/master/src/bits/Bits.sol\n*/\nlibrary Bits {\n\n    uint256 internal constant ONE = uint256(1);\n\n    /**\n    * @notice Sets the bit at the given \u0027index\u0027 in \u0027self\u0027 to:\n    *  \u00271\u0027 - if the bit is \u00270\u0027\n    *  \u00270\u0027 - if the bit is \u00271\u0027\n    * @return The modified value\n    */\n    function toggleBit(uint256 self, uint8 index) internal pure returns (uint256) {\n        return self ^ ONE \u003c\u003c index;\n    }\n\n    /**\n    * @notice Get the value of the bit at the given \u0027index\u0027 in \u0027self\u0027.\n    */\n    function bit(uint256 self, uint8 index) internal pure returns (uint8) {\n        return uint8(self \u003e\u003e index \u0026 1);\n    }\n\n    /**\n    * @notice Check if the bit at the given \u0027index\u0027 in \u0027self\u0027 is set.\n    * @return  \u0027true\u0027 - if the value of the bit is \u00271\u0027,\n    *          \u0027false\u0027 - if the value of the bit is \u00270\u0027\n    */\n    function bitSet(uint256 self, uint8 index) internal pure returns (bool) {\n        return self \u003e\u003e index \u0026 1 == 1;\n    }\n\n}\n"},"ERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\nimport \"SafeMath.sol\";\n\n\n/**\n * @title Standard ERC20 token\n *\n * @dev Implementation of the basic standard token.\n * https://github.com/ethereum/EIPs/blob/master/EIPS/eip-20.md\n * Originally based on code by FirstBlood:\n * https://github.com/Firstbloodio/token/blob/master/smart_contract/FirstBloodToken.sol\n *\n * This implementation emits additional Approval events, allowing applications to reconstruct the allowance status for\n * all accounts just by listening to said events. Note that this isn\u0027t required by the specification, and other\n * compliant implementations may not do it.\n */\ncontract ERC20 is IERC20 {\n    using SafeMath for uint256;\n\n    mapping (address =\u003e uint256) private _balances;\n\n    mapping (address =\u003e mapping (address =\u003e uint256)) private _allowed;\n\n    uint256 private _totalSupply;\n\n    /**\n     * @dev Total number of tokens in existence\n     */\n    function totalSupply() public view override returns (uint256) {\n        return _totalSupply;\n    }\n\n    /**\n     * @dev Gets the balance of the specified address.\n     * @param owner The address to query the balance of.\n     * @return An uint256 representing the amount owned by the passed address.\n     */\n    function balanceOf(address owner) public view override returns (uint256) {\n        return _balances[owner];\n    }\n\n    /**\n     * @dev Function to check the amount of tokens that an owner allowed to a spender.\n     * @param owner address The address which owns the funds.\n     * @param spender address The address which will spend the funds.\n     * @return A uint256 specifying the amount of tokens still available for the spender.\n     */\n    function allowance(address owner, address spender) public view override returns (uint256) {\n        return _allowed[owner][spender];\n    }\n\n    /**\n     * @dev Transfer token for a specified address\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function transfer(address to, uint256 value) public override returns (bool) {\n        _transfer(msg.sender, to, value);\n        return true;\n    }\n\n    /**\n     * @dev Approve the passed address to spend the specified amount of tokens on behalf of msg.sender.\n     * Beware that changing an allowance with this method brings the risk that someone may use both the old\n     * and the new allowance by unfortunate transaction ordering. One possible solution to mitigate this\n     * race condition is to first reduce the spender\u0027s allowance to 0 and set the desired value afterwards:\n     * https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n     * @param spender The address which will spend the funds.\n     * @param value The amount of tokens to be spent.\n     */\n    function approve(address spender, uint256 value) public override returns (bool) {\n\n        // To change the approve amount you first have to reduce the addresses`\n        //  allowance to zero by calling `approve(_spender, 0)` if it is not\n        //  already 0 to mitigate the race condition described here:\n        //  https://github.com/ethereum/EIPs/issues/20#issuecomment-263524729\n        require(value == 0 || _allowed[msg.sender][spender] == 0);\n\n        _approve(msg.sender, spender, value);\n        return true;\n    }\n\n    /**\n     * @dev Transfer tokens from one address to another.\n     * Note that while this function emits an Approval event, this is not required as per the specification,\n     * and other compliant implementations may not emit the event.\n     * @param from address The address which you want to send tokens from\n     * @param to address The address which you want to transfer to\n     * @param value uint256 the amount of tokens to be transferred\n     */\n    function transferFrom(address from, address to, uint256 value) public override returns (bool) {\n        _transfer(from, to, value);\n        _approve(from, msg.sender, _allowed[from][msg.sender].sub(value));\n        return true;\n    }\n\n    /**\n     * @dev Increase the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To increment\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * Emits an Approval event.\n     * @param spender The address which will spend the funds.\n     * @param addedValue The amount of tokens to increase the allowance by.\n     */\n    function increaseAllowance(address spender, uint256 addedValue) public returns (bool) {\n        _approve(msg.sender, spender, _allowed[msg.sender][spender].add(addedValue));\n        return true;\n    }\n\n    /**\n     * @dev Decrease the amount of tokens that an owner allowed to a spender.\n     * approve should be called when allowed_[_spender] == 0. To decrement\n     * allowed value is better to use this function to avoid 2 calls (and wait until\n     * the first transaction is mined)\n     * From MonolithDAO Token.sol\n     * Emits an Approval event.\n     * @param spender The address which will spend the funds.\n     * @param subtractedValue The amount of tokens to decrease the allowance by.\n     */\n    function decreaseAllowance(address spender, uint256 subtractedValue) public returns (bool) {\n        _approve(msg.sender, spender, _allowed[msg.sender][spender].sub(subtractedValue));\n        return true;\n    }\n\n    /**\n     * @dev Transfer token for a specified addresses\n     * @param from The address to transfer from.\n     * @param to The address to transfer to.\n     * @param value The amount to be transferred.\n     */\n    function _transfer(address from, address to, uint256 value) internal {\n        require(to != address(0));\n\n        _balances[from] = _balances[from].sub(value);\n        _balances[to] = _balances[to].add(value);\n        emit Transfer(from, to, value);\n    }\n\n    /**\n     * @dev Internal function that mints an amount of the token and assigns it to\n     * an account. This encapsulates the modification of balances such that the\n     * proper events are emitted.\n     * @param account The account that will receive the created tokens.\n     * @param value The amount that will be created.\n     */\n    function _mint(address account, uint256 value) internal {\n        require(account != address(0));\n\n        _totalSupply = _totalSupply.add(value);\n        _balances[account] = _balances[account].add(value);\n        emit Transfer(address(0), account, value);\n    }\n\n    /**\n     * @dev Internal function that burns an amount of the token of a given\n     * account.\n     * @param account The account whose tokens will be burnt.\n     * @param value The amount that will be burnt.\n     */\n    function _burn(address account, uint256 value) internal {\n        require(account != address(0));\n\n        _totalSupply = _totalSupply.sub(value);\n        _balances[account] = _balances[account].sub(value);\n        emit Transfer(account, address(0), value);\n    }\n\n    /**\n     * @dev Approve an address to spend another addresses\u0027 tokens.\n     * @param owner The address that owns the tokens.\n     * @param spender The address that will spend the tokens.\n     * @param value The number of tokens that can be spent.\n     */\n    function _approve(address owner, address spender, uint256 value) internal {\n        require(spender != address(0));\n        require(owner != address(0));\n\n        _allowed[owner][spender] = value;\n        emit Approval(owner, spender, value);\n    }\n\n    /**\n     * @dev Internal function that burns an amount of the token of a given\n     * account, deducting from the sender\u0027s allowance for said account. Uses the\n     * internal burn function.\n     * Emits an Approval event (reflecting the reduced allowance).\n     * @param account The account whose tokens will be burnt.\n     * @param value The amount that will be burnt.\n     */\n    function _burnFrom(address account, uint256 value) internal {\n        _burn(account, value);\n        _approve(account, msg.sender, _allowed[account][msg.sender].sub(value));\n    }\n\n}\n"},"ERC20Detailed.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\n\n\n/**\n * @title ERC20Detailed token\n * @dev The decimals are only for visualization purposes.\n * All the operations are done using the smallest and indivisible token unit,\n * just as on Ethereum all the operations are done in wei.\n */\nabstract contract ERC20Detailed is IERC20 {\n    string private _name;\n    string private _symbol;\n    uint8 private _decimals;\n\n    constructor (string memory name, string memory symbol, uint8 decimals) {\n        _name = name;\n        _symbol = symbol;\n        _decimals = decimals;\n    }\n\n    /**\n     * @return the name of the token.\n     */\n    function name() public view returns (string memory) {\n        return _name;\n    }\n\n    /**\n     * @return the symbol of the token.\n     */\n    function symbol() public view returns (string memory) {\n        return _symbol;\n    }\n\n    /**\n     * @return the number of decimals of the token.\n     */\n    function decimals() public view returns (uint8) {\n        return _decimals;\n    }\n}\n"},"IERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title ERC20 interface\n * @dev see https://github.com/ethereum/EIPs/issues/20\n */\ninterface IERC20 {\n    function transfer(address to, uint256 value) external returns (bool);\n\n    function approve(address spender, uint256 value) external returns (bool);\n\n    function transferFrom(address from, address to, uint256 value) external returns (bool);\n\n    function totalSupply() external view returns (uint256);\n\n    function balanceOf(address who) external view returns (uint256);\n\n    function allowance(address owner, address spender) external view returns (uint256);\n\n    event Transfer(address indexed from, address indexed to, uint256 value);\n\n    event Approval(address indexed owner, address indexed spender, uint256 value);\n}\n"},"IERC900History.sol":{"content":"// SPDX-License-Identifier: GPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\n// Minimum interface to interact with Aragon\u0027s Aggregator\ninterface IERC900History {\n    function totalStakedForAt(address addr, uint256 blockNumber) external view returns (uint256);\n    function totalStakedAt(uint256 blockNumber) external view returns (uint256);\n    function supportsHistory() external pure returns (bool);\n}\n"},"Issuer.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"NuCypherToken.sol\";\nimport \"Math.sol\";\nimport \"Upgradeable.sol\";\nimport \"AdditionalMath.sol\";\nimport \"SafeERC20.sol\";\n\n\n/**\n* @title Issuer\n* @notice Contract for calculation of issued tokens\n* @dev |v3.4.1|\n*/\nabstract contract Issuer is Upgradeable {\n    using SafeERC20 for NuCypherToken;\n    using AdditionalMath for uint32;\n\n    event Donated(address indexed sender, uint256 value);\n    /// Issuer is initialized with a reserved reward\n    event Initialized(uint256 reservedReward);\n\n    uint128 constant MAX_UINT128 = uint128(0) - 1;\n\n    NuCypherToken public immutable token;\n    uint128 public immutable totalSupply;\n\n    // d * k2\n    uint256 public immutable mintingCoefficient;\n    // k1\n    uint256 public immutable lockDurationCoefficient1;\n    // k2\n    uint256 public immutable lockDurationCoefficient2;\n\n    uint32 public immutable genesisSecondsPerPeriod;\n    uint32 public immutable secondsPerPeriod;\n\n    // kmax\n    uint16 public immutable maximumRewardedPeriods;\n\n    uint256 public immutable firstPhaseMaxIssuance;\n    uint256 public immutable firstPhaseTotalSupply;\n\n    /**\n    * Current supply is used in the minting formula and is stored to prevent different calculation\n    * for stakers which get reward in the same period. There are two values -\n    * supply for previous period (used in formula) and supply for current period which accumulates value\n    * before end of period.\n    */\n    uint128 public previousPeriodSupply;\n    uint128 public currentPeriodSupply;\n    uint16 public currentMintingPeriod;\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @dev Minting formula for one sub-stake in one period for the first phase\n    firstPhaseMaxIssuance * (lockedValue / totalLockedValue) * (k1 + min(allLockedPeriods, kmax)) / k2\n    * @dev Minting formula for one sub-stake in one period for the second phase\n    (totalSupply - currentSupply) / d * (lockedValue / totalLockedValue) * (k1 + min(allLockedPeriods, kmax)) / k2\n    if allLockedPeriods \u003e maximumRewardedPeriods then allLockedPeriods = maximumRewardedPeriods\n    * @param _token Token contract\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,\n    * only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.\n    * See Equation 10 in Staking Protocol \u0026 Economics paper\n    * @param _lockDurationCoefficient1 (k1) Numerator of the coefficient which modifies the extent \n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently. \n    * Applicable to Phase 1 and Phase 2. k1 = k2 * small_stake_multiplier where default small_stake_multiplier = 0.5.  \n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _lockDurationCoefficient2 (k2) Denominator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k2 = maximum_rewarded_periods / (1 - small_stake_multiplier)\n    * where default maximum_rewarded_periods = 365 and default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _maximumRewardedPeriods (kmax) Number of periods beyond which a stake\u0027s lock duration\n    * no longer increases the subsidy it receives. kmax = reward_saturation * 365 where default reward_saturation = 1.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _firstPhaseTotalSupply Total supply for the first phase\n    * @param _firstPhaseMaxIssuance (Imax) Maximum number of new tokens minted per period during Phase 1.\n    * See Equation 7 in Staking Protocol \u0026 Economics paper.\n    */\n    constructor(\n        NuCypherToken _token,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint256 _issuanceDecayCoefficient,\n        uint256 _lockDurationCoefficient1,\n        uint256 _lockDurationCoefficient2,\n        uint16 _maximumRewardedPeriods,\n        uint256 _firstPhaseTotalSupply,\n        uint256 _firstPhaseMaxIssuance\n    ) {\n        uint256 localTotalSupply = _token.totalSupply();\n        require(localTotalSupply \u003e 0 \u0026\u0026\n            _issuanceDecayCoefficient != 0 \u0026\u0026\n            _hoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod \u003c= _hoursPerPeriod \u0026\u0026\n            _lockDurationCoefficient1 != 0 \u0026\u0026\n            _lockDurationCoefficient2 != 0 \u0026\u0026\n            _maximumRewardedPeriods != 0);\n        require(localTotalSupply \u003c= uint256(MAX_UINT128), \"Token contract has supply more than supported\");\n\n        uint256 maxLockDurationCoefficient = _maximumRewardedPeriods + _lockDurationCoefficient1;\n        uint256 localMintingCoefficient = _issuanceDecayCoefficient * _lockDurationCoefficient2;\n        require(maxLockDurationCoefficient \u003e _maximumRewardedPeriods \u0026\u0026\n            localMintingCoefficient / _issuanceDecayCoefficient ==  _lockDurationCoefficient2 \u0026\u0026\n            // worst case for `totalLockedValue * d * k2`, when totalLockedValue == totalSupply\n            localTotalSupply * localMintingCoefficient / localTotalSupply == localMintingCoefficient \u0026\u0026\n            // worst case for `(totalSupply - currentSupply) * lockedValue * (k1 + min(allLockedPeriods, kmax))`,\n            // when currentSupply == 0, lockedValue == totalSupply\n            localTotalSupply * localTotalSupply * maxLockDurationCoefficient / localTotalSupply / localTotalSupply ==\n                maxLockDurationCoefficient,\n            \"Specified parameters cause overflow\");\n\n        require(maxLockDurationCoefficient \u003c= _lockDurationCoefficient2,\n            \"Resulting locking duration coefficient must be less than 1\");\n        require(_firstPhaseTotalSupply \u003c= localTotalSupply, \"Too many tokens for the first phase\");\n        require(_firstPhaseMaxIssuance \u003c= _firstPhaseTotalSupply, \"Reward for the first phase is too high\");\n\n        token = _token;\n        secondsPerPeriod = _hoursPerPeriod.mul32(1 hours);\n        genesisSecondsPerPeriod = _genesisHoursPerPeriod.mul32(1 hours);\n        lockDurationCoefficient1 = _lockDurationCoefficient1;\n        lockDurationCoefficient2 = _lockDurationCoefficient2;\n        maximumRewardedPeriods = _maximumRewardedPeriods;\n        firstPhaseTotalSupply = _firstPhaseTotalSupply;\n        firstPhaseMaxIssuance = _firstPhaseMaxIssuance;\n        totalSupply = uint128(localTotalSupply);\n        mintingCoefficient = localMintingCoefficient;\n    }\n\n    /**\n    * @dev Checks contract initialization\n    */\n    modifier isInitialized()\n    {\n        require(currentMintingPeriod != 0);\n        _;\n    }\n\n    /**\n    * @return Number of current period\n    */\n    function getCurrentPeriod() public view returns (uint16) {\n        return uint16(block.timestamp / secondsPerPeriod);\n    }\n\n    /**\n    * @return Recalculate period value using new basis\n    */\n    function recalculatePeriod(uint16 _period) internal view returns (uint16) {\n        return uint16(uint256(_period) * genesisSecondsPerPeriod / secondsPerPeriod);\n    }\n\n    /**\n    * @notice Initialize reserved tokens for reward\n    */\n    function initialize(uint256 _reservedReward, address _sourceOfFunds) external onlyOwner {\n        require(currentMintingPeriod == 0);\n        // Reserved reward must be sufficient for at least one period of the first phase\n        require(firstPhaseMaxIssuance \u003c= _reservedReward);\n        currentMintingPeriod = getCurrentPeriod();\n        currentPeriodSupply = totalSupply - uint128(_reservedReward);\n        previousPeriodSupply = currentPeriodSupply;\n        token.safeTransferFrom(_sourceOfFunds, address(this), _reservedReward);\n        emit Initialized(_reservedReward);\n    }\n\n    /**\n    * @notice Function to mint tokens for one period.\n    * @param _currentPeriod Current period number.\n    * @param _lockedValue The amount of tokens that were locked by user in specified period.\n    * @param _totalLockedValue The amount of tokens that were locked by all users in specified period.\n    * @param _allLockedPeriods The max amount of periods during which tokens will be locked after specified period.\n    * @return amount Amount of minted tokens.\n    */\n    function mint(\n        uint16 _currentPeriod,\n        uint256 _lockedValue,\n        uint256 _totalLockedValue,\n        uint16 _allLockedPeriods\n    )\n        internal returns (uint256 amount)\n    {\n        if (currentPeriodSupply == totalSupply) {\n            return 0;\n        }\n\n        if (_currentPeriod \u003e currentMintingPeriod) {\n            previousPeriodSupply = currentPeriodSupply;\n            currentMintingPeriod = _currentPeriod;\n        }\n\n        uint256 currentReward;\n        uint256 coefficient;\n\n        // first phase\n        // firstPhaseMaxIssuance * lockedValue * (k1 + min(allLockedPeriods, kmax)) / (totalLockedValue * k2)\n        if (previousPeriodSupply + firstPhaseMaxIssuance \u003c= firstPhaseTotalSupply) {\n            currentReward = firstPhaseMaxIssuance;\n            coefficient = lockDurationCoefficient2;\n        // second phase\n        // (totalSupply - currentSupply) * lockedValue * (k1 + min(allLockedPeriods, kmax)) / (totalLockedValue * d * k2)\n        } else {\n            currentReward = totalSupply - previousPeriodSupply;\n            coefficient = mintingCoefficient;\n        }\n\n        uint256 allLockedPeriods =\n            AdditionalMath.min16(_allLockedPeriods, maximumRewardedPeriods) + lockDurationCoefficient1;\n        amount = (uint256(currentReward) * _lockedValue * allLockedPeriods) /\n            (_totalLockedValue * coefficient);\n\n        // rounding the last reward\n        uint256 maxReward = getReservedReward();\n        if (amount == 0) {\n            amount = 1;\n        } else if (amount \u003e maxReward) {\n            amount = maxReward;\n        }\n\n        currentPeriodSupply += uint128(amount);\n    }\n\n    /**\n    * @notice Return tokens for future minting\n    * @param _amount Amount of tokens\n    */\n    function unMint(uint256 _amount) internal {\n        previousPeriodSupply -= uint128(_amount);\n        currentPeriodSupply -= uint128(_amount);\n    }\n\n    /**\n    * @notice Donate sender\u0027s tokens. Amount of tokens will be returned for future minting\n    * @param _value Amount to donate\n    */\n    function donate(uint256 _value) external isInitialized {\n        token.safeTransferFrom(msg.sender, address(this), _value);\n        unMint(_value);\n        emit Donated(msg.sender, _value);\n    }\n\n    /**\n    * @notice Returns the number of tokens that can be minted\n    */\n    function getReservedReward() public view returns (uint256) {\n        return totalSupply - currentPeriodSupply;\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n        require(uint16(delegateGet(_testTarget, this.currentMintingPeriod.selector)) == currentMintingPeriod);\n        require(uint128(delegateGet(_testTarget, this.previousPeriodSupply.selector)) == previousPeriodSupply);\n        require(uint128(delegateGet(_testTarget, this.currentPeriodSupply.selector)) == currentPeriodSupply);\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`\n    function finishUpgrade(address _target) public override virtual {\n        super.finishUpgrade(_target);\n        // recalculate currentMintingPeriod if needed\n        if (currentMintingPeriod \u003e getCurrentPeriod()) {\n            currentMintingPeriod = recalculatePeriod(currentMintingPeriod);\n        }\n    }\n\n}\n"},"Math.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Math\n * @dev Assorted math operations\n */\nlibrary Math {\n    /**\n     * @dev Returns the largest of two numbers.\n     */\n    function max(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a \u003e= b ? a : b;\n    }\n\n    /**\n     * @dev Returns the smallest of two numbers.\n     */\n    function min(uint256 a, uint256 b) internal pure returns (uint256) {\n        return a \u003c b ? a : b;\n    }\n\n    /**\n     * @dev Calculates the average of two numbers. Since these are integers,\n     * averages of an even and odd number cannot be represented, and will be\n     * rounded down.\n     */\n    function average(uint256 a, uint256 b) internal pure returns (uint256) {\n        // (a + b) / 2 can overflow, so we distribute\n        return (a / 2) + (b / 2) + ((a % 2 + b % 2) / 2);\n    }\n}\n"},"NuCypherToken.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"ERC20.sol\";\nimport \"ERC20Detailed.sol\";\n\n\n/**\n* @title NuCypher token\n* @notice ERC20 token\n* @dev Optional approveAndCall() functionality to notify a contract if an approve() has occurred.\n*/\ncontract NuCypherToken is ERC20, ERC20Detailed(\u0027NuCypher\u0027, \u0027NU\u0027, 18) {\n\n    /**\n    * @notice Set amount of tokens\n    * @param _totalSupplyOfTokens Total number of tokens\n    */\n    constructor (uint256 _totalSupplyOfTokens) {\n        _mint(msg.sender, _totalSupplyOfTokens);\n    }\n\n    /**\n    * @notice Approves and then calls the receiving contract\n    *\n    * @dev call the receiveApproval function on the contract you want to be notified.\n    * receiveApproval(address _from, uint256 _value, address _tokenContract, bytes _extraData)\n    */\n    function approveAndCall(address _spender, uint256 _value, bytes calldata _extraData)\n        external returns (bool success)\n    {\n        approve(_spender, _value);\n        TokenRecipient(_spender).receiveApproval(msg.sender, _value, address(this), _extraData);\n        return true;\n    }\n\n}\n\n\n/**\n* @dev Interface to use the receiveApproval method\n*/\ninterface TokenRecipient {\n\n    /**\n    * @notice Receives a notification of approval of the transfer\n    * @param _from Sender of approval\n    * @param _value  The amount of tokens to be spent\n    * @param _tokenContract Address of the token contract\n    * @param _extraData Extra data\n    */\n    function receiveApproval(address _from, uint256 _value, address _tokenContract, bytes calldata _extraData) external;\n\n}\n"},"Ownable.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Ownable\n * @dev The Ownable contract has an owner address, and provides basic authorization control\n * functions, this simplifies the implementation of \"user permissions\".\n */\nabstract contract Ownable {\n    address private _owner;\n\n    event OwnershipTransferred(address indexed previousOwner, address indexed newOwner);\n\n    /**\n     * @dev The Ownable constructor sets the original `owner` of the contract to the sender\n     * account.\n     */\n    constructor () {\n        _owner = msg.sender;\n        emit OwnershipTransferred(address(0), _owner);\n    }\n\n    /**\n     * @return the address of the owner.\n     */\n    function owner() public view returns (address) {\n        return _owner;\n    }\n\n    /**\n     * @dev Throws if called by any account other than the owner.\n     */\n    modifier onlyOwner() {\n        require(isOwner());\n        _;\n    }\n\n    /**\n     * @return true if `msg.sender` is the owner of the contract.\n     */\n    function isOwner() public view returns (bool) {\n        return msg.sender == _owner;\n    }\n\n    /**\n     * @dev Allows the current owner to relinquish control of the contract.\n     * @notice Renouncing to ownership will leave the contract without an owner.\n     * It will not be possible to call the functions with the `onlyOwner`\n     * modifier anymore.\n     */\n    function renounceOwnership() public onlyOwner {\n        emit OwnershipTransferred(_owner, address(0));\n        _owner = address(0);\n    }\n\n    /**\n     * @dev Allows the current owner to transfer control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function transferOwnership(address newOwner) public virtual onlyOwner {\n        _transferOwnership(newOwner);\n    }\n\n    /**\n     * @dev Transfers control of the contract to a newOwner.\n     * @param newOwner The address to transfer ownership to.\n     */\n    function _transferOwnership(address newOwner) internal {\n        require(newOwner != address(0));\n        emit OwnershipTransferred(_owner, newOwner);\n        _owner = newOwner;\n    }\n}\n"},"PolicyManager.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"SafeERC20.sol\";\nimport \"SafeMath.sol\";\nimport \"Math.sol\";\nimport \"Address.sol\";\nimport \"AdditionalMath.sol\";\nimport \"SignatureVerifier.sol\";\nimport \"StakingEscrow.sol\";\nimport \"NuCypherToken.sol\";\nimport \"Upgradeable.sol\";\n\n\n/**\n* @title PolicyManager\n* @notice Contract holds policy data and locks accrued policy fees\n* @dev |v6.2.2|\n*/\ncontract PolicyManager is Upgradeable {\n    using SafeERC20 for NuCypherToken;\n    using SafeMath for uint256;\n    using AdditionalMath for uint256;\n    using AdditionalMath for int256;\n    using AdditionalMath for uint16;\n    using Address for address payable;\n\n    event PolicyCreated(\n        bytes16 indexed policyId,\n        address indexed sponsor,\n        address indexed owner,\n        uint256 feeRate,\n        uint64 startTimestamp,\n        uint64 endTimestamp,\n        uint256 numberOfNodes\n    );\n    event ArrangementRevoked(\n        bytes16 indexed policyId,\n        address indexed sender,\n        address indexed node,\n        uint256 value\n    );\n    event RefundForArrangement(\n        bytes16 indexed policyId,\n        address indexed sender,\n        address indexed node,\n        uint256 value\n    );\n    event PolicyRevoked(bytes16 indexed policyId, address indexed sender, uint256 value);\n    event RefundForPolicy(bytes16 indexed policyId, address indexed sender, uint256 value);\n    event MinFeeRateSet(address indexed node, uint256 value);\n    // TODO #1501\n    // Range range\n    event FeeRateRangeSet(address indexed sender, uint256 min, uint256 defaultValue, uint256 max);\n    event Withdrawn(address indexed node, address indexed recipient, uint256 value);\n\n    struct ArrangementInfo {\n        address node;\n        uint256 indexOfDowntimePeriods;\n        uint16 lastRefundedPeriod;\n    }\n\n    struct Policy {\n        bool disabled;\n        address payable sponsor;\n        address owner;\n\n        uint128 feeRate;\n        uint64 startTimestamp;\n        uint64 endTimestamp;\n\n        uint256 reservedSlot1;\n        uint256 reservedSlot2;\n        uint256 reservedSlot3;\n        uint256 reservedSlot4;\n        uint256 reservedSlot5;\n\n        ArrangementInfo[] arrangements;\n    }\n\n    struct NodeInfo {\n        uint128 fee;\n        uint16 previousFeePeriod;\n        uint256 feeRate;\n        uint256 minFeeRate;\n        mapping (uint16 =\u003e int256) stub; // former slot for feeDelta\n        mapping (uint16 =\u003e int256) feeDelta;\n    }\n\n    // TODO used only for `delegateGetNodeInfo`, probably will be removed after #1512\n    struct MemoryNodeInfo {\n        uint128 fee;\n        uint16 previousFeePeriod;\n        uint256 feeRate;\n        uint256 minFeeRate;\n    }\n\n    struct Range {\n        uint128 min;\n        uint128 defaultValue;\n        uint128 max;\n    }\n\n    bytes16 internal constant RESERVED_POLICY_ID = bytes16(0);\n    address internal constant RESERVED_NODE = address(0);\n    uint256 internal constant MAX_BALANCE = uint256(uint128(0) - 1);\n    // controlled overflow to get max int256\n    int256 public constant DEFAULT_FEE_DELTA = int256((uint256(0) - 1) \u003e\u003e 1);\n\n    StakingEscrow public immutable escrow;\n    uint32 public immutable genesisSecondsPerPeriod;\n    uint32 public immutable secondsPerPeriod;\n\n    mapping (bytes16 =\u003e Policy) public policies;\n    mapping (address =\u003e NodeInfo) public nodes;\n    Range public feeRateRange;\n    uint64 public resetTimestamp;\n\n    /**\n    * @notice Constructor sets address of the escrow contract\n    * @dev Put same address in both inputs variables except when migration is happening\n    * @param _escrowDispatcher Address of escrow dispatcher\n    * @param _escrowImplementation Address of escrow implementation\n    */\n    constructor(StakingEscrow _escrowDispatcher, StakingEscrow _escrowImplementation) {\n        escrow = _escrowDispatcher;\n        // if the input address is not the StakingEscrow then calling `secondsPerPeriod` will throw error\n        uint32 localSecondsPerPeriod = _escrowImplementation.secondsPerPeriod();\n        require(localSecondsPerPeriod \u003e 0);\n        secondsPerPeriod = localSecondsPerPeriod;\n        uint32 localgenesisSecondsPerPeriod = _escrowImplementation.genesisSecondsPerPeriod();\n        require(localgenesisSecondsPerPeriod \u003e 0);\n        genesisSecondsPerPeriod = localgenesisSecondsPerPeriod;\n        // handle case when we deployed new StakingEscrow but not yet upgraded\n        if (_escrowDispatcher != _escrowImplementation) {\n            require(_escrowDispatcher.secondsPerPeriod() == localSecondsPerPeriod ||\n                _escrowDispatcher.secondsPerPeriod() == localgenesisSecondsPerPeriod);\n        }\n    }\n\n    /**\n    * @dev Checks that sender is the StakingEscrow contract\n    */\n    modifier onlyEscrowContract()\n    {\n        require(msg.sender == address(escrow));\n        _;\n    }\n\n    /**\n    * @return Number of current period\n    */\n    function getCurrentPeriod() public view returns (uint16) {\n        return uint16(block.timestamp / secondsPerPeriod);\n    }\n\n    /**\n    * @return Recalculate period value using new basis\n    */\n    function recalculatePeriod(uint16 _period) internal view returns (uint16) {\n        return uint16(uint256(_period) * genesisSecondsPerPeriod / secondsPerPeriod);\n    }\n\n    /**\n    * @notice Register a node\n    * @param _node Node address\n    * @param _period Initial period\n    */\n    function register(address _node, uint16 _period) external onlyEscrowContract {\n        NodeInfo storage nodeInfo = nodes[_node];\n        require(nodeInfo.previousFeePeriod == 0 \u0026\u0026 _period \u003c getCurrentPeriod());\n        nodeInfo.previousFeePeriod = _period;\n    }\n\n    /**\n    * @notice Migrate from the old period length to the new one\n    * @param _node Node address\n    */\n    function migrate(address _node) external onlyEscrowContract {\n        NodeInfo storage nodeInfo = nodes[_node];\n        // with previous period length any previousFeePeriod will be greater than current period\n        // this is a sign of not migrated node\n        require(nodeInfo.previousFeePeriod \u003e= getCurrentPeriod());\n        nodeInfo.previousFeePeriod = recalculatePeriod(nodeInfo.previousFeePeriod);\n        nodeInfo.feeRate = 0;\n    }\n\n    /**\n    * @notice Set minimum, default \u0026 maximum fee rate for all stakers and all policies (\u0027global fee range\u0027)\n    */\n    // TODO # 1501\n    // function setFeeRateRange(Range calldata _range) external onlyOwner {\n    function setFeeRateRange(uint128 _min, uint128 _default, uint128 _max) external onlyOwner {\n        require(_min \u003c= _default \u0026\u0026 _default \u003c= _max);\n        feeRateRange = Range(_min, _default, _max);\n        emit FeeRateRangeSet(msg.sender, _min, _default, _max);\n    }\n\n    /**\n    * @notice Set the minimum acceptable fee rate (set by staker for their associated worker)\n    * @dev Input value must fall within `feeRateRange` (global fee range)\n    */\n    function setMinFeeRate(uint256 _minFeeRate) external {\n        require(_minFeeRate \u003e= feeRateRange.min \u0026\u0026\n            _minFeeRate \u003c= feeRateRange.max,\n            \"The staker\u0027s min fee rate must fall within the global fee range\");\n        NodeInfo storage nodeInfo = nodes[msg.sender];\n        if (nodeInfo.minFeeRate == _minFeeRate) {\n            return;\n        }\n        nodeInfo.minFeeRate = _minFeeRate;\n        emit MinFeeRateSet(msg.sender, _minFeeRate);\n    }\n\n    /**\n    * @notice Get the minimum acceptable fee rate (set by staker for their associated worker)\n    */\n    function getMinFeeRate(NodeInfo storage _nodeInfo) internal view returns (uint256) {\n        // if minFeeRate has not been set or chosen value falls outside the global fee range\n        // a default value is returned instead\n        if (_nodeInfo.minFeeRate == 0 ||\n            _nodeInfo.minFeeRate \u003c feeRateRange.min ||\n            _nodeInfo.minFeeRate \u003e feeRateRange.max) {\n            return feeRateRange.defaultValue;\n        } else {\n            return _nodeInfo.minFeeRate;\n        }\n    }\n\n    /**\n    * @notice Get the minimum acceptable fee rate (set by staker for their associated worker)\n    */\n    function getMinFeeRate(address _node) public view returns (uint256) {\n        NodeInfo storage nodeInfo = nodes[_node];\n        return getMinFeeRate(nodeInfo);\n    }\n\n    /**\n    * @notice Create policy\n    * @dev Generate policy id before creation\n    * @param _policyId Policy id\n    * @param _policyOwner Policy owner. Zero address means sender is owner\n    * @param _endTimestamp End timestamp of the policy in seconds\n    * @param _nodes Nodes that will handle policy\n    */\n    function createPolicy(\n        bytes16 _policyId,\n        address _policyOwner,\n        uint64 _endTimestamp,\n        address[] calldata _nodes\n    )\n        external payable\n    {\n        Policy storage policy = policies[_policyId];\n        require(\n            _policyId != RESERVED_POLICY_ID \u0026\u0026\n            policy.feeRate == 0 \u0026\u0026\n            !policy.disabled \u0026\u0026\n            _endTimestamp \u003e block.timestamp \u0026\u0026\n            msg.value \u003e 0\n        );\n        require(address(this).balance \u003c= MAX_BALANCE);\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 endPeriod = uint16(_endTimestamp / secondsPerPeriod) + 1;\n        uint256 numberOfPeriods = endPeriod - currentPeriod;\n\n        policy.sponsor = msg.sender;\n        policy.startTimestamp = uint64(block.timestamp);\n        policy.endTimestamp = _endTimestamp;\n        policy.feeRate = uint128(msg.value.div(_nodes.length) / numberOfPeriods);\n        require(policy.feeRate \u003e 0 \u0026\u0026 policy.feeRate * numberOfPeriods * _nodes.length  == msg.value);\n        if (_policyOwner != msg.sender \u0026\u0026 _policyOwner != address(0)) {\n            policy.owner = _policyOwner;\n        }\n\n        for (uint256 i = 0; i \u003c _nodes.length; i++) {\n            address node = _nodes[i];\n            require(node != RESERVED_NODE);\n            NodeInfo storage nodeInfo = nodes[node];\n            require(nodeInfo.previousFeePeriod != 0 \u0026\u0026\n                nodeInfo.previousFeePeriod \u003c currentPeriod \u0026\u0026\n                policy.feeRate \u003e= getMinFeeRate(nodeInfo));\n            // Check default value for feeDelta\n            if (nodeInfo.feeDelta[currentPeriod] == DEFAULT_FEE_DELTA) {\n                nodeInfo.feeDelta[currentPeriod] = int256(policy.feeRate);\n            } else {\n                // Overflow protection removed, because ETH total supply less than uint255/int256\n                nodeInfo.feeDelta[currentPeriod] += int256(policy.feeRate);\n            }\n            if (nodeInfo.feeDelta[endPeriod] == DEFAULT_FEE_DELTA) {\n                nodeInfo.feeDelta[endPeriod] = -int256(policy.feeRate);\n            } else {\n                nodeInfo.feeDelta[endPeriod] -= int256(policy.feeRate);\n            }\n            // Reset to default value if needed\n            if (nodeInfo.feeDelta[currentPeriod] == 0) {\n                nodeInfo.feeDelta[currentPeriod] = DEFAULT_FEE_DELTA;\n            }\n            if (nodeInfo.feeDelta[endPeriod] == 0) {\n                nodeInfo.feeDelta[endPeriod] = DEFAULT_FEE_DELTA;\n            }\n            policy.arrangements.push(ArrangementInfo(node, 0, 0));\n        }\n\n        emit PolicyCreated(\n            _policyId,\n            msg.sender,\n            _policyOwner == address(0) ? msg.sender : _policyOwner,\n            policy.feeRate,\n            policy.startTimestamp,\n            policy.endTimestamp,\n            _nodes.length\n        );\n    }\n\n    /**\n    * @notice Get policy owner\n    */\n    function getPolicyOwner(bytes16 _policyId) public view returns (address) {\n        Policy storage policy = policies[_policyId];\n        return policy.owner == address(0) ? policy.sponsor : policy.owner;\n    }\n\n    /**\n    * @notice Call from StakingEscrow to update node info once per period.\n    * Set default `feeDelta` value for specified period and update node fee\n    * @param _node Node address\n    * @param _processedPeriod1 Processed period\n    * @param _processedPeriod2 Processed period\n    * @param _periodToSetDefault Period to set\n    */\n    function ping(\n        address _node,\n        uint16 _processedPeriod1,\n        uint16 _processedPeriod2,\n        uint16 _periodToSetDefault\n    )\n        external onlyEscrowContract\n    {\n        NodeInfo storage node = nodes[_node];\n        // protection from calling not migrated node, see migrate()\n        require(node.previousFeePeriod \u003c= getCurrentPeriod());\n        if (_processedPeriod1 != 0) {\n            updateFee(node, _processedPeriod1);\n        }\n        if (_processedPeriod2 != 0) {\n            updateFee(node, _processedPeriod2);\n        }\n        // This code increases gas cost for node in trade of decreasing cost for policy sponsor\n        if (_periodToSetDefault != 0 \u0026\u0026 node.feeDelta[_periodToSetDefault] == 0) {\n            node.feeDelta[_periodToSetDefault] = DEFAULT_FEE_DELTA;\n        }\n    }\n\n    /**\n    * @notice Update node fee\n    * @param _info Node info structure\n    * @param _period Processed period\n    */\n    function updateFee(NodeInfo storage _info, uint16 _period) internal {\n        if (_info.previousFeePeriod == 0 || _period \u003c= _info.previousFeePeriod) {\n            return;\n        }\n        for (uint16 i = _info.previousFeePeriod + 1; i \u003c= _period; i++) {\n            int256 delta = _info.feeDelta[i];\n            if (delta == DEFAULT_FEE_DELTA) {\n                // gas refund\n                _info.feeDelta[i] = 0;\n                continue;\n            }\n\n            _info.feeRate = _info.feeRate.addSigned(delta);\n            // gas refund\n            _info.feeDelta[i] = 0;\n        }\n        _info.previousFeePeriod = _period;\n        _info.fee += uint128(_info.feeRate);\n    }\n\n    /**\n    * @notice Withdraw fee by node\n    */\n    function withdraw() external returns (uint256) {\n        return withdraw(msg.sender);\n    }\n\n    /**\n    * @notice Withdraw fee by node\n    * @param _recipient Recipient of the fee\n    */\n    function withdraw(address payable _recipient) public returns (uint256) {\n        NodeInfo storage node = nodes[msg.sender];\n        uint256 fee = node.fee;\n        require(fee != 0);\n        node.fee = 0;\n        _recipient.sendValue(fee);\n        emit Withdrawn(msg.sender, _recipient, fee);\n        return fee;\n    }\n\n    /**\n    * @notice Calculate amount of refund\n    * @param _policy Policy\n    * @param _arrangement Arrangement\n    */\n    function calculateRefundValue(Policy storage _policy, ArrangementInfo storage _arrangement)\n        internal view returns (uint256 refundValue, uint256 indexOfDowntimePeriods, uint16 lastRefundedPeriod)\n    {\n        uint16 policyStartPeriod = uint16(_policy.startTimestamp / secondsPerPeriod);\n        uint16 maxPeriod = AdditionalMath.min16(getCurrentPeriod(), uint16(_policy.endTimestamp / secondsPerPeriod));\n        uint16 minPeriod = AdditionalMath.max16(policyStartPeriod, _arrangement.lastRefundedPeriod);\n        uint16 downtimePeriods = 0;\n        uint256 length = escrow.getPastDowntimeLength(_arrangement.node);\n        uint256 initialIndexOfDowntimePeriods;\n        if (_arrangement.lastRefundedPeriod == 0) {\n            initialIndexOfDowntimePeriods = escrow.findIndexOfPastDowntime(_arrangement.node, policyStartPeriod);\n        } else {\n            initialIndexOfDowntimePeriods = _arrangement.indexOfDowntimePeriods;\n        }\n\n        for (indexOfDowntimePeriods = initialIndexOfDowntimePeriods;\n             indexOfDowntimePeriods \u003c length;\n             indexOfDowntimePeriods++)\n        {\n            (uint16 startPeriod, uint16 endPeriod) =\n                escrow.getPastDowntime(_arrangement.node, indexOfDowntimePeriods);\n            if (startPeriod \u003e maxPeriod) {\n                break;\n            } else if (endPeriod \u003c minPeriod) {\n                continue;\n            }\n            downtimePeriods += AdditionalMath.min16(maxPeriod, endPeriod)\n                .sub16(AdditionalMath.max16(minPeriod, startPeriod)) + 1;\n            if (maxPeriod \u003c= endPeriod) {\n                break;\n            }\n        }\n\n        uint16 lastCommittedPeriod = escrow.getLastCommittedPeriod(_arrangement.node);\n        if (indexOfDowntimePeriods == length \u0026\u0026 lastCommittedPeriod \u003c maxPeriod) {\n            // Overflow protection removed:\n            // lastCommittedPeriod \u003c maxPeriod and minPeriod \u003c= maxPeriod + 1\n            downtimePeriods += maxPeriod - AdditionalMath.max16(minPeriod - 1, lastCommittedPeriod);\n        }\n\n        refundValue = _policy.feeRate * downtimePeriods;\n        lastRefundedPeriod = maxPeriod + 1;\n    }\n\n    /**\n    * @notice Revoke/refund arrangement/policy by the sponsor\n    * @param _policyId Policy id\n    * @param _node Node that will be excluded or RESERVED_NODE if full policy should be used\n    ( @param _forceRevoke Force revoke arrangement/policy\n    */\n    function refundInternal(bytes16 _policyId, address _node, bool _forceRevoke)\n        internal returns (uint256 refundValue)\n    {\n        refundValue = 0;\n        Policy storage policy = policies[_policyId];\n        require(!policy.disabled \u0026\u0026 policy.startTimestamp \u003e= resetTimestamp);\n        uint16 endPeriod = uint16(policy.endTimestamp / secondsPerPeriod) + 1;\n        uint256 numberOfActive = policy.arrangements.length;\n        uint256 i = 0;\n        for (; i \u003c policy.arrangements.length; i++) {\n            ArrangementInfo storage arrangement = policy.arrangements[i];\n            address node = arrangement.node;\n            if (node == RESERVED_NODE || _node != RESERVED_NODE \u0026\u0026 _node != node) {\n                numberOfActive--;\n                continue;\n            }\n            uint256 nodeRefundValue;\n            (nodeRefundValue, arrangement.indexOfDowntimePeriods, arrangement.lastRefundedPeriod) =\n                calculateRefundValue(policy, arrangement);\n            if (_forceRevoke) {\n                NodeInfo storage nodeInfo = nodes[node];\n\n                // Check default value for feeDelta\n                uint16 lastRefundedPeriod = arrangement.lastRefundedPeriod;\n                if (nodeInfo.feeDelta[lastRefundedPeriod] == DEFAULT_FEE_DELTA) {\n                    nodeInfo.feeDelta[lastRefundedPeriod] = -int256(policy.feeRate);\n                } else {\n                    nodeInfo.feeDelta[lastRefundedPeriod] -= int256(policy.feeRate);\n                }\n                if (nodeInfo.feeDelta[endPeriod] == DEFAULT_FEE_DELTA) {\n                    nodeInfo.feeDelta[endPeriod] = int256(policy.feeRate);\n                } else {\n                    nodeInfo.feeDelta[endPeriod] += int256(policy.feeRate);\n                }\n\n                // Reset to default value if needed\n                if (nodeInfo.feeDelta[lastRefundedPeriod] == 0) {\n                    nodeInfo.feeDelta[lastRefundedPeriod] = DEFAULT_FEE_DELTA;\n                }\n                if (nodeInfo.feeDelta[endPeriod] == 0) {\n                    nodeInfo.feeDelta[endPeriod] = DEFAULT_FEE_DELTA;\n                }\n                nodeRefundValue += uint256(endPeriod - lastRefundedPeriod) * policy.feeRate;\n            }\n            if (_forceRevoke || arrangement.lastRefundedPeriod \u003e= endPeriod) {\n                arrangement.node = RESERVED_NODE;\n                arrangement.indexOfDowntimePeriods = 0;\n                arrangement.lastRefundedPeriod = 0;\n                numberOfActive--;\n                emit ArrangementRevoked(_policyId, msg.sender, node, nodeRefundValue);\n            } else {\n                emit RefundForArrangement(_policyId, msg.sender, node, nodeRefundValue);\n            }\n\n            refundValue += nodeRefundValue;\n            if (_node != RESERVED_NODE) {\n               break;\n            }\n        }\n        address payable policySponsor = policy.sponsor;\n        if (_node == RESERVED_NODE) {\n            if (numberOfActive == 0) {\n                policy.disabled = true;\n                // gas refund\n                policy.sponsor = address(0);\n                policy.owner = address(0);\n                policy.feeRate = 0;\n                policy.startTimestamp = 0;\n                policy.endTimestamp = 0;\n                emit PolicyRevoked(_policyId, msg.sender, refundValue);\n            } else {\n                emit RefundForPolicy(_policyId, msg.sender, refundValue);\n            }\n        } else {\n            // arrangement not found\n            require(i \u003c policy.arrangements.length);\n        }\n        if (refundValue \u003e 0) {\n            policySponsor.sendValue(refundValue);\n        }\n    }\n\n    /**\n    * @notice Calculate amount of refund\n    * @param _policyId Policy id\n    * @param _node Node or RESERVED_NODE if all nodes should be used\n    */\n    function calculateRefundValueInternal(bytes16 _policyId, address _node)\n        internal view returns (uint256 refundValue)\n    {\n        refundValue = 0;\n        Policy storage policy = policies[_policyId];\n        require((policy.owner == msg.sender || policy.sponsor == msg.sender) \u0026\u0026 !policy.disabled);\n        uint256 i = 0;\n        for (; i \u003c policy.arrangements.length; i++) {\n            ArrangementInfo storage arrangement = policy.arrangements[i];\n            if (arrangement.node == RESERVED_NODE || _node != RESERVED_NODE \u0026\u0026 _node != arrangement.node) {\n                continue;\n            }\n            (uint256 nodeRefundValue,,) = calculateRefundValue(policy, arrangement);\n            refundValue += nodeRefundValue;\n            if (_node != RESERVED_NODE) {\n               break;\n            }\n        }\n        if (_node != RESERVED_NODE) {\n            // arrangement not found\n            require(i \u003c policy.arrangements.length);\n        }\n    }\n\n    /**\n    * @notice Revoke policy by the sponsor\n    * @param _policyId Policy id\n    */\n    function revokePolicy(bytes16 _policyId) external returns (uint256 refundValue) {\n        require(getPolicyOwner(_policyId) == msg.sender);\n        return refundInternal(_policyId, RESERVED_NODE, true);\n    }\n\n    /**\n    * @notice Revoke arrangement by the sponsor\n    * @param _policyId Policy id\n    * @param _node Node that will be excluded\n    */\n    function revokeArrangement(bytes16 _policyId, address _node)\n        external returns (uint256 refundValue)\n    {\n        require(_node != RESERVED_NODE);\n        require(getPolicyOwner(_policyId) == msg.sender);\n        return refundInternal(_policyId, _node, true);\n    }\n\n    /**\n    * @notice Get unsigned hash for revocation\n    * @param _policyId Policy id\n    * @param _node Node that will be excluded\n    * @return Revocation hash, EIP191 version 0x45 (\u0027E\u0027)\n    */\n    function getRevocationHash(bytes16 _policyId, address _node) public view returns (bytes32) {\n        return SignatureVerifier.hashEIP191(abi.encodePacked(_policyId, _node), byte(0x45));\n    }\n\n    /**\n    * @notice Check correctness of signature\n    * @param _policyId Policy id\n    * @param _node Node that will be excluded, zero address if whole policy will be revoked\n    * @param _signature Signature of owner\n    */\n    function checkOwnerSignature(bytes16 _policyId, address _node, bytes memory _signature) internal view {\n        bytes32 hash = getRevocationHash(_policyId, _node);\n        address recovered = SignatureVerifier.recover(hash, _signature);\n        require(getPolicyOwner(_policyId) == recovered);\n    }\n\n    /**\n    * @notice Revoke policy or arrangement using owner\u0027s signature\n    * @param _policyId Policy id\n    * @param _node Node that will be excluded, zero address if whole policy will be revoked\n    * @param _signature Signature of owner, EIP191 version 0x45 (\u0027E\u0027)\n    */\n    function revoke(bytes16 _policyId, address _node, bytes calldata _signature)\n        external returns (uint256 refundValue)\n    {\n        checkOwnerSignature(_policyId, _node, _signature);\n        return refundInternal(_policyId, _node, true);\n    }\n\n    /**\n    * @notice Refund part of fee by the sponsor\n    * @param _policyId Policy id\n    */\n    function refund(bytes16 _policyId) external {\n        Policy storage policy = policies[_policyId];\n        require(policy.owner == msg.sender || policy.sponsor == msg.sender);\n        refundInternal(_policyId, RESERVED_NODE, false);\n    }\n\n    /**\n    * @notice Refund part of one node\u0027s fee by the sponsor\n    * @param _policyId Policy id\n    * @param _node Node address\n    */\n    function refund(bytes16 _policyId, address _node)\n        external returns (uint256 refundValue)\n    {\n        require(_node != RESERVED_NODE);\n        Policy storage policy = policies[_policyId];\n        require(policy.owner == msg.sender || policy.sponsor == msg.sender);\n        return refundInternal(_policyId, _node, false);\n    }\n\n    /**\n    * @notice Calculate amount of refund\n    * @param _policyId Policy id\n    */\n    function calculateRefundValue(bytes16 _policyId)\n        external view returns (uint256 refundValue)\n    {\n        return calculateRefundValueInternal(_policyId, RESERVED_NODE);\n    }\n\n    /**\n    * @notice Calculate amount of refund\n    * @param _policyId Policy id\n    * @param _node Node\n    */\n    function calculateRefundValue(bytes16 _policyId, address _node)\n        external view returns (uint256 refundValue)\n    {\n        require(_node != RESERVED_NODE);\n        return calculateRefundValueInternal(_policyId, _node);\n    }\n\n    /**\n    * @notice Get number of arrangements in the policy\n    * @param _policyId Policy id\n    */\n    function getArrangementsLength(bytes16 _policyId) external view returns (uint256) {\n        return policies[_policyId].arrangements.length;\n    }\n\n    /**\n    * @notice Get information about staker\u0027s fee rate\n    * @param _node Address of staker\n    * @param _period Period to get fee delta\n    */\n    function getNodeFeeDelta(address _node, uint16 _period)\n        // TODO \"virtual\" only for tests, probably will be removed after #1512\n        public view virtual returns (int256)\n    {\n        // TODO remove after upgrade #2579\n        if (_node == RESERVED_NODE \u0026\u0026 _period == 11) {\n            return 55;\n        }\n        return nodes[_node].feeDelta[_period];\n    }\n\n    /**\n    * @notice Return the information about arrangement\n    */\n    function getArrangementInfo(bytes16 _policyId, uint256 _index)\n    // TODO change to structure when ABIEncoderV2 is released (#1501)\n//        public view returns (ArrangementInfo)\n        external view returns (address node, uint256 indexOfDowntimePeriods, uint16 lastRefundedPeriod)\n    {\n        ArrangementInfo storage info = policies[_policyId].arrangements[_index];\n        node = info.node;\n        indexOfDowntimePeriods = info.indexOfDowntimePeriods;\n        lastRefundedPeriod = info.lastRefundedPeriod;\n    }\n\n\n    /**\n    * @dev Get Policy structure by delegatecall\n    */\n    function delegateGetPolicy(address _target, bytes16 _policyId)\n        internal returns (Policy memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, this.policies.selector, 1, bytes32(_policyId), 0);\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get ArrangementInfo structure by delegatecall\n    */\n    function delegateGetArrangementInfo(address _target, bytes16 _policyId, uint256 _index)\n        internal returns (ArrangementInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(\n            _target, this.getArrangementInfo.selector, 2, bytes32(_policyId), bytes32(_index));\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get NodeInfo structure by delegatecall\n    */\n    function delegateGetNodeInfo(address _target, address _node)\n        internal returns (MemoryNodeInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, this.nodes.selector, 1, bytes32(uint256(_node)), 0);\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get feeRateRange structure by delegatecall\n    */\n    function delegateGetFeeRateRange(address _target) internal returns (Range memory result) {\n        bytes32 memoryAddress = delegateGetData(_target, this.feeRateRange.selector, 0, 0, 0);\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n        require(uint64(delegateGet(_testTarget, this.resetTimestamp.selector)) == resetTimestamp);\n\n        Range memory rangeToCheck = delegateGetFeeRateRange(_testTarget);\n        require(feeRateRange.min == rangeToCheck.min \u0026\u0026\n            feeRateRange.defaultValue == rangeToCheck.defaultValue \u0026\u0026\n            feeRateRange.max == rangeToCheck.max);\n\n        Policy storage policy = policies[RESERVED_POLICY_ID];\n        Policy memory policyToCheck = delegateGetPolicy(_testTarget, RESERVED_POLICY_ID);\n        require(policyToCheck.sponsor == policy.sponsor \u0026\u0026\n            policyToCheck.owner == policy.owner \u0026\u0026\n            policyToCheck.feeRate == policy.feeRate \u0026\u0026\n            policyToCheck.startTimestamp == policy.startTimestamp \u0026\u0026\n            policyToCheck.endTimestamp == policy.endTimestamp \u0026\u0026\n            policyToCheck.disabled == policy.disabled);\n\n        require(delegateGet(_testTarget, this.getArrangementsLength.selector, RESERVED_POLICY_ID) ==\n            policy.arrangements.length);\n        if (policy.arrangements.length \u003e 0) {\n            ArrangementInfo storage arrangement = policy.arrangements[0];\n            ArrangementInfo memory arrangementToCheck = delegateGetArrangementInfo(\n                _testTarget, RESERVED_POLICY_ID, 0);\n            require(arrangementToCheck.node == arrangement.node \u0026\u0026\n                arrangementToCheck.indexOfDowntimePeriods == arrangement.indexOfDowntimePeriods \u0026\u0026\n                arrangementToCheck.lastRefundedPeriod == arrangement.lastRefundedPeriod);\n        }\n\n        NodeInfo storage nodeInfo = nodes[RESERVED_NODE];\n        MemoryNodeInfo memory nodeInfoToCheck = delegateGetNodeInfo(_testTarget, RESERVED_NODE);\n        require(nodeInfoToCheck.fee == nodeInfo.fee \u0026\u0026\n            nodeInfoToCheck.feeRate == nodeInfo.feeRate \u0026\u0026\n            nodeInfoToCheck.previousFeePeriod == nodeInfo.previousFeePeriod \u0026\u0026\n            nodeInfoToCheck.minFeeRate == nodeInfo.minFeeRate);\n\n        require(int256(delegateGet(_testTarget, this.getNodeFeeDelta.selector,\n            bytes32(bytes20(RESERVED_NODE)), bytes32(uint256(11)))) == getNodeFeeDelta(RESERVED_NODE, 11));\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`\n    function finishUpgrade(address _target) public override virtual {\n        super.finishUpgrade(_target);\n\n        if (resetTimestamp == 0) {\n            resetTimestamp = uint64(block.timestamp);\n        }\n\n        // Create fake Policy and NodeInfo to use them in verifyState(address)\n        Policy storage policy = policies[RESERVED_POLICY_ID];\n        policy.sponsor = msg.sender;\n        policy.owner = address(this);\n        policy.startTimestamp = 1;\n        policy.endTimestamp = 2;\n        policy.feeRate = 3;\n        policy.disabled = true;\n        policy.arrangements.push(ArrangementInfo(RESERVED_NODE, 11, 22));\n        NodeInfo storage nodeInfo = nodes[RESERVED_NODE];\n        nodeInfo.fee = 100;\n        nodeInfo.feeRate = 33;\n        nodeInfo.previousFeePeriod = 44;\n        nodeInfo.feeDelta[11] = 55;\n        nodeInfo.minFeeRate = 777;\n    }\n}\n"},"SafeERC20.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC20.sol\";\nimport \"SafeMath.sol\";\n\n\n/**\n * @title SafeERC20\n * @dev Wrappers around ERC20 operations that throw on failure.\n * To use this library you can add a `using SafeERC20 for ERC20;` statement to your contract,\n * which allows you to call the safe operations as `token.safeTransfer(...)`, etc.\n */\nlibrary SafeERC20 {\n    using SafeMath for uint256;\n\n    function safeTransfer(IERC20 token, address to, uint256 value) internal {\n        require(token.transfer(to, value));\n    }\n\n    function safeTransferFrom(IERC20 token, address from, address to, uint256 value) internal {\n        require(token.transferFrom(from, to, value));\n    }\n\n    function safeApprove(IERC20 token, address spender, uint256 value) internal {\n        // safeApprove should only be called when setting an initial allowance,\n        // or when resetting it to zero. To increase and decrease it, use\n        // \u0027safeIncreaseAllowance\u0027 and \u0027safeDecreaseAllowance\u0027\n        require((value == 0) || (token.allowance(msg.sender, spender) == 0));\n        require(token.approve(spender, value));\n    }\n\n    function safeIncreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).add(value);\n        require(token.approve(spender, newAllowance));\n    }\n\n    function safeDecreaseAllowance(IERC20 token, address spender, uint256 value) internal {\n        uint256 newAllowance = token.allowance(address(this), spender).sub(value);\n        require(token.approve(spender, newAllowance));\n    }\n}\n"},"SafeMath.sol":{"content":"// SPDX-License-Identifier: MIT\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title SafeMath\n * @dev Unsigned math operations with safety checks that revert on error\n */\nlibrary SafeMath {\n    /**\n     * @dev Multiplies two unsigned integers, reverts on overflow.\n     */\n    function mul(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Gas optimization: this is cheaper than requiring \u0027a\u0027 not being zero, but the\n        // benefit is lost if \u0027b\u0027 is also tested.\n        // See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522\n        if (a == 0) {\n            return 0;\n        }\n\n        uint256 c = a * b;\n        require(c / a == b);\n\n        return c;\n    }\n\n    /**\n     * @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.\n     */\n    function div(uint256 a, uint256 b) internal pure returns (uint256) {\n        // Solidity only automatically asserts when dividing by 0\n        require(b \u003e 0);\n        uint256 c = a / b;\n        // assert(a == b * c + a % b); // There is no case in which this doesn\u0027t hold\n\n        return c;\n    }\n\n    /**\n     * @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).\n     */\n    function sub(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b \u003c= a);\n        uint256 c = a - b;\n\n        return c;\n    }\n\n    /**\n     * @dev Adds two unsigned integers, reverts on overflow.\n     */\n    function add(uint256 a, uint256 b) internal pure returns (uint256) {\n        uint256 c = a + b;\n        require(c \u003e= a);\n\n        return c;\n    }\n\n    /**\n     * @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),\n     * reverts when dividing by zero.\n     */\n    function mod(uint256 a, uint256 b) internal pure returns (uint256) {\n        require(b != 0);\n        return a % b;\n    }\n}\n"},"SignatureVerifier.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\n/**\n* @notice Library to recover address and verify signatures\n* @dev Simple wrapper for `ecrecover`\n*/\nlibrary SignatureVerifier {\n\n    enum HashAlgorithm {KECCAK256, SHA256, RIPEMD160}\n\n    // Header for Version E as defined by EIP191. First byte (\u0027E\u0027) is also the version\n    bytes25 constant EIP191_VERSION_E_HEADER = \"Ethereum Signed Message:\\n\";\n\n    /**\n    * @notice Recover signer address from hash and signature\n    * @param _hash 32 bytes message hash\n    * @param _signature Signature of hash - 32 bytes r + 32 bytes s + 1 byte v (could be 0, 1, 27, 28)\n    */\n    function recover(bytes32 _hash, bytes memory _signature)\n        internal\n        pure\n        returns (address)\n    {\n        require(_signature.length == 65);\n\n        bytes32 r;\n        bytes32 s;\n        uint8 v;\n        assembly {\n            r := mload(add(_signature, 32))\n            s := mload(add(_signature, 64))\n            v := byte(0, mload(add(_signature, 96)))\n        }\n\n        // Version of signature should be 27 or 28, but 0 and 1 are also possible versions\n        if (v \u003c 27) {\n            v += 27;\n        }\n        require(v == 27 || v == 28);\n        return ecrecover(_hash, v, r, s);\n    }\n\n    /**\n    * @notice Transform public key to address\n    * @param _publicKey secp256k1 public key\n    */\n    function toAddress(bytes memory _publicKey) internal pure returns (address) {\n        return address(uint160(uint256(keccak256(_publicKey))));\n    }\n\n    /**\n    * @notice Hash using one of pre built hashing algorithm\n    * @param _message Signed message\n    * @param _algorithm Hashing algorithm\n    */\n    function hash(bytes memory _message, HashAlgorithm _algorithm)\n        internal\n        pure\n        returns (bytes32 result)\n    {\n        if (_algorithm == HashAlgorithm.KECCAK256) {\n            result = keccak256(_message);\n        } else if (_algorithm == HashAlgorithm.SHA256) {\n            result = sha256(_message);\n        } else {\n            result = ripemd160(_message);\n        }\n    }\n\n    /**\n    * @notice Verify ECDSA signature\n    * @dev Uses one of pre built hashing algorithm\n    * @param _message Signed message\n    * @param _signature Signature of message hash\n    * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes)\n    * @param _algorithm Hashing algorithm\n    */\n    function verify(\n        bytes memory _message,\n        bytes memory _signature,\n        bytes memory _publicKey,\n        HashAlgorithm _algorithm\n    )\n        internal\n        pure\n        returns (bool)\n    {\n        require(_publicKey.length == 64);\n        return toAddress(_publicKey) == recover(hash(_message, _algorithm), _signature);\n    }\n\n    /**\n    * @notice Hash message according to EIP191 signature specification\n    * @dev It always assumes Keccak256 is used as hashing algorithm\n    * @dev Only supports version 0 and version E (0x45)\n    * @param _message Message to sign\n    * @param _version EIP191 version to use\n    */\n    function hashEIP191(\n        bytes memory _message,\n        byte _version\n    )\n        internal\n        view\n        returns (bytes32 result)\n    {\n        if(_version == byte(0x00)){  // Version 0: Data with intended validator\n            address validator = address(this);\n            return keccak256(abi.encodePacked(byte(0x19), byte(0x00), validator, _message));\n        } else if (_version == byte(0x45)){  // Version E: personal_sign messages\n            uint256 length = _message.length;\n            require(length \u003e 0, \"Empty message not allowed for version E\");\n\n            // Compute text-encoded length of message\n            uint256 digits = 0;\n            while (length != 0) {\n                digits++;\n                length /= 10;\n            }\n            bytes memory lengthAsText = new bytes(digits);\n            length = _message.length;\n            uint256 index = digits - 1;\n            while (length != 0) {\n                lengthAsText[index--] = byte(uint8(48 + length % 10));\n                length /= 10;\n            }\n\n            return keccak256(abi.encodePacked(byte(0x19), EIP191_VERSION_E_HEADER, lengthAsText, _message));\n        } else {\n            revert(\"Unsupported EIP191 version\");\n        }\n    }\n\n    /**\n    * @notice Verify EIP191 signature\n    * @dev It always assumes Keccak256 is used as hashing algorithm\n    * @dev Only supports version 0 and version E (0x45)\n    * @param _message Signed message\n    * @param _signature Signature of message hash\n    * @param _publicKey secp256k1 public key in uncompressed format without prefix byte (64 bytes)\n    * @param _version EIP191 version to use\n    */\n    function verifyEIP191(\n        bytes memory _message,\n        bytes memory _signature,\n        bytes memory _publicKey,\n        byte _version\n    )\n        internal\n        view\n        returns (bool)\n    {\n        require(_publicKey.length == 64);\n        return toAddress(_publicKey) == recover(hashEIP191(_message, _version), _signature);\n    }\n\n}\n"},"Snapshot.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\n/**\n * @title Snapshot\n * @notice Manages snapshots of size 128 bits (32 bits for timestamp, 96 bits for value)\n * 96 bits is enough for storing NU token values, and 32 bits should be OK for block numbers\n * @dev Since each storage slot can hold two snapshots, new slots are allocated every other TX. Thus, gas cost of adding snapshots is 51400 and 36400 gas, alternately.\n * Based on Aragon\u0027s Checkpointing (https://https://github.com/aragonone/voting-connectors/blob/master/shared/contract-utils/contracts/Checkpointing.sol)\n * On average, adding snapshots spends ~6500 less gas than the 256-bit checkpoints of Aragon\u0027s Checkpointing\n */\nlibrary Snapshot {\n\n    function encodeSnapshot(uint32 _time, uint96 _value) internal pure returns(uint128) {\n        return uint128(uint256(_time) \u003c\u003c 96 | uint256(_value));\n    }\n\n    function decodeSnapshot(uint128 _snapshot) internal pure returns(uint32 time, uint96 value){\n        time = uint32(bytes4(bytes16(_snapshot)));\n        value = uint96(_snapshot);\n    }\n\n    function addSnapshot(uint128[] storage _self, uint256 _value) internal {\n        addSnapshot(_self, block.number, _value);\n    }\n\n    function addSnapshot(uint128[] storage _self, uint256 _time, uint256 _value) internal {\n        uint256 length = _self.length;\n        if (length != 0) {\n            (uint32 currentTime, ) = decodeSnapshot(_self[length - 1]);\n            if (uint32(_time) == currentTime) {\n                _self[length - 1] = encodeSnapshot(uint32(_time), uint96(_value));\n                return;\n            } else if (uint32(_time) \u003c currentTime){\n                revert();\n            }\n        }\n        _self.push(encodeSnapshot(uint32(_time), uint96(_value)));\n    }\n\n    function lastSnapshot(uint128[] storage _self) internal view returns (uint32, uint96) {\n        uint256 length = _self.length;\n        if (length \u003e 0) {\n            return decodeSnapshot(_self[length - 1]);\n        }\n\n        return (0, 0);\n    }\n\n    function lastValue(uint128[] storage _self) internal view returns (uint96) {\n        (, uint96 value) = lastSnapshot(_self);\n        return value;\n    }\n\n    function getValueAt(uint128[] storage _self, uint256 _time256) internal view returns (uint96) {\n        uint32 _time = uint32(_time256);\n        uint256 length = _self.length;\n\n        // Short circuit if there\u0027s no checkpoints yet\n        // Note that this also lets us avoid using SafeMath later on, as we\u0027ve established that\n        // there must be at least one checkpoint\n        if (length == 0) {\n            return 0;\n        }\n\n        // Check last checkpoint\n        uint256 lastIndex = length - 1;\n        (uint32 snapshotTime, uint96 snapshotValue) = decodeSnapshot(_self[length - 1]);\n        if (_time \u003e= snapshotTime) {\n            return snapshotValue;\n        }\n\n        // Check first checkpoint (if not already checked with the above check on last)\n        (snapshotTime, snapshotValue) = decodeSnapshot(_self[0]);\n        if (length == 1 || _time \u003c snapshotTime) {\n            return 0;\n        }\n\n        // Do binary search\n        // As we\u0027ve already checked both ends, we don\u0027t need to check the last checkpoint again\n        uint256 low = 0;\n        uint256 high = lastIndex - 1;\n        uint32 midTime;\n        uint96 midValue;\n\n        while (high \u003e low) {\n            uint256 mid = (high + low + 1) / 2; // average, ceil round\n            (midTime, midValue) = decodeSnapshot(_self[mid]);\n\n            if (_time \u003e midTime) {\n                low = mid;\n            } else if (_time \u003c midTime) {\n                // Note that we don\u0027t need SafeMath here because mid must always be greater than 0\n                // from the while condition\n                high = mid - 1;\n            } else {\n                // _time == midTime\n                return midValue;\n            }\n        }\n\n        (, snapshotValue) = decodeSnapshot(_self[low]);\n        return snapshotValue;\n    }\n}\n"},"StakingEscrow.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"IERC900History.sol\";\nimport \"Issuer.sol\";\nimport \"Bits.sol\";\nimport \"Snapshot.sol\";\nimport \"SafeMath.sol\";\nimport \"SafeERC20.sol\";\n\n\n/**\n* @notice PolicyManager interface\n*/\ninterface PolicyManagerInterface {\n    function secondsPerPeriod() external view returns (uint32);\n    function register(address _node, uint16 _period) external;\n    function migrate(address _node) external;\n    function ping(\n        address _node,\n        uint16 _processedPeriod1,\n        uint16 _processedPeriod2,\n        uint16 _periodToSetDefault\n    ) external;\n}\n\n\n/**\n* @notice Adjudicator interface\n*/\ninterface AdjudicatorInterface {\n    function rewardCoefficient() external view returns (uint32);\n}\n\n\n/**\n* @notice WorkLock interface\n*/\ninterface WorkLockInterface {\n    function token() external view returns (NuCypherToken);\n}\n\n/**\n* @title StakingEscrowStub\n* @notice Stub is used to deploy main StakingEscrow after all other contract and make some variables immutable\n* @dev |v1.0.0|\n*/\ncontract StakingEscrowStub is Upgradeable {\n    using AdditionalMath for uint32;\n\n    NuCypherToken public immutable token;\n    uint32 public immutable genesisSecondsPerPeriod;\n    uint32 public immutable secondsPerPeriod;\n    uint16 public immutable minLockedPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n\n    /**\n    * @notice Predefines some variables for use when deploying other contracts\n    * @param _token Token contract\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _minLockedPeriods Min amount of periods during which tokens can be locked\n    * @param _minAllowableLockedTokens Min amount of tokens that can be locked\n    * @param _maxAllowableLockedTokens Max amount of tokens that can be locked\n    */\n    constructor(\n        NuCypherToken _token,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint16 _minLockedPeriods,\n        uint256 _minAllowableLockedTokens,\n        uint256 _maxAllowableLockedTokens\n    ) {\n        require(_token.totalSupply() \u003e 0 \u0026\u0026\n            _hoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod != 0 \u0026\u0026\n            _genesisHoursPerPeriod \u003c= _hoursPerPeriod \u0026\u0026\n            _minLockedPeriods \u003e 1 \u0026\u0026\n            _maxAllowableLockedTokens != 0);\n\n        token = _token;\n        secondsPerPeriod = _hoursPerPeriod.mul32(1 hours);\n        genesisSecondsPerPeriod = _genesisHoursPerPeriod.mul32(1 hours);\n        minLockedPeriods = _minLockedPeriods;\n        minAllowableLockedTokens = _minAllowableLockedTokens;\n        maxAllowableLockedTokens = _maxAllowableLockedTokens;\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n\n        // we have to use real values even though this is a stub\n        require(address(delegateGet(_testTarget, this.token.selector)) == address(token));\n        // TODO uncomment after merging this PR #2579\n//        require(uint32(delegateGet(_testTarget, this.genesisSecondsPerPeriod.selector)) == genesisSecondsPerPeriod);\n        require(uint32(delegateGet(_testTarget, this.secondsPerPeriod.selector)) == secondsPerPeriod);\n        require(uint16(delegateGet(_testTarget, this.minLockedPeriods.selector)) == minLockedPeriods);\n        require(delegateGet(_testTarget, this.minAllowableLockedTokens.selector) == minAllowableLockedTokens);\n        require(delegateGet(_testTarget, this.maxAllowableLockedTokens.selector) == maxAllowableLockedTokens);\n    }\n}\n\n\n/**\n* @title StakingEscrow\n* @notice Contract holds and locks stakers tokens.\n* Each staker that locks their tokens will receive some compensation\n* @dev |v5.7.1|\n*/\ncontract StakingEscrow is Issuer, IERC900History {\n\n    using AdditionalMath for uint256;\n    using AdditionalMath for uint16;\n    using Bits for uint256;\n    using SafeMath for uint256;\n    using Snapshot for uint128[];\n    using SafeERC20 for NuCypherToken;\n\n    /**\n    * @notice Signals that tokens were deposited\n    * @param staker Staker address\n    * @param value Amount deposited (in NuNits)\n    * @param periods Number of periods tokens will be locked\n    */\n    event Deposited(address indexed staker, uint256 value, uint16 periods);\n\n    /**\n    * @notice Signals that tokens were stake locked\n    * @param staker Staker address\n    * @param value Amount locked (in NuNits)\n    * @param firstPeriod Starting lock period\n    * @param periods Number of periods tokens will be locked\n    */\n    event Locked(address indexed staker, uint256 value, uint16 firstPeriod, uint16 periods);\n\n    /**\n    * @notice Signals that a sub-stake was divided\n    * @param staker Staker address\n    * @param oldValue Old sub-stake value (in NuNits)\n    * @param lastPeriod Final locked period of old sub-stake\n    * @param newValue New sub-stake value (in NuNits)\n    * @param periods Number of periods to extend sub-stake\n    */\n    event Divided(\n        address indexed staker,\n        uint256 oldValue,\n        uint16 lastPeriod,\n        uint256 newValue,\n        uint16 periods\n    );\n\n    /**\n    * @notice Signals that two sub-stakes were merged\n    * @param staker Staker address\n    * @param value1 Value of first sub-stake (in NuNits)\n    * @param value2 Value of second sub-stake (in NuNits)\n    * @param lastPeriod Final locked period of merged sub-stake\n    */\n    event Merged(address indexed staker, uint256 value1, uint256 value2, uint16 lastPeriod);\n\n    /**\n    * @notice Signals that a sub-stake was prolonged\n    * @param staker Staker address\n    * @param value Value of sub-stake\n    * @param lastPeriod Final locked period of old sub-stake\n    * @param periods Number of periods sub-stake was extended\n    */\n    event Prolonged(address indexed staker, uint256 value, uint16 lastPeriod, uint16 periods);\n\n    /**\n    * @notice Signals that tokens were withdrawn to the staker\n    * @param staker Staker address\n    * @param value Amount withdraws (in NuNits)\n    */\n    event Withdrawn(address indexed staker, uint256 value);\n\n    /**\n    * @notice Signals that the worker associated with the staker made a commitment to next period\n    * @param staker Staker address\n    * @param period Period committed to\n    * @param value Amount of tokens staked for the committed period\n    */\n    event CommitmentMade(address indexed staker, uint16 indexed period, uint256 value);\n\n    /**\n    * @notice Signals that tokens were minted for previous periods\n    * @param staker Staker address\n    * @param period Previous period tokens minted for\n    * @param value Amount minted (in NuNits)\n    */\n    event Minted(address indexed staker, uint16 indexed period, uint256 value);\n\n    /**\n    * @notice Signals that the staker was slashed\n    * @param staker Staker address\n    * @param penalty Slashing penalty\n    * @param investigator Investigator address\n    * @param reward Value of reward provided to investigator (in NuNits)\n    */\n    event Slashed(address indexed staker, uint256 penalty, address indexed investigator, uint256 reward);\n\n    /**\n    * @notice Signals that the restake parameter was activated/deactivated\n    * @param staker Staker address\n    * @param reStake Updated parameter value\n    */\n    event ReStakeSet(address indexed staker, bool reStake);\n\n    /**\n    * @notice Signals that a worker was bonded to the staker\n    * @param staker Staker address\n    * @param worker Worker address\n    * @param startPeriod Period bonding occurred\n    */\n    event WorkerBonded(address indexed staker, address indexed worker, uint16 indexed startPeriod);\n\n    /**\n    * @notice Signals that the winddown parameter was activated/deactivated\n    * @param staker Staker address\n    * @param windDown Updated parameter value\n    */\n    event WindDownSet(address indexed staker, bool windDown);\n\n    /**\n    * @notice Signals that the snapshot parameter was activated/deactivated\n    * @param staker Staker address\n    * @param snapshotsEnabled Updated parameter value\n    */\n    event SnapshotSet(address indexed staker, bool snapshotsEnabled);\n\n    /**\n    * @notice Signals that the staker migrated their stake to the new period length\n    * @param staker Staker address\n    * @param period Period when migration happened\n    */\n    event Migrated(address indexed staker, uint16 indexed period);\n\n    /// internal event\n    event WorkMeasurementSet(address indexed staker, bool measureWork);\n\n    struct SubStakeInfo {\n        uint16 firstPeriod;\n        uint16 lastPeriod;\n        uint16 unlockingDuration;\n        uint128 lockedValue;\n    }\n\n    struct Downtime {\n        uint16 startPeriod;\n        uint16 endPeriod;\n    }\n\n    struct StakerInfo {\n        uint256 value;\n        /*\n        * Stores periods that are committed but not yet rewarded.\n        * In order to optimize storage, only two values are used instead of an array.\n        * commitToNextPeriod() method invokes mint() method so there can only be two committed\n        * periods that are not yet rewarded: the current and the next periods.\n        */\n        uint16 currentCommittedPeriod;\n        uint16 nextCommittedPeriod;\n        uint16 lastCommittedPeriod;\n        uint16 stub1; // former slot for lockReStakeUntilPeriod\n        uint256 completedWork;\n        uint16 workerStartPeriod; // period when worker was bonded\n        address worker;\n        uint256 flags; // uint256 to acquire whole slot and minimize operations on it\n\n        uint256 reservedSlot1;\n        uint256 reservedSlot2;\n        uint256 reservedSlot3;\n        uint256 reservedSlot4;\n        uint256 reservedSlot5;\n\n        Downtime[] pastDowntime;\n        SubStakeInfo[] subStakes;\n        uint128[] history;\n\n    }\n\n    // used only for upgrading\n    uint16 internal constant RESERVED_PERIOD = 0;\n    uint16 internal constant MAX_CHECKED_VALUES = 5;\n    // to prevent high gas consumption in loops for slashing\n    uint16 public constant MAX_SUB_STAKES = 30;\n    uint16 internal constant MAX_UINT16 = 65535;\n\n    // indices for flags\n    uint8 internal constant RE_STAKE_DISABLED_INDEX = 0;\n    uint8 internal constant WIND_DOWN_INDEX = 1;\n    uint8 internal constant MEASURE_WORK_INDEX = 2;\n    uint8 internal constant SNAPSHOTS_DISABLED_INDEX = 3;\n    uint8 internal constant MIGRATED_INDEX = 4;\n\n    uint16 public immutable minLockedPeriods;\n    uint16 public immutable minWorkerPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n\n    PolicyManagerInterface public immutable policyManager;\n    AdjudicatorInterface public immutable adjudicator;\n    WorkLockInterface public immutable workLock;\n\n    mapping (address =\u003e StakerInfo) public stakerInfo;\n    address[] public stakers;\n    mapping (address =\u003e address) public stakerFromWorker;\n\n    mapping (uint16 =\u003e uint256) stub4; // former slot for lockedPerPeriod\n    uint128[] public balanceHistory;\n\n    address stub1; // former slot for PolicyManager\n    address stub2; // former slot for Adjudicator\n    address stub3; // former slot for WorkLock\n\n    mapping (uint16 =\u003e uint256) _lockedPerPeriod;\n    // only to make verifyState from previous version work, temporary\n    // TODO remove after upgrade #2579\n    function lockedPerPeriod(uint16 _period) public view returns (uint256) {\n        return _period != RESERVED_PERIOD ? _lockedPerPeriod[_period] : 111;\n    }\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @param _token Token contract\n    * @param _policyManager Policy Manager contract\n    * @param _adjudicator Adjudicator contract\n    * @param _workLock WorkLock contract. Zero address if there is no WorkLock\n    * @param _genesisHoursPerPeriod Size of period in hours at genesis\n    * @param _hoursPerPeriod Size of period in hours\n    * @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,\n    * only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.\n    * See Equation 10 in Staking Protocol \u0026 Economics paper\n    * @param _lockDurationCoefficient1 (k1) Numerator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k1 = k2 * small_stake_multiplier where default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _lockDurationCoefficient2 (k2) Denominator of the coefficient which modifies the extent\n    * to which a stake\u0027s lock duration affects the subsidy it receives. Affects stakers differently.\n    * Applicable to Phase 1 and Phase 2. k2 = maximum_rewarded_periods / (1 - small_stake_multiplier)\n    * where default maximum_rewarded_periods = 365 and default small_stake_multiplier = 0.5.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _maximumRewardedPeriods (kmax) Number of periods beyond which a stake\u0027s lock duration\n    * no longer increases the subsidy it receives. kmax = reward_saturation * 365 where default reward_saturation = 1.\n    * See Equation 8 in Staking Protocol \u0026 Economics paper.\n    * @param _firstPhaseTotalSupply Total supply for the first phase\n    * @param _firstPhaseMaxIssuance (Imax) Maximum number of new tokens minted per period during Phase 1.\n    * See Equation 7 in Staking Protocol \u0026 Economics paper.\n    * @param _minLockedPeriods Min amount of periods during which tokens can be locked\n    * @param _minAllowableLockedTokens Min amount of tokens that can be locked\n    * @param _maxAllowableLockedTokens Max amount of tokens that can be locked\n    * @param _minWorkerPeriods Min amount of periods while a worker can\u0027t be changed\n    */\n    constructor(\n        NuCypherToken _token,\n        PolicyManagerInterface _policyManager,\n        AdjudicatorInterface _adjudicator,\n        WorkLockInterface _workLock,\n        uint32 _genesisHoursPerPeriod,\n        uint32 _hoursPerPeriod,\n        uint256 _issuanceDecayCoefficient,\n        uint256 _lockDurationCoefficient1,\n        uint256 _lockDurationCoefficient2,\n        uint16 _maximumRewardedPeriods,\n        uint256 _firstPhaseTotalSupply,\n        uint256 _firstPhaseMaxIssuance,\n        uint16 _minLockedPeriods,\n        uint256 _minAllowableLockedTokens,\n        uint256 _maxAllowableLockedTokens,\n        uint16 _minWorkerPeriods\n    )\n        Issuer(\n            _token,\n            _genesisHoursPerPeriod,\n            _hoursPerPeriod,\n            _issuanceDecayCoefficient,\n            _lockDurationCoefficient1,\n            _lockDurationCoefficient2,\n            _maximumRewardedPeriods,\n            _firstPhaseTotalSupply,\n            _firstPhaseMaxIssuance\n        )\n    {\n        // constant `1` in the expression `_minLockedPeriods \u003e 1` uses to simplify the `lock` method\n        require(_minLockedPeriods \u003e 1 \u0026\u0026 _maxAllowableLockedTokens != 0);\n        minLockedPeriods = _minLockedPeriods;\n        minAllowableLockedTokens = _minAllowableLockedTokens;\n        maxAllowableLockedTokens = _maxAllowableLockedTokens;\n        minWorkerPeriods = _minWorkerPeriods;\n\n        require((_policyManager.secondsPerPeriod() == _hoursPerPeriod * (1 hours) ||\n            _policyManager.secondsPerPeriod() == _genesisHoursPerPeriod * (1 hours)) \u0026\u0026\n            _adjudicator.rewardCoefficient() != 0 \u0026\u0026\n            (address(_workLock) == address(0) || _workLock.token() == _token));\n        policyManager = _policyManager;\n        adjudicator = _adjudicator;\n        workLock = _workLock;\n    }\n\n    /**\n    * @dev Checks the existence of a staker in the contract\n    */\n    modifier onlyStaker()\n    {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require((info.value \u003e 0 || info.nextCommittedPeriod != 0) \u0026\u0026\n            info.flags.bitSet(MIGRATED_INDEX));\n        _;\n    }\n\n    //------------------------Main getters------------------------\n    /**\n    * @notice Get all tokens belonging to the staker\n    */\n    function getAllTokens(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].value;\n    }\n\n    /**\n    * @notice Get all flags for the staker\n    */\n    function getFlags(address _staker)\n        external view returns (\n            bool windDown,\n            bool reStake,\n            bool measureWork,\n            bool snapshots,\n            bool migrated\n        )\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        windDown = info.flags.bitSet(WIND_DOWN_INDEX);\n        reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);\n        measureWork = info.flags.bitSet(MEASURE_WORK_INDEX);\n        snapshots = !info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX);\n        migrated = info.flags.bitSet(MIGRATED_INDEX);\n    }\n\n    /**\n    * @notice Get the start period. Use in the calculation of the last period of the sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    */\n    function getStartPeriod(StakerInfo storage _info, uint16 _currentPeriod)\n        internal view returns (uint16)\n    {\n        // if the next period (after current) is committed\n        if (_info.flags.bitSet(WIND_DOWN_INDEX) \u0026\u0026 _info.nextCommittedPeriod \u003e _currentPeriod) {\n            return _currentPeriod + 1;\n        }\n        return _currentPeriod;\n    }\n\n    /**\n    * @notice Get the last period of the sub stake\n    * @param _subStake Sub stake structure\n    * @param _startPeriod Pre-calculated start period\n    */\n    function getLastPeriodOfSubStake(SubStakeInfo storage _subStake, uint16 _startPeriod)\n        internal view returns (uint16)\n    {\n        if (_subStake.lastPeriod != 0) {\n            return _subStake.lastPeriod;\n        }\n        uint32 lastPeriod = uint32(_startPeriod) + _subStake.unlockingDuration;\n        if (lastPeriod \u003e uint32(MAX_UINT16)) {\n            return MAX_UINT16;\n        }\n        return uint16(lastPeriod);\n    }\n\n    /**\n    * @notice Get the last period of the sub stake\n    * @param _staker Staker\n    * @param _index Stake index\n    */\n    function getLastPeriodOfSubStake(address _staker, uint256 _index)\n        public view returns (uint16)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 startPeriod = getStartPeriod(info, getCurrentPeriod());\n        return getLastPeriodOfSubStake(subStake, startPeriod);\n    }\n\n\n    /**\n    * @notice Get the value of locked tokens for a staker in a specified period\n    * @dev Information may be incorrect for rewarded or not committed surpassed period\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _period Next period\n    */\n    function getLockedTokens(StakerInfo storage _info, uint16 _currentPeriod, uint16 _period)\n        internal view returns (uint256 lockedValue)\n    {\n        lockedValue = 0;\n        uint16 startPeriod = getStartPeriod(_info, _currentPeriod);\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.firstPeriod \u003c= _period \u0026\u0026\n                getLastPeriodOfSubStake(subStake, startPeriod) \u003e= _period) {\n                lockedValue += subStake.lockedValue;\n            }\n        }\n    }\n\n    /**\n    * @notice Get the value of locked tokens for a staker in a future period\n    * @dev This function is used by PreallocationEscrow so its signature can\u0027t be updated.\n    * @param _staker Staker\n    * @param _offsetPeriods Amount of periods that will be added to the current period\n    */\n    function getLockedTokens(address _staker, uint16 _offsetPeriods)\n        external view returns (uint256 lockedValue)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_offsetPeriods);\n        return getLockedTokens(info, currentPeriod, nextPeriod);\n    }\n\n    /**\n    * @notice Get the last committed staker\u0027s period\n    * @param _staker Staker\n    */\n    function getLastCommittedPeriod(address _staker) public view returns (uint16) {\n        StakerInfo storage info = stakerInfo[_staker];\n        return info.nextCommittedPeriod != 0 ? info.nextCommittedPeriod : info.lastCommittedPeriod;\n    }\n\n    /**\n    * @notice Get the value of locked tokens for active stakers in (getCurrentPeriod() + _offsetPeriods) period\n    * as well as stakers and their locked tokens\n    * @param _offsetPeriods Amount of periods for locked tokens calculation\n    * @param _startIndex Start index for looking in stakers array\n    * @param _maxStakers Max stakers for looking, if set 0 then all will be used\n    * @return allLockedTokens Sum of locked tokens for active stakers\n    * @return activeStakers Array of stakers and their locked tokens. Stakers addresses stored as uint256\n    * @dev Note that activeStakers[0] in an array of uint256, but you want addresses. Careful when used directly!\n    */\n    function getActiveStakers(uint16 _offsetPeriods, uint256 _startIndex, uint256 _maxStakers)\n        external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)\n    {\n        require(_offsetPeriods \u003e 0);\n\n        uint256 endIndex = stakers.length;\n        require(_startIndex \u003c endIndex);\n        if (_maxStakers != 0 \u0026\u0026 _startIndex + _maxStakers \u003c endIndex) {\n            endIndex = _startIndex + _maxStakers;\n        }\n        activeStakers = new uint256[2][](endIndex - _startIndex);\n        allLockedTokens = 0;\n\n        uint256 resultIndex = 0;\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_offsetPeriods);\n\n        for (uint256 i = _startIndex; i \u003c endIndex; i++) {\n            address staker = stakers[i];\n            StakerInfo storage info = stakerInfo[staker];\n            if (info.currentCommittedPeriod != currentPeriod \u0026\u0026\n                info.nextCommittedPeriod != currentPeriod) {\n                continue;\n            }\n            uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n            if (lockedTokens != 0) {\n                activeStakers[resultIndex][0] = uint256(staker);\n                activeStakers[resultIndex++][1] = lockedTokens;\n                allLockedTokens += lockedTokens;\n            }\n        }\n        assembly {\n            mstore(activeStakers, resultIndex)\n        }\n    }\n\n    /**\n    * @notice Get worker using staker\u0027s address\n    */\n    function getWorkerFromStaker(address _staker) external view returns (address) {\n        return stakerInfo[_staker].worker;\n    }\n\n    /**\n    * @notice Get work that completed by the staker\n    */\n    function getCompletedWork(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].completedWork;\n    }\n\n    /**\n    * @notice Find index of downtime structure that includes specified period\n    * @dev If specified period is outside all downtime periods, the length of the array will be returned\n    * @param _staker Staker\n    * @param _period Specified period number\n    */\n    function findIndexOfPastDowntime(address _staker, uint16 _period) external view returns (uint256 index) {\n        StakerInfo storage info = stakerInfo[_staker];\n        for (index = 0; index \u003c info.pastDowntime.length; index++) {\n            if (_period \u003c= info.pastDowntime[index].endPeriod) {\n                return index;\n            }\n        }\n    }\n\n    //------------------------Main methods------------------------\n    /**\n    * @notice Start or stop measuring the work of a staker\n    * @param _staker Staker\n    * @param _measureWork Value for `measureWork` parameter\n    * @return Work that was previously done\n    */\n    function setWorkMeasurement(address _staker, bool _measureWork) external returns (uint256) {\n        require(msg.sender == address(workLock));\n        StakerInfo storage info = stakerInfo[_staker];\n        if (info.flags.bitSet(MEASURE_WORK_INDEX) == _measureWork) {\n            return info.completedWork;\n        }\n        info.flags = info.flags.toggleBit(MEASURE_WORK_INDEX);\n        emit WorkMeasurementSet(_staker, _measureWork);\n        return info.completedWork;\n    }\n\n    /**\n    * @notice Bond worker\n    * @param _worker Worker address. Must be a real address, not a contract\n    */\n    function bondWorker(address _worker) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Specified worker is already bonded with this staker\n        require(_worker != info.worker);\n        uint16 currentPeriod = getCurrentPeriod();\n        if (info.worker != address(0)) { // If this staker had a worker ...\n            // Check that enough time has passed to change it\n            require(currentPeriod \u003e= info.workerStartPeriod.add16(minWorkerPeriods));\n            // Remove the old relation \"worker-\u003estaker\"\n            stakerFromWorker[info.worker] = address(0);\n        }\n\n        if (_worker != address(0)) {\n            // Specified worker is already in use\n            require(stakerFromWorker[_worker] == address(0));\n            // Specified worker is a staker\n            require(stakerInfo[_worker].subStakes.length == 0 || _worker == msg.sender);\n            // Set new worker-\u003estaker relation\n            stakerFromWorker[_worker] = msg.sender;\n        }\n\n        // Bond new worker (or unbond if _worker == address(0))\n        info.worker = _worker;\n        info.workerStartPeriod = currentPeriod;\n        emit WorkerBonded(msg.sender, _worker, currentPeriod);\n    }\n\n    /**\n    * @notice Set `reStake` parameter. If true then all staking rewards will be added to locked stake\n    * @param _reStake Value for parameter\n    */\n    function setReStake(bool _reStake) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(RE_STAKE_DISABLED_INDEX) == !_reStake) {\n            return;\n        }\n        info.flags = info.flags.toggleBit(RE_STAKE_DISABLED_INDEX);\n        emit ReStakeSet(msg.sender, _reStake);\n    }\n\n    /**\n    * @notice Deposit tokens from WorkLock contract\n    * @param _staker Staker address\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function depositFromWorkLock(\n        address _staker,\n        uint256 _value,\n        uint16 _unlockingDuration\n    )\n        external\n    {\n        require(msg.sender == address(workLock));\n        StakerInfo storage info = stakerInfo[_staker];\n        if (!info.flags.bitSet(WIND_DOWN_INDEX) \u0026\u0026 info.subStakes.length == 0) {\n            info.flags = info.flags.toggleBit(WIND_DOWN_INDEX);\n            emit WindDownSet(_staker, true);\n        }\n        // WorkLock still uses the genesis period length (24h)\n        _unlockingDuration = recalculatePeriod(_unlockingDuration);\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Set `windDown` parameter.\n    * If true then stake\u0027s duration will be decreasing in each period with `commitToNextPeriod()`\n    * @param _windDown Value for parameter\n    */\n    function setWindDown(bool _windDown) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(WIND_DOWN_INDEX) == _windDown) {\n            return;\n        }\n        info.flags = info.flags.toggleBit(WIND_DOWN_INDEX);\n        emit WindDownSet(msg.sender, _windDown);\n\n        // duration adjustment if next period is committed\n        uint16 nextPeriod = getCurrentPeriod() + 1;\n        if (info.nextCommittedPeriod != nextPeriod) {\n           return;\n        }\n\n        // adjust sub-stakes duration for the new value of winding down parameter\n        for (uint256 index = 0; index \u003c info.subStakes.length; index++) {\n            SubStakeInfo storage subStake = info.subStakes[index];\n            // sub-stake does not have fixed last period when winding down is disabled\n            if (!_windDown \u0026\u0026 subStake.lastPeriod == nextPeriod) {\n                subStake.lastPeriod = 0;\n                subStake.unlockingDuration = 1;\n                continue;\n            }\n            // this sub-stake is no longer affected by winding down parameter\n            if (subStake.lastPeriod != 0 || subStake.unlockingDuration == 0) {\n                continue;\n            }\n\n            subStake.unlockingDuration = _windDown ? subStake.unlockingDuration - 1 : subStake.unlockingDuration + 1;\n            if (subStake.unlockingDuration == 0) {\n                subStake.lastPeriod = nextPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Activate/deactivate taking snapshots of balances\n    * @param _enableSnapshots True to activate snapshots, False to deactivate\n    */\n    function setSnapshots(bool _enableSnapshots) external {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        if (info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX) == !_enableSnapshots) {\n            return;\n        }\n\n        uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n        if(_enableSnapshots){\n            info.history.addSnapshot(info.value);\n            balanceHistory.addSnapshot(lastGlobalBalance + info.value);\n        } else {\n            info.history.addSnapshot(0);\n            balanceHistory.addSnapshot(lastGlobalBalance - info.value);\n        }\n        info.flags = info.flags.toggleBit(SNAPSHOTS_DISABLED_INDEX);\n\n        emit SnapshotSet(msg.sender, _enableSnapshots);\n    }\n\n    /**\n    * @notice Adds a new snapshot to both the staker and global balance histories,\n    * assuming the staker\u0027s balance was already changed\n    * @param _info Reference to affected staker\u0027s struct\n    * @param _addition Variance in balance. It can be positive or negative.\n    */\n    function addSnapshot(StakerInfo storage _info, int256 _addition) internal {\n        if(!_info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX)){\n            _info.history.addSnapshot(_info.value);\n            uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n            balanceHistory.addSnapshot(lastGlobalBalance.addSigned(_addition));\n        }\n    }\n\n    /**\n    * @notice Implementation of the receiveApproval(address,uint256,address,bytes) method\n    * (see NuCypherToken contract). Deposit all tokens that were approved to transfer\n    * @param _from Staker\n    * @param _value Amount of tokens to deposit\n    * @param _tokenContract Token contract address\n    * @notice (param _extraData) Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function receiveApproval(\n        address _from,\n        uint256 _value,\n        address _tokenContract,\n        bytes calldata /* _extraData */\n    )\n        external\n    {\n        require(_tokenContract == address(token) \u0026\u0026 msg.sender == address(token));\n\n        // Copy first 32 bytes from _extraData, according to calldata memory layout:\n        //\n        // 0x00: method signature      4 bytes\n        // 0x04: _from                 32 bytes after encoding\n        // 0x24: _value                32 bytes after encoding\n        // 0x44: _tokenContract        32 bytes after encoding\n        // 0x64: _extraData pointer    32 bytes. Value must be 0x80 (offset of _extraData wrt to 1st parameter)\n        // 0x84: _extraData length     32 bytes\n        // 0xA4: _extraData data       Length determined by previous variable\n        //\n        // See https://solidity.readthedocs.io/en/latest/abi-spec.html#examples\n\n        uint256 payloadSize;\n        uint256 payload;\n        assembly {\n            payloadSize := calldataload(0x84)\n            payload := calldataload(0xA4)\n        }\n        payload = payload \u003e\u003e 8*(32 - payloadSize);\n        deposit(_from, _from, MAX_SUB_STAKES, _value, uint16(payload));\n    }\n\n    /**\n    * @notice Deposit tokens and create new sub-stake. Use this method to become a staker\n    * @param _staker Staker\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function deposit(address _staker, uint256 _value, uint16 _unlockingDuration) external {\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Deposit tokens and increase lock amount of an existing sub-stake\n    * @dev This is preferable way to stake tokens because will be fewer active sub-stakes in the result\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function depositAndIncrease(uint256 _index, uint256 _value) external onlyStaker {\n        require(_index \u003c MAX_SUB_STAKES);\n        deposit(msg.sender, msg.sender, _index, _value, 0);\n    }\n\n    /**\n    * @notice Deposit tokens\n    * @dev Specify either index and zero periods (for an existing sub-stake)\n    * or index \u003e= MAX_SUB_STAKES and real value for periods (for a new sub-stake), not both\n    * @param _staker Staker\n    * @param _payer Owner of tokens\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens to deposit\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function deposit(address _staker, address _payer, uint256 _index, uint256 _value, uint16 _unlockingDuration) internal {\n        require(_value != 0);\n        StakerInfo storage info = stakerInfo[_staker];\n        // A staker can\u0027t be a worker for another staker\n        require(stakerFromWorker[_staker] == address(0) || stakerFromWorker[_staker] == info.worker);\n        // initial stake of the staker\n        if (info.subStakes.length == 0 \u0026\u0026 info.lastCommittedPeriod == 0) {\n            stakers.push(_staker);\n            policyManager.register(_staker, getCurrentPeriod() - 1);\n            info.flags = info.flags.toggleBit(MIGRATED_INDEX);\n        }\n        require(info.flags.bitSet(MIGRATED_INDEX));\n        token.safeTransferFrom(_payer, address(this), _value);\n        info.value += _value;\n        lock(_staker, _index, _value, _unlockingDuration);\n\n        addSnapshot(info, int256(_value));\n        if (_index \u003e= MAX_SUB_STAKES) {\n            emit Deposited(_staker, _value, _unlockingDuration);\n        } else {\n            uint16 lastPeriod = getLastPeriodOfSubStake(_staker, _index);\n            emit Deposited(_staker, _value, lastPeriod - getCurrentPeriod());\n        }\n    }\n\n    /**\n    * @notice Lock some tokens as a new sub-stake\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lockAndCreate(uint256 _value, uint16 _unlockingDuration) external onlyStaker {\n        lock(msg.sender, MAX_SUB_STAKES, _value, _unlockingDuration);\n    }\n\n    /**\n    * @notice Increase lock amount of an existing sub-stake\n    * @param _index Index of the sub-stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function lockAndIncrease(uint256 _index, uint256 _value) external onlyStaker {\n        require(_index \u003c MAX_SUB_STAKES);\n        lock(msg.sender, _index, _value, 0);\n    }\n\n    /**\n    * @notice Lock some tokens as a stake\n    * @dev Specify either index and zero periods (for an existing sub-stake)\n    * or index \u003e= MAX_SUB_STAKES and real value for periods (for a new sub-stake), not both\n    * @param _staker Staker\n    * @param _index Index of the sub stake\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lock(address _staker, uint256 _index, uint256 _value, uint16 _unlockingDuration) internal {\n        if (_index \u003c MAX_SUB_STAKES) {\n            require(_value \u003e 0);\n        } else {\n            require(_value \u003e= minAllowableLockedTokens \u0026\u0026 _unlockingDuration \u003e= minLockedPeriods);\n        }\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        StakerInfo storage info = stakerInfo[_staker];\n        uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n        uint256 requestedLockedTokens = _value.add(lockedTokens);\n        require(requestedLockedTokens \u003c= info.value \u0026\u0026 requestedLockedTokens \u003c= maxAllowableLockedTokens);\n\n        // next period is committed\n        if (info.nextCommittedPeriod == nextPeriod) {\n            _lockedPerPeriod[nextPeriod] += _value;\n            emit CommitmentMade(_staker, nextPeriod, _value);\n        }\n\n        // if index was provided then increase existing sub-stake\n        if (_index \u003c MAX_SUB_STAKES) {\n            lockAndIncrease(info, currentPeriod, nextPeriod, _staker, _index, _value);\n        // otherwise create new\n        } else {\n            lockAndCreate(info, nextPeriod, _staker, _value, _unlockingDuration);\n        }\n    }\n\n    /**\n    * @notice Lock some tokens as a new sub-stake\n    * @param _info Staker structure\n    * @param _nextPeriod Next period\n    * @param _staker Staker\n    * @param _value Amount of tokens which will be locked\n    * @param _unlockingDuration Amount of periods during which tokens will be unlocked when wind down is enabled\n    */\n    function lockAndCreate(\n        StakerInfo storage _info,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _value,\n        uint16 _unlockingDuration\n    )\n        internal\n    {\n        uint16 duration = _unlockingDuration;\n        // if winding down is enabled and next period is committed\n        // then sub-stakes duration were decreased\n        if (_info.nextCommittedPeriod == _nextPeriod \u0026\u0026 _info.flags.bitSet(WIND_DOWN_INDEX)) {\n            duration -= 1;\n        }\n        saveSubStake(_info, _nextPeriod, 0, duration, _value);\n\n        emit Locked(_staker, _value, _nextPeriod, _unlockingDuration);\n    }\n\n    /**\n    * @notice Increase lock amount of an existing sub-stake\n    * @dev Probably will be created a new sub-stake but it will be active only one period\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _nextPeriod Next period\n    * @param _staker Staker\n    * @param _index Index of the sub-stake\n    * @param _value Amount of tokens which will be locked\n    */\n    function lockAndIncrease(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _index,\n        uint256 _value\n    )\n        internal\n    {\n        SubStakeInfo storage subStake = _info.subStakes[_index];\n        (, uint16 lastPeriod) = checkLastPeriodOfSubStake(_info, subStake, _currentPeriod);\n\n        // create temporary sub-stake for current or previous committed periods\n        // to leave locked amount in this period unchanged\n        if (_info.currentCommittedPeriod != 0 \u0026\u0026\n            _info.currentCommittedPeriod \u003c= _currentPeriod ||\n            _info.nextCommittedPeriod != 0 \u0026\u0026\n            _info.nextCommittedPeriod \u003c= _currentPeriod)\n        {\n            saveSubStake(_info, subStake.firstPeriod, _currentPeriod, 0, subStake.lockedValue);\n        }\n\n        subStake.lockedValue += uint128(_value);\n        // all new locks should start from the next period\n        subStake.firstPeriod = _nextPeriod;\n\n        emit Locked(_staker, _value, _nextPeriod, lastPeriod - _currentPeriod);\n    }\n\n    /**\n    * @notice Checks that last period of sub-stake is greater than the current period\n    * @param _info Staker structure\n    * @param _subStake Sub-stake structure\n    * @param _currentPeriod Current period\n    * @return startPeriod Start period. Use in the calculation of the last period of the sub stake\n    * @return lastPeriod Last period of the sub stake\n    */\n    function checkLastPeriodOfSubStake(\n        StakerInfo storage _info,\n        SubStakeInfo storage _subStake,\n        uint16 _currentPeriod\n    )\n        internal view returns (uint16 startPeriod, uint16 lastPeriod)\n    {\n        startPeriod = getStartPeriod(_info, _currentPeriod);\n        lastPeriod = getLastPeriodOfSubStake(_subStake, startPeriod);\n        // The sub stake must be active at least in the next period\n        require(lastPeriod \u003e _currentPeriod);\n    }\n\n    /**\n    * @notice Save sub stake. First tries to override inactive sub stake\n    * @dev Inactive sub stake means that last period of sub stake has been surpassed and already rewarded\n    * @param _info Staker structure\n    * @param _firstPeriod First period of the sub stake\n    * @param _lastPeriod Last period of the sub stake\n    * @param _unlockingDuration Duration of the sub stake in periods\n    * @param _lockedValue Amount of locked tokens\n    */\n    function saveSubStake(\n        StakerInfo storage _info,\n        uint16 _firstPeriod,\n        uint16 _lastPeriod,\n        uint16 _unlockingDuration,\n        uint256 _lockedValue\n    )\n        internal\n    {\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.lastPeriod != 0 \u0026\u0026\n                (_info.currentCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c _info.currentCommittedPeriod) \u0026\u0026\n                (_info.nextCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c _info.nextCommittedPeriod))\n            {\n                subStake.firstPeriod = _firstPeriod;\n                subStake.lastPeriod = _lastPeriod;\n                subStake.unlockingDuration = _unlockingDuration;\n                subStake.lockedValue = uint128(_lockedValue);\n                return;\n            }\n        }\n        require(_info.subStakes.length \u003c MAX_SUB_STAKES);\n        _info.subStakes.push(SubStakeInfo(_firstPeriod, _lastPeriod, _unlockingDuration, uint128(_lockedValue)));\n    }\n\n    /**\n    * @notice Divide sub stake into two parts\n    * @param _index Index of the sub stake\n    * @param _newValue New sub stake value\n    * @param _additionalDuration Amount of periods for extending sub stake\n    */\n    function divideStake(uint256 _index, uint256 _newValue, uint16 _additionalDuration) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require(_newValue \u003e= minAllowableLockedTokens \u0026\u0026 _additionalDuration \u003e 0);\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 currentPeriod = getCurrentPeriod();\n        (, uint16 lastPeriod) = checkLastPeriodOfSubStake(info, subStake, currentPeriod);\n\n        uint256 oldValue = subStake.lockedValue;\n        subStake.lockedValue = uint128(oldValue.sub(_newValue));\n        require(subStake.lockedValue \u003e= minAllowableLockedTokens);\n        uint16 requestedPeriods = subStake.unlockingDuration.add16(_additionalDuration);\n        saveSubStake(info, subStake.firstPeriod, 0, requestedPeriods, _newValue);\n        emit Divided(msg.sender, oldValue, lastPeriod, _newValue, _additionalDuration);\n        emit Locked(msg.sender, _newValue, subStake.firstPeriod, requestedPeriods);\n    }\n\n    /**\n    * @notice Prolong active sub stake\n    * @param _index Index of the sub stake\n    * @param _additionalDuration Amount of periods for extending sub stake\n    */\n    function prolongStake(uint256 _index, uint16 _additionalDuration) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Incorrect parameters\n        require(_additionalDuration \u003e 0);\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        uint16 currentPeriod = getCurrentPeriod();\n        (uint16 startPeriod, uint16 lastPeriod) = checkLastPeriodOfSubStake(info, subStake, currentPeriod);\n\n        subStake.unlockingDuration = subStake.unlockingDuration.add16(_additionalDuration);\n        // if the sub stake ends in the next committed period then reset the `lastPeriod` field\n        if (lastPeriod == startPeriod) {\n            subStake.lastPeriod = 0;\n        }\n        // The extended sub stake must not be less than the minimum value\n        require(uint32(lastPeriod - currentPeriod) + _additionalDuration \u003e= minLockedPeriods);\n        emit Locked(msg.sender, subStake.lockedValue, lastPeriod + 1, _additionalDuration);\n        emit Prolonged(msg.sender, subStake.lockedValue, lastPeriod, _additionalDuration);\n    }\n\n    /**\n    * @notice Merge two sub-stakes into one if their last periods are equal\n    * @dev It\u0027s possible that both sub-stakes will be active after this transaction.\n    * But only one of them will be active until next call `commitToNextPeriod` (in the next period)\n    * @param _index1 Index of the first sub-stake\n    * @param _index2 Index of the second sub-stake\n    */\n    function mergeStake(uint256 _index1, uint256 _index2) external onlyStaker {\n        require(_index1 != _index2); // must be different sub-stakes\n\n        StakerInfo storage info = stakerInfo[msg.sender];\n        SubStakeInfo storage subStake1 = info.subStakes[_index1];\n        SubStakeInfo storage subStake2 = info.subStakes[_index2];\n        uint16 currentPeriod = getCurrentPeriod();\n\n        (, uint16 lastPeriod1) = checkLastPeriodOfSubStake(info, subStake1, currentPeriod);\n        (, uint16 lastPeriod2) = checkLastPeriodOfSubStake(info, subStake2, currentPeriod);\n        // both sub-stakes must have equal last period to be mergeable\n        require(lastPeriod1 == lastPeriod2);\n        emit Merged(msg.sender, subStake1.lockedValue, subStake2.lockedValue, lastPeriod1);\n\n        if (subStake1.firstPeriod == subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = 1;\n            subStake2.unlockingDuration = 0;\n        } else if (subStake1.firstPeriod \u003e subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = subStake1.firstPeriod - 1;\n            subStake2.unlockingDuration = 0;\n        } else {\n            subStake2.lockedValue += subStake1.lockedValue;\n            subStake1.lastPeriod = subStake2.firstPeriod - 1;\n            subStake1.unlockingDuration = 0;\n        }\n    }\n\n    /**\n    * @notice Remove unused sub-stake to decrease gas cost for several methods\n    */\n    function removeUnusedSubStake(uint16 _index) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n\n        uint256 lastIndex = info.subStakes.length - 1;\n        SubStakeInfo storage subStake = info.subStakes[_index];\n        require(subStake.lastPeriod != 0 \u0026\u0026\n                (info.currentCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c info.currentCommittedPeriod) \u0026\u0026\n                (info.nextCommittedPeriod == 0 ||\n                subStake.lastPeriod \u003c info.nextCommittedPeriod));\n\n        if (_index != lastIndex) {\n            SubStakeInfo storage lastSubStake = info.subStakes[lastIndex];\n            subStake.firstPeriod = lastSubStake.firstPeriod;\n            subStake.lastPeriod = lastSubStake.lastPeriod;\n            subStake.unlockingDuration = lastSubStake.unlockingDuration;\n            subStake.lockedValue = lastSubStake.lockedValue;\n        }\n        info.subStakes.pop();\n    }\n\n    /**\n    * @notice Withdraw available amount of tokens to staker\n    * @param _value Amount of tokens to withdraw\n    */\n    function withdraw(uint256 _value) external onlyStaker {\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // the max locked tokens in most cases will be in the current period\n        // but when the staker locks more then we should use the next period\n        uint256 lockedTokens = Math.max(getLockedTokens(info, currentPeriod, nextPeriod),\n            getLockedTokens(info, currentPeriod, currentPeriod));\n        require(_value \u003c= info.value.sub(lockedTokens));\n        info.value -= _value;\n\n        addSnapshot(info, - int256(_value));\n        token.safeTransfer(msg.sender, _value);\n        emit Withdrawn(msg.sender, _value);\n\n        // unbond worker if staker withdraws last portion of NU\n        if (info.value == 0 \u0026\u0026\n            info.nextCommittedPeriod == 0 \u0026\u0026\n            info.worker != address(0))\n        {\n            stakerFromWorker[info.worker] = address(0);\n            info.worker = address(0);\n            emit WorkerBonded(msg.sender, address(0), currentPeriod);\n        }\n    }\n\n    /**\n    * @notice Make a commitment to the next period and mint for the previous period\n    */\n    function commitToNextPeriod() external isInitialized {\n        address staker = stakerFromWorker[msg.sender];\n        StakerInfo storage info = stakerInfo[staker];\n        // Staker must have a stake to make a commitment\n        require(info.value \u003e 0);\n        // Only worker with real address can make a commitment\n        require(msg.sender == tx.origin);\n\n        migrate(staker);\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        // the period has already been committed\n        require(info.nextCommittedPeriod != nextPeriod);\n\n        uint16 lastCommittedPeriod = getLastCommittedPeriod(staker);\n        (uint16 processedPeriod1, uint16 processedPeriod2) = mint(staker);\n\n        uint256 lockedTokens = getLockedTokens(info, currentPeriod, nextPeriod);\n        require(lockedTokens \u003e 0);\n        _lockedPerPeriod[nextPeriod] += lockedTokens;\n\n        info.currentCommittedPeriod = info.nextCommittedPeriod;\n        info.nextCommittedPeriod = nextPeriod;\n\n        decreaseSubStakesDuration(info, nextPeriod);\n\n        // staker was inactive for several periods\n        if (lastCommittedPeriod \u003c currentPeriod) {\n            info.pastDowntime.push(Downtime(lastCommittedPeriod + 1, currentPeriod));\n        }\n\n        policyManager.ping(staker, processedPeriod1, processedPeriod2, nextPeriod);\n        emit CommitmentMade(staker, nextPeriod, lockedTokens);\n    }\n\n    /**\n    * @notice Migrate from the old period length to the new one. Can be done only once\n    * @param _staker Staker\n    */\n    function migrate(address _staker) public {\n        StakerInfo storage info = stakerInfo[_staker];\n        // check that provided address is/was a staker\n        require(info.subStakes.length != 0 || info.lastCommittedPeriod != 0);\n        if (info.flags.bitSet(MIGRATED_INDEX)) {\n            return;\n        }\n\n        // reset state\n        info.currentCommittedPeriod = 0;\n        info.nextCommittedPeriod = 0;\n        // maintain case when no more sub-stakes and need to avoid re-registering this staker during deposit\n        info.lastCommittedPeriod = 1;\n        info.workerStartPeriod = recalculatePeriod(info.workerStartPeriod);\n        delete info.pastDowntime;\n\n        // recalculate all sub-stakes\n        uint16 currentPeriod = getCurrentPeriod();\n        for (uint256 i = 0; i \u003c info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = info.subStakes[i];\n            subStake.firstPeriod = recalculatePeriod(subStake.firstPeriod);\n            // sub-stake has fixed last period\n            if (subStake.lastPeriod != 0) {\n                subStake.lastPeriod = recalculatePeriod(subStake.lastPeriod);\n                if (subStake.lastPeriod == 0) {\n                    subStake.lastPeriod = 1;\n                }\n                subStake.unlockingDuration = 0;\n            // sub-stake has no fixed ending but possible that with new period length will have\n            } else {\n                uint16 oldCurrentPeriod = uint16(block.timestamp / genesisSecondsPerPeriod);\n                uint16 lastPeriod = recalculatePeriod(oldCurrentPeriod + subStake.unlockingDuration);\n                subStake.unlockingDuration = lastPeriod - currentPeriod;\n                if (subStake.unlockingDuration == 0) {\n                    subStake.lastPeriod = lastPeriod;\n                }\n            }\n        }\n\n        policyManager.migrate(_staker);\n        info.flags = info.flags.toggleBit(MIGRATED_INDEX);\n        emit Migrated(_staker, currentPeriod);\n    }\n\n    /**\n    * @notice Decrease sub-stakes duration if `windDown` is enabled\n    */\n    function decreaseSubStakesDuration(StakerInfo storage _info, uint16 _nextPeriod) internal {\n        if (!_info.flags.bitSet(WIND_DOWN_INDEX)) {\n            return;\n        }\n        for (uint256 index = 0; index \u003c _info.subStakes.length; index++) {\n            SubStakeInfo storage subStake = _info.subStakes[index];\n            if (subStake.lastPeriod != 0 || subStake.unlockingDuration == 0) {\n                continue;\n            }\n            subStake.unlockingDuration--;\n            if (subStake.unlockingDuration == 0) {\n                subStake.lastPeriod = _nextPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Mint tokens for previous periods if staker locked their tokens and made a commitment\n    */\n    function mint() external onlyStaker {\n        // save last committed period to the storage if both periods will be empty after minting\n        // because we won\u0027t be able to calculate last committed period\n        // see getLastCommittedPeriod(address)\n        StakerInfo storage info = stakerInfo[msg.sender];\n        uint16 previousPeriod = getCurrentPeriod() - 1;\n        if (info.nextCommittedPeriod \u003c= previousPeriod \u0026\u0026 info.nextCommittedPeriod != 0) {\n            info.lastCommittedPeriod = info.nextCommittedPeriod;\n        }\n        (uint16 processedPeriod1, uint16 processedPeriod2) = mint(msg.sender);\n\n        if (processedPeriod1 != 0 || processedPeriod2 != 0) {\n            policyManager.ping(msg.sender, processedPeriod1, processedPeriod2, 0);\n        }\n    }\n\n    /**\n    * @notice Mint tokens for previous periods if staker locked their tokens and made a commitment\n    * @param _staker Staker\n    * @return processedPeriod1 Processed period: currentCommittedPeriod or zero\n    * @return processedPeriod2 Processed period: nextCommittedPeriod or zero\n    */\n    function mint(address _staker) internal returns (uint16 processedPeriod1, uint16 processedPeriod2) {\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 previousPeriod = currentPeriod - 1;\n        StakerInfo storage info = stakerInfo[_staker];\n\n        if (info.nextCommittedPeriod == 0 ||\n            info.currentCommittedPeriod == 0 \u0026\u0026\n            info.nextCommittedPeriod \u003e previousPeriod ||\n            info.currentCommittedPeriod \u003e previousPeriod) {\n            return (0, 0);\n        }\n\n        uint16 startPeriod = getStartPeriod(info, currentPeriod);\n        uint256 reward = 0;\n        bool reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);\n\n        if (info.currentCommittedPeriod != 0) {\n            reward = mint(info, info.currentCommittedPeriod, currentPeriod, startPeriod, reStake);\n            processedPeriod1 = info.currentCommittedPeriod;\n            info.currentCommittedPeriod = 0;\n            if (reStake) {\n                _lockedPerPeriod[info.nextCommittedPeriod] += reward;\n            }\n        }\n        if (info.nextCommittedPeriod \u003c= previousPeriod) {\n            reward += mint(info, info.nextCommittedPeriod, currentPeriod, startPeriod, reStake);\n            processedPeriod2 = info.nextCommittedPeriod;\n            info.nextCommittedPeriod = 0;\n        }\n\n        info.value += reward;\n        if (info.flags.bitSet(MEASURE_WORK_INDEX)) {\n            info.completedWork += reward;\n        }\n\n        addSnapshot(info, int256(reward));\n        emit Minted(_staker, previousPeriod, reward);\n    }\n\n    /**\n    * @notice Calculate reward for one period\n    * @param _info Staker structure\n    * @param _mintingPeriod Period for minting calculation\n    * @param _currentPeriod Current period\n    * @param _startPeriod Pre-calculated start period\n    */\n    function mint(\n        StakerInfo storage _info,\n        uint16 _mintingPeriod,\n        uint16 _currentPeriod,\n        uint16 _startPeriod,\n        bool _reStake\n    )\n        internal returns (uint256 reward)\n    {\n        reward = 0;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake =  _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (subStake.firstPeriod \u003c= _mintingPeriod \u0026\u0026 lastPeriod \u003e= _mintingPeriod) {\n                uint256 subStakeReward = mint(\n                    _currentPeriod,\n                    subStake.lockedValue,\n                    _lockedPerPeriod[_mintingPeriod],\n                    lastPeriod.sub16(_mintingPeriod));\n                reward += subStakeReward;\n                if (_reStake) {\n                    subStake.lockedValue += uint128(subStakeReward);\n                }\n            }\n        }\n        return reward;\n    }\n\n    //-------------------------Slashing-------------------------\n    /**\n    * @notice Slash the staker\u0027s stake and reward the investigator\n    * @param _staker Staker\u0027s address\n    * @param _penalty Penalty\n    * @param _investigator Investigator\n    * @param _reward Reward for the investigator\n    */\n    function slashStaker(\n        address _staker,\n        uint256 _penalty,\n        address _investigator,\n        uint256 _reward\n    )\n        public isInitialized\n    {\n        require(msg.sender == address(adjudicator));\n        require(_penalty \u003e 0);\n        StakerInfo storage info = stakerInfo[_staker];\n        require(info.flags.bitSet(MIGRATED_INDEX));\n        if (info.value \u003c= _penalty) {\n            _penalty = info.value;\n        }\n        info.value -= _penalty;\n        if (_reward \u003e _penalty) {\n            _reward = _penalty;\n        }\n\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        uint16 startPeriod = getStartPeriod(info, currentPeriod);\n\n        (uint256 currentLock, uint256 nextLock, uint256 currentAndNextLock, uint256 shortestSubStakeIndex) =\n            getLockedTokensAndShortestSubStake(info, currentPeriod, nextPeriod, startPeriod);\n\n        // Decrease the stake if amount of locked tokens in the current period more than staker has\n        uint256 lockedTokens = currentLock + currentAndNextLock;\n        if (info.value \u003c lockedTokens) {\n           decreaseSubStakes(info, lockedTokens - info.value, currentPeriod, startPeriod, shortestSubStakeIndex);\n        }\n        // Decrease the stake if amount of locked tokens in the next period more than staker has\n        if (nextLock \u003e 0) {\n            lockedTokens = nextLock + currentAndNextLock -\n                (currentAndNextLock \u003e info.value ? currentAndNextLock - info.value : 0);\n            if (info.value \u003c lockedTokens) {\n               decreaseSubStakes(info, lockedTokens - info.value, nextPeriod, startPeriod, MAX_SUB_STAKES);\n            }\n        }\n\n        emit Slashed(_staker, _penalty, _investigator, _reward);\n        if (_penalty \u003e _reward) {\n            unMint(_penalty - _reward);\n        }\n        // TODO change to withdrawal pattern (#1499)\n        if (_reward \u003e 0) {\n            token.safeTransfer(_investigator, _reward);\n        }\n\n        addSnapshot(info, - int256(_penalty));\n\n    }\n\n    /**\n    * @notice Get the value of locked tokens for a staker in the current and the next period\n    * and find the shortest sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _nextPeriod Next period\n    * @param _startPeriod Pre-calculated start period\n    * @return currentLock Amount of tokens that locked in the current period and unlocked in the next period\n    * @return nextLock Amount of tokens that locked in the next period and not locked in the current period\n    * @return currentAndNextLock Amount of tokens that locked in the current period and in the next period\n    * @return shortestSubStakeIndex Index of the shortest sub stake\n    */\n    function getLockedTokensAndShortestSubStake(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _nextPeriod,\n        uint16 _startPeriod\n    )\n        internal view returns (\n            uint256 currentLock,\n            uint256 nextLock,\n            uint256 currentAndNextLock,\n            uint256 shortestSubStakeIndex\n        )\n    {\n        uint16 minDuration = MAX_UINT16;\n        uint16 minLastPeriod = MAX_UINT16;\n        shortestSubStakeIndex = MAX_SUB_STAKES;\n        currentLock = 0;\n        nextLock = 0;\n        currentAndNextLock = 0;\n\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (lastPeriod \u003c subStake.firstPeriod) {\n                continue;\n            }\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _nextPeriod) {\n                currentAndNextLock += subStake.lockedValue;\n            } else if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod) {\n                currentLock += subStake.lockedValue;\n            } else if (subStake.firstPeriod \u003c= _nextPeriod \u0026\u0026\n                lastPeriod \u003e= _nextPeriod) {\n                nextLock += subStake.lockedValue;\n            }\n            uint16 duration = lastPeriod - subStake.firstPeriod;\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod \u0026\u0026\n                (lastPeriod \u003c minLastPeriod ||\n                lastPeriod == minLastPeriod \u0026\u0026 duration \u003c minDuration))\n            {\n                shortestSubStakeIndex = i;\n                minDuration = duration;\n                minLastPeriod = lastPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Decrease short sub stakes\n    * @param _info Staker structure\n    * @param _penalty Penalty rate\n    * @param _decreasePeriod The period when the decrease begins\n    * @param _startPeriod Pre-calculated start period\n    * @param _shortestSubStakeIndex Index of the shortest period\n    */\n    function decreaseSubStakes(\n        StakerInfo storage _info,\n        uint256 _penalty,\n        uint16 _decreasePeriod,\n        uint16 _startPeriod,\n        uint256 _shortestSubStakeIndex\n    )\n        internal\n    {\n        SubStakeInfo storage shortestSubStake = _info.subStakes[0];\n        uint16 minSubStakeLastPeriod = MAX_UINT16;\n        uint16 minSubStakeDuration = MAX_UINT16;\n        while(_penalty \u003e 0) {\n            if (_shortestSubStakeIndex \u003c MAX_SUB_STAKES) {\n                shortestSubStake = _info.subStakes[_shortestSubStakeIndex];\n                minSubStakeLastPeriod = getLastPeriodOfSubStake(shortestSubStake, _startPeriod);\n                minSubStakeDuration = minSubStakeLastPeriod - shortestSubStake.firstPeriod;\n                _shortestSubStakeIndex = MAX_SUB_STAKES;\n            } else {\n                (shortestSubStake, minSubStakeDuration, minSubStakeLastPeriod) =\n                    getShortestSubStake(_info, _decreasePeriod, _startPeriod);\n            }\n            if (minSubStakeDuration == MAX_UINT16) {\n                break;\n            }\n            uint256 appliedPenalty = _penalty;\n            if (_penalty \u003c shortestSubStake.lockedValue) {\n                shortestSubStake.lockedValue -= uint128(_penalty);\n                saveOldSubStake(_info, shortestSubStake.firstPeriod, _penalty, _decreasePeriod);\n                _penalty = 0;\n            } else {\n                shortestSubStake.lastPeriod = _decreasePeriod - 1;\n                _penalty -= shortestSubStake.lockedValue;\n                appliedPenalty = shortestSubStake.lockedValue;\n            }\n            if (_info.currentCommittedPeriod \u003e= _decreasePeriod \u0026\u0026\n                _info.currentCommittedPeriod \u003c= minSubStakeLastPeriod)\n            {\n                _lockedPerPeriod[_info.currentCommittedPeriod] -= appliedPenalty;\n            }\n            if (_info.nextCommittedPeriod \u003e= _decreasePeriod \u0026\u0026\n                _info.nextCommittedPeriod \u003c= minSubStakeLastPeriod)\n            {\n                _lockedPerPeriod[_info.nextCommittedPeriod] -= appliedPenalty;\n            }\n        }\n    }\n\n    /**\n    * @notice Get the shortest sub stake\n    * @param _info Staker structure\n    * @param _currentPeriod Current period\n    * @param _startPeriod Pre-calculated start period\n    * @return shortestSubStake The shortest sub stake\n    * @return minSubStakeDuration Duration of the shortest sub stake\n    * @return minSubStakeLastPeriod Last period of the shortest sub stake\n    */\n    function getShortestSubStake(\n        StakerInfo storage _info,\n        uint16 _currentPeriod,\n        uint16 _startPeriod\n    )\n        internal view returns (\n            SubStakeInfo storage shortestSubStake,\n            uint16 minSubStakeDuration,\n            uint16 minSubStakeLastPeriod\n        )\n    {\n        shortestSubStake = shortestSubStake;\n        minSubStakeDuration = MAX_UINT16;\n        minSubStakeLastPeriod = MAX_UINT16;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            uint16 lastPeriod = getLastPeriodOfSubStake(subStake, _startPeriod);\n            if (lastPeriod \u003c subStake.firstPeriod) {\n                continue;\n            }\n            uint16 duration = lastPeriod - subStake.firstPeriod;\n            if (subStake.firstPeriod \u003c= _currentPeriod \u0026\u0026\n                lastPeriod \u003e= _currentPeriod \u0026\u0026\n                (lastPeriod \u003c minSubStakeLastPeriod ||\n                lastPeriod == minSubStakeLastPeriod \u0026\u0026 duration \u003c minSubStakeDuration))\n            {\n                shortestSubStake = subStake;\n                minSubStakeDuration = duration;\n                minSubStakeLastPeriod = lastPeriod;\n            }\n        }\n    }\n\n    /**\n    * @notice Save the old sub stake values to prevent decreasing reward for the previous period\n    * @dev Saving happens only if the previous period is committed\n    * @param _info Staker structure\n    * @param _firstPeriod First period of the old sub stake\n    * @param _lockedValue Locked value of the old sub stake\n    * @param _currentPeriod Current period, when the old sub stake is already unlocked\n    */\n    function saveOldSubStake(\n        StakerInfo storage _info,\n        uint16 _firstPeriod,\n        uint256 _lockedValue,\n        uint16 _currentPeriod\n    )\n        internal\n    {\n        // Check that the old sub stake should be saved\n        bool oldCurrentCommittedPeriod = _info.currentCommittedPeriod != 0 \u0026\u0026\n            _info.currentCommittedPeriod \u003c _currentPeriod;\n        bool oldnextCommittedPeriod = _info.nextCommittedPeriod != 0 \u0026\u0026\n            _info.nextCommittedPeriod \u003c _currentPeriod;\n        bool crosscurrentCommittedPeriod = oldCurrentCommittedPeriod \u0026\u0026 _info.currentCommittedPeriod \u003e= _firstPeriod;\n        bool crossnextCommittedPeriod = oldnextCommittedPeriod \u0026\u0026 _info.nextCommittedPeriod \u003e= _firstPeriod;\n        if (!crosscurrentCommittedPeriod \u0026\u0026 !crossnextCommittedPeriod) {\n            return;\n        }\n        // Try to find already existent proper old sub stake\n        uint16 previousPeriod = _currentPeriod - 1;\n        for (uint256 i = 0; i \u003c _info.subStakes.length; i++) {\n            SubStakeInfo storage subStake = _info.subStakes[i];\n            if (subStake.lastPeriod == previousPeriod \u0026\u0026\n                ((crosscurrentCommittedPeriod ==\n                (oldCurrentCommittedPeriod \u0026\u0026 _info.currentCommittedPeriod \u003e= subStake.firstPeriod)) \u0026\u0026\n                (crossnextCommittedPeriod ==\n                (oldnextCommittedPeriod \u0026\u0026 _info.nextCommittedPeriod \u003e= subStake.firstPeriod))))\n            {\n                subStake.lockedValue += uint128(_lockedValue);\n                return;\n            }\n        }\n        saveSubStake(_info, _firstPeriod, previousPeriod, 0, _lockedValue);\n    }\n\n    //-------------Additional getters for stakers info-------------\n    /**\n    * @notice Return the length of the array of stakers\n    */\n    function getStakersLength() external view returns (uint256) {\n        return stakers.length;\n    }\n\n    /**\n    * @notice Return the length of the array of sub stakes\n    */\n    function getSubStakesLength(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].subStakes.length;\n    }\n\n    /**\n    * @notice Return the information about sub stake\n    */\n    function getSubStakeInfo(address _staker, uint256 _index)\n    // TODO change to structure when ABIEncoderV2 is released (#1501)\n//        public view returns (SubStakeInfo)\n        // TODO \"virtual\" only for tests, probably will be removed after #1512\n        external view virtual returns (\n            uint16 firstPeriod,\n            uint16 lastPeriod,\n            uint16 unlockingDuration,\n            uint128 lockedValue\n        )\n    {\n        SubStakeInfo storage info = stakerInfo[_staker].subStakes[_index];\n        firstPeriod = info.firstPeriod;\n        lastPeriod = info.lastPeriod;\n        unlockingDuration = info.unlockingDuration;\n        lockedValue = info.lockedValue;\n    }\n\n    /**\n    * @notice Return the length of the array of past downtime\n    */\n    function getPastDowntimeLength(address _staker) external view returns (uint256) {\n        return stakerInfo[_staker].pastDowntime.length;\n    }\n\n    /**\n    * @notice Return the information about past downtime\n    */\n    function  getPastDowntime(address _staker, uint256 _index)\n    // TODO change to structure when ABIEncoderV2 is released (#1501)\n//        public view returns (Downtime)\n        external view returns (uint16 startPeriod, uint16 endPeriod)\n    {\n        Downtime storage downtime = stakerInfo[_staker].pastDowntime[_index];\n        startPeriod = downtime.startPeriod;\n        endPeriod = downtime.endPeriod;\n    }\n\n    //------------------ ERC900 connectors ----------------------\n\n    function totalStakedForAt(address _owner, uint256 _blockNumber) public view override returns (uint256){\n        return stakerInfo[_owner].history.getValueAt(_blockNumber);\n    }\n\n    function totalStakedAt(uint256 _blockNumber) public view override returns (uint256){\n        return balanceHistory.getValueAt(_blockNumber);\n    }\n\n    function supportsHistory() external pure override returns (bool){\n        return true;\n    }\n\n    //------------------------Upgradeable------------------------\n    /**\n    * @dev Get StakerInfo structure by delegatecall\n    */\n    function delegateGetStakerInfo(address _target, bytes32 _staker)\n        internal returns (StakerInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, this.stakerInfo.selector, 1, _staker, 0);\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get SubStakeInfo structure by delegatecall\n    */\n    function delegateGetSubStakeInfo(address _target, bytes32 _staker, uint256 _index)\n        internal returns (SubStakeInfo memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(\n            _target, this.getSubStakeInfo.selector, 2, _staker, bytes32(_index));\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /**\n    * @dev Get Downtime structure by delegatecall\n    */\n    function delegateGetPastDowntime(address _target, bytes32 _staker, uint256 _index)\n        internal returns (Downtime memory result)\n    {\n        bytes32 memoryAddress = delegateGetData(\n            _target, this.getPastDowntime.selector, 2, _staker, bytes32(_index));\n        assembly {\n            result := memoryAddress\n        }\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `verifyState`\n    function verifyState(address _testTarget) public override virtual {\n        super.verifyState(_testTarget);\n        require(delegateGet(_testTarget, this.lockedPerPeriod.selector,\n            bytes32(bytes2(RESERVED_PERIOD))) == lockedPerPeriod(RESERVED_PERIOD));\n        require(address(delegateGet(_testTarget, this.stakerFromWorker.selector, bytes32(0))) ==\n            stakerFromWorker[address(0)]);\n\n        require(delegateGet(_testTarget, this.getStakersLength.selector) == stakers.length);\n        if (stakers.length == 0) {\n            return;\n        }\n        address stakerAddress = stakers[0];\n        require(address(uint160(delegateGet(_testTarget, this.stakers.selector, 0))) == stakerAddress);\n        StakerInfo storage info = stakerInfo[stakerAddress];\n        bytes32 staker = bytes32(uint256(stakerAddress));\n        StakerInfo memory infoToCheck = delegateGetStakerInfo(_testTarget, staker);\n        require(infoToCheck.value == info.value \u0026\u0026\n            infoToCheck.currentCommittedPeriod == info.currentCommittedPeriod \u0026\u0026\n            infoToCheck.nextCommittedPeriod == info.nextCommittedPeriod \u0026\u0026\n            infoToCheck.flags == info.flags \u0026\u0026\n            infoToCheck.lastCommittedPeriod == info.lastCommittedPeriod \u0026\u0026\n            infoToCheck.completedWork == info.completedWork \u0026\u0026\n            infoToCheck.worker == info.worker \u0026\u0026\n            infoToCheck.workerStartPeriod == info.workerStartPeriod);\n\n        require(delegateGet(_testTarget, this.getPastDowntimeLength.selector, staker) ==\n            info.pastDowntime.length);\n        for (uint256 i = 0; i \u003c info.pastDowntime.length \u0026\u0026 i \u003c MAX_CHECKED_VALUES; i++) {\n            Downtime storage downtime = info.pastDowntime[i];\n            Downtime memory downtimeToCheck = delegateGetPastDowntime(_testTarget, staker, i);\n            require(downtimeToCheck.startPeriod == downtime.startPeriod \u0026\u0026\n                downtimeToCheck.endPeriod == downtime.endPeriod);\n        }\n\n        require(delegateGet(_testTarget, this.getSubStakesLength.selector, staker) == info.subStakes.length);\n        for (uint256 i = 0; i \u003c info.subStakes.length \u0026\u0026 i \u003c MAX_CHECKED_VALUES; i++) {\n            SubStakeInfo storage subStakeInfo = info.subStakes[i];\n            SubStakeInfo memory subStakeInfoToCheck = delegateGetSubStakeInfo(_testTarget, staker, i);\n            require(subStakeInfoToCheck.firstPeriod == subStakeInfo.firstPeriod \u0026\u0026\n                subStakeInfoToCheck.lastPeriod == subStakeInfo.lastPeriod \u0026\u0026\n                subStakeInfoToCheck.unlockingDuration == subStakeInfo.unlockingDuration \u0026\u0026\n                subStakeInfoToCheck.lockedValue == subStakeInfo.lockedValue);\n        }\n\n        // it\u0027s not perfect because checks not only slot value but also decoding\n        // at least without additional functions\n        require(delegateGet(_testTarget, this.totalStakedForAt.selector, staker, bytes32(block.number)) ==\n            totalStakedForAt(stakerAddress, block.number));\n        require(delegateGet(_testTarget, this.totalStakedAt.selector, bytes32(block.number)) ==\n            totalStakedAt(block.number));\n\n        if (info.worker != address(0)) {\n            require(address(delegateGet(_testTarget, this.stakerFromWorker.selector, bytes32(uint256(info.worker)))) ==\n                stakerFromWorker[info.worker]);\n        }\n    }\n\n    /// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`\n    function finishUpgrade(address _target) public override virtual {\n        super.finishUpgrade(_target);\n        // Create fake period\n        _lockedPerPeriod[RESERVED_PERIOD] = 111;\n\n        // Create fake worker\n        stakerFromWorker[address(0)] = address(this);\n    }\n}\n"},"Upgradeable.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"Ownable.sol\";\n\n\n/**\n* @notice Base contract for upgradeable contract\n* @dev Inherited contract should implement verifyState(address) method by checking storage variables\n* (see verifyState(address) in Dispatcher). Also contract should implement finishUpgrade(address)\n* if it is using constructor parameters by coping this parameters to the dispatcher storage\n*/\nabstract contract Upgradeable is Ownable {\n\n    event StateVerified(address indexed testTarget, address sender);\n    event UpgradeFinished(address indexed target, address sender);\n\n    /**\n    * @dev Contracts at the target must reserve the same location in storage for this address as in Dispatcher\n    * Stored data actually lives in the Dispatcher\n    * However the storage layout is specified here in the implementing contracts\n    */\n    address public target;\n\n    /**\n    * @dev Previous contract address (if available). Used for rollback\n    */\n    address public previousTarget;\n\n    /**\n    * @dev Upgrade status. Explicit `uint8` type is used instead of `bool` to save gas by excluding 0 value\n    */\n    uint8 public isUpgrade;\n\n    /**\n    * @dev Guarantees that next slot will be separated from the previous\n    */\n    uint256 stubSlot;\n\n    /**\n    * @dev Constants for `isUpgrade` field\n    */\n    uint8 constant UPGRADE_FALSE = 1;\n    uint8 constant UPGRADE_TRUE = 2;\n\n    /**\n    * @dev Checks that function executed while upgrading\n    * Recommended to add to `verifyState` and `finishUpgrade` methods\n    */\n    modifier onlyWhileUpgrading()\n    {\n        require(isUpgrade == UPGRADE_TRUE);\n        _;\n    }\n\n    /**\n    * @dev Method for verifying storage state.\n    * Should check that new target contract returns right storage value\n    */\n    function verifyState(address _testTarget) public virtual onlyWhileUpgrading {\n        emit StateVerified(_testTarget, msg.sender);\n    }\n\n    /**\n    * @dev Copy values from the new target to the current storage\n    * @param _target New target contract address\n    */\n    function finishUpgrade(address _target) public virtual onlyWhileUpgrading {\n        emit UpgradeFinished(_target, msg.sender);\n    }\n\n    /**\n    * @dev Base method to get data\n    * @param _target Target to call\n    * @param _selector Method selector\n    * @param _numberOfArguments Number of used arguments\n    * @param _argument1 First method argument\n    * @param _argument2 Second method argument\n    * @return memoryAddress Address in memory where the data is located\n    */\n    function delegateGetData(\n        address _target,\n        bytes4 _selector,\n        uint8 _numberOfArguments,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (bytes32 memoryAddress)\n    {\n        assembly {\n            memoryAddress := mload(0x40)\n            mstore(memoryAddress, _selector)\n            if gt(_numberOfArguments, 0) {\n                mstore(add(memoryAddress, 0x04), _argument1)\n            }\n            if gt(_numberOfArguments, 1) {\n                mstore(add(memoryAddress, 0x24), _argument2)\n            }\n            switch delegatecall(gas(), _target, memoryAddress, add(0x04, mul(0x20, _numberOfArguments)), 0, 0)\n                case 0 {\n                    revert(memoryAddress, 0)\n                }\n                default {\n                    returndatacopy(memoryAddress, 0x0, returndatasize())\n                }\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" without parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 0, 0, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with one parameter.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(address _target, bytes4 _selector, bytes32 _argument)\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 1, _argument, 0);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n\n    /**\n    * @dev Call \"getter\" with two parameters.\n    * Result should not exceed 32 bytes\n    */\n    function delegateGet(\n        address _target,\n        bytes4 _selector,\n        bytes32 _argument1,\n        bytes32 _argument2\n    )\n        internal returns (uint256 result)\n    {\n        bytes32 memoryAddress = delegateGetData(_target, _selector, 2, _argument1, _argument2);\n        assembly {\n            result := mload(memoryAddress)\n        }\n    }\n}\n"}}