Transaction Hash:
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 | ||
---|---|---|---|---|---|
0xbbD3C0C7...6fcfCb2e2 | (NuCypher: StakingEscrow) | ||||
0xD224cA0c...503B79f53
Miner
| (UUPool) | 489.407230137745978501 Eth | 489.41586076386477174 Eth | 0.008630626118793239 | |
0xE2A82cdc...4Bd41FBEC |
826.032025272785980846 Eth
Nonce: 168
|
1,338.023394646667187607 Eth
Nonce: 169
| 511.991369373881206761 | ||
0xe9778E69...1d34667c2 | (NuCypher: WorkLock) | 22,900.221470220195492317 Eth | 22,388.221470220195492317 Eth | 512 |
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
File 2 of 3: Dispatcher
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"},"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"}}