Merge pull request #2188 from 0xProject/feature/staking/remove-ref-counting
Remove reference counting for cumulative rewards
This commit is contained in:
commit
b65fd06e95
@ -61,6 +61,14 @@
|
||||
{
|
||||
"note": "Introduce multi-block finalization.",
|
||||
"pr": 2155
|
||||
},
|
||||
{
|
||||
"note": "Removed reference counting for cumulative rewards.",
|
||||
"pr": 2188
|
||||
},
|
||||
{
|
||||
"note": "Removed explicit dependency on epoch+1 when delegating.",
|
||||
"pr": 2188
|
||||
}
|
||||
]
|
||||
}
|
||||
|
@ -261,14 +261,6 @@ contract Staking is
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
_cumulativeRewardsByPoolReferenceCounter_slot,
|
||||
_cumulativeRewardsByPoolReferenceCounter_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
_cumulativeRewardsByPoolLastStored_slot,
|
||||
_cumulativeRewardsByPoolLastStored_offset,
|
||||
|
@ -94,9 +94,6 @@ contract MixinStorage is
|
||||
// mapping from Pool Id to Epoch to Reward Ratio
|
||||
mapping (bytes32 => mapping (uint256 => IStructs.Fraction)) internal _cumulativeRewardsByPool;
|
||||
|
||||
// mapping from Pool Id to Epoch to Cumulative Rewards Reference Counter
|
||||
mapping (bytes32 => mapping (uint256 => uint256)) internal _cumulativeRewardsByPoolReferenceCounter;
|
||||
|
||||
// mapping from Pool Id to Epoch
|
||||
mapping (bytes32 => uint256) internal _cumulativeRewardsByPoolLastStored;
|
||||
|
||||
|
@ -63,30 +63,6 @@ contract MixinCumulativeRewards is
|
||||
return cumulativeReward.denominator != 0;
|
||||
}
|
||||
|
||||
/// @dev Returns true iff the cumulative reward for `poolId` at `epoch` can
|
||||
/// be unset.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of the cumulative reward.
|
||||
function _canUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
view
|
||||
returns (bool)
|
||||
{
|
||||
// Must be a value to unset
|
||||
if (!_isCumulativeRewardSet(_cumulativeRewardsByPool[poolId][epoch])) {
|
||||
return false;
|
||||
}
|
||||
// Must be no references to this CR
|
||||
if (_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] != 0) {
|
||||
return false;
|
||||
}
|
||||
// Must not be the most recently *stored* CR.
|
||||
if (_cumulativeRewardsByPoolLastStored[poolId] == epoch) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/// @dev Tries to set a cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch of cumulative reward.
|
||||
@ -129,27 +105,6 @@ contract MixinCumulativeRewards is
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Tries to unset the cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of cumulative reward to unset.
|
||||
function _tryUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
if (!_canUnsetCumulativeReward(poolId, epoch)) {
|
||||
return;
|
||||
}
|
||||
_forceUnsetCumulativeReward(poolId, epoch);
|
||||
}
|
||||
|
||||
/// @dev Unsets the cumulative reward for `poolId` at `epoch`.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param epoch Epoch of cumulative reward to unset.
|
||||
function _forceUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
delete _cumulativeRewardsByPool[poolId][epoch];
|
||||
}
|
||||
|
||||
/// @dev Tries to set the epoch of the most recent cumulative reward.
|
||||
/// The value will only be set if the input epoch is greater than the
|
||||
/// current most recent value.
|
||||
@ -191,37 +146,6 @@ contract MixinCumulativeRewards is
|
||||
// Sanity check that we're not trying to go back in time
|
||||
assert(newMostRecentEpoch >= currentMostRecentEpoch);
|
||||
_cumulativeRewardsByPoolLastStored[poolId] = newMostRecentEpoch;
|
||||
|
||||
// Unset the previous most recent reward, if it is no longer needed
|
||||
_tryUnsetCumulativeReward(poolId, currentMostRecentEpoch);
|
||||
}
|
||||
|
||||
/// @dev Adds a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
/// @param mostRecentCumulativeReward The most recent cumulative reward.
|
||||
/// @param isDependent True iff there is a dependency on the cumulative
|
||||
/// reward for `poolId` at `epoch`
|
||||
function _addOrRemoveDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch,
|
||||
IStructs.Fraction memory mostRecentCumulativeReward,
|
||||
bool isDependent
|
||||
)
|
||||
internal
|
||||
{
|
||||
if (isDependent) {
|
||||
_addDependencyOnCumulativeReward(
|
||||
poolId,
|
||||
epoch,
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
} else {
|
||||
_removeDependencyOnCumulativeReward(
|
||||
poolId,
|
||||
epoch
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Computes a member's reward over a given epoch interval.
|
||||
@ -241,22 +165,22 @@ contract MixinCumulativeRewards is
|
||||
view
|
||||
returns (uint256 reward)
|
||||
{
|
||||
if (memberStakeOverInterval == 0) {
|
||||
// Sanity check if we can skip computation, as it will result in zero.
|
||||
if (memberStakeOverInterval == 0 || beginEpoch == endEpoch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Sanity check interval
|
||||
require(beginEpoch <= endEpoch, "CR_INTERVAL_INVALID");
|
||||
require(beginEpoch < endEpoch, "CR_INTERVAL_INVALID");
|
||||
|
||||
// Sanity check begin reward
|
||||
IStructs.Fraction memory beginReward =
|
||||
_cumulativeRewardsByPool[poolId][beginEpoch];
|
||||
require(_isCumulativeRewardSet(beginReward), "CR_INTERVAL_INVALID_BEGIN");
|
||||
(IStructs.Fraction memory beginReward, uint256 beginRewardStoredAt) = _getCumulativeRewardAtEpoch(poolId, beginEpoch);
|
||||
(IStructs.Fraction memory endReward, uint256 endRewardStoredAt) = _getCumulativeRewardAtEpoch(poolId, endEpoch);
|
||||
|
||||
// Sanity check end reward
|
||||
IStructs.Fraction memory endReward =
|
||||
_cumulativeRewardsByPool[poolId][endEpoch];
|
||||
require(_isCumulativeRewardSet(endReward), "CR_INTERVAL_INVALID_END");
|
||||
// If the rewards were stored at the same epoch then the computation will result in zero.
|
||||
if (beginRewardStoredAt == endRewardStoredAt) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compute reward
|
||||
reward = LibFractions.scaleDifference(
|
||||
@ -280,43 +204,44 @@ contract MixinCumulativeRewards is
|
||||
return _cumulativeRewardsByPool[poolId][lastStoredEpoch];
|
||||
}
|
||||
|
||||
/// @dev Adds a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
/// @param mostRecentCumulativeReward The most recent cumulative reward.
|
||||
function _addDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch,
|
||||
IStructs.Fraction memory mostRecentCumulativeReward
|
||||
/// @dev Fetch the cumulative reward for a given epoch.
|
||||
/// If the corresponding CR does not exist in state, then we backtrack
|
||||
/// to find its value by querying `epoch-1` and then most recent CR.
|
||||
/// @param poolId Unique ID of pool.
|
||||
/// @param epoch The epoch to find the
|
||||
/// @return cumulativeReward The cumulative reward for `poolId` at `epoch`.
|
||||
/// @return cumulativeRewardStoredAt Epoch that the `cumulativeReward` is stored at.
|
||||
function _getCumulativeRewardAtEpoch(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
view
|
||||
returns (
|
||||
IStructs.Fraction memory cumulativeReward,
|
||||
uint256 cumulativeRewardStoredAt
|
||||
)
|
||||
private
|
||||
{
|
||||
// Add dependency by increasing the reference counter
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] =
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch].safeAdd(1);
|
||||
|
||||
// Set CR to most recent reward (if it is not already set)
|
||||
_trySetCumulativeReward(
|
||||
poolId,
|
||||
epoch,
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
// Return CR at `epoch`, given it's set.
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][epoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return (cumulativeReward, epoch);
|
||||
}
|
||||
|
||||
/// @dev Removes a dependency on a cumulative reward for a given epoch.
|
||||
/// @param poolId Unique Id of pool.
|
||||
/// @param epoch Epoch to remove dependency from.
|
||||
function _removeDependencyOnCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
)
|
||||
private
|
||||
{
|
||||
// Remove dependency by decreasing reference counter
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch] =
|
||||
_cumulativeRewardsByPoolReferenceCounter[poolId][epoch].safeSub(1);
|
||||
// Return CR at `epoch-1`, given it's set.
|
||||
uint256 lastEpoch = epoch.safeSub(1);
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][lastEpoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return (cumulativeReward, lastEpoch);
|
||||
}
|
||||
|
||||
// Clear cumulative reward from state, if it is no longer needed
|
||||
_tryUnsetCumulativeReward(poolId, epoch);
|
||||
// Return the most recent CR, given it's less than `epoch`.
|
||||
uint256 mostRecentEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
if (mostRecentEpoch < epoch) {
|
||||
cumulativeReward = _cumulativeRewardsByPool[poolId][mostRecentEpoch];
|
||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
||||
return (cumulativeReward, mostRecentEpoch);
|
||||
}
|
||||
}
|
||||
|
||||
// Could not find a CR for `epoch`
|
||||
revert("CR_INVALID_EPOCH");
|
||||
}
|
||||
}
|
||||
|
@ -116,7 +116,6 @@ contract MixinStakingPoolRewards is
|
||||
return _computeDelegatorReward(
|
||||
poolId,
|
||||
_loadUnsyncedBalance(_delegatedStakeToPoolByOwner[member][poolId]),
|
||||
currentEpoch,
|
||||
unfinalizedMembersReward,
|
||||
unfinalizedMembersStake
|
||||
);
|
||||
@ -144,24 +143,14 @@ contract MixinStakingPoolRewards is
|
||||
_finalizePoolAndWithdrawDelegatorRewards(
|
||||
poolId,
|
||||
member,
|
||||
initialDelegatedStakeToPoolByOwner,
|
||||
currentEpoch
|
||||
initialDelegatedStakeToPoolByOwner
|
||||
);
|
||||
|
||||
// Add dependencies on cumulative rewards for this epoch and the next
|
||||
// epoch, if necessary.
|
||||
_setCumulativeRewardDependenciesForDelegator(
|
||||
poolId,
|
||||
finalDelegatedStakeToPoolByOwner,
|
||||
true
|
||||
);
|
||||
|
||||
// Remove dependencies on previous cumulative rewards, if they are no
|
||||
// longer needed.
|
||||
_setCumulativeRewardDependenciesForDelegator(
|
||||
poolId,
|
||||
initialDelegatedStakeToPoolByOwner,
|
||||
false
|
||||
finalDelegatedStakeToPoolByOwner
|
||||
);
|
||||
}
|
||||
|
||||
@ -270,8 +259,7 @@ contract MixinStakingPoolRewards is
|
||||
function _finalizePoolAndWithdrawDelegatorRewards(
|
||||
bytes32 poolId,
|
||||
address member,
|
||||
IStructs.StoredBalance memory unsyncedStake,
|
||||
uint256 currentEpoch
|
||||
IStructs.StoredBalance memory unsyncedStake
|
||||
)
|
||||
private
|
||||
{
|
||||
@ -282,7 +270,6 @@ contract MixinStakingPoolRewards is
|
||||
uint256 balance = _computeDelegatorReward(
|
||||
poolId,
|
||||
unsyncedStake,
|
||||
currentEpoch,
|
||||
// No unfinalized values because we ensured the pool is already
|
||||
// finalized.
|
||||
0,
|
||||
@ -302,15 +289,12 @@ contract MixinStakingPoolRewards is
|
||||
/// @dev Computes the reward balance in ETH of a specific member of a pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param unsyncedStake Unsynced delegated stake to pool by owner
|
||||
/// @param currentEpoch The epoch in which this call is executing
|
||||
/// @param unfinalizedMembersReward Unfinalized total members reward
|
||||
/// (if any).
|
||||
/// @param unfinalizedMembersReward Unfinalized total members reward (if any).
|
||||
/// @param unfinalizedMembersStake Unfinalized total members stake (if any).
|
||||
/// @return totalReward Balance in ETH.
|
||||
/// @return reward Balance in WETH.
|
||||
function _computeDelegatorReward(
|
||||
bytes32 poolId,
|
||||
IStructs.StoredBalance memory unsyncedStake,
|
||||
uint256 currentEpoch,
|
||||
uint256 unfinalizedMembersReward,
|
||||
uint256 unfinalizedMembersStake
|
||||
)
|
||||
@ -320,113 +304,122 @@ contract MixinStakingPoolRewards is
|
||||
{
|
||||
// There can be no rewards in epoch 0 because there is no delegated
|
||||
// stake.
|
||||
if (currentEpoch == 0) {
|
||||
uint256 _currentEpoch = currentEpoch;
|
||||
if (_currentEpoch == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// There can be no rewards if the last epoch when stake was synced is
|
||||
// equal to the current epoch, because all prior rewards, including
|
||||
// rewards finalized this epoch have been claimed.
|
||||
if (unsyncedStake.currentEpoch == currentEpoch) {
|
||||
if (unsyncedStake.currentEpoch == _currentEpoch) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// If there are unfinalized rewards this epoch, compute the member's
|
||||
// share.
|
||||
if (unfinalizedMembersReward != 0 && unfinalizedMembersStake != 0) {
|
||||
// Unfinalized rewards are always earned from stake in
|
||||
// the prior epoch so we want the stake at `currentEpoch-1`.
|
||||
uint256 _stake = unsyncedStake.currentEpoch >= currentEpoch.safeSub(1) ?
|
||||
unsyncedStake.currentEpochBalance :
|
||||
unsyncedStake.nextEpochBalance;
|
||||
if (_stake != 0) {
|
||||
reward = LibMath.getPartialAmountFloor(
|
||||
// We account for rewards over 3 intervals, below.
|
||||
|
||||
// 1/3 Unfinalized rewards earned in `currentEpoch - 1`.
|
||||
reward = _computeUnfinalizedDelegatorReward(
|
||||
unsyncedStake,
|
||||
_currentEpoch,
|
||||
unfinalizedMembersReward,
|
||||
unfinalizedMembersStake,
|
||||
_stake
|
||||
unfinalizedMembersStake
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Get the last epoch where a reward was credited to this pool, which
|
||||
// also happens to be when we last created a cumulative reward entry.
|
||||
uint256 lastRewardEpoch = _cumulativeRewardsByPoolLastStored[poolId];
|
||||
|
||||
// If the stake has been touched since the last reward epoch,
|
||||
// it has already been claimed.
|
||||
if (unsyncedStake.currentEpoch >= lastRewardEpoch) {
|
||||
return reward;
|
||||
}
|
||||
// From here we know: `unsyncedStake.currentEpoch < currentEpoch > 0`.
|
||||
|
||||
uint256 nextStakeEpoch = uint256(unsyncedStake.currentEpoch).safeAdd(1);
|
||||
// 2/3 Finalized rewards earned in epochs [`unsyncedStake.currentEpoch + 1` .. `currentEpoch - 1`]
|
||||
uint256 unsyncedStakeNextEpoch = uint256(unsyncedStake.currentEpoch).safeAdd(1);
|
||||
reward = reward.safeAdd(
|
||||
_computeMemberRewardOverInterval(
|
||||
poolId,
|
||||
unsyncedStake.currentEpochBalance,
|
||||
unsyncedStake.currentEpoch,
|
||||
nextStakeEpoch
|
||||
unsyncedStakeNextEpoch
|
||||
)
|
||||
);
|
||||
if (nextStakeEpoch < lastRewardEpoch) {
|
||||
|
||||
// 3/3 Finalized rewards earned in epoch `unsyncedStake.currentEpoch`.
|
||||
reward = reward.safeAdd(
|
||||
_computeMemberRewardOverInterval(
|
||||
poolId,
|
||||
unsyncedStake.nextEpochBalance,
|
||||
nextStakeEpoch,
|
||||
lastRewardEpoch
|
||||
unsyncedStakeNextEpoch,
|
||||
_currentEpoch
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
return reward;
|
||||
}
|
||||
|
||||
/// @dev Computes the unfinalized rewards earned by a delegator in the last epoch.
|
||||
/// @param unsyncedStake Unsynced delegated stake to pool by owner
|
||||
/// @param currentEpoch The epoch in which this call is executing
|
||||
/// @param unfinalizedMembersReward Unfinalized total members reward (if any).
|
||||
/// @param unfinalizedMembersStake Unfinalized total members stake (if any).
|
||||
/// @return reward Balance in WETH.
|
||||
function _computeUnfinalizedDelegatorReward(
|
||||
IStructs.StoredBalance memory unsyncedStake,
|
||||
uint256 currentEpoch,
|
||||
uint256 unfinalizedMembersReward,
|
||||
uint256 unfinalizedMembersStake
|
||||
)
|
||||
private
|
||||
view
|
||||
returns (uint256)
|
||||
{
|
||||
// If there are unfinalized rewards this epoch, compute the member's
|
||||
// share.
|
||||
if (unfinalizedMembersReward == 0 || unfinalizedMembersStake == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Unfinalized rewards are always earned from stake in
|
||||
// the prior epoch so we want the stake at `currentEpoch-1`.
|
||||
uint256 unfinalizedStakeBalance = unsyncedStake.currentEpoch >= currentEpoch.safeSub(1) ?
|
||||
unsyncedStake.currentEpochBalance :
|
||||
unsyncedStake.nextEpochBalance;
|
||||
|
||||
// Sanity check to save gas on computation
|
||||
if (unfinalizedStakeBalance == 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Compute unfinalized reward
|
||||
return LibMath.getPartialAmountFloor(
|
||||
unfinalizedMembersReward,
|
||||
unfinalizedMembersStake,
|
||||
unfinalizedStakeBalance
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Adds or removes cumulative reward dependencies for a delegator.
|
||||
/// A delegator always depends on the cumulative reward for the current
|
||||
/// and next epoch, if they would still have stake in the next epoch.
|
||||
/// @param poolId Unique id of pool.
|
||||
/// @param _delegatedStakeToPoolByOwner Amount of stake the member has
|
||||
/// delegated to the pool.
|
||||
/// @param isDependent is true iff adding a dependency. False, otherwise.
|
||||
function _setCumulativeRewardDependenciesForDelegator(
|
||||
bytes32 poolId,
|
||||
IStructs.StoredBalance memory _delegatedStakeToPoolByOwner,
|
||||
bool isDependent
|
||||
IStructs.StoredBalance memory _delegatedStakeToPoolByOwner
|
||||
)
|
||||
private
|
||||
{
|
||||
// If this delegator is not yet initialized then there's no dependency
|
||||
// to unset.
|
||||
if (!isDependent && !_delegatedStakeToPoolByOwner.isInitialized) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the most recent cumulative reward, which will serve as a
|
||||
// reference point when updating dependencies
|
||||
IStructs.Fraction memory mostRecentCumulativeReward = _getMostRecentCumulativeReward(poolId);
|
||||
|
||||
// Record dependency on current epoch.
|
||||
if (_delegatedStakeToPoolByOwner.currentEpochBalance != 0
|
||||
|| _delegatedStakeToPoolByOwner.nextEpochBalance != 0)
|
||||
{
|
||||
_addOrRemoveDependencyOnCumulativeReward(
|
||||
poolId,
|
||||
_delegatedStakeToPoolByOwner.currentEpoch,
|
||||
mostRecentCumulativeReward,
|
||||
isDependent
|
||||
);
|
||||
// The delegator depends on the Cumulative Reward for this epoch
|
||||
// only if they are currently staked or will be staked next epoch.
|
||||
if (_delegatedStakeToPoolByOwner.currentEpochBalance == 0 && _delegatedStakeToPoolByOwner.nextEpochBalance == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Record dependency on the next epoch
|
||||
if (_delegatedStakeToPoolByOwner.nextEpochBalance != 0) {
|
||||
_addOrRemoveDependencyOnCumulativeReward(
|
||||
// Delegator depends on the Cumulative Reward for this epoch - ensure it is set.
|
||||
_trySetCumulativeReward(
|
||||
poolId,
|
||||
uint256(_delegatedStakeToPoolByOwner.currentEpoch).safeAdd(1),
|
||||
mostRecentCumulativeReward,
|
||||
isDependent
|
||||
_delegatedStakeToPoolByOwner.currentEpoch,
|
||||
mostRecentCumulativeReward
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Increments rewards for a pool.
|
||||
/// @param poolId Unique id of pool.
|
||||
|
@ -30,11 +30,6 @@ contract TestCumulativeRewardTracking is
|
||||
uint256 epoch
|
||||
);
|
||||
|
||||
event UnsetCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
);
|
||||
|
||||
event SetMostRecentCumulativeReward(
|
||||
bytes32 poolId,
|
||||
uint256 epoch
|
||||
@ -59,13 +54,6 @@ contract TestCumulativeRewardTracking is
|
||||
);
|
||||
}
|
||||
|
||||
function _forceUnsetCumulativeReward(bytes32 poolId, uint256 epoch)
|
||||
internal
|
||||
{
|
||||
emit UnsetCumulativeReward(poolId, epoch);
|
||||
MixinCumulativeRewards._forceUnsetCumulativeReward(poolId, epoch);
|
||||
}
|
||||
|
||||
function _forceSetMostRecentCumulativeRewardEpoch(
|
||||
bytes32 poolId,
|
||||
uint256 currentMostRecentEpoch,
|
||||
|
@ -53,7 +53,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Creates CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 0 }, { event: 'SetCumulativeReward', epoch: 1 }],
|
||||
[{ event: 'SetCumulativeReward', epoch: 0 }],
|
||||
);
|
||||
});
|
||||
it('re-delegating in the same epoch', async () => {
|
||||
@ -64,34 +64,11 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
],
|
||||
[
|
||||
// Updates CR for epoch 0
|
||||
// Creates CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
// Updates CR for epoch 0
|
||||
// Updates CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
);
|
||||
});
|
||||
it('delegating then undelegating in the same epoch', async () => {
|
||||
await simulation.runTestAsync(
|
||||
[
|
||||
// Creates CR for epoch 0
|
||||
TestAction.CreatePool,
|
||||
// Updates CR for epoch 0
|
||||
// Creates CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
// Unsets the CR for epoch 1
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[{ event: 'UnsetCumulativeReward', epoch: 1 }],
|
||||
[{ event: 'SetCumulativeReward', epoch: 0 }, { event: 'SetCumulativeReward', epoch: 0 }],
|
||||
);
|
||||
});
|
||||
it('delegating in new epoch', async () => {
|
||||
@ -107,15 +84,9 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Creates a CR for epoch 1
|
||||
// Sets MRCR to epoch 1
|
||||
// Unsets the CR for epoch 0
|
||||
// Creates a CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 1 }, { event: 'SetMostRecentCumulativeReward', epoch: 1 }],
|
||||
);
|
||||
});
|
||||
it('re-delegating in a new epoch', async () => {
|
||||
@ -132,38 +103,9 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
[
|
||||
// Updates CR for epoch 1
|
||||
// Sets MRCR to epoch 1
|
||||
// Creates CR for epoch 2
|
||||
// Clears CR for epoch 0
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
],
|
||||
);
|
||||
});
|
||||
it('delegate then undelegate to remove all dependencies', async () => {
|
||||
await simulation.runTestAsync(
|
||||
[
|
||||
// Creates CR for epoch 0
|
||||
TestAction.CreatePool,
|
||||
// Moves to epoch 1
|
||||
TestAction.Finalize,
|
||||
// Creates CR for epoch 1
|
||||
// Sets MRCR to epoch 1
|
||||
// Clears CR for epoch 0
|
||||
// Creates CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
// Clears CR from epoch 2
|
||||
// Does NOT clear CR from epoch 1 because it is the current
|
||||
// epoch.
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[{ event: 'UnsetCumulativeReward', epoch: 2 }],
|
||||
[{ event: 'SetCumulativeReward', epoch: 1 }, { event: 'SetMostRecentCumulativeReward', epoch: 1 }],
|
||||
);
|
||||
});
|
||||
it('delegating in epoch 1 then again in epoch 2', async () => {
|
||||
@ -175,8 +117,6 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
TestAction.Finalize,
|
||||
// Creates CR for epoch 1
|
||||
// Sets MRCR to epoch 1
|
||||
// Clears CR for epoch 0
|
||||
// Creates CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
// Move to epoch 2
|
||||
TestAction.Finalize,
|
||||
@ -188,12 +128,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 2 }, { event: 'SetMostRecentCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1 then undelegate in epoch 2', async () => {
|
||||
@ -217,11 +152,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clear CR for epoch 1
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 2 }, { event: 'SetMostRecentCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 0 and epoch 1, then undelegate half in epoch 2', async () => {
|
||||
@ -250,12 +181,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 1
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 2 }, { event: 'SetMostRecentCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1 and 2 then again in 3', async () => {
|
||||
@ -284,12 +210,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 2 },
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 2 }, { event: 'SetMostRecentCumulativeReward', epoch: 2 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 0, earn reward in epoch 1', async () => {
|
||||
@ -347,12 +268,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 3 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 0 and 1, earn reward in epoch 3, then undelegate half', async () => {
|
||||
@ -387,12 +303,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 2
|
||||
TestAction.Undelegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 3 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1, 2, earn rewards in epoch 3, skip to epoch 4, then delegate', async () => {
|
||||
@ -430,14 +341,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 1
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 5 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 4 }, { event: 'SetMostRecentCumulativeReward', epoch: 4 }],
|
||||
);
|
||||
});
|
||||
it('earn reward in epoch 1 with no stake, then delegate', async () => {
|
||||
@ -458,12 +362,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Creates CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 1 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 0 },
|
||||
{ event: 'SetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 1 }, { event: 'SetMostRecentCumulativeReward', epoch: 1 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1, 3, then delegate in epoch 4', async () => {
|
||||
@ -498,12 +397,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Creates CR for epoch 5
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 4 },
|
||||
{ event: 'SetCumulativeReward', epoch: 5 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 3 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 4 }, { event: 'SetMostRecentCumulativeReward', epoch: 4 }],
|
||||
);
|
||||
});
|
||||
it('delegate in epoch 1, then epoch 3', async () => {
|
||||
@ -531,13 +425,7 @@ blockchainTests.resets('Cumulative Reward Tracking', env => {
|
||||
// Clears CR for epoch 2
|
||||
TestAction.Delegate,
|
||||
],
|
||||
[
|
||||
{ event: 'SetCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetMostRecentCumulativeReward', epoch: 3 },
|
||||
{ event: 'SetCumulativeReward', epoch: 4 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 1 },
|
||||
{ event: 'UnsetCumulativeReward', epoch: 2 },
|
||||
],
|
||||
[{ event: 'SetCumulativeReward', epoch: 3 }, { event: 'SetMostRecentCumulativeReward', epoch: 3 }],
|
||||
);
|
||||
});
|
||||
});
|
||||
|
@ -46,11 +46,6 @@ export class CumulativeRewardTrackingSimulation {
|
||||
event: log.event,
|
||||
epoch: log.args.epoch.toNumber(),
|
||||
});
|
||||
} else if (log.event === TestCumulativeRewardTrackingEvents.UnsetCumulativeReward) {
|
||||
logs.push({
|
||||
event: log.event,
|
||||
epoch: log.args.epoch.toNumber(),
|
||||
});
|
||||
}
|
||||
}
|
||||
return logs;
|
||||
|
Loading…
x
Reference in New Issue
Block a user