@0x/contracts-staking
: Last call before embarking of V3 of staking integration.
This commit is contained in:
parent
7ef3c12722
commit
0196ce18f3
@ -255,36 +255,80 @@ contract MixinStakingPoolRewards is
|
|||||||
view
|
view
|
||||||
returns (uint256 totalReward)
|
returns (uint256 totalReward)
|
||||||
{
|
{
|
||||||
// reward balance is always zero in these two scenarios:
|
uint256 currentEpoch = getCurrentEpoch();
|
||||||
// 1. The owner's delegated stake is current as of this epoch: their rewards have been moved to the ETH vault.
|
// There can be no rewards in epoch 0 because there is no delegated
|
||||||
// 2. The current epoch is zero: delegation begins at epoch 1
|
// stake.
|
||||||
if (unsyncedDelegatedStakeToPoolByOwner.currentEpoch == currentEpoch || currentEpoch == 0) return 0;
|
if (currentEpoch == 0) {
|
||||||
|
return reward = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// compute reward accumulated during `delegatedStake.currentEpoch`;
|
IStructs.StoredBalance memory stake =
|
||||||
uint256 rewardsAccumulatedDuringLastStoredEpoch = (unsyncedDelegatedStakeToPoolByOwner.currentEpochBalance != 0)
|
_loadUnsyncedBalance(delegatedStakeToPoolByOwner[member][poolId]);
|
||||||
? _computeMemberRewardOverInterval(
|
// 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 (stake.currentEpoch == currentEpoch) {
|
||||||
|
return reward = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// From here we know:
|
||||||
|
// 1. `currentEpoch > 0`
|
||||||
|
// 2. `stake.currentEpoch < currentEpoch`.
|
||||||
|
|
||||||
|
// Get the last epoch where a reward was credited to this pool.
|
||||||
|
uint256 lastRewardEpoch = cumulativeRewardsByPoolLastStored[poolId];
|
||||||
|
|
||||||
|
// If there are unfinalized rewards this epoch, compute the member's
|
||||||
|
// share.
|
||||||
|
if (unfinalizedMembersReward != 0 && unfinalizedDelegatedStake != 0) {
|
||||||
|
// Unfinalized rewards are always earned from stake in
|
||||||
|
// the prior epoch so we want the stake at `currentEpoch-1`.
|
||||||
|
uint256 _stake = stake.currentEpoch == currentEpoch - 1 ?
|
||||||
|
stake.currentEpochBalance :
|
||||||
|
stake.nextEpochBalance;
|
||||||
|
if (_stake != 0) {
|
||||||
|
reward = _stake
|
||||||
|
.safeMul(unfinalizedMembersReward)
|
||||||
|
.safeDiv(unfinalizedDelegatedStake);
|
||||||
|
}
|
||||||
|
// Add rewards up to the last reward epoch.
|
||||||
|
if (lastRewardEpoch != 0 && lastRewardEpoch > stake.currentEpoch) {
|
||||||
|
reward = reward.safeAdd(
|
||||||
|
_computeMemberRewardOverInterval(
|
||||||
|
poolId,
|
||||||
|
stake,
|
||||||
|
stake.currentEpoch,
|
||||||
|
stake.currentEpoch + 1
|
||||||
|
)
|
||||||
|
);
|
||||||
|
if (lastRewardEpoch > stake.currentEpoch + 1) {
|
||||||
|
reward = reward.safeAdd(
|
||||||
|
_computeMemberRewardOverInterval(
|
||||||
|
poolId,
|
||||||
|
stake,
|
||||||
|
stake.currentEpoch + 1,
|
||||||
|
lastRewardEpoch
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Otherwise get the rewards earned up to the last reward epoch.
|
||||||
|
} else if (stake.currentEpoch < lastRewardEpoch) {
|
||||||
|
reward = _computeMemberRewardOverInterval(
|
||||||
poolId,
|
poolId,
|
||||||
unsyncedDelegatedStakeToPoolByOwner.currentEpochBalance,
|
stake,
|
||||||
uint256(unsyncedDelegatedStakeToPoolByOwner.currentEpoch).safeSub(1),
|
stake.currentEpoch,
|
||||||
unsyncedDelegatedStakeToPoolByOwner.currentEpoch
|
stake.currentEpoch + 1
|
||||||
)
|
);
|
||||||
: 0;
|
if (lastRewardEpoch > stake.currentEpoch + 1) {
|
||||||
|
reward = _computeMemberRewardOverInterval(
|
||||||
// compute the reward accumulated by the `next` balance;
|
poolId,
|
||||||
// this starts at `delegatedStake.currentEpoch + 1` and goes up until the last epoch, during which
|
stake,
|
||||||
// rewards were accumulated. This is at most the most recently finalized epoch (current epoch - 1).
|
stake.currentEpoch + 1,
|
||||||
uint256 rewardsAccumulatedAfterLastStoredEpoch = (_cumulativeRewardsByPoolLastStored[poolId] > unsyncedDelegatedStakeToPoolByOwner.currentEpoch)
|
lastRewardEpoch
|
||||||
? _computeMemberRewardOverInterval(
|
).safeSub(reward);
|
||||||
poolId,
|
}
|
||||||
unsyncedDelegatedStakeToPoolByOwner.nextEpochBalance,
|
}
|
||||||
unsyncedDelegatedStakeToPoolByOwner.currentEpoch,
|
|
||||||
_cumulativeRewardsByPoolLastStored[poolId]
|
|
||||||
)
|
|
||||||
: 0;
|
|
||||||
|
|
||||||
// compute the total reward
|
|
||||||
totalReward = rewardsAccumulatedDuringLastStoredEpoch.safeAdd(rewardsAccumulatedAfterLastStoredEpoch);
|
|
||||||
return totalReward;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @dev Adds or removes cumulative reward dependencies for a delegator.
|
/// @dev Adds or removes cumulative reward dependencies for a delegator.
|
||||||
|
@ -273,7 +273,22 @@ blockchainTests.resets('delegator unit rewards', env => {
|
|||||||
assertRoughlyEquals(delegatorReward, expectedDelegatorRewards);
|
assertRoughlyEquals(delegatorReward, expectedDelegatorRewards);
|
||||||
});
|
});
|
||||||
|
|
||||||
it.only('has correct reward immediately after unstaking', async () => {
|
it('has correct reward immediately after unstaking', async () => {
|
||||||
|
const poolId = hexRandom();
|
||||||
|
const { delegator, stake } = await delegateStakeAsync(poolId);
|
||||||
|
await advanceEpochAsync(); // epoch 1 (stake now active)
|
||||||
|
await advanceEpochAsync(); // epoch 2
|
||||||
|
// rewards paid for stake in epoch 1.
|
||||||
|
const { reward } = await rewardPoolMembersAsync(
|
||||||
|
{ poolId, stake },
|
||||||
|
);
|
||||||
|
const { deposit } = await undelegateStakeAsync(poolId, delegator);
|
||||||
|
expect(deposit).to.bignumber.eq(reward);
|
||||||
|
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
|
||||||
|
expect(delegatorReward).to.bignumber.eq(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it('has correct reward immediately after unstaking and restaking', async () => {
|
||||||
const poolId = hexRandom();
|
const poolId = hexRandom();
|
||||||
const { delegator, stake } = await delegateStakeAsync(poolId);
|
const { delegator, stake } = await delegateStakeAsync(poolId);
|
||||||
await advanceEpochAsync(); // epoch 1 (stake now active)
|
await advanceEpochAsync(); // epoch 1 (stake now active)
|
||||||
@ -282,8 +297,28 @@ blockchainTests.resets('delegator unit rewards', env => {
|
|||||||
const { reward } = await rewardPoolMembersAsync(
|
const { reward } = await rewardPoolMembersAsync(
|
||||||
{ poolId, stake },
|
{ poolId, stake },
|
||||||
);
|
);
|
||||||
|
const { deposit } = await undelegateStakeAsync(poolId, delegator);
|
||||||
|
expect(deposit).to.bignumber.eq(reward);
|
||||||
|
await delegateStakeAsync(poolId, { delegator, stake });
|
||||||
|
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
|
||||||
|
expect(delegatorReward).to.bignumber.eq(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
it.only('has correct reward immediately after unstaking, restaking, and rewarding fees', async () => {
|
||||||
|
const poolId = hexRandom();
|
||||||
|
const { delegator, stake } = await delegateStakeAsync(poolId);
|
||||||
|
await advanceEpochAsync(); // epoch 1 (stake now active)
|
||||||
|
await advanceEpochAsync(); // epoch 2
|
||||||
|
// rewards paid for stake in epoch 1.
|
||||||
|
await rewardPoolMembersAsync({ poolId, stake });
|
||||||
await undelegateStakeAsync(poolId, delegator);
|
await undelegateStakeAsync(poolId, delegator);
|
||||||
|
await delegateStakeAsync(poolId, { delegator, stake });
|
||||||
await advanceEpochAsync(); // epoch 3
|
await advanceEpochAsync(); // epoch 3
|
||||||
|
await advanceEpochAsync(); // epoch 4
|
||||||
|
// rewards paid for stake in epoch 3.
|
||||||
|
const { reward } = await rewardPoolMembersAsync(
|
||||||
|
{ poolId, stake },
|
||||||
|
);
|
||||||
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
|
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
|
||||||
expect(delegatorReward).to.bignumber.eq(reward);
|
expect(delegatorReward).to.bignumber.eq(reward);
|
||||||
});
|
});
|
||||||
|
@ -57,7 +57,7 @@ library LibFractions {
|
|||||||
pure
|
pure
|
||||||
returns (uint256 result)
|
returns (uint256 result)
|
||||||
{
|
{
|
||||||
if (s == 0) {
|
if (s == 0 || d1 == 0) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (n2 == 0) {
|
if (n2 == 0) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user