Draft of period extension

pull/2623/head
vzotova 2021-02-05 17:32:15 +03:00 committed by Kieran Prasch
parent c5816b7e95
commit b0a605ab25
19 changed files with 210 additions and 75 deletions

View File

@ -0,0 +1 @@
Period increasing and nodes migration in contracts

View File

@ -217,6 +217,7 @@ class BaseEconomics:
deploy_parameters = (
# Period
self.hours_per_period, # Former hours in single period
self.hours_per_period, # Hours in single period
# Coefficients
@ -461,6 +462,7 @@ class EconomicsFactory:
# Staking Escrow
staking_parameters = list(staking_agent.staking_parameters())
staking_parameters.pop(0) # FIXME
seconds_per_period = staking_parameters.pop(0)
staking_parameters.insert(6, seconds_per_period // 60 // 60) # hours_per_period
minting_coefficient = staking_parameters[0]

View File

@ -581,8 +581,8 @@ class StakingEscrowAgent(EthereumContractAgent):
@contract_api(CONTRACT_CALL)
def get_flags(self, staker_address: ChecksumAddress) -> StakerFlags:
flags: tuple = self.contract.functions.getFlags(staker_address).call()
wind_down_flag, restake_flag, measure_work_flag, snapshot_flag = flags
return StakerFlags(wind_down_flag, restake_flag, measure_work_flag, snapshot_flag)
wind_down_flag, restake_flag, measure_work_flag, snapshot_flag, migration_flag = flags
return StakerFlags(wind_down_flag, restake_flag, measure_work_flag, snapshot_flag, migration_flag)
@contract_api(CONTRACT_CALL)
def is_restaking(self, staker_address: ChecksumAddress) -> bool:
@ -620,8 +620,8 @@ class StakingEscrowAgent(EthereumContractAgent):
@contract_api(CONTRACT_CALL)
def is_taking_snapshots(self, staker_address: ChecksumAddress) -> bool:
_winddown_flag, _restake_flag, _measure_work_flag, snapshots_flag = self.get_flags(staker_address)
return snapshots_flag
flags = self.get_flags(staker_address)
return flags.snapshot_flag
@contract_api(TRANSACTION)
def set_snapshots(self, transacting_power: TransactingPower, activate: bool) -> TxReceipt:
@ -646,7 +646,8 @@ class StakingEscrowAgent(EthereumContractAgent):
parameter_signatures = (
# Period
'secondsPerPeriod', # Seconds in single period
'formerSecondsPerPeriod', # Former seconds in single period
'secondsPerPeriod', # Seconds in single period
# Coefficients
'mintingCoefficient', # Minting coefficient (d * k2)

View File

@ -598,17 +598,18 @@ class StakingEscrowDeployer(BaseContractDeployer, UpgradeableContractMixin, Owna
**overrides):
args = self.economics.staking_deployment_parameters
constructor_kwargs = {
"_hoursPerPeriod": args[0],
"_issuanceDecayCoefficient": args[1],
"_lockDurationCoefficient1": args[2],
"_lockDurationCoefficient2": args[3],
"_maximumRewardedPeriods": args[4],
"_firstPhaseTotalSupply": args[5],
"_firstPhaseMaxIssuance": args[6],
"_minLockedPeriods": args[7],
"_minAllowableLockedTokens": args[8],
"_maxAllowableLockedTokens": args[9],
"_minWorkerPeriods": args[10]
"_formerHoursPerPeriod": args[0],
"_hoursPerPeriod": args[1],
"_issuanceDecayCoefficient": args[2],
"_lockDurationCoefficient1": args[3],
"_lockDurationCoefficient2": args[4],
"_maximumRewardedPeriods": args[5],
"_firstPhaseTotalSupply": args[6],
"_firstPhaseMaxIssuance": args[7],
"_minLockedPeriods": args[8],
"_minAllowableLockedTokens": args[9],
"_maxAllowableLockedTokens": args[10],
"_minWorkerPeriods": args[11]
}
constructor_kwargs.update(overrides)
constructor_kwargs = {k: v for k, v in constructor_kwargs.items() if v is not None}

View File

@ -142,12 +142,14 @@ def merge_contract_outputs(*compiled_versions) -> VersionedContractOutputs:
except KeyError:
# New Version Entry
bytecode = contract_outputs['evm']['bytecode']['object']
for existing_version, existing_contract_outputs in versioned_outputs.items():
existing_bytecode = existing_contract_outputs['evm']['bytecode']['object']
if bytecode == existing_bytecode:
raise CompilationError(f"Two solidity sources compiled identical bytecode for version {version}. "
"Ensure the correct solidity paths are targeted for compilation.")
bytecode = METADATA_HASH_PATTERN.sub('', contract_outputs['evm']['bytecode']['object'])
if len(bytecode) > 0:
for existing_version, existing_contract_outputs in versioned_outputs.items():
existing_bytecode = METADATA_HASH_PATTERN.sub('', existing_contract_outputs['evm']['bytecode']['object'])
if bytecode == existing_bytecode:
raise CompilationError(
f"Two solidity sources compiled identical bytecode for versions {version} and {existing_version}. "
"Ensure the correct solidity paths are targeted for compilation.")
versioned_outputs[version] = contract_outputs
else:

View File

@ -13,7 +13,7 @@ import "zeppelin/token/ERC20/SafeERC20.sol";
/**
* @title Issuer
* @notice Contract for calculation of issued tokens
* @dev |v3.3.1|
* @dev |v3.4.1|
*/
abstract contract Issuer is Upgradeable {
using SafeERC20 for NuCypherToken;
@ -34,7 +34,10 @@ abstract contract Issuer is Upgradeable {
uint256 public immutable lockDurationCoefficient1;
// k2
uint256 public immutable lockDurationCoefficient2;
uint32 public immutable formerSecondsPerPeriod;
uint32 public immutable secondsPerPeriod;
// kmax
uint16 public immutable maximumRewardedPeriods;
@ -59,6 +62,7 @@ abstract contract Issuer is Upgradeable {
(totalSupply - currentSupply) / d * (lockedValue / totalLockedValue) * (k1 + min(allLockedPeriods, kmax)) / k2
if allLockedPeriods > maximumRewardedPeriods then allLockedPeriods = maximumRewardedPeriods
* @param _token Token contract
* @param _formerHoursPerPeriod Former size of period in hours
* @param _hoursPerPeriod Size of period in hours
* @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,
* only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.
@ -81,6 +85,7 @@ abstract contract Issuer is Upgradeable {
*/
constructor(
NuCypherToken _token,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -93,6 +98,8 @@ abstract contract Issuer is Upgradeable {
require(localTotalSupply > 0 &&
_issuanceDecayCoefficient != 0 &&
_hoursPerPeriod != 0 &&
_formerHoursPerPeriod != 0 &&
_formerHoursPerPeriod <= _hoursPerPeriod &&
_lockDurationCoefficient1 != 0 &&
_lockDurationCoefficient2 != 0 &&
_maximumRewardedPeriods != 0);
@ -117,6 +124,7 @@ abstract contract Issuer is Upgradeable {
token = _token;
secondsPerPeriod = _hoursPerPeriod.mul32(1 hours);
formerSecondsPerPeriod = _formerHoursPerPeriod.mul32(1 hours);
lockDurationCoefficient1 = _lockDurationCoefficient1;
lockDurationCoefficient2 = _lockDurationCoefficient2;
maximumRewardedPeriods = _maximumRewardedPeriods;
@ -142,6 +150,13 @@ abstract contract Issuer is Upgradeable {
return uint16(block.timestamp / secondsPerPeriod);
}
/**
* @return Recalculate period value using new basis
*/
function recalculatePeriod(uint16 _period) public view returns (uint16) { // TODO internal?
return uint16(uint256(_period) * formerSecondsPerPeriod / secondsPerPeriod);
}
/**
* @notice Initialize reserved tokens for reward
*/
@ -246,4 +261,13 @@ abstract contract Issuer is Upgradeable {
require(uint128(delegateGet(_testTarget, this.currentPeriodSupply.selector)) == currentPeriodSupply);
}
/// @dev the `onlyWhileUpgrading` modifier works through a call to the parent `finishUpgrade`
function finishUpgrade(address _target) public override virtual {
super.finishUpgrade(_target);
// recalculate currentMintingPeriod if needed
if (currentMintingPeriod > getCurrentPeriod()) {
currentMintingPeriod = recalculatePeriod(currentMintingPeriod); // TODO maybe extract to additional method?
}
}
}

View File

@ -17,7 +17,7 @@ import "contracts/proxy/Upgradeable.sol";
/**
* @title PolicyManager
* @notice Contract holds policy data and locks accrued policy fees
* @dev |v6.1.4|
* @dev |v6.2.1|
*/
contract PolicyManager is Upgradeable {
using SafeERC20 for NuCypherToken;
@ -109,6 +109,7 @@ contract PolicyManager is Upgradeable {
int256 public constant DEFAULT_FEE_DELTA = int256((uint256(0) - 1) >> 1);
StakingEscrow public immutable escrow;
uint32 public immutable formerSecondsPerPeriod;
uint32 public immutable secondsPerPeriod;
mapping (bytes16 => Policy) public policies;
@ -125,6 +126,9 @@ contract PolicyManager is Upgradeable {
require(localSecondsPerPeriod > 0);
secondsPerPeriod = localSecondsPerPeriod;
escrow = _escrow;
uint32 localFormerSecondsPerPeriod = _escrow.secondsPerPeriod();
require(localFormerSecondsPerPeriod > 0);
formerSecondsPerPeriod = localFormerSecondsPerPeriod;
}
/**
@ -143,6 +147,13 @@ contract PolicyManager is Upgradeable {
return uint16(block.timestamp / secondsPerPeriod);
}
/**
* @return Recalculate period value using new basis
*/
function recalculatePeriod(uint16 _period) internal view returns (uint16) {
return uint16(uint256(_period) * formerSecondsPerPeriod / secondsPerPeriod);
}
/**
* @notice Register a node
* @param _node Node address
@ -154,6 +165,16 @@ contract PolicyManager is Upgradeable {
nodeInfo.previousFeePeriod = _period;
}
/**
* @notice Migrate from the old period length to the new one
* @param _node Node address
*/
function migrate(address _node) external onlyEscrowContract {
NodeInfo storage nodeInfo = nodes[_node];
require(nodeInfo.previousFeePeriod >= getCurrentPeriod());
nodeInfo.previousFeePeriod = recalculatePeriod(nodeInfo.previousFeePeriod);
}
/**
* @notice Set minimum, default & maximum fee rate for all stakers and all policies ('global fee range')
*/

View File

@ -17,6 +17,7 @@ import "zeppelin/token/ERC20/SafeERC20.sol";
interface PolicyManagerInterface {
function secondsPerPeriod() external view returns (uint32);
function register(address _node, uint16 _period) external;
function migrate(address _node) external;
function ping(
address _node,
uint16 _processedPeriod1,
@ -98,7 +99,7 @@ contract StakingEscrowStub is Upgradeable {
* @title StakingEscrow
* @notice Contract holds and locks stakers tokens.
* Each staker that locks their tokens will receive some compensation
* @dev |v5.6.1|
* @dev |v5.7.1|
*/
contract StakingEscrow is Issuer, IERC900History {
@ -220,6 +221,7 @@ contract StakingEscrow is Issuer, IERC900History {
* @param snapshotsEnabled Updated parameter value
*/
event SnapshotSet(address indexed staker, bool snapshotsEnabled);
event Migrated(address indexed staker);
/// internal event
event WorkMeasurementSet(address indexed staker, bool measureWork);
@ -277,6 +279,7 @@ contract StakingEscrow is Issuer, IERC900History {
uint8 internal constant WIND_DOWN_INDEX = 1;
uint8 internal constant MEASURE_WORK_INDEX = 2;
uint8 internal constant SNAPSHOTS_DISABLED_INDEX = 3;
uint8 internal constant MIGRATED_INDEX = 4;
uint16 public immutable minLockedPeriods;
uint16 public immutable minWorkerPeriods;
@ -291,19 +294,22 @@ contract StakingEscrow is Issuer, IERC900History {
address[] public stakers;
mapping (address => address) public stakerFromWorker;
mapping (uint16 => uint256) public lockedPerPeriod;
mapping (uint16 => uint256) stub4; // former lockedPerPeriod
uint128[] public balanceHistory;
address stub1; // former slot for PolicyManager
address stub2; // former slot for Adjudicator
address stub3; // former slot for WorkLock
mapping (uint16 => uint256) public lockedPerPeriod; // TODO rename or make custom public getter to make verifyState() work
/**
* @notice Constructor sets address of token contract and coefficients for minting
* @param _token Token contract
* @param _policyManager Policy Manager contract
* @param _adjudicator Adjudicator contract
* @param _workLock WorkLock contract. Zero address if there is no WorkLock
* @param _formerHoursPerPeriod Former size of period in hours
* @param _hoursPerPeriod Size of period in hours
* @param _issuanceDecayCoefficient (d) Coefficient which modifies the rate at which the maximum issuance decays,
* only applicable to Phase 2. d = 365 * half-life / LOG2 where default half-life = 2.
@ -333,6 +339,7 @@ contract StakingEscrow is Issuer, IERC900History {
PolicyManagerInterface _policyManager,
AdjudicatorInterface _adjudicator,
WorkLockInterface _workLock,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -347,6 +354,7 @@ contract StakingEscrow is Issuer, IERC900History {
)
Issuer(
_token,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,
@ -377,7 +385,8 @@ contract StakingEscrow is Issuer, IERC900History {
modifier onlyStaker()
{
StakerInfo storage info = stakerInfo[msg.sender];
require(info.value > 0 || info.nextCommittedPeriod != 0);
require((info.value > 0 || info.nextCommittedPeriod != 0) &&
info.flags.bitSet(MIGRATED_INDEX));
_;
}
@ -397,7 +406,8 @@ contract StakingEscrow is Issuer, IERC900History {
bool windDown,
bool reStake,
bool measureWork,
bool snapshots
bool snapshots,
bool migrated
)
{
StakerInfo storage info = stakerInfo[_staker];
@ -405,6 +415,7 @@ contract StakingEscrow is Issuer, IERC900History {
reStake = !info.flags.bitSet(RE_STAKE_DISABLED_INDEX);
measureWork = info.flags.bitSet(MEASURE_WORK_INDEX);
snapshots = !info.flags.bitSet(SNAPSHOTS_DISABLED_INDEX);
migrated = !info.flags.bitSet(MIGRATED_INDEX);
}
/**
@ -656,6 +667,7 @@ contract StakingEscrow is Issuer, IERC900History {
info.flags = info.flags.toggleBit(WIND_DOWN_INDEX);
emit WindDownSet(_staker, true);
}
_periods = recalculatePeriod(_periods); // TODO rounding or ceiling
deposit(_staker, msg.sender, MAX_SUB_STAKES, _value, _periods);
}
@ -816,7 +828,9 @@ contract StakingEscrow is Issuer, IERC900History {
if (info.subStakes.length == 0) {
stakers.push(_staker);
policyManager.register(_staker, getCurrentPeriod() - 1);
info.flags = info.flags.toggleBit(MIGRATED_INDEX);
}
require(info.flags.bitSet(MIGRATED_INDEX));
token.safeTransferFrom(_payer, address(this), _value);
info.value += _value;
lock(_staker, _index, _value, _periods);
@ -1160,6 +1174,8 @@ contract StakingEscrow is Issuer, IERC900History {
// Only worker with real address can make a commitment
require(msg.sender == tx.origin);
migrate(staker);
uint16 currentPeriod = getCurrentPeriod();
uint16 nextPeriod = currentPeriod + 1;
// the period has already been committed
@ -1186,6 +1202,50 @@ contract StakingEscrow is Issuer, IERC900History {
emit CommitmentMade(staker, nextPeriod, lockedTokens);
}
/**
* @notice Migrate from the old period length to the new one
*/
// TODO docs
function migrate(address _staker) public {
StakerInfo storage info = stakerInfo[_staker];
// TODO allow only for staker
if (info.flags.bitSet(MIGRATED_INDEX)) {
return;
}
info.currentCommittedPeriod = 0;
info.nextCommittedPeriod = 0;
// info.lastCommittedPeriod = getCurrentPeriod(); // TODO not sure
info.lastCommittedPeriod = 0;
info.workerStartPeriod = recalculatePeriod(info.workerStartPeriod);
delete info.pastDowntime;
// if (info.pastDowntime.length > 0) { // TODO slippery way
// uint16 temp = info.pastDowntime[0].endPeriod;
// delete info.pastDowntime;
// info.pastDowntime.push(1, recalculatePeriod(temp));
// }
// TODO rounding or ceiling
for (uint256 i = 0; i < info.subStakes.length; i++) {
SubStakeInfo storage subStake = info.subStakes[i];
subStake.firstPeriod = recalculatePeriod(subStake.firstPeriod);
if (subStake.lastPeriod != 0) {
subStake.lastPeriod = recalculatePeriod(subStake.lastPeriod);
subStake.periods = 0;
} else {
subStake.periods = recalculatePeriod(subStake.periods);
// if (subStake.periods == 0) { // TODO not sure
// subStake.periods == 1;
// }
}
}
policyManager.migrate(_staker);
info.flags = info.flags.toggleBit(MIGRATED_INDEX);
emit Migrated(_staker);
}
/**
* @notice Decrease sub-stakes duration if `windDown` is enabled
*/
@ -1323,6 +1383,7 @@ contract StakingEscrow is Issuer, IERC900History {
require(msg.sender == address(adjudicator));
require(_penalty > 0);
StakerInfo storage info = stakerInfo[_staker];
require(info.flags.bitSet(MIGRATED_INDEX));
if (info.value <= _penalty) {
_penalty = info.value;
}

View File

@ -77,6 +77,7 @@ class StakerFlags(NamedTuple):
restake_flag: bool
measure_work_flag: bool
snapshot_flag: bool
migration_flag: bool
class StakerInfo(NamedTuple):

View File

@ -58,9 +58,10 @@ def test_deployment_parameters(staking_escrow_deployer,
staking_agent = ContractAgency.get_agent(StakingEscrowAgent, registry=test_registry)
params = staking_agent.staking_parameters()
assert token_economics.staking_deployment_parameters[2:] == params[2:]
assert token_economics.staking_deployment_parameters[1] == params[1] // params[3]
assert token_economics.staking_deployment_parameters[3:] == params[3:]
assert token_economics.staking_deployment_parameters[2] == params[2] // params[4]
assert token_economics.staking_deployment_parameters[0]*60*60 == params[0] # FIXME: Do we really want this?
assert token_economics.staking_deployment_parameters[1]*60*60 == params[1]
def test_staking_escrow_has_dispatcher(staking_escrow_deployer, testerchain, test_registry, transacting_power):

View File

@ -59,6 +59,7 @@ def test_issuer(testerchain, token, deploy_contract):
# Only token contract is allowed in Issuer constructor
bad_args = dict(_token=staker,
_formerHoursPerPeriod=economics.hours_per_period,
_hoursPerPeriod=economics.hours_per_period,
_issuanceDecayCoefficient=economics.issuance_decay_coefficient,
_lockDurationCoefficient1=economics.lock_duration_coefficient_1,
@ -210,6 +211,7 @@ def test_issuance_first_phase(testerchain, token, deploy_contract):
# Creator deploys the contract
issuer, _ = deploy_contract(contract_name='IssuerMock',
_token=token.address,
_formerHoursPerPeriod=economics.hours_per_period,
_hoursPerPeriod=economics.hours_per_period,
_issuanceDecayCoefficient=economics.issuance_decay_coefficient,
_lockDurationCoefficient1=economics.lock_duration_coefficient_1,
@ -313,6 +315,7 @@ def test_issuance_second_phase(testerchain, token, deploy_contract):
# Creator deploys the contract
issuer, _ = deploy_contract(contract_name='IssuerMock',
_token=token.address,
_formerHoursPerPeriod=economics.hours_per_period,
_hoursPerPeriod=economics.hours_per_period,
_issuanceDecayCoefficient=economics.issuance_decay_coefficient,
_lockDurationCoefficient1=economics.lock_duration_coefficient_1,
@ -392,6 +395,7 @@ def test_upgrading(testerchain, token, deploy_contract):
contract_library_v1, _ = deploy_contract(
contract_name='IssuerMock',
_token=token.address,
_formerHoursPerPeriod=1,
_hoursPerPeriod=1,
_issuanceDecayCoefficient=1,
_lockDurationCoefficient1=1,
@ -406,6 +410,7 @@ def test_upgrading(testerchain, token, deploy_contract):
contract_library_v2, _ = deploy_contract(
contract_name='IssuerV2Mock',
_token=token.address,
_formerHoursPerPeriod=2,
_hoursPerPeriod=2,
_issuanceDecayCoefficient=2,
_lockDurationCoefficient1=2,
@ -441,6 +446,7 @@ def test_upgrading(testerchain, token, deploy_contract):
assert contract_library_v2.address == dispatcher.functions.target().call()
assert 8 == contract.functions.mintingCoefficient().call()
assert 2 * 3600 == contract.functions.secondsPerPeriod().call()
assert 2 * 3600 == contract.functions.formerSecondsPerPeriod().call()
assert 2 == contract.functions.lockDurationCoefficient1().call()
assert 4 == contract.functions.lockDurationCoefficient2().call()
assert 2 == contract.functions.maximumRewardedPeriods().call()
@ -457,6 +463,7 @@ def test_upgrading(testerchain, token, deploy_contract):
contract_library_bad, _ = deploy_contract(
contract_name='IssuerBad',
_token=token.address,
_formerHoursPerPeriod=2,
_hoursPerPeriod=2,
_issuanceDecayCoefficient=2,
_lockDurationCoefficient1=2,
@ -479,6 +486,7 @@ def test_upgrading(testerchain, token, deploy_contract):
assert contract_library_v1.address == dispatcher.functions.target().call()
assert 2 == contract.functions.mintingCoefficient().call()
assert 3600 == contract.functions.secondsPerPeriod().call()
assert 3600 == contract.functions.formerSecondsPerPeriod().call()
assert 1 == contract.functions.lockDurationCoefficient1().call()
assert 2 == contract.functions.lockDurationCoefficient2().call()
assert 1 == contract.functions.maximumRewardedPeriods().call()

View File

@ -15,6 +15,7 @@ contract IssuerMock is Issuer {
constructor(
NuCypherToken _token,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -25,6 +26,7 @@ contract IssuerMock is Issuer {
)
Issuer(
_token,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,
@ -76,6 +78,7 @@ contract IssuerV2Mock is Issuer {
constructor(
NuCypherToken _token,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -86,6 +89,7 @@ contract IssuerV2Mock is Issuer {
)
Issuer(
_token,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,

View File

@ -17,6 +17,7 @@ contract EnhancedStakingEscrow is StakingEscrow {
PolicyManagerInterface _policyManager,
AdjudicatorInterface _adjudicator,
WorkLockInterface _workLock,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -34,6 +35,7 @@ contract EnhancedStakingEscrow is StakingEscrow {
_policyManager,
_adjudicator,
_workLock,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,
@ -77,6 +79,7 @@ contract StakingEscrowBad is StakingEscrow {
PolicyManagerInterface _policyManager,
AdjudicatorInterface _adjudicator,
WorkLockInterface _workLock,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -94,6 +97,7 @@ contract StakingEscrowBad is StakingEscrow {
_policyManager,
_adjudicator,
_workLock,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,
@ -126,6 +130,7 @@ contract StakingEscrowV2Mock is StakingEscrow {
PolicyManagerInterface _policyManager,
AdjudicatorInterface _adjudicator,
WorkLockInterface _workLock,
uint32 _formerHoursPerPeriod,
uint32 _hoursPerPeriod,
uint256 _issuanceDecayCoefficient,
uint256 _lockDurationCoefficient1,
@ -136,14 +141,14 @@ contract StakingEscrowV2Mock is StakingEscrow {
uint16 _minLockedPeriods,
uint256 _minAllowableLockedTokens,
uint256 _maxAllowableLockedTokens,
uint16 _minWorkerPeriods,
uint256 _valueToCheck
uint16 _minWorkerPeriods
)
StakingEscrow(
_token,
_policyManager,
_adjudicator,
_workLock,
_formerHoursPerPeriod,
_hoursPerPeriod,
_issuanceDecayCoefficient,
_lockDurationCoefficient1,
@ -157,7 +162,7 @@ contract StakingEscrowV2Mock is StakingEscrow {
_minWorkerPeriods
)
{
valueToCheck = _valueToCheck;
valueToCheck = _minWorkerPeriods;
}
function setValueToCheck(uint256 _valueToCheck) public {

View File

@ -354,7 +354,7 @@ def test_staking_before_initialization(testerchain,
testerchain.wait_for_receipt(tx)
# Set and lock re-stake parameter in first preallocation escrow
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(preallocation_escrow_1.address).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(preallocation_escrow_1.address).call()
assert re_stake
current_period = escrow.functions.getCurrentPeriod().call()
@ -558,7 +558,7 @@ def test_worklock_phases(testerchain,
tx = worklock.functions.claim().transact({'from': staker2, 'gas_price': 0})
testerchain.wait_for_receipt(tx)
assert worklock.functions.workInfo(staker2).call()[2]
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker2).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker2).call()
assert wind_down
assert token.functions.balanceOf(staker2).call() == 0
@ -576,7 +576,7 @@ def test_worklock_phases(testerchain,
pytest.escrow_supply += staker2_tokens
assert escrow.functions.getAllTokens(staker2).call() == staker2_tokens
assert escrow.functions.getCompletedWork(staker2).call() == 0
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker2).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker2).call()
assert wind_down
# Initialize escrow
@ -597,7 +597,7 @@ def test_worklock_phases(testerchain,
pytest.staker1_tokens += staker1_claims
assert escrow.functions.getLockedTokens(staker1, 1).call() == pytest.staker1_tokens
pytest.escrow_supply += staker1_claims
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert not wind_down
# Staker prolongs lock duration
@ -643,7 +643,7 @@ def test_staking_after_worklock(testerchain,
testerchain.wait_for_receipt(tx)
tx = escrow.functions.setWindDown(True).transact({'from': staker1})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert wind_down
tx = escrow.functions.commitToNextPeriod().transact({'from': staker1})
testerchain.wait_for_receipt(tx)
@ -701,7 +701,7 @@ def test_policy(testerchain,
testerchain.wait_for_receipt(tx)
tx = preallocation_escrow_interface_1.functions.setWindDown(True).transact({'from': staker3})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(preallocation_escrow_interface_1.address).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(preallocation_escrow_interface_1.address).call()
assert wind_down
tx = escrow.functions.commitToNextPeriod().transact({'from': staker3})
testerchain.wait_for_receipt(tx)
@ -1218,7 +1218,7 @@ def test_withdraw(testerchain,
# Now can turn off re-stake
tx = preallocation_escrow_interface_1.functions.setReStake(False).transact({'from': staker3})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(preallocation_escrow_1.address).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(preallocation_escrow_1.address).call()
assert not re_stake
tx = escrow.functions.mint().transact({'from': staker1})

View File

@ -81,8 +81,8 @@ def escrow_contract(testerchain,
deploy_parameters = list(token_economics.staking_deployment_parameters)
deploy_parameters[-2] = max_allowed_locked_tokens
if disable_reward:
deploy_parameters[5] = 0
deploy_parameters[6] = 0
deploy_parameters[7] = 0
contract, _ = deploy_contract('EnhancedStakingEscrow',
token.address,

View File

@ -1282,7 +1282,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
assert token.functions.balanceOf(escrow.address).call() == 0
# Can claim before initialization
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert not wind_down
current_period = escrow.functions.getCurrentPeriod().call()
tx = worklock.functions.depositFromWorkLock(staker1, value, duration).transact()
@ -1292,7 +1292,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
assert escrow.functions.getLockedTokens(staker1, 1).call() == value
assert escrow.functions.getLockedTokens(staker1, duration).call() == value
assert escrow.functions.getLockedTokens(staker1, duration + 1).call() == 0
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert wind_down
# Check that all events are emitted
@ -1328,7 +1328,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
tx = escrow.functions.initialize(0, creator).transact({'from': creator})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker2).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker2).call()
assert not wind_down
current_period = escrow.functions.getCurrentPeriod().call()
tx = worklock.functions.depositFromWorkLock(staker2, value, duration).transact()
@ -1338,7 +1338,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
assert escrow.functions.getLockedTokens(staker2, 1).call() == 2 * value
assert escrow.functions.getLockedTokens(staker2, duration).call() == 2 * value
assert escrow.functions.getLockedTokens(staker2, duration + 1).call() == 0
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker2).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker2).call()
assert not wind_down
# Check that all events are emitted
@ -1370,7 +1370,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
tx = escrow.functions.setWindDown(True).transact({'from': staker3})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker3).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker3).call()
assert wind_down
events = wind_down_log.get_all_entries()
assert len(events) == 2
@ -1383,7 +1383,7 @@ def test_staking_from_worklock(testerchain, token, worklock, escrow_contract, to
assert escrow.functions.getLockedTokens(staker3, 1).call() == 2 * value
assert escrow.functions.getLockedTokens(staker3, duration).call() == 2 * value
assert escrow.functions.getLockedTokens(staker3, duration + 1).call() == 0
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker3).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker3).call()
assert wind_down
# Check that all events are emitted

View File

@ -54,6 +54,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
contract_library_v2, _ = deploy_contract(
contract_name='StakingEscrowV2Mock',
_token=token.address,
_formerHoursPerPeriod=token_economics.hours_per_period,
_hoursPerPeriod=token_economics.hours_per_period,
_issuanceDecayCoefficient=2,
_lockDurationCoefficient1=2,
@ -67,8 +68,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
_minWorkerPeriods=2,
_policyManager=policy_manager.address,
_adjudicator=adjudicator.address,
_workLock=worklock.address,
_valueToCheck=2
_workLock=worklock.address
)
contract = testerchain.client.get_contract(
@ -127,6 +127,7 @@ def test_upgrading(testerchain, token, token_economics, deploy_contract):
contract_library_bad, _ = deploy_contract(
contract_name='StakingEscrowBad',
_token=token.address,
_formerHoursPerPeriod=token_economics.hours_per_period,
_hoursPerPeriod=token_economics.hours_per_period,
_issuanceDecayCoefficient=2,
_lockDurationCoefficient1=2,
@ -205,8 +206,8 @@ def test_flags(testerchain, token, escrow_contract):
testerchain.wait_for_receipt(tx)
# Check flag defaults
wind_down, re_stake, measure_work, snapshots = escrow.functions.getFlags(staker).call()
assert all((not wind_down, re_stake, not measure_work, snapshots))
wind_down, re_stake, measure_work, snapshots, migrated = escrow.functions.getFlags(staker).call()
assert all((not wind_down, re_stake, not measure_work, snapshots, migrated))
# There should be no events so far
assert 0 == len(wind_down_log.get_all_entries())
@ -220,8 +221,8 @@ def test_flags(testerchain, token, escrow_contract):
tx = escrow.functions.setSnapshots(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, re_stake, measure_work, snapshots = escrow.functions.getFlags(staker).call()
assert all((not wind_down, re_stake, not measure_work, snapshots))
wind_down, re_stake, measure_work, snapshots, migrated = escrow.functions.getFlags(staker).call()
assert all((not wind_down, re_stake, not measure_work, snapshots, migrated))
# There should be no events so far
assert 0 == len(wind_down_log.get_all_entries())
@ -233,8 +234,8 @@ def test_flags(testerchain, token, escrow_contract):
tx = escrow.functions.setReStake(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, re_stake, measure_work, snapshots = escrow.functions.getFlags(staker).call()
assert all((not wind_down, not re_stake, not measure_work, snapshots))
wind_down, re_stake, measure_work, snapshots, migrated = escrow.functions.getFlags(staker).call()
assert all((not wind_down, not re_stake, not measure_work, snapshots, migrated))
assert 0 == len(wind_down_log.get_all_entries())
assert 1 == len(restake_log.get_all_entries())
@ -249,8 +250,8 @@ def test_flags(testerchain, token, escrow_contract):
tx = escrow.functions.setSnapshots(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, re_stake, measure_work, snapshots = escrow.functions.getFlags(staker).call()
assert all((not wind_down, not re_stake, not measure_work, not snapshots))
wind_down, re_stake, measure_work, snapshots, migrated = escrow.functions.getFlags(staker).call()
assert all((not wind_down, not re_stake, not measure_work, not snapshots, migrated))
assert 0 == len(wind_down_log.get_all_entries())
assert 1 == len(restake_log.get_all_entries())
@ -278,23 +279,23 @@ def test_re_stake(testerchain, token, escrow_contract):
testerchain.wait_for_receipt(tx)
# Set re-stake parameter even before initialization
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert re_stake
tx = escrow.functions.setReStake(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not re_stake
tx = escrow.functions.setReStake(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert re_stake
tx = escrow.functions.setReStake(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert re_stake
tx = escrow.functions.setReStake(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not re_stake
events = re_stake_log.get_all_entries()
@ -354,7 +355,7 @@ def test_re_stake(testerchain, token, escrow_contract):
# Set re-stake
tx = escrow.functions.setReStake(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert re_stake
# Make a commitment and try to mint with re-stake
@ -474,7 +475,7 @@ def test_re_stake(testerchain, token, escrow_contract):
# Now turn off re-stake
tx = escrow.functions.setReStake(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not re_stake
events = re_stake_log.get_all_entries()
@ -890,19 +891,19 @@ def test_wind_down(testerchain, token, escrow_contract, token_economics):
check_last_period()
# Set wind-down parameter
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not wind_down
tx = escrow.functions.setWindDown(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not wind_down
tx = escrow.functions.setWindDown(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert wind_down
tx = escrow.functions.setWindDown(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert wind_down
check_events(wind_down=True, length=1)
@ -921,11 +922,11 @@ def test_wind_down(testerchain, token, escrow_contract, token_economics):
check_last_period()
# Turn off wind-down and make a commitment, duration will be the same
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert wind_down
tx = escrow.functions.setWindDown(False).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert not wind_down
check_events(wind_down=False, length=2)
@ -941,7 +942,7 @@ def test_wind_down(testerchain, token, escrow_contract, token_economics):
# Turn on wind-down and make a commitment, duration will be reduced in the next period
tx = escrow.functions.setWindDown(True).transact({'from': staker})
testerchain.wait_for_receipt(tx)
wind_down, _re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker).call()
wind_down, _re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker).call()
assert wind_down
check_events(wind_down=True, length=3)
@ -1146,7 +1147,7 @@ def test_snapshots(testerchain, token, escrow_contract):
return self.history == other.history and self.timestamps == other.timestamps
def staker_has_snapshots_enabled(staker) -> bool:
_, _, _, snapshots_enabled = escrow.functions.getFlags(staker).call()
_, _, _, snapshots_enabled, _ = escrow.functions.getFlags(staker).call()
return snapshots_enabled
def decode_snapshots_from_slot(slot):
@ -1235,11 +1236,11 @@ def test_snapshots(testerchain, token, escrow_contract):
assert event_args['snapshotsEnabled']
# Staker disables restaking, deposits some tokens and makes a commitment
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert re_stake
tx = escrow.functions.setReStake(False).transact({'from': staker1})
testerchain.wait_for_receipt(tx)
_wind_down, re_stake, _measure_work, _snapshots = escrow.functions.getFlags(staker1).call()
_wind_down, re_stake, _measure_work, _snapshots, _migrated = escrow.functions.getFlags(staker1).call()
assert not re_stake
tx = token.functions.transfer(staker1, 10000).transact({'from': creator})

View File

@ -91,7 +91,8 @@ CONSTRUCTOR_OVERRIDES = {
"_firstPhaseMaxIssuance": None,
"_miningCoefficient": 2,
"_lockedPeriodsCoefficient": 1,
"_rewardedPeriods": 1}
"_rewardedPeriods": 1},
"v5.7.1": {"_formerHoursPerPeriod": None}
}
}

View File

@ -89,6 +89,7 @@ def test_exact_economics():
# After sanity checking, assemble expected test deployment parameters
expected_deployment_parameters = (24, # Hours in single period
24, # Hours in single period
1053, # Coefficient which modifies the rate at which the maximum issuance decays (d)
365, # Numerator of the locking duration coefficient (k1)
730, # Denominator of the locking duration coefficient (k2)