@0x/contracts-exchange: Fixing tests and writing new ones.

This commit is contained in:
Lawrence Forman
2019-09-13 19:48:54 -04:00
committed by Lawrence Forman
parent d548ddac0d
commit a1aad2e55e
11 changed files with 469 additions and 200 deletions

View File

@@ -146,6 +146,15 @@ export class StakerActor extends BaseActor {
expect(finalZrxBalanceOfVault, 'final balance of zrx vault').to.be.bignumber.equal(initZrxBalanceOfVault);
}
public async stakeWithPoolAsync(poolId: string, amount: BigNumber): Promise<void> {
await this.stakeAsync(amount);
await this.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
amount,
);
}
public async goToNextEpochAsync(): Promise<void> {
// cache balances
const initZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync();

View File

@@ -4,6 +4,7 @@ import {
expect,
filterLogsToArguments,
hexRandom,
Numberish,
randomAddress,
} from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
@@ -54,9 +55,26 @@ blockchainTests('Protocol Fee Unit Tests', env => {
wethAssetData = await testContract.getWethAssetData.callAsync();
});
async function createTestPoolAsync(stake: BigNumber, makers: string[]): Promise<string> {
interface CreatePoolOpts {
operatorStake: Numberish;
membersStake: Numberish;
makers: string[];
}
async function createTestPoolAsync(opts: Partial<CreatePoolOpts>): Promise<string> {
const _opts = {
operatorStake: 0,
membersStake: 0,
makers: [],
...opts,
};
const poolId = hexRandom();
await testContract.createTestPool.awaitTransactionSuccessAsync(poolId, stake, makers);
await testContract.createTestPool.awaitTransactionSuccessAsync(
poolId,
new BigNumber(_opts.operatorStake),
new BigNumber(_opts.membersStake),
_opts.makers,
);
return poolId;
}
@@ -154,7 +172,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
}
it('should not transfer WETH if value is sent', async () => {
await createTestPoolAsync(minimumStake, []);
await createTestPoolAsync({ operatorStake: minimumStake });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -164,8 +182,8 @@ blockchainTests('Protocol Fee Unit Tests', env => {
assertNoWETHTransferLogs(receipt.logs);
});
it('should update `protocolFeesThisEpochByPool` if the maker is in a pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
it('should credit pool if the maker is in a pool', async () => {
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -177,8 +195,8 @@ blockchainTests('Protocol Fee Unit Tests', env => {
expect(poolFees).to.bignumber.eq(DEFAULT_PROTOCOL_FEE_PAID);
});
it('should not update `protocolFeesThisEpochByPool` if maker is not in a pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, []);
it('should not credit the pool if maker is not in a pool', async () => {
const poolId = await createTestPoolAsync({ operatorStake: minimumStake });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -191,7 +209,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('fees paid to the same maker should go to the same pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const payAsync = async () => {
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
@@ -225,7 +243,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
}
it('should transfer WETH if no value is sent and the maker is not in a pool', async () => {
await createTestPoolAsync(minimumStake, []);
await createTestPoolAsync({ operatorStake: minimumStake });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -236,7 +254,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('should update `protocolFeesThisEpochByPool` if the maker is in a pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -249,7 +267,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('should not update `protocolFeesThisEpochByPool` if maker is not in a pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, []);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake });
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
payerAddress,
@@ -262,7 +280,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('fees paid to the same maker should go to the same pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const payAsync = async () => {
const receipt = await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
@@ -280,7 +298,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('fees paid to the same maker in WETH then ETH should go to the same pool', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const payAsync = async (inWETH: boolean) => {
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
@@ -303,7 +321,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
describe('Multiple makers', () => {
it('fees paid to different makers in the same pool go to that pool', async () => {
const otherMakerAddress = randomAddress();
const poolId = await createTestPoolAsync(minimumStake, [makerAddress, otherMakerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress, otherMakerAddress] });
const payAsync = async (_makerAddress: string) => {
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
_makerAddress,
@@ -322,8 +340,8 @@ blockchainTests('Protocol Fee Unit Tests', env => {
it('fees paid to makers in different pools go to their respective pools', async () => {
const [fee, otherFee] = _.times(2, () => getRandomPortion(DEFAULT_PROTOCOL_FEE_PAID));
const otherMakerAddress = randomAddress();
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const otherPoolId = await createTestPoolAsync(minimumStake, [otherMakerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
const otherPoolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [otherMakerAddress]});
const payAsync = async (_poolId: string, _makerAddress: string, _fee: BigNumber) => {
// prettier-ignore
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
@@ -346,7 +364,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
describe('Dust stake', () => {
it('credits pools with stake > minimum', async () => {
const poolId = await createTestPoolAsync(minimumStake.plus(1), [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake.plus(1), makers: [makerAddress] });
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
constants.NULL_ADDRESS,
@@ -358,7 +376,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('credits pools with stake == minimum', async () => {
const poolId = await createTestPoolAsync(minimumStake, [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake, makers: [makerAddress] });
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
constants.NULL_ADDRESS,
@@ -370,7 +388,7 @@ blockchainTests('Protocol Fee Unit Tests', env => {
});
it('does not credit pools with stake < minimum', async () => {
const poolId = await createTestPoolAsync(minimumStake.minus(1), [makerAddress]);
const poolId = await createTestPoolAsync({ operatorStake: minimumStake.minus(1), makers: [makerAddress] });
await testContract.payProtocolFee.awaitTransactionSuccessAsync(
makerAddress,
constants.NULL_ADDRESS,

View File

@@ -6,6 +6,7 @@ import * as _ from 'lodash';
import { artifacts } from '../src';
import { FinalizerActor } from './actors/finalizer_actor';
import { PoolOperatorActor } from './actors/pool_operator_actor';
import { StakerActor } from './actors/staker_actor';
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
import { toBaseUnitAmount } from './utils/number_utils';
@@ -26,8 +27,9 @@ blockchainTests.resets('Testing Rewards', env => {
let erc20Wrapper: ERC20Wrapper;
// test parameters
let stakers: StakerActor[];
let poolOperatorStaker: StakerActor;
let poolId: string;
let poolOperator: string;
let poolOperator: PoolOperatorActor;
let finalizer: FinalizerActor;
// tests
before(async () => {
@@ -43,7 +45,7 @@ blockchainTests.resets('Testing Rewards', env => {
stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper, artifacts.TestStaking);
// set up staking parameters
await stakingApiWrapper.utils.setParamsAsync({
minimumPoolStake: new BigNumber(0),
minimumPoolStake: new BigNumber(1),
cobbDouglasAlphaNumerator: new BigNumber(1),
cobbDouglasAlphaDenominator: new BigNumber(6),
rewardVaultAddress: stakingApiWrapper.rewardVaultContract.address,
@@ -51,22 +53,26 @@ blockchainTests.resets('Testing Rewards', env => {
zrxVaultAddress: stakingApiWrapper.zrxVaultContract.address,
});
// setup stakers
stakers = [new StakerActor(actors[0], stakingApiWrapper), new StakerActor(actors[1], stakingApiWrapper)];
stakers = actors.slice(0, 2).map(a => new StakerActor(a, stakingApiWrapper));
// setup pools
poolOperator = actors[2];
poolId = await stakingApiWrapper.utils.createStakingPoolAsync(poolOperator, 0, true); // add operator as maker
poolOperator = new PoolOperatorActor(actors[2], stakingApiWrapper);
// Create a pool where all rewards go to members.
poolId = await poolOperator.createStakingPoolAsync(0, true);
// Stake something in the pool or else it won't get any rewards.
poolOperatorStaker = new StakerActor(poolOperator.getOwner(), stakingApiWrapper);
await poolOperatorStaker.stakeWithPoolAsync(poolId, new BigNumber(1));
// set exchange address
await stakingApiWrapper.stakingContract.addExchangeAddress.awaitTransactionSuccessAsync(exchangeAddress);
// associate operators for tracking in Finalizer
const operatorByPoolId: OperatorByPoolId = {};
operatorByPoolId[poolId] = poolOperator;
operatorByPoolId[poolId] = poolOperator;
operatorByPoolId[poolId] = poolOperator.getOwner();
// associate actors with pools for tracking in Finalizer
const membersByPoolId: MembersByPoolId = {};
membersByPoolId[poolId] = [actors[0], actors[1]];
membersByPoolId[poolId] = [actors[0], actors[1]];
// create Finalizer actor
finalizer = new FinalizerActor(actors[3], stakingApiWrapper, [poolId], operatorByPoolId, membersByPoolId);
// Skip to next epoch so operator stake is realized.
await stakingApiWrapper.utils.skipToNextEpochAndFinalizeAsync();
});
describe('Reward Simulation', () => {
interface EndBalances {
@@ -154,7 +160,7 @@ blockchainTests.resets('Testing Rewards', env => {
const fee = _fee !== undefined ? _fee : ZERO;
if (!fee.eq(ZERO)) {
await stakingApiWrapper.stakingContract.payProtocolFee.awaitTransactionSuccessAsync(
poolOperator,
poolOperator.getOwner(),
takerAddress,
fee,
{ from: exchangeAddress, value: fee },
@@ -196,12 +202,7 @@ blockchainTests.resets('Testing Rewards', env => {
(staker joins this epoch but is active next epoch)`, async () => {
// delegate
const amount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(amount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
amount,
);
await stakers[0].stakeWithPoolAsync(poolId, amount);
// finalize
const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward);
@@ -213,12 +214,7 @@ blockchainTests.resets('Testing Rewards', env => {
it('Should give pool reward to delegator', async () => {
// delegate
const amount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(amount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
amount,
);
await stakers[0].stakeWithPoolAsync(poolId, amount);
// skip epoch, so staker can start earning rewards
await payProtocolFeeAndFinalize();
// finalize
@@ -232,22 +228,12 @@ blockchainTests.resets('Testing Rewards', env => {
});
});
it('Should split pool reward between delegators', async () => {
// first staker delegates
const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)];
const totalStakeAmount = toBaseUnitAmount(10);
await stakers[0].stakeAsync(stakeAmounts[0]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[0],
);
// first staker delegates
await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]);
// second staker delegates
await stakers[1].stakeAsync(stakeAmounts[1]);
await stakers[1].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[1],
);
await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]);
// skip epoch, so staker can start earning rewards
await payProtocolFeeAndFinalize();
// finalize
@@ -299,24 +285,14 @@ blockchainTests.resets('Testing Rewards', env => {
});
});
it('Should give pool reward to delegators only for the epoch during which they delegated', async () => {
// first staker delegates (epoch 0)
const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)];
const totalStakeAmount = toBaseUnitAmount(10);
await stakers[0].stakeAsync(stakeAmounts[0]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[0],
);
// first staker delegates (epoch 0)
await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// second staker delegates (epoch 1)
await stakers[1].stakeAsync(stakeAmounts[1]);
await stakers[1].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[1],
);
await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]);
// only the first staker will get this reward
const rewardForOnlyFirstDelegator = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(rewardForOnlyFirstDelegator);
@@ -349,24 +325,14 @@ blockchainTests.resets('Testing Rewards', env => {
return v.toNumber();
});
const totalSharedRewards = new BigNumber(totalSharedRewardsAsNumber);
// first staker delegates (epoch 0)
const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)];
const totalStakeAmount = toBaseUnitAmount(10);
await stakers[0].stakeAsync(stakeAmounts[0]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[0],
);
// first staker delegates (epoch 0)
await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// second staker delegates (epoch 1)
await stakers[1].stakeAsync(stakeAmounts[1]);
await stakers[1].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[1],
);
await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]);
// only the first staker will get this reward
await payProtocolFeeAndFinalize(rewardForOnlyFirstDelegator);
// earn a bunch of rewards
@@ -386,14 +352,9 @@ blockchainTests.resets('Testing Rewards', env => {
});
});
it('Should send existing rewards from reward vault to eth vault correctly when undelegating stake', async () => {
// first staker delegates (epoch 0)
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
// first staker delegates (epoch 0)
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// earn reward
@@ -412,26 +373,16 @@ blockchainTests.resets('Testing Rewards', env => {
});
});
it('Should send existing rewards from reward vault to eth vault correctly when delegating more stake', async () => {
// first staker delegates (epoch 0)
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
// first staker delegates (epoch 0)
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// earn reward
const reward = toBaseUnitAmount(10);
await payProtocolFeeAndFinalize(reward);
// add more stake
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// sanity check final balances
await validateEndBalances({
stakerRewardVaultBalance_1: ZERO,
@@ -453,23 +404,13 @@ blockchainTests.resets('Testing Rewards', env => {
return v.toNumber();
}),
);
// first staker delegates (epoch 0)
const stakeAmounts = [toBaseUnitAmount(4), toBaseUnitAmount(6)];
await stakers[0].stakeAsync(stakeAmounts[0]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[0],
);
// first staker delegates (epoch 0)
await stakers[0].stakeWithPoolAsync(poolId, stakeAmounts[0]);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// second staker delegates (epoch 1)
await stakers[0].stakeAsync(stakeAmounts[1]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[1],
);
await stakers[1].stakeWithPoolAsync(poolId, stakeAmounts[1]);
// only the first staker will get this reward
await payProtocolFeeAndFinalize(rewardBeforeAddingMoreStake);
// earn a bunch of rewards
@@ -488,12 +429,7 @@ blockchainTests.resets('Testing Rewards', env => {
const rewardForDelegator = toBaseUnitAmount(10);
const rewardNotForDelegator = toBaseUnitAmount(7);
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// earn reward
@@ -534,12 +470,7 @@ blockchainTests.resets('Testing Rewards', env => {
}),
);
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// earn reward
@@ -566,12 +497,7 @@ blockchainTests.resets('Testing Rewards', env => {
const rewardsForDelegator = [toBaseUnitAmount(10), toBaseUnitAmount(15)];
const rewardNotForDelegator = toBaseUnitAmount(7);
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so first staker can start earning rewards
await payProtocolFeeAndFinalize();
// earn reward
@@ -668,12 +594,7 @@ blockchainTests.resets('Testing Rewards', env => {
const staker = stakers[0];
const stakeAmount = toBaseUnitAmount(5);
// stake and delegate
await staker.stakeAsync(stakeAmount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await stakers[0].stakeWithPoolAsync(poolId, stakeAmount);
// skip epoch, so staker can start earning rewards
await payProtocolFeeAndFinalize();
// undelegate some stake
@@ -703,12 +624,7 @@ blockchainTests.resets('Testing Rewards', env => {
// stake and delegate both
const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as Array<[StakerActor, BigNumber]>;
for (const [staker, stakeAmount] of stakersAndStake) {
await staker.stakeAsync(stakeAmount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await staker.stakeWithPoolAsync(poolId, stakeAmount);
}
// skip epoch, so staker can start earning rewards
await payProtocolFeeAndFinalize();
@@ -739,12 +655,7 @@ blockchainTests.resets('Testing Rewards', env => {
// stake and delegate both
const stakersAndStake = _.zip(stakers.slice(0, 2), stakeAmounts) as Array<[StakerActor, BigNumber]>;
for (const [staker, stakeAmount] of stakersAndStake) {
await staker.stakeAsync(stakeAmount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
await staker.stakeWithPoolAsync(poolId, stakeAmount);
}
// skip epoch, so staker can start earning rewards
await payProtocolFeeAndFinalize();

View File

@@ -7,7 +7,7 @@ blockchainTests('delegator rewards', env => {
before(async () => {
testContract = await TestDelegatorRewardsContract.deployFrom0xArtifactAsync(
artifacts.TestLibFixedMath,
artifacts.TestDelegatorRewards,
env.provider,
env.txDefaults,
artifacts,

View File

@@ -0,0 +1,55 @@
import { blockchainTests, expect, filterLogsToArguments, Numberish } from '@0x/contracts-test-utils';
import {
artifacts,
IStakingEventsEpochEndedEventArgs,
IStakingEventsEpochFinalizedEventArgs,
IStakingEventsEvents,
TestFinalizerContract,
} from '../../src';
blockchainTests.resets.only('finalization tests', env => {
let testContract: TestFinalizerContract;
const INITIAL_EPOCH = 0;
before(async () => {
testContract = await TestFinalizerContract.deployFrom0xArtifactAsync(
artifacts.TestFinalizer,
env.provider,
env.txDefaults,
artifacts,
);
});
describe('endEpoch()', () => {
it('emits an `EpochEnded` event', async () => {
const receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const [epochEndedEvent] = filterLogsToArguments<IStakingEventsEpochEndedEventArgs>(
receipt.logs,
IStakingEventsEvents.EpochEnded,
);
expect(epochEndedEvent.epoch).to.bignumber.eq(INITIAL_EPOCH);
expect(epochEndedEvent.numActivePools).to.bignumber.eq(0);
expect(epochEndedEvent.rewardsAvailable).to.bignumber.eq(0);
expect(epochEndedEvent.totalFeesCollected).to.bignumber.eq(0);
expect(epochEndedEvent.totalWeightedStake).to.bignumber.eq(0);
});
it('advances the epoch', async () => {
await testContract.endEpoch.awaitTransactionSuccessAsync();
const currentEpoch = await testContract.getCurrentEpoch.callAsync();
expect(currentEpoch).to.be.bignumber.eq(INITIAL_EPOCH + 1);
});
it('immediately finalizes if there are no active pools', async () => {
const receipt = await testContract.endEpoch.awaitTransactionSuccessAsync();
const [epochFinalizedEvent] = filterLogsToArguments<IStakingEventsEpochFinalizedEventArgs>(
receipt.logs,
IStakingEventsEvents.EpochFinalized,
);
expect(epochFinalizedEvent.epoch).to.bignumber.eq(INITIAL_EPOCH);
expect(epochFinalizedEvent.rewardsPaid).to.bignumber.eq(0);
expect(epochFinalizedEvent.rewardsRemaining).to.bignumber.eq(0);
});
});
});