ETH Price: $2,432.88 (+0.41%)

Transaction Decoder

Block:
11968277 at Mar-03-2021 11:29:31 PM +UTC
Transaction Fee:
0.008630626118793239 ETH $21.00
Gas Used:
81,421 Gas / 106.000001459 Gwei

Emitted Events:

138 Dispatcher.0xdc3bbcef212790ff00528dc9ef9c9b7638f290efd77f50f50c067bb14d7f9c11( 0xdc3bbcef212790ff00528dc9ef9c9b7638f290efd77f50f50c067bb14d7f9c11, 0x000000000000000000000000e2a82cdccbfa6ebf9817b0c4aed45264bd41fbec, 0000000000000000000000000000000000000000000000000000000000000000 )
139 WorkLock.Refund( sender=[Sender] 0xe2a82cdccbfa6ebf9817b0c4aed45264bd41fbec, refundETH=512000000000000000000, completedWork=37784139661507914648179 )

Account State Difference:

  Address   Before After State Difference Code
0xbbD3C0C7...6fcfCb2e2
(NuCypher: StakingEscrow)
(UUPool)
489.407230137745978501 Eth489.41586076386477174 Eth0.008630626118793239
0xE2A82cdc...4Bd41FBEC
826.032025272785980846 Eth
Nonce: 168
1,338.023394646667187607 Eth
Nonce: 169
511.991369373881206761
0xe9778E69...1d34667c2
(NuCypher: WorkLock)
22,900.221470220195492317 Eth22,388.221470220195492317 Eth512

Execution Trace

WorkLock.CALL( )
  • Dispatcher.d094adbf( )
    • StakingEscrow.getCompletedWork( _staker=0xE2A82cdccbFA6EBF9817b0C4aEd45264Bd41FBEC ) => ( 46551091616136284043377 )
    • Dispatcher.49e5add4( )
      • StakingEscrow.setWorkMeasurement( _staker=0xE2A82cdccbFA6EBF9817b0C4aEd45264Bd41FBEC, _measureWork=False ) => ( 46551091616136284043377 )
      • ETH 512 0xe2a82cdccbfa6ebf9817b0c4aed45264bd41fbec.CALL( )
        File 1 of 3: WorkLock
        {"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* @notice Contract for calculation of issued tokens\n* @dev |v3.3.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    uint32 public immutable secondsPerPeriod;\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 _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 _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            _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        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    * @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}\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 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 register(address _node, uint16 _period) external;\n    function updateFee(address _node, uint16 _period) external;\n    function escrow() external view returns (address);\n    function setDefaultFeeDelta(address _node, uint16 _period) external;\n}\n\n\n/**\n* @notice Adjudicator interface\n*/\ninterface AdjudicatorInterface {\n    function escrow() external view returns (address);\n}\n\n\n/**\n* @notice WorkLock interface\n*/\ninterface WorkLockInterface {\n    function escrow() external view returns (address);\n}\n\n\n/**\n* @notice Contract holds and locks stakers tokens.\n* Each staker that locks their tokens will receive some compensation\n* @dev |v5.3.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    event Deposited(address indexed staker, uint256 value, uint16 periods);\n    event Locked(address indexed staker, uint256 value, uint16 firstPeriod, uint16 periods);\n    event Divided(\n        address indexed staker,\n        uint256 oldValue,\n        uint16 lastPeriod,\n        uint256 newValue,\n        uint16 periods\n    );\n    event Merged(address indexed staker, uint256 value1, uint256 value2, uint16 lastPeriod);\n    event Prolonged(address indexed staker, uint256 value, uint16 lastPeriod, uint16 periods);\n    event Withdrawn(address indexed staker, uint256 value);\n    event CommitmentMade(address indexed staker, uint16 indexed period, uint256 value);\n    event Minted(address indexed staker, uint16 indexed period, uint256 value);\n    event Slashed(address indexed staker, uint256 penalty, address indexed investigator, uint256 reward);\n    event ReStakeSet(address indexed staker, bool reStake);\n    event ReStakeLocked(address indexed staker, uint16 lockUntilPeriod);\n    event WorkerBonded(address indexed staker, address indexed worker, uint16 indexed startPeriod);\n    event WorkMeasurementSet(address indexed staker, bool measureWork);\n    event WindDownSet(address indexed staker, bool windDown);\n    event SnapshotSet(address indexed staker, bool snapshotsEnabled);\n\n    struct SubStakeInfo {\n        uint16 firstPeriod;\n        uint16 lastPeriod;\n        uint16 periods;\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 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\n    uint16 public immutable minLockedPeriods;\n    uint16 public immutable minWorkerPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n    bool public immutable isTestContract;\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) public lockedPerPeriod;\n    uint128[] public balanceHistory;\n\n    PolicyManagerInterface public policyManager;\n    AdjudicatorInterface public adjudicator;\n    WorkLockInterface public workLock;\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @param _token Token contract\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    * @param _isTestContract True if contract is only for tests\n    */\n    constructor(\n        NuCypherToken _token,\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        bool _isTestContract\n    )\n        Issuer(\n            _token,\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        isTestContract = _isTestContract;\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);\n        _;\n    }\n\n    //------------------------Initialization------------------------\n    /**\n    * @notice Set policy manager address\n    */\n    function setPolicyManager(PolicyManagerInterface _policyManager) external onlyOwner {\n        // Policy manager can be set only once\n        require(address(policyManager) == address(0));\n        // This escrow must be the escrow for the new policy manager\n        require(_policyManager.escrow() == address(this));\n        policyManager = _policyManager;\n    }\n\n    /**\n    * @notice Set adjudicator address\n    */\n    function setAdjudicator(AdjudicatorInterface _adjudicator) external onlyOwner {\n        // Adjudicator can be set only once\n        require(address(adjudicator) == address(0));\n        // This escrow must be the escrow for the new adjudicator\n        require(_adjudicator.escrow() == address(this));\n        adjudicator = _adjudicator;\n    }\n\n    /**\n    * @notice Set worklock address\n    */\n    function setWorkLock(WorkLockInterface _workLock) external onlyOwner {\n        // WorkLock can be set only once\n        require(address(workLock) == address(0) || isTestContract);\n        // This escrow must be the escrow for the new worklock\n        require(_workLock.escrow() == address(this));\n        workLock = _workLock;\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        )\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    }\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.periods;\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 _periods Amount of periods that will be added to the current period\n    */\n    function getLockedTokens(address _staker, uint16 _periods)\n        external view returns (uint256 lockedValue)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_periods);\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() + _periods) period\n    * as well as stakers and their locked tokens\n    * @param _periods 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 _periods, uint256 _startIndex, uint256 _maxStakers)\n        external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)\n    {\n        require(_periods \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(_periods);\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 Checks if `reStake` parameter is available for changing\n    * @param _staker Staker\n    */\n    function isReStakeLocked(address _staker) public view returns (bool) {\n        return getCurrentPeriod() \u003c stakerInfo[_staker].lockReStakeUntilPeriod;\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    * Only if this parameter is not locked\n    * @param _reStake Value for parameter\n    */\n    function setReStake(bool _reStake) external {\n        require(!isReStakeLocked(msg.sender));\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 Lock `reStake` parameter. Only if this parameter is not locked\n    * @param _lockReStakeUntilPeriod Can\u0027t change `reStake` value until this period\n    */\n    function lockReStake(uint16 _lockReStakeUntilPeriod) external {\n        require(!isReStakeLocked(msg.sender) \u0026\u0026\n            _lockReStakeUntilPeriod \u003e getCurrentPeriod());\n        stakerInfo[msg.sender].lockReStakeUntilPeriod = _lockReStakeUntilPeriod;\n        emit ReStakeLocked(msg.sender, _lockReStakeUntilPeriod);\n    }\n\n    /**\n    * @notice Enable `reStake` and lock this parameter even if parameter is locked\n    * @param _staker Staker address\n    * @param _info Staker structure\n    * @param _lockReStakeUntilPeriod Can\u0027t change `reStake` value until this period\n    */\n    function forceLockReStake(\n        address _staker,\n        StakerInfo storage _info,\n        uint16 _lockReStakeUntilPeriod\n    )\n        internal\n    {\n        // reset bit when `reStake` is already disabled\n        if (_info.flags.bitSet(RE_STAKE_DISABLED_INDEX) == true) {\n            _info.flags = _info.flags.toggleBit(RE_STAKE_DISABLED_INDEX);\n            emit ReStakeSet(_staker, true);\n        }\n        // lock `reStake` parameter if it\u0027s not locked or locked for too short duration\n        if (_lockReStakeUntilPeriod \u003e _info.lockReStakeUntilPeriod) {\n            _info.lockReStakeUntilPeriod = _lockReStakeUntilPeriod;\n            emit ReStakeLocked(_staker, _lockReStakeUntilPeriod);\n        }\n    }\n\n    /**\n    * @notice Deposit tokens and lock `reStake` parameter from WorkLock contract\n    * @param _staker Staker address\n    * @param _value Amount of tokens to deposit\n    * @param _periods Amount of periods during which tokens will be locked\n    * and number of period after which `reStake` can be changed\n    */\n    function depositFromWorkLock(\n        address _staker,\n        uint256 _value,\n        uint16 _periods\n    )\n        external\n    {\n        require(msg.sender == address(workLock));\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _periods);\n        StakerInfo storage info = stakerInfo[_staker];\n        uint16 lockReStakeUntilPeriod = getCurrentPeriod().add16(_periods).add16(1);\n        forceLockReStake(_staker, info, lockReStakeUntilPeriod);\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 onlyStaker {\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\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n        emit WindDownSet(msg.sender, _windDown);\n\n        // duration adjustment if next period is committed\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.periods = 1;\n                continue;\n            }\n            // this sub-stake is no longer affected by winding down parameter\n            if (subStake.lastPeriod != 0 || subStake.periods == 0) {\n                continue;\n            }\n\n            subStake.periods = _windDown ? subStake.periods - 1 : subStake.periods + 1;\n            if (subStake.periods == 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    /**\n    * @notice Batch deposit. Allowed only initial deposit for each staker\n    * @param _stakers Stakers\n    * @param _numberOfSubStakes Number of sub-stakes which belong to staker in _values and _periods arrays\n    * @param _values Amount of tokens to deposit for each staker\n    * @param _periods Amount of periods during which tokens will be locked for each staker\n    * @param _lockReStakeUntilPeriod Can\u0027t change `reStake` value until this period. Zero value will disable locking\n    */\n    function batchDeposit(\n        address[] calldata _stakers,\n        uint256[] calldata _numberOfSubStakes,\n        uint256[] calldata _values,\n        uint16[] calldata _periods,\n        uint16 _lockReStakeUntilPeriod\n    )\n        // `onlyOwner` modifier is for prevent malicious using of `forceLockReStake`\n        // remove `onlyOwner` if `forceLockReStake` will be removed\n        external onlyOwner\n    {\n        uint256 subStakesLength = _values.length;\n        require(_stakers.length != 0 \u0026\u0026\n            _stakers.length == _numberOfSubStakes.length \u0026\u0026\n            subStakesLength \u003e= _stakers.length \u0026\u0026\n            _periods.length == subStakesLength);\n        uint16 previousPeriod = getCurrentPeriod() - 1;\n        uint16 nextPeriod = previousPeriod + 2;\n        uint256 sumValue = 0;\n\n        uint256 j = 0;\n        for (uint256 i = 0; i \u003c _stakers.length; i++) {\n            address staker = _stakers[i];\n            uint256 numberOfSubStakes = _numberOfSubStakes[i];\n            uint256 endIndex = j + numberOfSubStakes;\n            require(numberOfSubStakes \u003e 0 \u0026\u0026 subStakesLength \u003e= endIndex);\n            StakerInfo storage info = stakerInfo[staker];\n            require(info.subStakes.length == 0);\n            // A staker can\u0027t be a worker for another staker\n            require(stakerFromWorker[staker] == address(0));\n            stakers.push(staker);\n            policyManager.register(staker, previousPeriod);\n\n            for (; j \u003c endIndex; j++) {\n                uint256 value =  _values[j];\n                uint16 periods = _periods[j];\n                require(value \u003e= minAllowableLockedTokens \u0026\u0026 periods \u003e= minLockedPeriods);\n                info.value = info.value.add(value);\n                info.subStakes.push(SubStakeInfo(nextPeriod, 0, periods, uint128(value)));\n                sumValue = sumValue.add(value);\n                emit Deposited(staker, value, periods);\n                emit Locked(staker, value, nextPeriod, periods);\n            }\n            require(info.value \u003c= maxAllowableLockedTokens);\n            info.history.addSnapshot(info.value);\n\n            if (_lockReStakeUntilPeriod \u003e= nextPeriod) {\n                forceLockReStake(staker, info, _lockReStakeUntilPeriod);\n            }\n        }\n        require(j == subStakesLength);\n        uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n        balanceHistory.addSnapshot(lastGlobalBalance + sumValue);\n        token.safeTransferFrom(msg.sender, address(this), sumValue);\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 locked\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 _periods Amount of periods during which tokens will be locked\n    */\n    function deposit(address _staker, uint256 _value, uint16 _periods) external {\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function deposit(address _staker, address _payer, uint256 _index, uint256 _value, uint16 _periods) 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) {\n            stakers.push(_staker);\n            policyManager.register(_staker, getCurrentPeriod() - 1);\n        }\n        token.safeTransferFrom(_payer, address(this), _value);\n        info.value += _value;\n        lock(_staker, _index, _value, _periods);\n\n        addSnapshot(info, int256(_value));\n        if (_index \u003e= MAX_SUB_STAKES) {\n            emit Deposited(_staker, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lockAndCreate(uint256 _value, uint16 _periods) external onlyStaker {\n        lock(msg.sender, MAX_SUB_STAKES, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lock(address _staker, uint256 _index, uint256 _value, uint16 _periods) internal {\n        if (_index \u003c MAX_SUB_STAKES) {\n            require(_value \u003e 0);\n        } else {\n            require(_value \u003e= minAllowableLockedTokens \u0026\u0026 _periods \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, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lockAndCreate(\n        StakerInfo storage _info,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _value,\n        uint16 _periods\n    )\n        internal\n    {\n        uint16 duration = _periods;\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, _periods);\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 _periods 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 _periods,\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.periods = _periods;\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, _periods, 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 _periods Amount of periods for extending sub stake\n    */\n    function divideStake(uint256 _index, uint256 _newValue, uint16 _periods) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require(_newValue \u003e= minAllowableLockedTokens \u0026\u0026 _periods \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.periods.add16(_periods);\n        saveSubStake(info, subStake.firstPeriod, 0, requestedPeriods, _newValue);\n        emit Divided(msg.sender, oldValue, lastPeriod, _newValue, _periods);\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 _periods Amount of periods for extending sub stake\n    */\n    function prolongStake(uint256 _index, uint16 _periods) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Incorrect parameters\n        require(_periods \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.periods = subStake.periods.add16(_periods);\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) + _periods \u003e= minLockedPeriods);\n        emit Locked(msg.sender, subStake.lockedValue, lastPeriod + 1, _periods);\n        emit Prolonged(msg.sender, subStake.lockedValue, lastPeriod, _periods);\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.periods = 0;\n        } else if (subStake1.firstPeriod \u003e subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = subStake1.firstPeriod - 1;\n            subStake2.periods = 0;\n        } else {\n            subStake2.lockedValue += subStake1.lockedValue;\n            subStake1.lastPeriod = subStake2.firstPeriod - 1;\n            subStake1.periods = 0;\n        }\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        uint16 lastCommittedPeriod = getLastCommittedPeriod(staker);\n        mint(staker);\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n\n        // the period has already been committed\n        if (info.nextCommittedPeriod == nextPeriod) {\n            return;\n        }\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        policyManager.setDefaultFeeDelta(staker, nextPeriod);\n        emit CommitmentMade(staker, nextPeriod, lockedTokens);\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.periods == 0) {\n                continue;\n            }\n            subStake.periods--;\n            if (subStake.periods == 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        mint(msg.sender);\n    }\n\n    /**\n    * @notice Mint tokens for previous periods if staker locked their tokens and made a commitment\n    * @param _staker Staker\n    */\n    function mint(address _staker) internal {\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;\n        }\n\n        uint16 startPeriod = getStartPeriod(info, currentPeriod);\n        uint256 reward = 0;\n        bool reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);\n        if (info.currentCommittedPeriod != 0) {\n            reward = mint(_staker, info, info.currentCommittedPeriod, currentPeriod, startPeriod, reStake);\n            info.currentCommittedPeriod = 0;\n            if (reStake) {\n                lockedPerPeriod[info.nextCommittedPeriod] += reward;\n            }\n        }\n        if (info.nextCommittedPeriod \u003c= previousPeriod) {\n            reward += mint(_staker, info, info.nextCommittedPeriod, currentPeriod, startPeriod, reStake);\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 _staker Staker\u0027s address\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        address _staker,\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        policyManager.updateFee(_staker, _mintingPeriod);\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        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 (uint16 firstPeriod, uint16 lastPeriod, uint16 periods, uint128 lockedValue)\n    {\n        SubStakeInfo storage info = stakerInfo[_staker].subStakes[_index];\n        firstPeriod = info.firstPeriod;\n        lastPeriod = info.lastPeriod;\n        periods = info.periods;\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(address(delegateGet(_testTarget, this.policyManager.selector)) == address(policyManager));\n        require(address(delegateGet(_testTarget, this.adjudicator.selector)) == address(adjudicator));\n        require(address(delegateGet(_testTarget, this.workLock.selector)) == address(workLock));\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.lockReStakeUntilPeriod == info.lockReStakeUntilPeriod \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.periods == subStakeInfo.periods \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"},"WorkLock.sol":{"content":"// SPDX-License-Identifier: AGPL-3.0-or-later\n\npragma solidity ^0.7.0;\n\n\nimport \"./SafeMath.sol\";\nimport \"./SafeERC20.sol\";\nimport \"./Address.sol\";\nimport \"./Ownable.sol\";\nimport \"./NuCypherToken.sol\";\nimport \"./StakingEscrow.sol\";\nimport \"./AdditionalMath.sol\";\n\n\n/**\n* @notice The WorkLock distribution contract\n*/\ncontract WorkLock is Ownable {\n    using SafeERC20 for NuCypherToken;\n    using SafeMath for uint256;\n    using AdditionalMath for uint256;\n    using Address for address payable;\n    using Address for address;\n\n    event Deposited(address indexed sender, uint256 value);\n    event Bid(address indexed sender, uint256 depositedETH);\n    event Claimed(address indexed sender, uint256 claimedTokens);\n    event Refund(address indexed sender, uint256 refundETH, uint256 completedWork);\n    event Canceled(address indexed sender, uint256 value);\n    event BiddersChecked(address indexed sender, uint256 startIndex, uint256 endIndex);\n    event ForceRefund(address indexed sender, address indexed bidder, uint256 refundETH);\n    event CompensationWithdrawn(address indexed sender, uint256 value);\n    event Shutdown(address indexed sender);\n\n    struct WorkInfo {\n        uint256 depositedETH;\n        uint256 completedWork;\n        bool claimed;\n        uint128 index;\n    }\n\n    uint16 public constant SLOWING_REFUND = 100;\n    uint256 private constant MAX_ETH_SUPPLY = 2e10 ether;\n\n    NuCypherToken public immutable token;\n    StakingEscrow public immutable escrow;\n\n    /*\n    * @dev WorkLock calculations:\n    * bid = minBid + bonusETHPart\n    * bonusTokenSupply = tokenSupply - bidders.length * minAllowableLockedTokens\n    * bonusDepositRate = bonusTokenSupply / bonusETHSupply\n    * claimedTokens = minAllowableLockedTokens + bonusETHPart * bonusDepositRate\n    * bonusRefundRate = bonusDepositRate * SLOWING_REFUND / boostingRefund\n    * refundETH = completedWork / refundRate\n    */\n    uint256 public immutable boostingRefund;\n    uint256 public immutable minAllowedBid;\n    uint16 public immutable stakingPeriods;\n    // copy from the escrow contract\n    uint256 public immutable maxAllowableLockedTokens;\n    uint256 public immutable minAllowableLockedTokens;\n\n    uint256 public tokenSupply;\n    uint256 public startBidDate;\n    uint256 public endBidDate;\n    uint256 public endCancellationDate;\n\n    uint256 public bonusETHSupply;\n    mapping(address =\u003e WorkInfo) public workInfo;\n    mapping(address =\u003e uint256) public compensation;\n\n    address[] public bidders;\n    // if value == bidders.length then WorkLock is fully checked\n    uint256 public nextBidderToCheck;\n\n    /**\n    * @dev Checks timestamp regarding cancellation window\n    */\n    modifier afterCancellationWindow()\n    {\n        require(block.timestamp \u003e= endCancellationDate,\n            \"Operation is allowed when cancellation phase is over\");\n        _;\n    }\n\n    /**\n    * @param _token Token contract\n    * @param _escrow Escrow contract\n    * @param _startBidDate Timestamp when bidding starts\n    * @param _endBidDate Timestamp when bidding will end\n    * @param _endCancellationDate Timestamp when cancellation will ends\n    * @param _boostingRefund Coefficient to boost refund ETH\n    * @param _stakingPeriods Amount of periods during which tokens will be locked after claiming\n    * @param _minAllowedBid Minimum allowed ETH amount for bidding\n    */\n    constructor(\n        NuCypherToken _token,\n        StakingEscrow _escrow,\n        uint256 _startBidDate,\n        uint256 _endBidDate,\n        uint256 _endCancellationDate,\n        uint256 _boostingRefund,\n        uint16 _stakingPeriods,\n        uint256 _minAllowedBid\n    ) {\n        uint256 totalSupply = _token.totalSupply();\n        require(totalSupply \u003e 0 \u0026\u0026                              // token contract is deployed and accessible\n            _escrow.secondsPerPeriod() \u003e 0 \u0026\u0026                   // escrow contract is deployed and accessible\n            _escrow.token() == _token \u0026\u0026                        // same token address for worklock and escrow\n            _endBidDate \u003e _startBidDate \u0026\u0026                      // bidding period lasts some time\n            _endBidDate \u003e block.timestamp \u0026\u0026                    // there is time to make a bid\n            _endCancellationDate \u003e= _endBidDate \u0026\u0026              // cancellation window includes bidding\n            _minAllowedBid \u003e 0 \u0026\u0026                               // min allowed bid was set\n            _boostingRefund \u003e 0 \u0026\u0026                              // boosting coefficient was set\n            _stakingPeriods \u003e= _escrow.minLockedPeriods());     // staking duration is consistent with escrow contract\n        // worst case for `ethToWork()` and `workToETH()`,\n        // when ethSupply == MAX_ETH_SUPPLY and tokenSupply == totalSupply\n        require(MAX_ETH_SUPPLY * totalSupply * SLOWING_REFUND / MAX_ETH_SUPPLY / totalSupply == SLOWING_REFUND \u0026\u0026\n            MAX_ETH_SUPPLY * totalSupply * _boostingRefund / MAX_ETH_SUPPLY / totalSupply == _boostingRefund);\n\n        token = _token;\n        escrow = _escrow;\n        startBidDate = _startBidDate;\n        endBidDate = _endBidDate;\n        endCancellationDate = _endCancellationDate;\n        boostingRefund = _boostingRefund;\n        stakingPeriods = _stakingPeriods;\n        minAllowedBid = _minAllowedBid;\n        maxAllowableLockedTokens = _escrow.maxAllowableLockedTokens();\n        minAllowableLockedTokens = _escrow.minAllowableLockedTokens();\n    }\n\n    /**\n    * @notice Deposit tokens to contract\n    * @param _value Amount of tokens to transfer\n    */\n    function tokenDeposit(uint256 _value) external {\n        require(block.timestamp \u003c endBidDate, \"Can\u0027t deposit more tokens after end of bidding\");\n        token.safeTransferFrom(msg.sender, address(this), _value);\n        tokenSupply += _value;\n        emit Deposited(msg.sender, _value);\n    }\n\n    /**\n    * @notice Calculate amount of tokens that will be get for specified amount of ETH\n    * @dev This value will be fixed only after end of bidding\n    */\n    function ethToTokens(uint256 _ethAmount) public view returns (uint256) {\n        if (_ethAmount \u003c minAllowedBid) {\n            return 0;\n        }\n\n        // when all participants bid with the same minimum amount of eth\n        if (bonusETHSupply == 0) {\n            return tokenSupply / bidders.length;\n        }\n\n        uint256 bonusETH = _ethAmount - minAllowedBid;\n        uint256 bonusTokenSupply = tokenSupply - bidders.length * minAllowableLockedTokens;\n        return minAllowableLockedTokens + bonusETH.mul(bonusTokenSupply).div(bonusETHSupply);\n    }\n\n    /**\n    * @notice Calculate amount of work that need to be done to refund specified amount of ETH\n    */\n    function ethToWork(uint256 _ethAmount, uint256 _tokenSupply, uint256 _ethSupply)\n        internal view returns (uint256)\n    {\n        return _ethAmount.mul(_tokenSupply).mul(SLOWING_REFUND).divCeil(_ethSupply.mul(boostingRefund));\n    }\n\n    /**\n    * @notice Calculate amount of work that need to be done to refund specified amount of ETH\n    * @dev This value will be fixed only after end of bidding\n    * @param _ethToReclaim Specified sum of ETH staker wishes to reclaim following completion of work\n    * @param _restOfDepositedETH Remaining ETH in staker\u0027s deposit once ethToReclaim sum has been subtracted\n    * @dev _ethToReclaim + _restOfDepositedETH = depositedETH\n    */\n    function ethToWork(uint256 _ethToReclaim, uint256 _restOfDepositedETH) internal view returns (uint256) {\n\n        uint256 baseETHSupply = bidders.length * minAllowedBid;\n        // when all participants bid with the same minimum amount of eth\n        if (bonusETHSupply == 0) {\n            return ethToWork(_ethToReclaim, tokenSupply, baseETHSupply);\n        }\n\n        uint256 baseETH = 0;\n        uint256 bonusETH = 0;\n\n        // If the staker\u0027s total remaining deposit (including the specified sum of ETH to reclaim)\n        // is lower than the minimum bid size,\n        // then only the base part is used to calculate the work required to reclaim ETH\n        if (_ethToReclaim + _restOfDepositedETH \u003c= minAllowedBid) {\n            baseETH = _ethToReclaim;\n\n        // If the staker\u0027s remaining deposit (not including the specified sum of ETH to reclaim)\n        // is still greater than the minimum bid size,\n        // then only the bonus part is used to calculate the work required to reclaim ETH\n        } else if (_restOfDepositedETH \u003e= minAllowedBid) {\n            bonusETH = _ethToReclaim;\n\n        // If the staker\u0027s remaining deposit (not including the specified sum of ETH to reclaim)\n        // is lower than the minimum bid size,\n        // then both the base and bonus parts must be used to calculate the work required to reclaim ETH\n        } else {\n            bonusETH = _ethToReclaim + _restOfDepositedETH - minAllowedBid;\n            baseETH = _ethToReclaim - bonusETH;\n        }\n\n        uint256 baseTokenSupply = bidders.length * minAllowableLockedTokens;\n        uint256 work = 0;\n        if (baseETH \u003e 0) {\n            work = ethToWork(baseETH, baseTokenSupply, baseETHSupply);\n        }\n\n        if (bonusETH \u003e 0) {\n            uint256 bonusTokenSupply = tokenSupply - baseTokenSupply;\n            work += ethToWork(bonusETH, bonusTokenSupply, bonusETHSupply);\n        }\n\n        return work;\n    }\n\n    /**\n    * @notice Calculate amount of work that need to be done to refund specified amount of ETH\n    * @dev This value will be fixed only after end of bidding\n    */\n    function ethToWork(uint256 _ethAmount) public view returns (uint256) {\n        return ethToWork(_ethAmount, 0);\n    }\n\n    /**\n    * @notice Calculate amount of ETH that will be refund for completing specified amount of work\n    */\n    function workToETH(uint256 _completedWork, uint256 _ethSupply, uint256 _tokenSupply)\n        internal view returns (uint256)\n    {\n        return _completedWork.mul(_ethSupply).mul(boostingRefund).div(_tokenSupply.mul(SLOWING_REFUND));\n    }\n\n    /**\n    * @notice Calculate amount of ETH that will be refund for completing specified amount of work\n    * @dev This value will be fixed only after end of bidding\n    */\n    function workToETH(uint256 _completedWork, uint256 _depositedETH) public view returns (uint256) {\n        uint256 baseETHSupply = bidders.length * minAllowedBid;\n        // when all participants bid with the same minimum amount of eth\n        if (bonusETHSupply == 0) {\n            return workToETH(_completedWork, baseETHSupply, tokenSupply);\n        }\n\n        uint256 bonusWork = 0;\n        uint256 bonusETH = 0;\n        uint256 baseTokenSupply = bidders.length * minAllowableLockedTokens;\n\n        if (_depositedETH \u003e minAllowedBid) {\n            bonusETH = _depositedETH - minAllowedBid;\n            uint256 bonusTokenSupply = tokenSupply - baseTokenSupply;\n            bonusWork = ethToWork(bonusETH, bonusTokenSupply, bonusETHSupply);\n\n            if (_completedWork \u003c= bonusWork) {\n                return workToETH(_completedWork, bonusETHSupply, bonusTokenSupply);\n            }\n        }\n\n        _completedWork -= bonusWork;\n        return bonusETH + workToETH(_completedWork, baseETHSupply, baseTokenSupply);\n    }\n\n    /**\n    * @notice Get remaining work to full refund\n    */\n    function getRemainingWork(address _bidder) external view returns (uint256) {\n        WorkInfo storage info = workInfo[_bidder];\n        uint256 completedWork = escrow.getCompletedWork(_bidder).sub(info.completedWork);\n        uint256 remainingWork = ethToWork(info.depositedETH);\n        if (remainingWork \u003c= completedWork) {\n            return 0;\n        }\n        return remainingWork - completedWork;\n    }\n\n    /**\n    * @notice Get length of bidders array\n    */\n    function getBiddersLength() external view returns (uint256) {\n        return bidders.length;\n    }\n\n    /**\n    * @notice Bid for tokens by transferring ETH\n    */\n    function bid() external payable {\n        require(block.timestamp \u003e= startBidDate, \"Bidding is not open yet\");\n        require(block.timestamp \u003c endBidDate, \"Bidding is already finished\");\n        WorkInfo storage info = workInfo[msg.sender];\n\n        // first bid\n        if (info.depositedETH == 0) {\n            require(msg.value \u003e= minAllowedBid, \"Bid must be at least minimum\");\n            require(bidders.length \u003c tokenSupply / minAllowableLockedTokens, \"Not enough tokens for more bidders\");\n            info.index = uint128(bidders.length);\n            bidders.push(msg.sender);\n            bonusETHSupply = bonusETHSupply.add(msg.value - minAllowedBid);\n        } else {\n            bonusETHSupply = bonusETHSupply.add(msg.value);\n        }\n\n        info.depositedETH = info.depositedETH.add(msg.value);\n        emit Bid(msg.sender, msg.value);\n    }\n\n    /**\n    * @notice Cancel bid and refund deposited ETH\n    */\n    function cancelBid() external {\n        require(block.timestamp \u003c endCancellationDate,\n            \"Cancellation allowed only during cancellation window\");\n        WorkInfo storage info = workInfo[msg.sender];\n        require(info.depositedETH \u003e 0, \"No bid to cancel\");\n        require(!info.claimed, \"Tokens are already claimed\");\n        uint256 refundETH = info.depositedETH;\n        info.depositedETH = 0;\n\n        // remove from bidders array, move last bidder to the empty place\n        uint256 lastIndex = bidders.length - 1;\n        if (info.index != lastIndex) {\n            address lastBidder = bidders[lastIndex];\n            bidders[info.index] = lastBidder;\n            workInfo[lastBidder].index = info.index;\n        }\n        bidders.pop();\n\n        if (refundETH \u003e minAllowedBid) {\n            bonusETHSupply = bonusETHSupply.sub(refundETH - minAllowedBid);\n        }\n        msg.sender.sendValue(refundETH);\n        emit Canceled(msg.sender, refundETH);\n    }\n\n    /**\n    * @notice Cancels distribution, makes possible to retrieve all bids and owner gets all tokens\n    */\n    function shutdown() external onlyOwner {\n        require(!isClaimingAvailable(), \"Claiming has already been enabled\");\n        internalShutdown();\n    }\n\n    /**\n    * @notice Cancels distribution, makes possible to retrieve all bids and owner gets all tokens\n    */\n    function internalShutdown() internal {\n        startBidDate = 0;\n        endBidDate = 0;\n        endCancellationDate = uint256(0) - 1; // \"infinite\" cancellation window\n        token.safeTransfer(owner(), tokenSupply);\n        emit Shutdown(msg.sender);\n    }\n\n    /**\n    * @notice Make force refund to bidders who can get tokens more than maximum allowed\n    * @param _biddersForRefund Sorted list of unique bidders. Only bidders who must receive a refund\n    */\n    function forceRefund(address payable[] calldata _biddersForRefund) external afterCancellationWindow {\n        require(nextBidderToCheck != bidders.length, \"Bidders have already been checked\");\n\n        uint256 length = _biddersForRefund.length;\n        require(length \u003e 0, \"Must be at least one bidder for a refund\");\n\n        uint256 minNumberOfBidders = tokenSupply.divCeil(maxAllowableLockedTokens);\n        if (bidders.length \u003c minNumberOfBidders) {\n            internalShutdown();\n            return;\n        }\n\n        address previousBidder = _biddersForRefund[0];\n        uint256 minBid = workInfo[previousBidder].depositedETH;\n        uint256 maxBid = minBid;\n\n        // get minimum and maximum bids\n        for (uint256 i = 1; i \u003c length; i++) {\n            address bidder = _biddersForRefund[i];\n            uint256 depositedETH = workInfo[bidder].depositedETH;\n            require(bidder \u003e previousBidder \u0026\u0026 depositedETH \u003e 0, \"Addresses must be an array of unique bidders\");\n            if (minBid \u003e depositedETH) {\n                minBid = depositedETH;\n            } else if (maxBid \u003c depositedETH) {\n                maxBid = depositedETH;\n            }\n            previousBidder = bidder;\n        }\n\n        uint256[] memory refunds = new uint256[](length);\n        // first step - align at a minimum bid\n        if (minBid != maxBid) {\n            for (uint256 i = 0; i \u003c length; i++) {\n                address bidder = _biddersForRefund[i];\n                WorkInfo storage info = workInfo[bidder];\n                if (info.depositedETH \u003e minBid) {\n                    refunds[i] = info.depositedETH - minBid;\n                    info.depositedETH = minBid;\n                    bonusETHSupply -= refunds[i];\n                }\n            }\n        }\n\n        require(ethToTokens(minBid) \u003e maxAllowableLockedTokens,\n            \"At least one of bidders has allowable bid\");\n\n        // final bids adjustment (only for bonus part)\n        // (min_whale_bid * token_supply - max_stake * eth_supply) / (token_supply - max_stake * n_whales)\n        uint256 maxBonusTokens = maxAllowableLockedTokens - minAllowableLockedTokens;\n        uint256 minBonusETH = minBid - minAllowedBid;\n        uint256 bonusTokenSupply = tokenSupply - bidders.length * minAllowableLockedTokens;\n        uint256 refundETH = minBonusETH.mul(bonusTokenSupply)\n                                .sub(maxBonusTokens.mul(bonusETHSupply))\n                                .divCeil(bonusTokenSupply - maxBonusTokens.mul(length));\n        uint256 resultBid = minBid.sub(refundETH);\n        bonusETHSupply -= length * refundETH;\n        for (uint256 i = 0; i \u003c length; i++) {\n            address bidder = _biddersForRefund[i];\n            WorkInfo storage info = workInfo[bidder];\n            refunds[i] += refundETH;\n            info.depositedETH = resultBid;\n        }\n\n        // reset verification\n        nextBidderToCheck = 0;\n\n        // save a refund\n        for (uint256 i = 0; i \u003c length; i++) {\n            address bidder = _biddersForRefund[i];\n            compensation[bidder] += refunds[i];\n            emit ForceRefund(msg.sender, bidder, refunds[i]);\n        }\n\n    }\n\n    /**\n    * @notice Withdraw compensation after force refund\n    */\n    function withdrawCompensation() external {\n        uint256 refund = compensation[msg.sender];\n        require(refund \u003e 0, \"There is no compensation\");\n        compensation[msg.sender] = 0;\n        msg.sender.sendValue(refund);\n        emit CompensationWithdrawn(msg.sender, refund);\n    }\n\n    /**\n    * @notice Check that the claimed tokens are within `maxAllowableLockedTokens` for all participants,\n    * starting from the last point `nextBidderToCheck`\n    * @dev Method stops working when the remaining gas is less than `_gasToSaveState`\n    * and saves the state in `nextBidderToCheck`.\n    * If all bidders have been checked then `nextBidderToCheck` will be equal to the length of the bidders array\n    */\n    function verifyBiddingCorrectness(uint256 _gasToSaveState) external afterCancellationWindow returns (uint256) {\n        require(nextBidderToCheck != bidders.length, \"Bidders have already been checked\");\n\n        // all participants bid with the same minimum amount of eth\n        uint256 index = nextBidderToCheck;\n        if (bonusETHSupply == 0) {\n            require(tokenSupply / bidders.length \u003c= maxAllowableLockedTokens, \"Not enough bidders\");\n            index = bidders.length;\n        }\n\n        uint256 maxBonusTokens = maxAllowableLockedTokens - minAllowableLockedTokens;\n        uint256 bonusTokenSupply = tokenSupply - bidders.length * minAllowableLockedTokens;\n        uint256 maxBidFromMaxStake = minAllowedBid + maxBonusTokens.mul(bonusETHSupply).div(bonusTokenSupply);\n\n\n        while (index \u003c bidders.length \u0026\u0026 gasleft() \u003e _gasToSaveState) {\n            address bidder = bidders[index];\n            require(workInfo[bidder].depositedETH \u003c= maxBidFromMaxStake, \"Bid is greater than max allowable bid\");\n            index++;\n        }\n\n        if (index != nextBidderToCheck) {\n            emit BiddersChecked(msg.sender, nextBidderToCheck, index);\n            nextBidderToCheck = index;\n        }\n        return nextBidderToCheck;\n    }\n\n    /**\n    * @notice Checks if claiming available\n    */\n    function isClaimingAvailable() public view returns (bool) {\n        return block.timestamp \u003e= endCancellationDate \u0026\u0026\n            nextBidderToCheck == bidders.length;\n    }\n\n    /**\n    * @notice Claimed tokens will be deposited and locked as stake in the StakingEscrow contract.\n    */\n    function claim() external returns (uint256 claimedTokens) {\n        require(isClaimingAvailable(), \"Claiming has not been enabled yet\");\n        WorkInfo storage info = workInfo[msg.sender];\n        require(!info.claimed, \"Tokens are already claimed\");\n        claimedTokens = ethToTokens(info.depositedETH);\n        require(claimedTokens \u003e 0, \"Nothing to claim\");\n\n        info.claimed = true;\n        token.approve(address(escrow), claimedTokens);\n        escrow.depositFromWorkLock(msg.sender, claimedTokens, stakingPeriods);\n        info.completedWork = escrow.setWorkMeasurement(msg.sender, true);\n        emit Claimed(msg.sender, claimedTokens);\n    }\n\n    /**\n    * @notice Get available refund for bidder\n    */\n    function getAvailableRefund(address _bidder) public view returns (uint256) {\n        WorkInfo storage info = workInfo[_bidder];\n        // nothing to refund\n        if (info.depositedETH == 0) {\n            return 0;\n        }\n\n        uint256 currentWork = escrow.getCompletedWork(_bidder);\n        uint256 completedWork = currentWork.sub(info.completedWork);\n        // no work that has been completed since last refund\n        if (completedWork == 0) {\n            return 0;\n        }\n\n        uint256 refundETH = workToETH(completedWork, info.depositedETH);\n        if (refundETH \u003e info.depositedETH) {\n            refundETH = info.depositedETH;\n        }\n        return refundETH;\n    }\n\n    /**\n    * @notice Refund ETH for the completed work\n    */\n    function refund() external returns (uint256 refundETH) {\n        WorkInfo storage info = workInfo[msg.sender];\n        require(info.claimed, \"Tokens must be claimed before refund\");\n        refundETH = getAvailableRefund(msg.sender);\n        require(refundETH \u003e 0, \"Nothing to refund: there is no ETH to refund or no completed work\");\n\n        if (refundETH == info.depositedETH) {\n            escrow.setWorkMeasurement(msg.sender, false);\n        }\n        info.depositedETH = info.depositedETH.sub(refundETH);\n        // convert refund back to work to eliminate potential rounding errors\n        uint256 completedWork = ethToWork(refundETH, info.depositedETH);\n\n        info.completedWork = info.completedWork.add(completedWork);\n        emit Refund(msg.sender, refundETH, completedWork);\n        msg.sender.sendValue(refundETH);\n    }\n}\n"}}

        File 2 of 3: 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 3 of 3: 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* @notice Contract for calculation of issued tokens\n* @dev |v3.3.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    uint32 public immutable secondsPerPeriod;\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 _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 _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            _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        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    * @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}\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 register(address _node, uint16 _period) external;\n    function escrow() external view returns (address);\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 escrow() external view returns (address);\n}\n\n\n/**\n* @notice WorkLock interface\n*/\ninterface WorkLockInterface {\n    function escrow() external view returns (address);\n}\n\n\n/**\n* @notice Contract holds and locks stakers tokens.\n* Each staker that locks their tokens will receive some compensation\n* @dev |v5.5.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    event Deposited(address indexed staker, uint256 value, uint16 periods);\n    event Locked(address indexed staker, uint256 value, uint16 firstPeriod, uint16 periods);\n    event Divided(\n        address indexed staker,\n        uint256 oldValue,\n        uint16 lastPeriod,\n        uint256 newValue,\n        uint16 periods\n    );\n    event Merged(address indexed staker, uint256 value1, uint256 value2, uint16 lastPeriod);\n    event Prolonged(address indexed staker, uint256 value, uint16 lastPeriod, uint16 periods);\n    event Withdrawn(address indexed staker, uint256 value);\n    event CommitmentMade(address indexed staker, uint16 indexed period, uint256 value);\n    event Minted(address indexed staker, uint16 indexed period, uint256 value);\n    event Slashed(address indexed staker, uint256 penalty, address indexed investigator, uint256 reward);\n    event ReStakeSet(address indexed staker, bool reStake);\n    event ReStakeLocked(address indexed staker, uint16 lockUntilPeriod);\n    event WorkerBonded(address indexed staker, address indexed worker, uint16 indexed startPeriod);\n    event WorkMeasurementSet(address indexed staker, bool measureWork);\n    event WindDownSet(address indexed staker, bool windDown);\n    event SnapshotSet(address indexed staker, bool snapshotsEnabled);\n\n    struct SubStakeInfo {\n        uint16 firstPeriod;\n        uint16 lastPeriod;\n        uint16 periods;\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 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\n    uint16 public immutable minLockedPeriods;\n    uint16 public immutable minWorkerPeriods;\n    uint256 public immutable minAllowableLockedTokens;\n    uint256 public immutable maxAllowableLockedTokens;\n    bool public immutable isTestContract;\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) public lockedPerPeriod;\n    uint128[] public balanceHistory;\n\n    PolicyManagerInterface public policyManager;\n    AdjudicatorInterface public adjudicator;\n    WorkLockInterface public workLock;\n\n    /**\n    * @notice Constructor sets address of token contract and coefficients for minting\n    * @param _token Token contract\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    * @param _isTestContract True if contract is only for tests\n    */\n    constructor(\n        NuCypherToken _token,\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        bool _isTestContract\n    )\n        Issuer(\n            _token,\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        isTestContract = _isTestContract;\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);\n        _;\n    }\n\n    //------------------------Initialization------------------------\n    /**\n    * @notice Set policy manager address\n    */\n    function setPolicyManager(PolicyManagerInterface _policyManager) external onlyOwner {\n        // Policy manager can be set only once\n        require(address(policyManager) == address(0));\n        // This escrow must be the escrow for the new policy manager\n        require(_policyManager.escrow() == address(this));\n        policyManager = _policyManager;\n    }\n\n    /**\n    * @notice Set adjudicator address\n    */\n    function setAdjudicator(AdjudicatorInterface _adjudicator) external onlyOwner {\n        // Adjudicator can be set only once\n        require(address(adjudicator) == address(0));\n        // This escrow must be the escrow for the new adjudicator\n        require(_adjudicator.escrow() == address(this));\n        adjudicator = _adjudicator;\n    }\n\n    /**\n    * @notice Set worklock address\n    */\n    function setWorkLock(WorkLockInterface _workLock) external onlyOwner {\n        // WorkLock can be set only once\n        require(address(workLock) == address(0) || isTestContract);\n        // This escrow must be the escrow for the new worklock\n        require(_workLock.escrow() == address(this));\n        workLock = _workLock;\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        )\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    }\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.periods;\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 _periods Amount of periods that will be added to the current period\n    */\n    function getLockedTokens(address _staker, uint16 _periods)\n        external view returns (uint256 lockedValue)\n    {\n        StakerInfo storage info = stakerInfo[_staker];\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod.add16(_periods);\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() + _periods) period\n    * as well as stakers and their locked tokens\n    * @param _periods 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 _periods, uint256 _startIndex, uint256 _maxStakers)\n        external view returns (uint256 allLockedTokens, uint256[2][] memory activeStakers)\n    {\n        require(_periods \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(_periods);\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 Checks if `reStake` parameter is available for changing\n    * @param _staker Staker\n    */\n    function isReStakeLocked(address _staker) public view returns (bool) {\n        return getCurrentPeriod() \u003c stakerInfo[_staker].lockReStakeUntilPeriod;\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    * Only if this parameter is not locked\n    * @param _reStake Value for parameter\n    */\n    function setReStake(bool _reStake) external {\n        require(!isReStakeLocked(msg.sender));\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 Lock `reStake` parameter. Only if this parameter is not locked\n    * @param _lockReStakeUntilPeriod Can\u0027t change `reStake` value until this period\n    */\n    function lockReStake(uint16 _lockReStakeUntilPeriod) external {\n        require(!isReStakeLocked(msg.sender) \u0026\u0026\n            _lockReStakeUntilPeriod \u003e getCurrentPeriod());\n        stakerInfo[msg.sender].lockReStakeUntilPeriod = _lockReStakeUntilPeriod;\n        emit ReStakeLocked(msg.sender, _lockReStakeUntilPeriod);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function depositFromWorkLock(\n        address _staker,\n        uint256 _value,\n        uint16 _periods\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        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _periods);\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.periods = 1;\n                continue;\n            }\n            // this sub-stake is no longer affected by winding down parameter\n            if (subStake.lastPeriod != 0 || subStake.periods == 0) {\n                continue;\n            }\n\n            subStake.periods = _windDown ? subStake.periods - 1 : subStake.periods + 1;\n            if (subStake.periods == 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    /**\n    * @notice Batch deposit. Allowed only initial deposit for each staker\n    * @param _stakers Stakers\n    * @param _numberOfSubStakes Number of sub-stakes which belong to staker in _values and _periods arrays\n    * @param _values Amount of tokens to deposit for each staker\n    * @param _periods Amount of periods during which tokens will be locked for each staker\n    */\n    function batchDeposit(\n        address[] calldata _stakers,\n        uint256[] calldata _numberOfSubStakes,\n        uint256[] calldata _values,\n        uint16[] calldata _periods\n    )\n        external\n    {\n        uint256 subStakesLength = _values.length;\n        require(_stakers.length != 0 \u0026\u0026\n            _stakers.length == _numberOfSubStakes.length \u0026\u0026\n            subStakesLength \u003e= _stakers.length \u0026\u0026\n            _periods.length == subStakesLength);\n        uint16 previousPeriod = getCurrentPeriod() - 1;\n        uint16 nextPeriod = previousPeriod + 2;\n        uint256 sumValue = 0;\n\n        uint256 j = 0;\n        for (uint256 i = 0; i \u003c _stakers.length; i++) {\n            address staker = _stakers[i];\n            uint256 numberOfSubStakes = _numberOfSubStakes[i];\n            uint256 endIndex = j + numberOfSubStakes;\n            require(numberOfSubStakes \u003e 0 \u0026\u0026 subStakesLength \u003e= endIndex);\n            StakerInfo storage info = stakerInfo[staker];\n            require(info.subStakes.length == 0 \u0026\u0026 !info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX));\n            // A staker can\u0027t be a worker for another staker\n            require(stakerFromWorker[staker] == address(0));\n            stakers.push(staker);\n            policyManager.register(staker, previousPeriod);\n\n            for (; j \u003c endIndex; j++) {\n                uint256 value =  _values[j];\n                uint16 periods = _periods[j];\n                require(value \u003e= minAllowableLockedTokens \u0026\u0026 periods \u003e= minLockedPeriods);\n                info.value = info.value.add(value);\n                info.subStakes.push(SubStakeInfo(nextPeriod, 0, periods, uint128(value)));\n                sumValue = sumValue.add(value);\n                emit Deposited(staker, value, periods);\n                emit Locked(staker, value, nextPeriod, periods);\n            }\n            require(info.value \u003c= maxAllowableLockedTokens);\n            info.history.addSnapshot(info.value);\n        }\n        require(j == subStakesLength);\n        uint256 lastGlobalBalance = uint256(balanceHistory.lastValue());\n        balanceHistory.addSnapshot(lastGlobalBalance + sumValue);\n        token.safeTransferFrom(msg.sender, address(this), sumValue);\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 locked\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 _periods Amount of periods during which tokens will be locked\n    */\n    function deposit(address _staker, uint256 _value, uint16 _periods) external {\n        deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function deposit(address _staker, address _payer, uint256 _index, uint256 _value, uint16 _periods) 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) {\n            stakers.push(_staker);\n            policyManager.register(_staker, getCurrentPeriod() - 1);\n        }\n        token.safeTransferFrom(_payer, address(this), _value);\n        info.value += _value;\n        lock(_staker, _index, _value, _periods);\n\n        addSnapshot(info, int256(_value));\n        if (_index \u003e= MAX_SUB_STAKES) {\n            emit Deposited(_staker, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lockAndCreate(uint256 _value, uint16 _periods) external onlyStaker {\n        lock(msg.sender, MAX_SUB_STAKES, _value, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lock(address _staker, uint256 _index, uint256 _value, uint16 _periods) internal {\n        if (_index \u003c MAX_SUB_STAKES) {\n            require(_value \u003e 0);\n        } else {\n            require(_value \u003e= minAllowableLockedTokens \u0026\u0026 _periods \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, _periods);\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 _periods Amount of periods during which tokens will be locked\n    */\n    function lockAndCreate(\n        StakerInfo storage _info,\n        uint16 _nextPeriod,\n        address _staker,\n        uint256 _value,\n        uint16 _periods\n    )\n        internal\n    {\n        uint16 duration = _periods;\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, _periods);\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 _periods 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 _periods,\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.periods = _periods;\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, _periods, 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 _periods Amount of periods for extending sub stake\n    */\n    function divideStake(uint256 _index, uint256 _newValue, uint16 _periods) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        require(_newValue \u003e= minAllowableLockedTokens \u0026\u0026 _periods \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.periods.add16(_periods);\n        saveSubStake(info, subStake.firstPeriod, 0, requestedPeriods, _newValue);\n        emit Divided(msg.sender, oldValue, lastPeriod, _newValue, _periods);\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 _periods Amount of periods for extending sub stake\n    */\n    function prolongStake(uint256 _index, uint16 _periods) external onlyStaker {\n        StakerInfo storage info = stakerInfo[msg.sender];\n        // Incorrect parameters\n        require(_periods \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.periods = subStake.periods.add16(_periods);\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) + _periods \u003e= minLockedPeriods);\n        emit Locked(msg.sender, subStake.lockedValue, lastPeriod + 1, _periods);\n        emit Prolonged(msg.sender, subStake.lockedValue, lastPeriod, _periods);\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.periods = 0;\n        } else if (subStake1.firstPeriod \u003e subStake2.firstPeriod) {\n            subStake1.lockedValue += subStake2.lockedValue;\n            subStake2.lastPeriod = subStake1.firstPeriod - 1;\n            subStake2.periods = 0;\n        } else {\n            subStake2.lockedValue += subStake1.lockedValue;\n            subStake1.lastPeriod = subStake2.firstPeriod - 1;\n            subStake1.periods = 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.periods = lastSubStake.periods;\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        uint16 lastCommittedPeriod = getLastCommittedPeriod(staker);\n        (uint16 processedPeriod1, uint16 processedPeriod2) = mint(staker);\n        uint16 currentPeriod = getCurrentPeriod();\n        uint16 nextPeriod = currentPeriod + 1;\n\n        // the period has already been committed\n        if (info.nextCommittedPeriod == nextPeriod) {\n            return;\n        }\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 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.periods == 0) {\n                continue;\n            }\n            subStake.periods--;\n            if (subStake.periods == 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        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 (uint16 firstPeriod, uint16 lastPeriod, uint16 periods, uint128 lockedValue)\n    {\n        SubStakeInfo storage info = stakerInfo[_staker].subStakes[_index];\n        firstPeriod = info.firstPeriod;\n        lastPeriod = info.lastPeriod;\n        periods = info.periods;\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(address(delegateGet(_testTarget, this.policyManager.selector)) == address(policyManager));\n        require(address(delegateGet(_testTarget, this.adjudicator.selector)) == address(adjudicator));\n        require(address(delegateGet(_testTarget, this.workLock.selector)) == address(workLock));\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.lockReStakeUntilPeriod == info.lockReStakeUntilPeriod \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.periods == subStakeInfo.periods \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"}}