fixing bugs
This commit is contained in:
parent
be0e6c8925
commit
ccb477687a
@ -100,9 +100,9 @@ export function KeeperMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
|
|
||||||
private async *_validEndEpoch(): AsyncIterableIterator<AssertionResult | void> {
|
private async *_validEndEpoch(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
const assertion = validEndEpochAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
const assertion = validEndEpochAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
||||||
const { currentEpoch } = this.actor.simulationEnvironment!;
|
|
||||||
const { stakingWrapper } = this.actor.deployment.staking;
|
const { stakingWrapper } = this.actor.deployment.staking;
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const { currentEpoch } = this.actor.simulationEnvironment!;
|
||||||
const aggregatedStats = AggregatedStats.fromArray(
|
const aggregatedStats = AggregatedStats.fromArray(
|
||||||
await stakingWrapper.aggregatedStatsByEpoch(currentEpoch.minus(1)).callAsync(),
|
await stakingWrapper.aggregatedStatsByEpoch(currentEpoch.minus(1)).callAsync(),
|
||||||
);
|
);
|
||||||
|
@ -71,8 +71,8 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
|
|
||||||
private async *_validStake(): AsyncIterableIterator<AssertionResult> {
|
private async *_validStake(): AsyncIterableIterator<AssertionResult> {
|
||||||
const { zrx } = this.actor.deployment.tokens;
|
const { zrx } = this.actor.deployment.tokens;
|
||||||
const { deployment, balanceStore, globalStake } = this.actor.simulationEnvironment!;
|
const { deployment, balanceStore } = this.actor.simulationEnvironment!;
|
||||||
const assertion = validStakeAssertion(deployment, balanceStore, globalStake, this.stake);
|
const assertion = validStakeAssertion(deployment, this.actor.simulationEnvironment!, this.stake);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
await balanceStore.updateErc20BalancesAsync();
|
await balanceStore.updateErc20BalancesAsync();
|
||||||
@ -84,8 +84,8 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
|
|
||||||
private async *_validUnstake(): AsyncIterableIterator<AssertionResult> {
|
private async *_validUnstake(): AsyncIterableIterator<AssertionResult> {
|
||||||
const { stakingWrapper } = this.actor.deployment.staking;
|
const { stakingWrapper } = this.actor.deployment.staking;
|
||||||
const { deployment, balanceStore, globalStake } = this.actor.simulationEnvironment!;
|
const { deployment, balanceStore } = this.actor.simulationEnvironment!;
|
||||||
const assertion = validUnstakeAssertion(deployment, balanceStore, globalStake, this.stake);
|
const assertion = validUnstakeAssertion(deployment, this.actor.simulationEnvironment!, this.stake);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
await balanceStore.updateErc20BalancesAsync();
|
await balanceStore.updateErc20BalancesAsync();
|
||||||
@ -102,22 +102,23 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async *_validMoveStake(): AsyncIterableIterator<AssertionResult> {
|
private async *_validMoveStake(): AsyncIterableIterator<AssertionResult> {
|
||||||
const { deployment, globalStake, stakingPools } = this.actor.simulationEnvironment!;
|
const { deployment, stakingPools } = this.actor.simulationEnvironment!;
|
||||||
const assertion = validMoveStakeAssertion(deployment, globalStake, this.stake, stakingPools);
|
const assertion = validMoveStakeAssertion(deployment, this.actor.simulationEnvironment!, this.stake);
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
const { currentEpoch } = this.actor.simulationEnvironment!;
|
||||||
const fromPoolId = Pseudorandom.sample(
|
const fromPoolId = Pseudorandom.sample(
|
||||||
Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total'])),
|
Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total'])),
|
||||||
);
|
);
|
||||||
const fromStatus =
|
const fromStatus =
|
||||||
fromPoolId === undefined
|
fromPoolId === undefined || stakingPools[fromPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
|
||||||
? StakeStatus.Undelegated
|
? StakeStatus.Undelegated
|
||||||
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||||
const from = new StakeInfo(fromStatus, fromPoolId);
|
const from = new StakeInfo(fromStatus, fromPoolId);
|
||||||
|
|
||||||
const toPoolId = Pseudorandom.sample(Object.keys(stakingPools));
|
const toPoolId = Pseudorandom.sample(Object.keys(stakingPools));
|
||||||
const toStatus =
|
const toStatus =
|
||||||
toPoolId === undefined
|
toPoolId === undefined || stakingPools[toPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
|
||||||
? StakeStatus.Undelegated
|
? StakeStatus.Undelegated
|
||||||
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
: (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||||
const to = new StakeInfo(toStatus, toPoolId);
|
const to = new StakeInfo(toStatus, toPoolId);
|
||||||
@ -134,9 +135,17 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
|
|
||||||
private async *_validWithdrawDelegatorRewards(): AsyncIterableIterator<AssertionResult | void> {
|
private async *_validWithdrawDelegatorRewards(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||||
const assertion = validWithdrawDelegatorRewardsAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
const assertion = validWithdrawDelegatorRewardsAssertion(
|
||||||
|
this.actor.deployment,
|
||||||
|
this.actor.simulationEnvironment!,
|
||||||
|
);
|
||||||
while (true) {
|
while (true) {
|
||||||
const poolId = Pseudorandom.sample(Object.keys(stakingPools));
|
const prevEpoch = this.actor.simulationEnvironment!.currentEpoch.minus(1);
|
||||||
|
const poolId = Pseudorandom.sample(
|
||||||
|
Object.keys(stakingPools).filter(poolId =>
|
||||||
|
stakingPools[poolId].lastFinalized.isGreaterThanOrEqualTo(prevEpoch),
|
||||||
|
),
|
||||||
|
);
|
||||||
if (poolId === undefined) {
|
if (poolId === undefined) {
|
||||||
yield;
|
yield;
|
||||||
} else {
|
} else {
|
||||||
|
@ -83,11 +83,9 @@ export function TakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
|||||||
token: DummyERC20TokenContract,
|
token: DummyERC20TokenContract,
|
||||||
): Promise<BigNumber> => {
|
): Promise<BigNumber> => {
|
||||||
let balance = balanceStore.balances.erc20[owner.address][token.address];
|
let balance = balanceStore.balances.erc20[owner.address][token.address];
|
||||||
if (balance === undefined || balance.isZero()) {
|
|
||||||
await owner.configureERC20TokenAsync(token);
|
await owner.configureERC20TokenAsync(token);
|
||||||
balance = balanceStore.balances.erc20[owner.address][token.address] =
|
balance = balanceStore.balances.erc20[owner.address][token.address] =
|
||||||
constants.INITIAL_ERC20_BALANCE;
|
constants.INITIAL_ERC20_BALANCE;
|
||||||
}
|
|
||||||
return Pseudorandom.integer(balance.dividedToIntegerBy(2));
|
return Pseudorandom.integer(balance.dividedToIntegerBy(2));
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -37,6 +37,9 @@ export function validCreateStakingPoolAssertion(
|
|||||||
args: [number, boolean],
|
args: [number, boolean],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [operatorShare] = args;
|
const [operatorShare] = args;
|
||||||
|
|
||||||
// Checks the logs for the new poolId, verifies that it is as expected
|
// Checks the logs for the new poolId, verifies that it is as expected
|
||||||
|
@ -17,7 +17,10 @@ export function validDecreaseStakingPoolOperatorShareAssertion(
|
|||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion<[string, number], {}, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', {
|
return new FunctionAssertion<[string, number], {}, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', {
|
||||||
after: async (_beforeInfo, _result: FunctionResult, args: [string, number], _txData: Partial<TxData>) => {
|
after: async (_beforeInfo, result: FunctionResult, args: [string, number], _txData: Partial<TxData>) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [poolId, expectedOperatorShare] = args;
|
const [poolId, expectedOperatorShare] = args;
|
||||||
|
|
||||||
// Checks that the on-chain pool's operator share has been updated.
|
// Checks that the on-chain pool's operator share has been updated.
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
import { WETH9DepositEventArgs, WETH9Events } from '@0x/contracts-erc20';
|
import { WETH9DepositEventArgs, WETH9Events } from '@0x/contracts-erc20';
|
||||||
import { AggregatedStats, StakingEvents, StakingEpochEndedEventArgs } from '@0x/contracts-staking';
|
import {
|
||||||
import { expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
AggregatedStats,
|
||||||
|
StakingEvents,
|
||||||
|
StakingEpochEndedEventArgs,
|
||||||
|
StakingEpochFinalizedEventArgs,
|
||||||
|
} from '@0x/contracts-staking';
|
||||||
|
import { constants, expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TxData } from 'ethereum-types';
|
import { TxData } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
import { SimulationEnvironment } from '../simulation';
|
import { SimulationEnvironment } from '../simulation';
|
||||||
@ -25,20 +31,25 @@ export function validEndEpochAssertion(
|
|||||||
simulationEnvironment: SimulationEnvironment,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
): FunctionAssertion<[], EndEpochBeforeInfo, void> {
|
): FunctionAssertion<[], EndEpochBeforeInfo, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
const { balanceStore, currentEpoch } = simulationEnvironment;
|
const { balanceStore } = simulationEnvironment;
|
||||||
|
|
||||||
return new FunctionAssertion(stakingWrapper, 'endEpoch', {
|
return new FunctionAssertion(stakingWrapper, 'endEpoch', {
|
||||||
before: async () => {
|
before: async () => {
|
||||||
await balanceStore.updateEthBalancesAsync();
|
await balanceStore.updateEthBalancesAsync();
|
||||||
const aggregatedStatsBefore = AggregatedStats.fromArray(
|
const aggregatedStatsBefore = AggregatedStats.fromArray(
|
||||||
await stakingWrapper.aggregatedStatsByEpoch(currentEpoch).callAsync(),
|
await stakingWrapper.aggregatedStatsByEpoch(simulationEnvironment.currentEpoch).callAsync(),
|
||||||
);
|
);
|
||||||
const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync();
|
const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync();
|
||||||
return { wethReservedForPoolRewards, aggregatedStatsBefore };
|
return { wethReservedForPoolRewards, aggregatedStatsBefore };
|
||||||
},
|
},
|
||||||
after: async (beforeInfo: EndEpochBeforeInfo, result: FunctionResult, _args: [], _txData: Partial<TxData>) => {
|
after: async (beforeInfo: EndEpochBeforeInfo, result: FunctionResult, _args: [], _txData: Partial<TxData>) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
|
const { currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
// Check WETH deposit event
|
// Check WETH deposit event
|
||||||
const previousEthBalance = balanceStore.balances.eth[stakingWrapper.address];
|
const previousEthBalance = balanceStore.balances.eth[stakingWrapper.address] || constants.ZERO_AMOUNT;
|
||||||
if (previousEthBalance.isGreaterThan(0)) {
|
if (previousEthBalance.isGreaterThan(0)) {
|
||||||
verifyEventsFromLogs<WETH9DepositEventArgs>(
|
verifyEventsFromLogs<WETH9DepositEventArgs>(
|
||||||
result.receipt!.logs,
|
result.receipt!.logs,
|
||||||
@ -56,9 +67,11 @@ export function validEndEpochAssertion(
|
|||||||
const { wethReservedForPoolRewards, aggregatedStatsBefore } = beforeInfo;
|
const { wethReservedForPoolRewards, aggregatedStatsBefore } = beforeInfo;
|
||||||
const expectedAggregatedStats = {
|
const expectedAggregatedStats = {
|
||||||
...aggregatedStatsBefore,
|
...aggregatedStatsBefore,
|
||||||
rewardsAvailable: balanceStore.balances.erc20[stakingWrapper.address][
|
rewardsAvailable: _.get(
|
||||||
deployment.tokens.weth.address
|
balanceStore.balances,
|
||||||
].minus(wethReservedForPoolRewards),
|
['erc20', stakingWrapper.address, deployment.tokens.weth.address],
|
||||||
|
constants.ZERO_AMOUNT,
|
||||||
|
).minus(wethReservedForPoolRewards),
|
||||||
};
|
};
|
||||||
|
|
||||||
const aggregatedStatsAfter = AggregatedStats.fromArray(
|
const aggregatedStatsAfter = AggregatedStats.fromArray(
|
||||||
@ -66,8 +79,9 @@ export function validEndEpochAssertion(
|
|||||||
);
|
);
|
||||||
expect(aggregatedStatsAfter).to.deep.equal(expectedAggregatedStats);
|
expect(aggregatedStatsAfter).to.deep.equal(expectedAggregatedStats);
|
||||||
|
|
||||||
const expectedEpochEndedEvents = aggregatedStatsAfter.numPoolsToFinalize.isZero()
|
verifyEventsFromLogs<StakingEpochEndedEventArgs>(
|
||||||
? [
|
result.receipt!.logs,
|
||||||
|
[
|
||||||
{
|
{
|
||||||
epoch: currentEpoch,
|
epoch: currentEpoch,
|
||||||
numPoolsToFinalize: aggregatedStatsAfter.numPoolsToFinalize,
|
numPoolsToFinalize: aggregatedStatsAfter.numPoolsToFinalize,
|
||||||
@ -75,13 +89,25 @@ export function validEndEpochAssertion(
|
|||||||
totalFeesCollected: aggregatedStatsAfter.totalFeesCollected,
|
totalFeesCollected: aggregatedStatsAfter.totalFeesCollected,
|
||||||
totalWeightedStake: aggregatedStatsAfter.totalWeightedStake,
|
totalWeightedStake: aggregatedStatsAfter.totalWeightedStake,
|
||||||
},
|
},
|
||||||
]
|
],
|
||||||
: [];
|
|
||||||
verifyEventsFromLogs<StakingEpochEndedEventArgs>(
|
|
||||||
result.receipt!.logs,
|
|
||||||
expectedEpochEndedEvents,
|
|
||||||
StakingEvents.EpochEnded,
|
StakingEvents.EpochEnded,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
const expectedEpochFinalizedEvents = aggregatedStatsAfter.numPoolsToFinalize.isZero()
|
||||||
|
? [
|
||||||
|
{
|
||||||
|
epoch: currentEpoch,
|
||||||
|
rewardsPaid: constants.ZERO_AMOUNT,
|
||||||
|
rewardsRemaining: aggregatedStatsAfter.rewardsAvailable,
|
||||||
|
},
|
||||||
|
]
|
||||||
|
: [];
|
||||||
|
verifyEventsFromLogs<StakingEpochFinalizedEventArgs>(
|
||||||
|
result.receipt!.logs,
|
||||||
|
expectedEpochFinalizedEvents,
|
||||||
|
StakingEvents.EpochFinalized,
|
||||||
|
);
|
||||||
|
|
||||||
expect(result.data, 'endEpoch should return the number of unfinalized pools').to.bignumber.equal(
|
expect(result.data, 'endEpoch should return the number of unfinalized pools').to.bignumber.equal(
|
||||||
aggregatedStatsAfter.numPoolsToFinalize,
|
aggregatedStatsAfter.numPoolsToFinalize,
|
||||||
);
|
);
|
||||||
|
@ -104,7 +104,7 @@ export function validFillOrderAssertion(
|
|||||||
simulationEnvironment: SimulationEnvironment,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
): FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults> {
|
): FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
const { actors, currentEpoch } = simulationEnvironment;
|
const { actors } = simulationEnvironment;
|
||||||
|
|
||||||
return new FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults>(
|
return new FunctionAssertion<[Order, BigNumber, string], FillOrderBeforeInfo | void, FillResults>(
|
||||||
deployment.exchange,
|
deployment.exchange,
|
||||||
@ -112,6 +112,7 @@ export function validFillOrderAssertion(
|
|||||||
{
|
{
|
||||||
before: async (args: [Order, BigNumber, string]) => {
|
before: async (args: [Order, BigNumber, string]) => {
|
||||||
const [order] = args;
|
const [order] = args;
|
||||||
|
const { currentEpoch } = simulationEnvironment;
|
||||||
const maker = filterActorsByRole(actors, Maker).find(maker => maker.address === order.makerAddress);
|
const maker = filterActorsByRole(actors, Maker).find(maker => maker.address === order.makerAddress);
|
||||||
|
|
||||||
const poolId = maker!.makerPoolId;
|
const poolId = maker!.makerPoolId;
|
||||||
@ -139,11 +140,12 @@ export function validFillOrderAssertion(
|
|||||||
args: [Order, BigNumber, string],
|
args: [Order, BigNumber, string],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
const [order, fillAmount] = args;
|
|
||||||
|
|
||||||
// Ensure that the tx succeeded.
|
// Ensure that the tx succeeded.
|
||||||
expect(result.success, `Error: ${result.data}`).to.be.true();
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
|
const [order, fillAmount] = args;
|
||||||
|
const { currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
// Ensure that the correct events were emitted.
|
// Ensure that the correct events were emitted.
|
||||||
verifyFillEvents(txData, order, result.receipt!, deployment, fillAmount);
|
verifyFillEvents(txData, order, result.receipt!, deployment, fillAmount);
|
||||||
|
|
||||||
|
@ -65,12 +65,12 @@ export function validFinalizePoolAssertion(
|
|||||||
simulationEnvironment: SimulationEnvironment,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
): FunctionAssertion<[string], FinalizePoolBeforeInfo, void> {
|
): FunctionAssertion<[string], FinalizePoolBeforeInfo, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
const { currentEpoch } = simulationEnvironment;
|
|
||||||
const prevEpoch = currentEpoch.minus(1);
|
|
||||||
|
|
||||||
return new FunctionAssertion<[string], FinalizePoolBeforeInfo, void>(stakingWrapper, 'finalizePool', {
|
return new FunctionAssertion<[string], FinalizePoolBeforeInfo, void>(stakingWrapper, 'finalizePool', {
|
||||||
before: async (args: [string]) => {
|
before: async (args: [string]) => {
|
||||||
const [poolId] = args;
|
const [poolId] = args;
|
||||||
|
const { currentEpoch } = simulationEnvironment;
|
||||||
|
const prevEpoch = currentEpoch.minus(1);
|
||||||
|
|
||||||
const poolStats = PoolStats.fromArray(await stakingWrapper.poolStatsByEpoch(poolId, prevEpoch).callAsync());
|
const poolStats = PoolStats.fromArray(await stakingWrapper.poolStatsByEpoch(poolId, prevEpoch).callAsync());
|
||||||
const aggregatedStats = AggregatedStats.fromArray(
|
const aggregatedStats = AggregatedStats.fromArray(
|
||||||
@ -90,10 +90,14 @@ export function validFinalizePoolAssertion(
|
|||||||
};
|
};
|
||||||
},
|
},
|
||||||
after: async (beforeInfo: FinalizePoolBeforeInfo, result: FunctionResult, args: [string]) => {
|
after: async (beforeInfo: FinalizePoolBeforeInfo, result: FunctionResult, args: [string]) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
// // Compute relevant epochs
|
// // Compute relevant epochs
|
||||||
// uint256 currentEpoch_ = currentEpoch;
|
// uint256 currentEpoch_ = currentEpoch;
|
||||||
// uint256 prevEpoch = currentEpoch_.safeSub(1);
|
// uint256 prevEpoch = currentEpoch_.safeSub(1);
|
||||||
const { stakingPools } = simulationEnvironment;
|
const { stakingPools, currentEpoch } = simulationEnvironment;
|
||||||
|
const prevEpoch = currentEpoch.minus(1);
|
||||||
const [poolId] = args;
|
const [poolId] = args;
|
||||||
const pool = stakingPools[poolId];
|
const pool = stakingPools[poolId];
|
||||||
|
|
||||||
@ -155,9 +159,8 @@ export function validFinalizePoolAssertion(
|
|||||||
expect(events.length, 'Number of RewardsPaid events emitted').to.equal(1);
|
expect(events.length, 'Number of RewardsPaid events emitted').to.equal(1);
|
||||||
const [rewardsPaidEvent] = events;
|
const [rewardsPaidEvent] = events;
|
||||||
|
|
||||||
expect(rewardsPaidEvent.currentEpoch_, 'RewardsPaid event: currentEpoch_').to.bignumber.equal(currentEpoch);
|
expect(rewardsPaidEvent.poolId, 'RewardsPaid event: poolId').to.equal(poolId);
|
||||||
expect(rewardsPaidEvent.poolId, 'RewardsPaid event: poolId').to.bignumber.equal(poolId);
|
expect(rewardsPaidEvent.epoch, 'RewardsPaid event: currentEpoch_').to.bignumber.equal(currentEpoch);
|
||||||
expect(rewardsPaidEvent.currentEpoch_, 'RewardsPaid event: currentEpoch_').to.bignumber.equal(currentEpoch);
|
|
||||||
|
|
||||||
const { operatorReward, membersReward } = rewardsPaidEvent;
|
const { operatorReward, membersReward } = rewardsPaidEvent;
|
||||||
const totalReward = operatorReward.plus(membersReward);
|
const totalReward = operatorReward.plus(membersReward);
|
||||||
@ -189,6 +192,7 @@ export function validFinalizePoolAssertion(
|
|||||||
},
|
},
|
||||||
]
|
]
|
||||||
: [];
|
: [];
|
||||||
|
|
||||||
// Check for WETH transfer event emitted when paying out operator's reward.
|
// Check for WETH transfer event emitted when paying out operator's reward.
|
||||||
verifyEventsFromLogs<WETH9TransferEventArgs>(
|
verifyEventsFromLogs<WETH9TransferEventArgs>(
|
||||||
result.receipt!.logs,
|
result.receipt!.logs,
|
||||||
|
@ -79,13 +79,15 @@ export class FunctionAssertion<TArgs extends any[], TBefore, ReturnDataType> imp
|
|||||||
// Initialize the callResult so that the default success value is true.
|
// Initialize the callResult so that the default success value is true.
|
||||||
const callResult: FunctionResult = { success: true };
|
const callResult: FunctionResult = { success: true };
|
||||||
|
|
||||||
|
// Log function name, arguments, and txData
|
||||||
|
logger.logFunctionAssertion(this._functionName, args, txData);
|
||||||
|
|
||||||
// Try to make the call to the function. If it is successful, pass the
|
// Try to make the call to the function. If it is successful, pass the
|
||||||
// result and receipt to the after condition.
|
// result and receipt to the after condition.
|
||||||
try {
|
try {
|
||||||
const functionWithArgs = (this._contractWrapper as any)[this._functionName](
|
const functionWithArgs = (this._contractWrapper as any)[this._functionName](
|
||||||
...args,
|
...args,
|
||||||
) as ContractTxFunctionObj<ReturnDataType>;
|
) as ContractTxFunctionObj<ReturnDataType>;
|
||||||
logger.logFunctionAssertion(this._functionName, args, txData);
|
|
||||||
callResult.data = await functionWithArgs.callAsync(txData);
|
callResult.data = await functionWithArgs.callAsync(txData);
|
||||||
callResult.receipt =
|
callResult.receipt =
|
||||||
functionWithArgs.awaitTransactionSuccessAsync !== undefined
|
functionWithArgs.awaitTransactionSuccessAsync !== undefined
|
||||||
|
@ -15,12 +15,13 @@ export function validJoinStakingPoolAssertion(deployment: DeploymentManager): Fu
|
|||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion<[string], {}, void>(stakingWrapper, 'joinStakingPoolAsMaker', {
|
return new FunctionAssertion<[string], {}, void>(stakingWrapper, 'joinStakingPoolAsMaker', {
|
||||||
after: async (_beforeInfo, _result: FunctionResult, args: [string], txData: Partial<TxData>) => {
|
after: async (_beforeInfo, result: FunctionResult, args: [string], txData: Partial<TxData>) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [poolId] = args;
|
const [poolId] = args;
|
||||||
|
|
||||||
expect(_result.success).to.be.true();
|
const logs = result.receipt!.logs;
|
||||||
|
|
||||||
const logs = _result.receipt!.logs;
|
|
||||||
const logArgs = filterLogsToArguments<StakingMakerStakingPoolSetEventArgs>(
|
const logArgs = filterLogsToArguments<StakingMakerStakingPoolSetEventArgs>(
|
||||||
logs,
|
logs,
|
||||||
StakingEvents.MakerStakingPoolSet,
|
StakingEvents.MakerStakingPoolSet,
|
||||||
|
@ -1,75 +1,94 @@
|
|||||||
import {
|
import { OwnerStakeByStatus, StakeInfo, StakeStatus, StoredBalance } from '@0x/contracts-staking';
|
||||||
GlobalStakeByStatus,
|
|
||||||
OwnerStakeByStatus,
|
|
||||||
StakeInfo,
|
|
||||||
StakeStatus,
|
|
||||||
StakingPoolById,
|
|
||||||
StoredBalance,
|
|
||||||
} from '@0x/contracts-staking';
|
|
||||||
import { constants, expect } from '@0x/contracts-test-utils';
|
import { constants, expect } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TxData } from 'ethereum-types';
|
import { TxData } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
|
import { SimulationEnvironment } from '../simulation';
|
||||||
|
|
||||||
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void {
|
function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber, currentEpoch: BigNumber): void {
|
||||||
|
stakeBalance.currentEpochBalance = currentEpoch.isGreaterThan(stakeBalance.currentEpoch)
|
||||||
|
? stakeBalance.nextEpochBalance
|
||||||
|
: stakeBalance.currentEpochBalance;
|
||||||
|
stakeBalance.currentEpoch = currentEpoch;
|
||||||
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount));
|
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
function decrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void {
|
function decrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber, currentEpoch: BigNumber): void {
|
||||||
|
stakeBalance.currentEpochBalance = currentEpoch.isGreaterThan(stakeBalance.currentEpoch)
|
||||||
|
? stakeBalance.nextEpochBalance
|
||||||
|
: stakeBalance.currentEpochBalance;
|
||||||
|
stakeBalance.currentEpoch = currentEpoch;
|
||||||
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).minus(amount));
|
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).minus(amount));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function loadCurrentBalance(balance: StoredBalance, currentEpoch: BigNumber): StoredBalance {
|
||||||
|
return {
|
||||||
|
...balance,
|
||||||
|
currentEpoch: currentEpoch,
|
||||||
|
currentEpochBalance: currentEpoch.isGreaterThan(balance.currentEpoch)
|
||||||
|
? balance.nextEpochBalance
|
||||||
|
: balance.currentEpochBalance,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
function updateNextEpochBalances(
|
function updateNextEpochBalances(
|
||||||
globalStake: GlobalStakeByStatus,
|
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
pools: StakingPoolById,
|
|
||||||
from: StakeInfo,
|
from: StakeInfo,
|
||||||
to: StakeInfo,
|
to: StakeInfo,
|
||||||
amount: BigNumber,
|
amount: BigNumber,
|
||||||
|
simulationEnvironment: SimulationEnvironment,
|
||||||
): string[] {
|
): string[] {
|
||||||
|
const { globalStake, stakingPools, currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
// The on-chain state of these updated pools will be verified in the `after` of the assertion.
|
// The on-chain state of these updated pools will be verified in the `after` of the assertion.
|
||||||
const updatedPools = [];
|
const updatedPools = [];
|
||||||
|
|
||||||
// Decrement next epoch balances associated with the `from` stake
|
// Decrement next epoch balances associated with the `from` stake
|
||||||
if (from.status === StakeStatus.Undelegated) {
|
if (from.status === StakeStatus.Undelegated) {
|
||||||
// Decrement owner undelegated stake
|
// Decrement owner undelegated stake
|
||||||
decrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
decrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount, currentEpoch);
|
||||||
// Decrement global undelegated stake
|
// Decrement global undelegated stake
|
||||||
decrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
decrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount, currentEpoch);
|
||||||
} else if (from.status === StakeStatus.Delegated) {
|
} else if (from.status === StakeStatus.Delegated) {
|
||||||
// Decrement owner's delegated stake to this pool
|
// Decrement owner's delegated stake to this pool
|
||||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated][from.poolId], amount);
|
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated][from.poolId], amount, currentEpoch);
|
||||||
// Decrement owner's total delegated stake
|
// Decrement owner's total delegated stake
|
||||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount, currentEpoch);
|
||||||
// Decrement global delegated stake
|
// Decrement global delegated stake
|
||||||
decrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
decrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount, currentEpoch);
|
||||||
// Decrement pool's delegated stake
|
// Decrement pool's delegated stake
|
||||||
decrementNextEpochBalance(pools[from.poolId].delegatedStake, amount);
|
decrementNextEpochBalance(stakingPools[from.poolId].delegatedStake, amount, currentEpoch);
|
||||||
updatedPools.push(from.poolId);
|
updatedPools.push(from.poolId);
|
||||||
|
|
||||||
|
// TODO: Check that delegator rewards have been withdrawn/synced
|
||||||
}
|
}
|
||||||
|
|
||||||
// Increment next epoch balances associated with the `to` stake
|
// Increment next epoch balances associated with the `to` stake
|
||||||
if (to.status === StakeStatus.Undelegated) {
|
if (to.status === StakeStatus.Undelegated) {
|
||||||
incrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
// Increment owner undelegated stake
|
||||||
incrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
incrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount, currentEpoch);
|
||||||
|
// Increment global undelegated stake
|
||||||
|
incrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount, currentEpoch);
|
||||||
} else if (to.status === StakeStatus.Delegated) {
|
} else if (to.status === StakeStatus.Delegated) {
|
||||||
// Initializes the balance for this pool if the user has not previously delegated to it
|
// Initializes the balance for this pool if the user has not previously delegated to it
|
||||||
_.defaults(ownerStake[StakeStatus.Delegated], {
|
_.defaults(ownerStake[StakeStatus.Delegated], {
|
||||||
[to.poolId]: new StoredBalance(),
|
[to.poolId]: new StoredBalance(),
|
||||||
});
|
});
|
||||||
// Increment owner's delegated stake to this pool
|
// Increment owner's delegated stake to this pool
|
||||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated][to.poolId], amount);
|
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated][to.poolId], amount, currentEpoch);
|
||||||
// Increment owner's total delegated stake
|
// Increment owner's total delegated stake
|
||||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount, currentEpoch);
|
||||||
// Increment global delegated stake
|
// Increment global delegated stake
|
||||||
incrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
incrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount, currentEpoch);
|
||||||
// Increment pool's delegated stake
|
// Increment pool's delegated stake
|
||||||
incrementNextEpochBalance(pools[to.poolId].delegatedStake, amount);
|
incrementNextEpochBalance(stakingPools[to.poolId].delegatedStake, amount, currentEpoch);
|
||||||
updatedPools.push(to.poolId);
|
updatedPools.push(to.poolId);
|
||||||
|
|
||||||
|
// TODO: Check that delegator rewards have been withdrawn/synced
|
||||||
}
|
}
|
||||||
return updatedPools;
|
return updatedPools;
|
||||||
}
|
}
|
||||||
@ -80,25 +99,28 @@ function updateNextEpochBalances(
|
|||||||
/* tslint:disable:no-unnecessary-type-assertion */
|
/* tslint:disable:no-unnecessary-type-assertion */
|
||||||
export function validMoveStakeAssertion(
|
export function validMoveStakeAssertion(
|
||||||
deployment: DeploymentManager,
|
deployment: DeploymentManager,
|
||||||
globalStake: GlobalStakeByStatus,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
pools: StakingPoolById,
|
|
||||||
): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void> {
|
): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper, zrxVault } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>(stakingWrapper, 'moveStake', {
|
return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>(stakingWrapper, 'moveStake', {
|
||||||
after: async (
|
after: async (
|
||||||
_beforeInfo: {},
|
_beforeInfo: {},
|
||||||
_result: FunctionResult,
|
result: FunctionResult,
|
||||||
args: [StakeInfo, StakeInfo, BigNumber],
|
args: [StakeInfo, StakeInfo, BigNumber],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [from, to, amount] = args;
|
const [from, to, amount] = args;
|
||||||
|
const { stakingPools, globalStake, currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
const owner = txData.from!; // tslint:disable-line:no-non-null-assertion
|
const owner = txData.from!; // tslint:disable-line:no-non-null-assertion
|
||||||
|
|
||||||
// Update local balances to match the expected result of this `moveStake` operation
|
// Update local balances to match the expected result of this `moveStake` operation
|
||||||
const updatedPools = updateNextEpochBalances(globalStake, ownerStake, pools, from, to, amount);
|
const updatedPools = updateNextEpochBalances(ownerStake, from, to, amount, simulationEnvironment);
|
||||||
|
|
||||||
// Fetches on-chain owner stake balances and checks against local balances
|
// Fetches on-chain owner stake balances and checks against local balances
|
||||||
const ownerUndelegatedStake = {
|
const ownerUndelegatedStake = {
|
||||||
@ -109,16 +131,27 @@ export function validMoveStakeAssertion(
|
|||||||
...new StoredBalance(),
|
...new StoredBalance(),
|
||||||
...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Delegated).callAsync()),
|
...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Delegated).callAsync()),
|
||||||
};
|
};
|
||||||
expect(ownerUndelegatedStake).to.deep.equal(ownerStake[StakeStatus.Undelegated]);
|
expect(ownerUndelegatedStake).to.deep.equal(
|
||||||
expect(ownerDelegatedStake).to.deep.equal(ownerStake[StakeStatus.Delegated].total);
|
loadCurrentBalance(ownerStake[StakeStatus.Undelegated], currentEpoch),
|
||||||
|
);
|
||||||
|
expect(ownerDelegatedStake).to.deep.equal(
|
||||||
|
loadCurrentBalance(ownerStake[StakeStatus.Delegated].total, currentEpoch),
|
||||||
|
);
|
||||||
|
|
||||||
// Fetches on-chain global stake balances and checks against local balances
|
// Fetches on-chain global stake balances and checks against local balances
|
||||||
|
const globalDelegatedStake = await stakingWrapper.getGlobalStakeByStatus(StakeStatus.Delegated).callAsync();
|
||||||
const globalUndelegatedStake = await stakingWrapper
|
const globalUndelegatedStake = await stakingWrapper
|
||||||
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const globalDelegatedStake = await stakingWrapper.getGlobalStakeByStatus(StakeStatus.Delegated).callAsync();
|
const totalStake = await zrxVault.balanceOfZrxVault().callAsync();
|
||||||
expect(globalUndelegatedStake).to.deep.equal(globalStake[StakeStatus.Undelegated]);
|
expect(globalDelegatedStake).to.deep.equal(
|
||||||
expect(globalDelegatedStake).to.deep.equal(globalStake[StakeStatus.Delegated]);
|
loadCurrentBalance(globalStake[StakeStatus.Delegated], currentEpoch),
|
||||||
|
);
|
||||||
|
expect(globalUndelegatedStake).to.deep.equal({
|
||||||
|
currentEpochBalance: totalStake.minus(globalDelegatedStake.currentEpochBalance),
|
||||||
|
nextEpochBalance: totalStake.minus(globalDelegatedStake.nextEpochBalance),
|
||||||
|
currentEpoch,
|
||||||
|
});
|
||||||
|
|
||||||
// Fetches on-chain pool stake balances and checks against local balances
|
// Fetches on-chain pool stake balances and checks against local balances
|
||||||
for (const poolId of updatedPools) {
|
for (const poolId of updatedPools) {
|
||||||
@ -126,8 +159,12 @@ export function validMoveStakeAssertion(
|
|||||||
.getStakeDelegatedToPoolByOwner(owner, poolId)
|
.getStakeDelegatedToPoolByOwner(owner, poolId)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const totalStakeDelegated = await stakingWrapper.getTotalStakeDelegatedToPool(poolId).callAsync();
|
const totalStakeDelegated = await stakingWrapper.getTotalStakeDelegatedToPool(poolId).callAsync();
|
||||||
expect(stakeDelegatedByOwner).to.deep.equal(ownerStake[StakeStatus.Delegated][poolId]);
|
expect(stakeDelegatedByOwner).to.deep.equal(
|
||||||
expect(totalStakeDelegated).to.deep.equal(pools[poolId].delegatedStake);
|
loadCurrentBalance(ownerStake[StakeStatus.Delegated][poolId], currentEpoch),
|
||||||
|
);
|
||||||
|
expect(totalStakeDelegated).to.deep.equal(
|
||||||
|
loadCurrentBalance(stakingPools[poolId].delegatedStake, currentEpoch),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
@ -3,19 +3,23 @@ import { expect } from '@0x/contracts-test-utils';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TxData } from 'ethereum-types';
|
import { TxData } from 'ethereum-types';
|
||||||
|
|
||||||
import { BlockchainBalanceStore } from '../balances/blockchain_balance_store';
|
|
||||||
import { LocalBalanceStore } from '../balances/local_balance_store';
|
import { LocalBalanceStore } from '../balances/local_balance_store';
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
|
import { SimulationEnvironment } from '../simulation';
|
||||||
|
|
||||||
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function expectedUndelegatedStake(
|
function expectedUndelegatedStake(
|
||||||
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
||||||
amount: BigNumber,
|
amount: BigNumber,
|
||||||
|
currentEpoch: BigNumber,
|
||||||
): StoredBalance {
|
): StoredBalance {
|
||||||
return {
|
return {
|
||||||
currentEpoch: initStake[StakeStatus.Undelegated].currentEpoch,
|
currentEpoch: currentEpoch,
|
||||||
currentEpochBalance: initStake[StakeStatus.Undelegated].currentEpochBalance.plus(amount),
|
currentEpochBalance: (currentEpoch.isGreaterThan(initStake[StakeStatus.Undelegated].currentEpoch)
|
||||||
|
? initStake[StakeStatus.Undelegated].nextEpochBalance
|
||||||
|
: initStake[StakeStatus.Undelegated].currentEpochBalance
|
||||||
|
).plus(amount),
|
||||||
nextEpochBalance: initStake[StakeStatus.Undelegated].nextEpochBalance.plus(amount),
|
nextEpochBalance: initStake[StakeStatus.Undelegated].nextEpochBalance.plus(amount),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -28,8 +32,7 @@ function expectedUndelegatedStake(
|
|||||||
/* tslint:disable:no-unnecessary-type-assertion */
|
/* tslint:disable:no-unnecessary-type-assertion */
|
||||||
export function validStakeAssertion(
|
export function validStakeAssertion(
|
||||||
deployment: DeploymentManager,
|
deployment: DeploymentManager,
|
||||||
balanceStore: BlockchainBalanceStore,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
globalStake: GlobalStakeByStatus,
|
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
||||||
const { stakingWrapper, zrxVault } = deployment.staking;
|
const { stakingWrapper, zrxVault } = deployment.staking;
|
||||||
@ -37,6 +40,7 @@ export function validStakeAssertion(
|
|||||||
return new FunctionAssertion(stakingWrapper, 'stake', {
|
return new FunctionAssertion(stakingWrapper, 'stake', {
|
||||||
before: async (args: [BigNumber], txData: Partial<TxData>) => {
|
before: async (args: [BigNumber], txData: Partial<TxData>) => {
|
||||||
const [amount] = args;
|
const [amount] = args;
|
||||||
|
const { balanceStore } = simulationEnvironment;
|
||||||
|
|
||||||
// Simulates the transfer of ZRX from staker to vault
|
// Simulates the transfer of ZRX from staker to vault
|
||||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||||
@ -50,11 +54,15 @@ export function validStakeAssertion(
|
|||||||
},
|
},
|
||||||
after: async (
|
after: async (
|
||||||
expectedBalances: LocalBalanceStore,
|
expectedBalances: LocalBalanceStore,
|
||||||
_result: FunctionResult,
|
result: FunctionResult,
|
||||||
args: [BigNumber],
|
args: [BigNumber],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [amount] = args;
|
const [amount] = args;
|
||||||
|
const { balanceStore, globalStake, currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
// Checks that the ZRX transfer updated balances as expected.
|
// Checks that the ZRX transfer updated balances as expected.
|
||||||
await balanceStore.updateErc20BalancesAsync();
|
await balanceStore.updateErc20BalancesAsync();
|
||||||
@ -64,7 +72,7 @@ export function validStakeAssertion(
|
|||||||
const ownerUndelegatedStake = await stakingWrapper
|
const ownerUndelegatedStake = await stakingWrapper
|
||||||
.getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated) // tslint:disable-line:no-non-null-assertion
|
.getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated) // tslint:disable-line:no-non-null-assertion
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount, currentEpoch);
|
||||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||||
// Updates local state accordingly
|
// Updates local state accordingly
|
||||||
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
||||||
@ -73,7 +81,7 @@ export function validStakeAssertion(
|
|||||||
const globalUndelegatedStake = await stakingWrapper
|
const globalUndelegatedStake = await stakingWrapper
|
||||||
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount);
|
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount, currentEpoch);
|
||||||
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
||||||
// Updates local state accordingly
|
// Updates local state accordingly
|
||||||
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
||||||
|
@ -3,19 +3,23 @@ import { expect } from '@0x/contracts-test-utils';
|
|||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TxData } from 'ethereum-types';
|
import { TxData } from 'ethereum-types';
|
||||||
|
|
||||||
import { BlockchainBalanceStore } from '../balances/blockchain_balance_store';
|
|
||||||
import { LocalBalanceStore } from '../balances/local_balance_store';
|
import { LocalBalanceStore } from '../balances/local_balance_store';
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
|
import { SimulationEnvironment } from '../simulation';
|
||||||
|
|
||||||
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
import { FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function expectedUndelegatedStake(
|
function expectedUndelegatedStake(
|
||||||
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
||||||
amount: BigNumber,
|
amount: BigNumber,
|
||||||
|
currentEpoch: BigNumber,
|
||||||
): StoredBalance {
|
): StoredBalance {
|
||||||
return {
|
return {
|
||||||
currentEpoch: initStake[StakeStatus.Undelegated].currentEpoch,
|
currentEpoch: currentEpoch,
|
||||||
currentEpochBalance: initStake[StakeStatus.Undelegated].currentEpochBalance.minus(amount),
|
currentEpochBalance: (currentEpoch.isGreaterThan(initStake[StakeStatus.Undelegated].currentEpoch)
|
||||||
|
? initStake[StakeStatus.Undelegated].nextEpochBalance
|
||||||
|
: initStake[StakeStatus.Undelegated].currentEpochBalance
|
||||||
|
).minus(amount),
|
||||||
nextEpochBalance: initStake[StakeStatus.Undelegated].nextEpochBalance.minus(amount),
|
nextEpochBalance: initStake[StakeStatus.Undelegated].nextEpochBalance.minus(amount),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -29,8 +33,7 @@ function expectedUndelegatedStake(
|
|||||||
/* tslint:disable:no-non-null-assertion */
|
/* tslint:disable:no-non-null-assertion */
|
||||||
export function validUnstakeAssertion(
|
export function validUnstakeAssertion(
|
||||||
deployment: DeploymentManager,
|
deployment: DeploymentManager,
|
||||||
balanceStore: BlockchainBalanceStore,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
globalStake: GlobalStakeByStatus,
|
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
||||||
const { stakingWrapper, zrxVault } = deployment.staking;
|
const { stakingWrapper, zrxVault } = deployment.staking;
|
||||||
@ -38,6 +41,7 @@ export function validUnstakeAssertion(
|
|||||||
return new FunctionAssertion(stakingWrapper, 'unstake', {
|
return new FunctionAssertion(stakingWrapper, 'unstake', {
|
||||||
before: async (args: [BigNumber], txData: Partial<TxData>) => {
|
before: async (args: [BigNumber], txData: Partial<TxData>) => {
|
||||||
const [amount] = args;
|
const [amount] = args;
|
||||||
|
const { balanceStore } = simulationEnvironment;
|
||||||
|
|
||||||
// Simulates the transfer of ZRX from vault to staker
|
// Simulates the transfer of ZRX from vault to staker
|
||||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||||
@ -51,11 +55,15 @@ export function validUnstakeAssertion(
|
|||||||
},
|
},
|
||||||
after: async (
|
after: async (
|
||||||
expectedBalances: LocalBalanceStore,
|
expectedBalances: LocalBalanceStore,
|
||||||
_result: FunctionResult,
|
result: FunctionResult,
|
||||||
args: [BigNumber],
|
args: [BigNumber],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [amount] = args;
|
const [amount] = args;
|
||||||
|
const { balanceStore, globalStake, currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
// Checks that the ZRX transfer updated balances as expected.
|
// Checks that the ZRX transfer updated balances as expected.
|
||||||
await balanceStore.updateErc20BalancesAsync();
|
await balanceStore.updateErc20BalancesAsync();
|
||||||
@ -65,7 +73,7 @@ export function validUnstakeAssertion(
|
|||||||
const ownerUndelegatedStake = await stakingWrapper
|
const ownerUndelegatedStake = await stakingWrapper
|
||||||
.getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated)
|
.getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount, currentEpoch);
|
||||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||||
// Updates local state accordingly
|
// Updates local state accordingly
|
||||||
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
||||||
@ -74,7 +82,7 @@ export function validUnstakeAssertion(
|
|||||||
const globalUndelegatedStake = await stakingWrapper
|
const globalUndelegatedStake = await stakingWrapper
|
||||||
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
.getGlobalStakeByStatus(StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount);
|
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount, currentEpoch);
|
||||||
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
||||||
// Updates local state accordingly
|
// Updates local state accordingly
|
||||||
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
import { WETH9TransferEventArgs, WETH9Events } from '@0x/contracts-erc20';
|
import { WETH9TransferEventArgs, WETH9Events } from '@0x/contracts-erc20';
|
||||||
import { StoredBalance } from '@0x/contracts-staking';
|
import { StoredBalance } from '@0x/contracts-staking';
|
||||||
import { expect, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
import { expect, filterLogsToArguments, verifyEventsFromLogs } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { TxData } from 'ethereum-types';
|
import { TxData } from 'ethereum-types';
|
||||||
|
|
||||||
@ -13,7 +13,6 @@ interface WithdrawDelegatorRewardsBeforeInfo {
|
|||||||
delegatorStake: StoredBalance;
|
delegatorStake: StoredBalance;
|
||||||
poolRewards: BigNumber;
|
poolRewards: BigNumber;
|
||||||
wethReservedForPoolRewards: BigNumber;
|
wethReservedForPoolRewards: BigNumber;
|
||||||
delegatorReward: BigNumber;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -27,35 +26,17 @@ export function validWithdrawDelegatorRewardsAssertion(
|
|||||||
simulationEnvironment: SimulationEnvironment,
|
simulationEnvironment: SimulationEnvironment,
|
||||||
): FunctionAssertion<[string], WithdrawDelegatorRewardsBeforeInfo, void> {
|
): FunctionAssertion<[string], WithdrawDelegatorRewardsBeforeInfo, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
const { currentEpoch } = simulationEnvironment;
|
|
||||||
|
|
||||||
return new FunctionAssertion(stakingWrapper, 'withdrawDelegatorRewards', {
|
return new FunctionAssertion(stakingWrapper, 'withdrawDelegatorRewards', {
|
||||||
before: async (args: [string], txData: Partial<TxData>) => {
|
before: async (args: [string], txData: Partial<TxData>) => {
|
||||||
const [poolId] = args;
|
const [poolId] = args;
|
||||||
|
|
||||||
const delegatorStake = await stakingWrapper
|
const delegatorStake = await stakingWrapper
|
||||||
.getStakeDelegatedToPoolByOwner(txData.from!, poolId)
|
.getStakeDelegatedToPoolByOwner(txData.from!, poolId)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync();
|
const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync();
|
||||||
const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync();
|
const wethReservedForPoolRewards = await stakingWrapper.wethReservedForPoolRewards().callAsync();
|
||||||
const delegatorReward = BigNumber.sum(
|
return { delegatorStake, poolRewards, wethReservedForPoolRewards };
|
||||||
await stakingWrapper
|
|
||||||
.computeMemberRewardOverInterval(
|
|
||||||
poolId,
|
|
||||||
delegatorStake.currentEpochBalance,
|
|
||||||
delegatorStake.currentEpoch,
|
|
||||||
delegatorStake.currentEpoch.plus(1),
|
|
||||||
)
|
|
||||||
.callAsync(),
|
|
||||||
await stakingWrapper
|
|
||||||
.computeMemberRewardOverInterval(
|
|
||||||
poolId,
|
|
||||||
delegatorStake.nextEpochBalance,
|
|
||||||
delegatorStake.currentEpoch.plus(1),
|
|
||||||
currentEpoch,
|
|
||||||
)
|
|
||||||
.callAsync(),
|
|
||||||
); // TODO: Test the reward computation more robustly
|
|
||||||
return { delegatorStake, poolRewards, wethReservedForPoolRewards, delegatorReward };
|
|
||||||
},
|
},
|
||||||
after: async (
|
after: async (
|
||||||
beforeInfo: WithdrawDelegatorRewardsBeforeInfo,
|
beforeInfo: WithdrawDelegatorRewardsBeforeInfo,
|
||||||
@ -63,7 +44,11 @@ export function validWithdrawDelegatorRewardsAssertion(
|
|||||||
args: [string],
|
args: [string],
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>,
|
||||||
) => {
|
) => {
|
||||||
|
// Ensure that the tx succeeded.
|
||||||
|
expect(result.success, `Error: ${result.data}`).to.be.true();
|
||||||
|
|
||||||
const [poolId] = args;
|
const [poolId] = args;
|
||||||
|
const { currentEpoch } = simulationEnvironment;
|
||||||
|
|
||||||
const expectedDelegatorStake = {
|
const expectedDelegatorStake = {
|
||||||
...beforeInfo.delegatorStake,
|
...beforeInfo.delegatorStake,
|
||||||
@ -77,18 +62,16 @@ export function validWithdrawDelegatorRewardsAssertion(
|
|||||||
.callAsync();
|
.callAsync();
|
||||||
expect(delegatorStake).to.deep.equal(expectedDelegatorStake);
|
expect(delegatorStake).to.deep.equal(expectedDelegatorStake);
|
||||||
|
|
||||||
const expectedPoolRewards = beforeInfo.poolRewards.minus(beforeInfo.delegatorReward);
|
const transferEvents = filterLogsToArguments<WETH9TransferEventArgs>(
|
||||||
const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync();
|
|
||||||
expect(poolRewards).to.bignumber.equal(expectedPoolRewards);
|
|
||||||
|
|
||||||
const expectedTransferEvents = beforeInfo.delegatorReward.isZero()
|
|
||||||
? []
|
|
||||||
: [{ _from: stakingWrapper.address, _to: txData.from!, _value: beforeInfo.delegatorReward }];
|
|
||||||
verifyEventsFromLogs<WETH9TransferEventArgs>(
|
|
||||||
result.receipt!.logs,
|
result.receipt!.logs,
|
||||||
expectedTransferEvents,
|
|
||||||
WETH9Events.Transfer,
|
WETH9Events.Transfer,
|
||||||
);
|
);
|
||||||
|
const expectedPoolRewards =
|
||||||
|
transferEvents.length > 0
|
||||||
|
? beforeInfo.poolRewards.minus(transferEvents[0]._value)
|
||||||
|
: beforeInfo.poolRewards;
|
||||||
|
const poolRewards = await stakingWrapper.rewardsByPoolId(poolId).callAsync();
|
||||||
|
expect(poolRewards).to.bignumber.equal(expectedPoolRewards);
|
||||||
|
|
||||||
// TODO: Check CR
|
// TODO: Check CR
|
||||||
},
|
},
|
||||||
|
@ -393,7 +393,16 @@ export class DeploymentManager {
|
|||||||
stakingLogic.address,
|
stakingLogic.address,
|
||||||
);
|
);
|
||||||
|
|
||||||
const stakingWrapper = new TestStakingContract(stakingProxy.address, environment.provider, txDefaults);
|
const logDecoderDependencies = _.mapValues(
|
||||||
|
{ ...stakingArtifacts, ...ERC20Artifacts },
|
||||||
|
v => v.compilerOutput.abi,
|
||||||
|
);
|
||||||
|
const stakingWrapper = new TestStakingContract(
|
||||||
|
stakingProxy.address,
|
||||||
|
environment.provider,
|
||||||
|
txDefaults,
|
||||||
|
logDecoderDependencies,
|
||||||
|
);
|
||||||
|
|
||||||
// Add the zrx vault and the weth contract to the staking proxy.
|
// Add the zrx vault and the weth contract to the staking proxy.
|
||||||
await stakingWrapper.setWethContract(tokens.weth.address).awaitTransactionSuccessAsync({ from: owner });
|
await stakingWrapper.setWethContract(tokens.weth.address).awaitTransactionSuccessAsync({ from: owner });
|
||||||
|
@ -29,7 +29,7 @@ class Logger {
|
|||||||
msg: `Function called: ${functionName}(${functionArgs
|
msg: `Function called: ${functionName}(${functionArgs
|
||||||
.map(arg => JSON.stringify(arg).replace(/"/g, "'"))
|
.map(arg => JSON.stringify(arg).replace(/"/g, "'"))
|
||||||
.join(', ')})`,
|
.join(', ')})`,
|
||||||
step: this._step++,
|
step: ++this._step,
|
||||||
txData,
|
txData,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
@ -3,7 +3,7 @@ import { BigNumber } from '@0x/utils';
|
|||||||
import * as seedrandom from 'seedrandom';
|
import * as seedrandom from 'seedrandom';
|
||||||
|
|
||||||
class PRNGWrapper {
|
class PRNGWrapper {
|
||||||
public readonly seed = process.env.UUID || Math.random().toString();
|
public readonly seed = process.env.SEED || Math.random().toString();
|
||||||
private readonly _rng = seedrandom(this.seed);
|
private readonly _rng = seedrandom(this.seed);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -20,7 +20,6 @@ import { DeploymentManager } from '../framework/deployment_manager';
|
|||||||
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
||||||
import { Pseudorandom } from '../framework/utils/pseudorandom';
|
import { Pseudorandom } from '../framework/utils/pseudorandom';
|
||||||
|
|
||||||
import { PoolManagementSimulation } from './pool_management_test';
|
|
||||||
import { PoolMembershipSimulation } from './pool_membership_test';
|
import { PoolMembershipSimulation } from './pool_membership_test';
|
||||||
import { StakeManagementSimulation } from './stake_management_test';
|
import { StakeManagementSimulation } from './stake_management_test';
|
||||||
|
|
||||||
@ -30,7 +29,6 @@ export class StakingRewardsSimulation extends Simulation {
|
|||||||
const stakers = filterActorsByRole(actors, Staker);
|
const stakers = filterActorsByRole(actors, Staker);
|
||||||
const keepers = filterActorsByRole(actors, Keeper);
|
const keepers = filterActorsByRole(actors, Keeper);
|
||||||
|
|
||||||
const poolManagement = new PoolManagementSimulation(this.environment);
|
|
||||||
const poolMembership = new PoolMembershipSimulation(this.environment);
|
const poolMembership = new PoolMembershipSimulation(this.environment);
|
||||||
const stakeManagement = new StakeManagementSimulation(this.environment);
|
const stakeManagement = new StakeManagementSimulation(this.environment);
|
||||||
|
|
||||||
@ -38,7 +36,6 @@ export class StakingRewardsSimulation extends Simulation {
|
|||||||
...stakers.map(staker => staker.simulationActions.validWithdrawDelegatorRewards),
|
...stakers.map(staker => staker.simulationActions.validWithdrawDelegatorRewards),
|
||||||
...keepers.map(keeper => keeper.simulationActions.validFinalizePool),
|
...keepers.map(keeper => keeper.simulationActions.validFinalizePool),
|
||||||
...keepers.map(keeper => keeper.simulationActions.validEndEpoch),
|
...keepers.map(keeper => keeper.simulationActions.validEndEpoch),
|
||||||
poolManagement.generator,
|
|
||||||
poolMembership.generator,
|
poolMembership.generator,
|
||||||
stakeManagement.generator,
|
stakeManagement.generator,
|
||||||
];
|
];
|
||||||
@ -66,12 +63,22 @@ blockchainTests('Staking rewards fuzz test', env => {
|
|||||||
numErc721TokensToDeploy: 0,
|
numErc721TokensToDeploy: 0,
|
||||||
numErc1155TokensToDeploy: 0,
|
numErc1155TokensToDeploy: 0,
|
||||||
});
|
});
|
||||||
|
const [ERC20TokenA, ERC20TokenB, ERC20TokenC, ERC20TokenD] = deployment.tokens.erc20;
|
||||||
const balanceStore = new BlockchainBalanceStore(
|
const balanceStore = new BlockchainBalanceStore(
|
||||||
{
|
{
|
||||||
StakingProxy: deployment.staking.stakingProxy.address,
|
StakingProxy: deployment.staking.stakingProxy.address,
|
||||||
ZRXVault: deployment.staking.zrxVault.address,
|
ZRXVault: deployment.staking.zrxVault.address,
|
||||||
},
|
},
|
||||||
{ erc20: { ZRX: deployment.tokens.zrx } },
|
{
|
||||||
|
erc20: {
|
||||||
|
ZRX: deployment.tokens.zrx,
|
||||||
|
WETH: deployment.tokens.weth,
|
||||||
|
ERC20TokenA,
|
||||||
|
ERC20TokenB,
|
||||||
|
ERC20TokenC,
|
||||||
|
ERC20TokenD,
|
||||||
|
},
|
||||||
|
},
|
||||||
);
|
);
|
||||||
const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore);
|
const simulationEnvironment = new SimulationEnvironment(deployment, balanceStore);
|
||||||
|
|
||||||
|
@ -67,69 +67,6 @@ contract TestStaking is
|
|||||||
cumulativeRewards = _cumulativeRewardsByPool[poolId][lastStoredEpoch];
|
cumulativeRewards = _cumulativeRewardsByPool[poolId][lastStoredEpoch];
|
||||||
}
|
}
|
||||||
|
|
||||||
function computeMemberRewardOverInterval(
|
|
||||||
bytes32 poolId,
|
|
||||||
uint256 memberStakeOverInterval,
|
|
||||||
uint256 beginEpoch,
|
|
||||||
uint256 endEpoch
|
|
||||||
)
|
|
||||||
external
|
|
||||||
view
|
|
||||||
returns (uint256 reward)
|
|
||||||
{
|
|
||||||
// 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");
|
|
||||||
|
|
||||||
// Sanity check begin reward
|
|
||||||
IStructs.Fraction memory beginReward = getCumulativeRewardAtEpoch(poolId, beginEpoch);
|
|
||||||
IStructs.Fraction memory endReward = getCumulativeRewardAtEpoch(poolId, endEpoch);
|
|
||||||
|
|
||||||
// Compute reward
|
|
||||||
reward = LibFractions.scaleDifference(
|
|
||||||
endReward.numerator,
|
|
||||||
endReward.denominator,
|
|
||||||
beginReward.numerator,
|
|
||||||
beginReward.denominator,
|
|
||||||
memberStakeOverInterval
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
function getCumulativeRewardAtEpoch(bytes32 poolId, uint256 epoch)
|
|
||||||
public
|
|
||||||
view
|
|
||||||
returns (IStructs.Fraction memory cumulativeReward)
|
|
||||||
{
|
|
||||||
// Return CR at `epoch`, given it's set.
|
|
||||||
cumulativeReward = _cumulativeRewardsByPool[poolId][epoch];
|
|
||||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
|
||||||
return cumulativeReward;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Return CR at `epoch-1`, given it's set.
|
|
||||||
uint256 lastEpoch = epoch.safeSub(1);
|
|
||||||
cumulativeReward = _cumulativeRewardsByPool[poolId][lastEpoch];
|
|
||||||
if (_isCumulativeRewardSet(cumulativeReward)) {
|
|
||||||
return cumulativeReward;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Otherwise return an empty CR.
|
|
||||||
return IStructs.Fraction(0, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// @dev Overridden to use testWethAddress;
|
/// @dev Overridden to use testWethAddress;
|
||||||
function getWethContract()
|
function getWethContract()
|
||||||
public
|
public
|
||||||
|
Loading…
x
Reference in New Issue
Block a user