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