@0x/contracts-staking: All tests passing!

This commit is contained in:
Lawrence Forman 2019-09-17 14:04:07 -04:00 committed by Lawrence Forman
parent 527ec28915
commit a43b494302
8 changed files with 260 additions and 250 deletions

View File

@ -57,6 +57,10 @@
{
"note": "Refactored out `_cobbDouglas()` into its own library",
"pr": 2179
},
{
"note": "Introduce multi-block finalization.",
"pr": 2155
}
]
}

View File

@ -271,29 +271,12 @@ contract MixinStakingPoolRewards is
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 = lastPoolRewardEpoch[poolId];
// Get the last reward epoch for which we collected rewards from.
uint256 lastCollectedRewardEpoch =
lastCollectedRewardsEpochToPoolByOwner[member][poolId];
// If either of these are true, the most recent reward has already been
// claimed.
if (lastCollectedRewardEpoch == lastRewardEpoch
|| stake.currentEpoch >= lastRewardEpoch) {
return reward = 0;
}
// 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 ?
uint256 _stake = stake.currentEpoch >= currentEpoch - 1 ?
stake.currentEpochBalance :
stake.nextEpochBalance;
if (_stake != 0) {
@ -303,16 +286,35 @@ contract MixinStakingPoolRewards is
}
}
// Add rewards up to the last reward epoch.
if (lastRewardEpoch != 0) {
// Get the last epoch where a reward was credited to this pool.
uint256 lastRewardEpoch = lastPoolRewardEpoch[poolId];
// If the stake has been touched since the last reward epoch,
// it has already been claimed.
if (stake.currentEpoch >= lastRewardEpoch) {
return reward;
}
// From here we know: `stake.currentEpoch < currentEpoch > 0`.
if (stake.currentEpoch < lastRewardEpoch) {
reward = reward.safeAdd(
_computeMemberRewardOverInterval(
poolId,
stake,
stake.currentEpoch + 1,
lastRewardEpoch
stake.currentEpoch,
stake.currentEpoch + 1
)
);
if (stake.currentEpoch + 1 < lastRewardEpoch) {
reward = reward.safeAdd(
_computeMemberRewardOverInterval(
poolId,
stake,
stake.currentEpoch + 1,
lastRewardEpoch
)
);
}
}
}
@ -356,5 +358,9 @@ contract MixinStakingPoolRewards is
isDependent
);
}
uint256 nextEpoch = epoch.safeAdd(1);
if (!_isCumulativeRewardSet(cumulativeRewardsByPoolPtr[nextEpoch])) {
cumulativeRewardsByPoolPtr[nextEpoch] = mostRecentCumulativeRewards;
}
}
}

View File

@ -165,14 +165,11 @@ contract MixinFinalizer is
poolsRemaining = poolsRemaining.safeSub(1);
}
// Deposit all the rewards at once into the RewardVault.
if (rewardsPaid != 0) {
_depositIntoStakingPoolRewardVault(rewardsPaid);
}
// Update finalization states.
totalRewardsPaidLastEpoch =
totalRewardsPaidLastEpoch.safeAdd(rewardsPaid);
if (rewardsPaid != 0) {
totalRewardsPaidLastEpoch =
totalRewardsPaidLastEpoch.safeAdd(rewardsPaid);
}
unfinalizedPoolsRemaining = _unfinalizedPoolsRemaining = poolsRemaining;
// If there are no more unfinalized pools remaining, the epoch is
@ -184,6 +181,12 @@ contract MixinFinalizer is
unfinalizedRewardsAvailable.safeSub(totalRewardsPaidLastEpoch)
);
}
// Deposit all the rewards at once into the RewardVault.
if (rewardsPaid != 0) {
_depositIntoStakingPoolRewardVault(rewardsPaid);
}
}
/// @dev Instantly finalizes a single pool that was active in the previous

View File

@ -43,42 +43,33 @@ export class FinalizerActor extends BaseActor {
public async finalizeAsync(rewards: Reward[] = []): Promise<void> {
// cache initial info and balances
const operatorShareByPoolId =
await this._getOperatorShareByPoolIdAsync(this._poolIds);
const rewardVaultBalanceByPoolId =
await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
const delegatorBalancesByPoolId =
await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId);
const delegatorStakesByPoolId =
await this._getDelegatorStakesByPoolIdAsync(this._delegatorsByPoolId);
const operatorShareByPoolId = await this._getOperatorShareByPoolIdAsync(this._poolIds);
const rewardVaultBalanceByPoolId = await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
const delegatorBalancesByPoolId = await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId);
const delegatorStakesByPoolId = await this._getDelegatorStakesByPoolIdAsync(this._delegatorsByPoolId);
// compute expected changes
const expectedRewardVaultBalanceByPoolId =
await this._computeExpectedRewardVaultBalanceAsyncByPoolIdAsync(
rewards,
rewardVaultBalanceByPoolId,
operatorShareByPoolId,
);
const totalRewardsByPoolId =
_.zipObject(_.map(rewards, 'poolId'), _.map(rewards, 'reward'));
const expectedDelegatorBalancesByPoolId =
await this._computeExpectedDelegatorBalancesByPoolIdAsync(
this._delegatorsByPoolId,
delegatorBalancesByPoolId,
delegatorStakesByPoolId,
operatorShareByPoolId,
totalRewardsByPoolId,
);
const expectedRewardVaultBalanceByPoolId = await this._computeExpectedRewardVaultBalanceAsyncByPoolIdAsync(
rewards,
rewardVaultBalanceByPoolId,
operatorShareByPoolId,
);
const totalRewardsByPoolId = _.zipObject(_.map(rewards, 'poolId'), _.map(rewards, 'reward'));
const expectedDelegatorBalancesByPoolId = await this._computeExpectedDelegatorBalancesByPoolIdAsync(
this._delegatorsByPoolId,
delegatorBalancesByPoolId,
delegatorStakesByPoolId,
operatorShareByPoolId,
totalRewardsByPoolId,
);
// finalize
await this._stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
// assert reward vault changes
const finalRewardVaultBalanceByPoolId =
await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
const finalRewardVaultBalanceByPoolId = await this._getRewardVaultBalanceByPoolIdAsync(this._poolIds);
expect(finalRewardVaultBalanceByPoolId, 'final pool balances in reward vault').to.be.deep.equal(
expectedRewardVaultBalanceByPoolId,
);
// assert delegator balances
const finalDelegatorBalancesByPoolId =
await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId);
const finalDelegatorBalancesByPoolId = await this._getDelegatorBalancesByPoolIdAsync(this._delegatorsByPoolId);
expect(finalDelegatorBalancesByPoolId, 'final delegator balances in reward vault').to.be.deep.equal(
expectedDelegatorBalancesByPoolId,
);
@ -103,13 +94,12 @@ export class FinalizerActor extends BaseActor {
}
const operator = this._operatorByPoolId[poolId];
const [, membersStakeInPool] =
await this._getOperatorAndDelegatorsStakeInPoolAsync(poolId);
const [, membersStakeInPool] = await this._getOperatorAndDelegatorsStakeInPoolAsync(poolId);
const operatorShare = operatorShareByPoolId[poolId].dividedBy(PPM_100_PERCENT);
const totalReward = totalRewardByPoolId[poolId];
const operatorReward = membersStakeInPool.eq(0) ?
totalReward :
totalReward.times(operatorShare).integerValue(BigNumber.ROUND_DOWN);
const operatorReward = membersStakeInPool.eq(0)
? totalReward
: totalReward.times(operatorShare).integerValue(BigNumber.ROUND_DOWN);
const membersTotalReward = totalReward.minus(operatorReward);
for (const delegator of delegatorsByPoolId[poolId]) {
@ -133,10 +123,8 @@ export class FinalizerActor extends BaseActor {
private async _getDelegatorBalancesByPoolIdAsync(
delegatorsByPoolId: DelegatorsByPoolId,
): Promise<DelegatorBalancesByPoolId> {
const computeRewardBalanceOfDelegator =
this._stakingApiWrapper.stakingContract.computeRewardBalanceOfDelegator;
const rewardVaultBalanceOfOperator =
this._stakingApiWrapper.rewardVaultContract.balanceOfOperator;
const computeRewardBalanceOfDelegator = this._stakingApiWrapper.stakingContract.computeRewardBalanceOfDelegator;
const rewardVaultBalanceOfOperator = this._stakingApiWrapper.rewardVaultContract.balanceOfOperator;
const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {};
for (const poolId of Object.keys(delegatorsByPoolId)) {
@ -144,19 +132,11 @@ export class FinalizerActor extends BaseActor {
const delegators = delegatorsByPoolId[poolId];
delegatorBalancesByPoolId[poolId] = {};
for (const delegator of delegators) {
let balance =
new BigNumber(delegatorBalancesByPoolId[poolId][delegator] || 0);
let balance = new BigNumber(delegatorBalancesByPoolId[poolId][delegator] || 0);
if (delegator === operator) {
balance = balance.plus(
await rewardVaultBalanceOfOperator.callAsync(poolId),
);
balance = balance.plus(await rewardVaultBalanceOfOperator.callAsync(poolId));
} else {
balance = balance.plus(
await computeRewardBalanceOfDelegator.callAsync(
poolId,
delegator,
),
);
balance = balance.plus(await computeRewardBalanceOfDelegator.callAsync(poolId, delegator));
}
delegatorBalancesByPoolId[poolId][delegator] = balance;
}
@ -167,16 +147,13 @@ export class FinalizerActor extends BaseActor {
private async _getDelegatorStakesByPoolIdAsync(
delegatorsByPoolId: DelegatorsByPoolId,
): Promise<DelegatorBalancesByPoolId> {
const getStakeDelegatedToPoolByOwner =
this._stakingApiWrapper.stakingContract.getStakeDelegatedToPoolByOwner;
const getStakeDelegatedToPoolByOwner = this._stakingApiWrapper.stakingContract.getStakeDelegatedToPoolByOwner;
const delegatorBalancesByPoolId: DelegatorBalancesByPoolId = {};
for (const poolId of Object.keys(delegatorsByPoolId)) {
const delegators = delegatorsByPoolId[poolId];
delegatorBalancesByPoolId[poolId] = {};
for (const delegator of delegators) {
delegatorBalancesByPoolId[poolId][
delegator
] = (await getStakeDelegatedToPoolByOwner.callAsync(
delegatorBalancesByPoolId[poolId][delegator] = (await getStakeDelegatedToPoolByOwner.callAsync(
delegator,
poolId,
)).currentEpochBalance;
@ -195,13 +172,12 @@ export class FinalizerActor extends BaseActor {
const expectedRewardVaultBalanceByPoolId = _.cloneDeep(rewardVaultBalanceByPoolId);
for (const reward of rewards) {
const operatorShare = operatorShareByPoolId[reward.poolId];
expectedRewardVaultBalanceByPoolId[reward.poolId] =
await this._computeExpectedRewardVaultBalanceAsync(
reward.poolId,
reward.reward,
expectedRewardVaultBalanceByPoolId[reward.poolId],
operatorShare,
);
expectedRewardVaultBalanceByPoolId[reward.poolId] = await this._computeExpectedRewardVaultBalanceAsync(
reward.poolId,
reward.reward,
expectedRewardVaultBalanceByPoolId[reward.poolId],
operatorShare,
);
}
return [expectedOperatorBalanceByPoolId, expectedRewardVaultBalanceByPoolId];
}
@ -233,18 +209,13 @@ export class FinalizerActor extends BaseActor {
return operatorBalanceByPoolId;
}
private async _getOperatorAndDelegatorsStakeInPoolAsync(
poolId: string,
): Promise<[BigNumber, BigNumber]> {
private async _getOperatorAndDelegatorsStakeInPoolAsync(poolId: string): Promise<[BigNumber, BigNumber]> {
const stakingContract = this._stakingApiWrapper.stakingContract;
const operator = await stakingContract.getPoolOperator.callAsync(poolId);
const totalStakeInPool = (await stakingContract.getTotalStakeDelegatedToPool.callAsync(
poolId,
)).currentEpochBalance;
const operatorStakeInPool = (await stakingContract.getStakeDelegatedToPoolByOwner.callAsync(
operator,
poolId,
)).currentEpochBalance;
const totalStakeInPool = (await stakingContract.getTotalStakeDelegatedToPool.callAsync(poolId))
.currentEpochBalance;
const operatorStakeInPool = (await stakingContract.getStakeDelegatedToPoolByOwner.callAsync(operator, poolId))
.currentEpochBalance;
const membersStakeInPool = totalStakeInPool.minus(operatorStakeInPool);
return [operatorStakeInPool, membersStakeInPool];
}

View File

@ -74,7 +74,7 @@ blockchainTests.resets('Testing Rewards', env => {
// Skip to next epoch so operator stake is realized.
await stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
});
describe.skip('Reward Simulation', () => {
describe('Reward Simulation', () => {
interface EndBalances {
// staker 1
stakerRewardVaultBalance_1?: BigNumber;
@ -494,7 +494,7 @@ blockchainTests.resets('Testing Rewards', env => {
operatorEthVaultBalance: totalRewardsNotForDelegator,
});
});
it.only('Should collect fees correctly when leaving and returning to a pool', async () => {
it('Should collect fees correctly when leaving and returning to a pool', async () => {
// first staker delegates (epoch 0)
const rewardsForDelegator = [toBaseUnitAmount(10), toBaseUnitAmount(15)];
const rewardNotForDelegator = toBaseUnitAmount(7);
@ -628,13 +628,13 @@ blockchainTests.resets('Testing Rewards', env => {
for (const [staker, stakeAmount] of stakersAndStake) {
await staker.stakeWithPoolAsync(poolId, stakeAmount);
}
// skip epoch, so staker can start earning rewards
// skip epoch, so stakers can start earning rewards
await payProtocolFeeAndFinalize();
// finalize
const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward);
// Undelegate 0 stake to move rewards from RewardVault into the EthVault.
for (const [staker] of stakersAndStake) {
for (const [staker] of _.reverse(stakersAndStake)) {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),

View File

@ -36,9 +36,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
stake: Numberish;
}
async function rewardPoolMembersAsync(
opts?: Partial<RewardPoolMembersOpts>,
): Promise<RewardPoolMembersOpts> {
async function rewardPoolMembersAsync(opts?: Partial<RewardPoolMembersOpts>): Promise<RewardPoolMembersOpts> {
const _opts = {
poolId: hexRandom(),
reward: getRandomInteger(1, toBaseUnitAmount(100)),
@ -103,11 +101,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
...opts,
};
const fn = now ? testContract.delegateStakeNow : testContract.delegateStake;
const receipt = await fn.awaitTransactionSuccessAsync(
_opts.delegator,
poolId,
new BigNumber(_opts.stake),
);
const receipt = await fn.awaitTransactionSuccessAsync(_opts.delegator, poolId, new BigNumber(_opts.stake));
return {
..._opts,
deposit: getDepositFromLogs(receipt.logs, poolId, _opts.delegator),
@ -120,17 +114,10 @@ blockchainTests.resets.only('delegator unit rewards', env => {
stake?: Numberish,
): Promise<ResultWithDeposit<{ stake: BigNumber }>> {
const _stake = new BigNumber(
stake || (await
testContract
.getStakeDelegatedToPoolByOwner
.callAsync(delegator, poolId)
).currentEpochBalance,
);
const receipt = await testContract.undelegateStake.awaitTransactionSuccessAsync(
delegator,
poolId,
_stake,
stake ||
(await testContract.getStakeDelegatedToPoolByOwner.callAsync(delegator, poolId)).currentEpochBalance,
);
const receipt = await testContract.undelegateStake.awaitTransactionSuccessAsync(delegator, poolId, _stake);
return {
stake: _stake,
deposit: getDepositFromLogs(receipt.logs, poolId, delegator),
@ -138,11 +125,10 @@ blockchainTests.resets.only('delegator unit rewards', env => {
}
function getDepositFromLogs(logs: LogEntry[], poolId: string, delegator?: string): BigNumber {
const events =
filterLogsToArguments<TestDelegatorRewardsDepositEventArgs>(
logs,
TestDelegatorRewardsEvents.Deposit,
);
const events = filterLogsToArguments<TestDelegatorRewardsDepositEventArgs>(
logs,
TestDelegatorRewardsEvents.Deposit,
);
if (events.length > 0) {
expect(events.length).to.eq(1);
expect(events[0].poolId).to.eq(poolId);
@ -160,11 +146,8 @@ blockchainTests.resets.only('delegator unit rewards', env => {
return epoch.toNumber();
}
async function getDelegatorRewardAsync(poolId: string, delegator: string): Promise<BigNumber> {
return testContract.computeRewardBalanceOfDelegator.callAsync(
poolId,
delegator,
);
async function getDelegatorRewardBalanceAsync(poolId: string, delegator: string): Promise<BigNumber> {
return testContract.computeRewardBalanceOfDelegator.callAsync(poolId, delegator);
}
async function touchStakeAsync(poolId: string, delegator: string): Promise<ResultWithDeposit<{}>> {
@ -197,7 +180,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
it('nothing in epoch 0 for delegator with no stake', async () => {
const { poolId } = await rewardPoolMembersAsync();
const delegator = randomAddress();
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -205,7 +188,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1
const { poolId } = await rewardPoolMembersAsync();
const delegator = randomAddress();
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -214,7 +197,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
// Assign active stake to pool in epoch 0, which is usuaslly not
// possible due to delegating delays.
const { delegator } = await delegateStakeNowAsync(poolId);
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -222,7 +205,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1
const { poolId } = await rewardPoolMembersAsync();
const { delegator } = await delegateStakeAsync(poolId);
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -232,7 +215,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
// rewards paid for stake in epoch 0.
await rewardPoolMembersAsync({ poolId, stake });
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -243,7 +226,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
@ -255,7 +238,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake });
await advanceEpochAsync(); // epoch 3
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake });
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(BigNumber.sum(reward1, reward2));
});
@ -265,10 +248,11 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward, stake: rewardStake } = await rewardPoolMembersAsync(
{ poolId, stake: new BigNumber(delegatorStake).times(2) },
);
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const { reward, stake: rewardStake } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(2),
});
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorRewards = computeDelegatorRewards(reward, delegatorStake, rewardStake);
assertRoughlyEquals(delegatorReward, expectedDelegatorRewards);
});
@ -279,12 +263,10 @@ blockchainTests.resets.only('delegator unit rewards', env => {
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 { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { deposit } = await undelegateStakeAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -294,13 +276,11 @@ blockchainTests.resets.only('delegator unit rewards', env => {
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 { reward } = await rewardPoolMembersAsync({ 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);
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(0);
});
@ -316,14 +296,50 @@ blockchainTests.resets.only('delegator unit rewards', env => {
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 { reward } = await rewardPoolMembersAsync({ poolId, stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
it.only('computes correct rewards for 2 staggered delegators', async () => {
it('ignores rewards paid in the same epoch the stake was first active in', async () => {
const poolId = hexRandom();
// stake at 0
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake now active)
// Pay rewards for epoch 0.
await advanceEpochAsync(); // epoch 2
// Pay rewards for epoch 1.
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(delegatorReward).to.bignumber.eq(reward);
});
it('uses old stake for rewards paid in the same epoch EXTRA stake was first active in', async () => {
const poolId = hexRandom();
// stake at 0
const { delegator, stake: stake1 } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake1 now active)
// add extra stake
const { stake: stake2 } = await delegateStakeAsync(poolId, { delegator });
const totalStake = BigNumber.sum(stake1, stake2);
// Make the total stake in rewards > totalStake so delegator never
// receives 100% of rewards.
const rewardStake = totalStake.times(2);
await advanceEpochAsync(); // epoch 2 (stake2 now active)
// Pay rewards for epoch 1.
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
await advanceEpochAsync(); // epoch 3
// Pay rewards for epoch 2.
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake1, rewardStake),
computeDelegatorRewards(reward2, totalStake, rewardStake),
);
expect(delegatorReward).to.bignumber.eq(expectedDelegatorReward);
});
it('computes correct rewards for 2 staggered delegators', async () => {
const poolId = hexRandom();
const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1 (stake A now active)
@ -331,24 +347,18 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const totalStake = BigNumber.sum(stakeA, stakeB);
await advanceEpochAsync(); // epoch 2 (stake B now active)
// rewards paid for stake in epoch 1 (delegator A only)
const { reward: reward1 } = await rewardPoolMembersAsync(
{ poolId, stake: stakeA },
);
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: stakeA });
await advanceEpochAsync(); // epoch 3
// rewards paid for stake in epoch 2 (delegator A and B)
const { reward: reward2 } = await rewardPoolMembersAsync(
{ poolId, stake: totalStake },
);
const delegatorRewardA = await getDelegatorRewardAsync(poolId, delegatorA);
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA);
const expectedDelegatorRewardA = BigNumber.sum(
computeDelegatorRewards(reward1, stakeA, stakeA),
computeDelegatorRewards(reward2, stakeA, totalStake),
);
assertRoughlyEquals(delegatorRewardA, expectedDelegatorRewardA);
const delegatorRewardB = await getDelegatorRewardAsync(poolId, delegatorB);
const expectedDelegatorRewardB = BigNumber.sum(
computeDelegatorRewards(BigNumber.sum(reward1, reward2), stakeB, totalStake),
);
const delegatorRewardB = await getDelegatorRewardBalanceAsync(poolId, delegatorB);
const expectedDelegatorRewardB = BigNumber.sum(computeDelegatorRewards(reward2, stakeB, totalStake));
assertRoughlyEquals(delegatorRewardB, expectedDelegatorRewardB);
});
@ -360,25 +370,19 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const totalStake = BigNumber.sum(stakeA, stakeB);
await advanceEpochAsync(); // epoch 2 (stake B now active)
// rewards paid for stake in epoch 1 (delegator A only)
const { reward: reward1 } = await rewardPoolMembersAsync(
{ poolId, stake: stakeA },
);
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: stakeA });
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
// rewards paid for stake in epoch 3 (delegator A and B)
const { reward: reward2 } = await rewardPoolMembersAsync(
{ poolId, stake: totalStake },
);
const delegatorRewardA = await getDelegatorRewardAsync(poolId, delegatorA);
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const delegatorRewardA = await getDelegatorRewardBalanceAsync(poolId, delegatorA);
const expectedDelegatorRewardA = BigNumber.sum(
computeDelegatorRewards(reward1, stakeA, stakeA),
computeDelegatorRewards(reward2, stakeA, totalStake),
);
assertRoughlyEquals(delegatorRewardA, expectedDelegatorRewardA);
const delegatorRewardB = await getDelegatorRewardAsync(poolId, delegatorB);
const expectedDelegatorRewardB = BigNumber.sum(
computeDelegatorRewards(reward2, stakeB, totalStake),
);
const delegatorRewardB = await getDelegatorRewardBalanceAsync(poolId, delegatorB);
const expectedDelegatorRewardB = BigNumber.sum(computeDelegatorRewards(reward2, stakeB, totalStake));
assertRoughlyEquals(delegatorRewardB, expectedDelegatorRewardB);
});
@ -388,15 +392,17 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 1 (stake now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1.
const { reward: reward1, stake: rewardStake1 } = await rewardPoolMembersAsync(
{ poolId, stake: new BigNumber(delegatorStake).times(2) },
);
const { reward: reward1, stake: rewardStake1 } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(2),
});
await advanceEpochAsync(); // epoch 3
// rewards paid for stake in epoch 2
const { reward: reward2, stake: rewardStake2 } = await rewardPoolMembersAsync(
{ poolId, stake: new BigNumber(delegatorStake).times(3) },
);
const delegatorReward = await getDelegatorRewardAsync(poolId, delegator);
const { reward: reward2, stake: rewardStake2 } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(delegatorStake).times(3),
});
const delegatorReward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedDelegatorReward = BigNumber.sum(
computeDelegatorRewards(reward1, delegatorStake, rewardStake1),
computeDelegatorRewards(reward2, delegatorStake, rewardStake2),
@ -410,7 +416,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId, { stake: 0 });
await advanceEpochAsync(); // epoch 1
await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(0);
});
@ -419,32 +425,32 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(0);
});
it('returns only unfinalized rewards from epoch 2 for delegator delegating in epoch 1', async () => {
it('returns unfinalized rewards from epoch 2 for delegator delegating in epoch 0', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(unfinalizedReward);
});
it('returns only unfinalized rewards from epoch 3 for delegator delegating in epoch 1', async () => {
it('returns unfinalized rewards from epoch 3 for delegator delegating in epoch 0', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
await advanceEpochAsync(); // epoch 3
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(reward).to.bignumber.eq(unfinalizedReward);
});
it('returns unfinalized rewards from epoch 3 + rewards from epoch 2 for delegator delegating in epoch 1', async () => {
it('returns unfinalized rewards from epoch 3 + rewards from epoch 2 for delegator delegating in epoch 0', async () => {
const poolId = hexRandom();
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
@ -452,7 +458,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake });
await advanceEpochAsync(); // epoch 3
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(prevReward, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
});
@ -466,7 +472,7 @@ blockchainTests.resets.only('delegator unit rewards', env => {
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake });
const reward = await getDelegatorRewardAsync(poolId, delegator);
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(prevReward, unfinalizedReward);
expect(reward).to.bignumber.eq(expectedReward);
});
@ -476,16 +482,17 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { delegator, stake } = await delegateStakeAsync(poolId);
await advanceEpochAsync(); // epoch 1
await advanceEpochAsync(); // epoch 2
const { reward: prevReward, stake: prevStake } = await rewardPoolMembersAsync(
{ poolId, stake: new BigNumber(stake).times(2) },
);
const { reward: prevReward, stake: prevStake } = await rewardPoolMembersAsync({
poolId,
stake: new BigNumber(stake).times(2),
});
await advanceEpochAsync(); // epoch 3
await advanceEpochAsync(); // epoch 4
const { reward: unfinalizedReward, stake: unfinalizedStake } =
await setUnfinalizedMembersRewardsAsync(
{ poolId, stake: new BigNumber(stake).times(5) },
);
const reward = await getDelegatorRewardAsync(poolId, delegator);
const { reward: unfinalizedReward, stake: unfinalizedStake } = await setUnfinalizedMembersRewardsAsync({
poolId,
stake: new BigNumber(stake).times(5),
});
const reward = await getDelegatorRewardBalanceAsync(poolId, delegator);
const expectedReward = BigNumber.sum(
computeDelegatorRewards(prevReward, stake, prevStake),
computeDelegatorRewards(unfinalizedReward, stake, unfinalizedStake),
@ -504,7 +511,9 @@ blockchainTests.resets.only('delegator unit rewards', env => {
// rewards paid for stake in epoch 1
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { deposit } = await touchStakeAsync(poolId, delegator);
const finalRewardBalance = await getDelegatorRewardBalanceAsync(poolId, delegator);
expect(deposit).to.bignumber.eq(reward);
expect(finalRewardBalance).to.bignumber.eq(0);
});
it('does not collect extra rewards from delegating more stake in the reward epoch', async () => {
@ -513,21 +522,21 @@ blockchainTests.resets.only('delegator unit rewards', env => {
// stake
stakeResults.push(await delegateStakeAsync(poolId));
const { delegator, stake } = stakeResults[0];
const totalStake = new BigNumber(stake).times(2);
const rewardStake = new BigNumber(stake).times(2);
await advanceEpochAsync(); // epoch 1 (stake now active)
// add more stake.
stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake }));
await advanceEpochAsync(); // epoch 1 (2 * stake now active)
// reward for epoch 1, using 2 * stake so delegator should
// only be entitled to a fraction of the rewards.
const { reward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
const { reward } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
await advanceEpochAsync(); // epoch 2
// touch the stake one last time
stakeResults.push(await touchStakeAsync(poolId, delegator));
// Should only see deposits for epoch 2.
const expectedDeposit = computeDelegatorRewards(reward, stake, totalStake);
const allDeposits = stakeResults.map(r => r.deposit);
assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedDeposit);
const expectedReward = computeDelegatorRewards(reward, stake, rewardStake);
assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward);
});
it('only collects rewards from staked epochs', async () => {
@ -536,27 +545,46 @@ blockchainTests.resets.only('delegator unit rewards', env => {
// stake
stakeResults.push(await delegateStakeAsync(poolId));
const { delegator, stake } = stakeResults[0];
await advanceEpochAsync(); // epoch 1 (stake now active)
// unstake before and after reward payout, to be extra sneaky.
const unstake1 = new BigNumber(stake).dividedToIntegerBy(2);
stakeResults.push(await undelegateStakeAsync(poolId, delegator, unstake1));
const rewardStake = new BigNumber(stake).times(2);
await advanceEpochAsync(); // epoch 1 (full stake now active)
// reward for epoch 0
await rewardPoolMembersAsync({ poolId, stake });
const unstake2 = new BigNumber(stake).minus(unstake1);
stakeResults.push(await undelegateStakeAsync(poolId, delegator, unstake2));
await advanceEpochAsync(); // epoch 2 (no active stake)
await rewardPoolMembersAsync({ poolId, stake: rewardStake });
// unstake some
const unstake = new BigNumber(stake).dividedToIntegerBy(2);
stakeResults.push(await undelegateStakeAsync(poolId, delegator, unstake));
await advanceEpochAsync(); // epoch 2 (half active stake)
// reward for epoch 1
const { reward } = await rewardPoolMembersAsync({ poolId, stake });
const { reward: reward1 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
// re-stake
stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake }));
await advanceEpochAsync(); // epoch 3 (stake now active)
stakeResults.push(await delegateStakeAsync(poolId, { delegator, stake: unstake }));
await advanceEpochAsync(); // epoch 3 (full stake now active)
// reward for epoch 2
await rewardPoolMembersAsync({ poolId, stake });
// touch the stake one last time
const { reward: reward2 } = await rewardPoolMembersAsync({ poolId, stake: rewardStake });
// touch the stake to claim rewards
stakeResults.push(await touchStakeAsync(poolId, delegator));
// Should only see deposits for epoch 2.
const allDeposits = stakeResults.map(r => r.deposit);
assertRoughlyEquals(BigNumber.sum(...allDeposits), reward);
const expectedReward = BigNumber.sum(
computeDelegatorRewards(reward1, stake, rewardStake),
computeDelegatorRewards(reward2, new BigNumber(stake).minus(unstake), rewardStake),
);
assertRoughlyEquals(BigNumber.sum(...allDeposits), expectedReward);
});
it('two delegators can collect split rewards as soon as available', async () => {
const poolId = hexRandom();
const { delegator: delegatorA, stake: stakeA } = await delegateStakeAsync(poolId);
const { delegator: delegatorB, stake: stakeB } = await delegateStakeAsync(poolId);
const totalStake = BigNumber.sum(stakeA, stakeB);
await advanceEpochAsync(); // epoch 1 (stakes now active)
await advanceEpochAsync(); // epoch 2
// rewards paid for stake in epoch 1
const { reward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
// delegator A will finalize and collect rewards by touching stake.
const { deposit: depositA } = await touchStakeAsync(poolId, delegatorA);
assertRoughlyEquals(depositA, computeDelegatorRewards(reward, stakeA, totalStake));
// delegator B will collect rewards by touching stake
const { deposit: depositB } = await touchStakeAsync(poolId, delegatorB);
assertRoughlyEquals(depositB, computeDelegatorRewards(reward, stakeB, totalStake));
});
it('delegator B collects correct rewards after delegator A finalizes', async () => {
@ -570,7 +598,10 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
await advanceEpochAsync(); // epoch 3
// unfinalized rewards for stake in epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake: totalStake });
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({
poolId,
stake: totalStake,
});
const totalRewards = BigNumber.sum(prevReward, unfinalizedReward);
// delegator A will finalize and collect rewards by touching stake.
const { deposit: depositA } = await touchStakeAsync(poolId, delegatorA);
@ -591,7 +622,10 @@ blockchainTests.resets.only('delegator unit rewards', env => {
const { reward: prevReward } = await rewardPoolMembersAsync({ poolId, stake: totalStake });
await advanceEpochAsync(); // epoch 3
// unfinalized rewards for stake in epoch 2
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({ poolId, stake: totalStake });
const { reward: unfinalizedReward } = await setUnfinalizedMembersRewardsAsync({
poolId,
stake: totalStake,
});
const totalRewards = BigNumber.sum(prevReward, unfinalizedReward);
// finalize
await finalizePoolAsync(poolId);

View File

@ -255,7 +255,7 @@ blockchainTests.resets('finalizer unit tests', env => {
// Add a pool so there is state to clear.
await addActivePoolAsync();
await testContract.endEpoch.awaitTransactionSuccessAsync();
assertFinalizationStateAsync({
return assertFinalizationStateAsync({
currentEpoch: INITIAL_EPOCH + 1,
closingEpoch: INITIAL_EPOCH,
numActivePoolsThisEpoch: 0,
@ -268,7 +268,7 @@ blockchainTests.resets('finalizer unit tests', env => {
// Add a pool so there is state to clear.
const pool = await addActivePoolAsync();
await testContract.endEpoch.awaitTransactionSuccessAsync();
assertFinalizationStateAsync({
return assertFinalizationStateAsync({
unfinalizedPoolsRemaining: 1,
unfinalizedRewardsAvailable: INITIAL_BALANCE,
unfinalizedTotalFeesCollected: pool.feesCollected,
@ -318,7 +318,7 @@ blockchainTests.resets('finalizer unit tests', env => {
it('can finalize multiple pools', async () => {
const nextEpoch = INITIAL_EPOCH + 1;
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const poolIds = pools.map(p => p.poolId);
await testContract.endEpoch.awaitTransactionSuccessAsync();
const receipt = await testContract.finalizePools.awaitTransactionSuccessAsync(poolIds);
@ -338,7 +338,7 @@ blockchainTests.resets('finalizer unit tests', env => {
it('can finalize multiple pools over multiple transactions', async () => {
const nextEpoch = INITIAL_EPOCH + 1;
const pools = await Promise.all(_.times(2, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(2, async () => addActivePoolAsync()));
await testContract.endEpoch.awaitTransactionSuccessAsync();
const receipts = await Promise.all(
pools.map(pool => testContract.finalizePools.awaitTransactionSuccessAsync([pool.poolId])),
@ -358,7 +358,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('ignores a non-active pool', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const nonActivePoolId = hexRandom();
const poolIds = _.shuffle([...pools.map(p => p.poolId), nonActivePoolId]);
await testContract.endEpoch.awaitTransactionSuccessAsync();
@ -371,7 +371,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('ignores a finalized pool', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const poolIds = pools.map(p => p.poolId);
await testContract.endEpoch.awaitTransactionSuccessAsync();
const [finalizedPool] = _.sampleSize(pools, 1);
@ -385,7 +385,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('resets pool state after finalizing it', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const pool = _.sample(pools) as ActivePoolOpts;
await testContract.endEpoch.awaitTransactionSuccessAsync();
await testContract.finalizePools.awaitTransactionSuccessAsync([pool.poolId]);
@ -399,7 +399,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('`rewardsPaid` is the sum of all pool rewards', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const poolIds = pools.map(p => p.poolId);
await testContract.endEpoch.awaitTransactionSuccessAsync();
const receipt = await testContract.finalizePools.awaitTransactionSuccessAsync(poolIds);
@ -412,7 +412,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('`rewardsPaid` <= `rewardsAvailable` <= contract balance at the end of the epoch', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const poolIds = pools.map(p => p.poolId);
let receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0];
@ -438,7 +438,7 @@ blockchainTests.resets('finalizer unit tests', env => {
for (const i of _.times(numTests)) {
const numPools = _.random(1, 32);
it(`${i + 1}/${numTests} \`rewardsPaid\` <= \`rewardsAvailable\` (${numPools} pools)`, async () => {
const pools = await Promise.all(_.times(numPools, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(numPools, async () => addActivePoolAsync()));
const poolIds = pools.map(p => p.poolId);
let receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0];
@ -477,7 +477,7 @@ blockchainTests.resets('finalizer unit tests', env => {
it('can finalize multiple pools over multiple transactions', async () => {
const nextEpoch = INITIAL_EPOCH + 1;
const pools = await Promise.all(_.times(2, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(2, async () => addActivePoolAsync()));
await testContract.endEpoch.awaitTransactionSuccessAsync();
const receipts = await Promise.all(
pools.map(pool => testContract.internalFinalizePool.awaitTransactionSuccessAsync(pool.poolId)),
@ -497,7 +497,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('ignores a finalized pool', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
await testContract.endEpoch.awaitTransactionSuccessAsync();
const [finalizedPool] = _.sampleSize(pools, 1);
await testContract.internalFinalizePool.awaitTransactionSuccessAsync(finalizedPool.poolId);
@ -507,7 +507,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('resets pool state after finalizing it', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const pool = _.sample(pools) as ActivePoolOpts;
await testContract.endEpoch.awaitTransactionSuccessAsync();
await testContract.internalFinalizePool.awaitTransactionSuccessAsync(pool.poolId);
@ -521,7 +521,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('`rewardsPaid` <= `rewardsAvailable` <= contract balance at the end of the epoch', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0];
expect(rewardsAvailable).to.bignumber.lte(INITIAL_BALANCE);
@ -551,7 +551,7 @@ blockchainTests.resets('finalizer unit tests', env => {
for (const i of _.times(numTests)) {
const numPools = _.random(1, 32);
it(`${i + 1}/${numTests} \`rewardsPaid\` <= \`rewardsAvailable\` (${numPools} pools)`, async () => {
const pools = await Promise.all(_.times(numPools, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(numPools, async () => addActivePoolAsync()));
const receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0];
const receipts = await Promise.all(
@ -601,11 +601,11 @@ blockchainTests.resets('finalizer unit tests', env => {
it('rolls over leftover rewards into th next epoch', async () => {
const poolIds = _.times(3, () => hexRandom());
await Promise.all(poolIds.map(id => addActivePoolAsync({ poolId: id })));
await Promise.all(poolIds.map(async id => addActivePoolAsync({ poolId: id })));
await testContract.endEpoch.awaitTransactionSuccessAsync();
let receipt = await testContract.finalizePools.awaitTransactionSuccessAsync(poolIds);
const { rewardsRemaining: rolledOverRewards } = getEpochFinalizedEvents(receipt.logs)[0];
await Promise.all(poolIds.map(id => addActivePoolAsync({ poolId: id })));
await Promise.all(poolIds.map(async id => addActivePoolAsync({ poolId: id })));
receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const { rewardsAvailable } = getEpochEndedEvents(receipt.logs)[0];
expect(rewardsAvailable).to.bignumber.eq(rolledOverRewards);
@ -690,7 +690,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('returns empty if pool was already finalized', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
const [pool] = _.sampleSize(pools, 1);
await testContract.endEpoch.awaitTransactionSuccessAsync();
await testContract.finalizePools.awaitTransactionSuccessAsync([pool.poolId]);
@ -712,7 +712,7 @@ blockchainTests.resets('finalizer unit tests', env => {
});
it('computes one reward among multiple pools', async () => {
const pools = await Promise.all(_.times(3, () => addActivePoolAsync()));
const pools = await Promise.all(_.times(3, async () => addActivePoolAsync()));
await testContract.endEpoch.awaitTransactionSuccessAsync();
const [pool] = _.sampleSize(pools, 1);
const totalFeesCollected = BigNumber.sum(...pools.map(p => p.feesCollected));

View File

@ -1,12 +1,4 @@
import {
blockchainTests,
constants,
expect,
hexConcat,
hexRandom,
hexSlice,
testCombinatoriallyWithReferenceFunc,
} from '@0x/contracts-test-utils';
import { blockchainTests, constants, expect, hexConcat, hexRandom, hexSlice } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { cartesianProduct } from 'js-combinatorics';