Add assertion generators to keeper, staker, taker mixins for the new function assertions
This commit is contained in:
@@ -1,12 +1,17 @@
|
|||||||
import {
|
import {
|
||||||
|
AggregatedStats,
|
||||||
IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs,
|
IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs,
|
||||||
TestStakingContract,
|
|
||||||
TestStakingEvents,
|
TestStakingEvents,
|
||||||
} from '@0x/contracts-staking';
|
} from '@0x/contracts-staking';
|
||||||
import { filterLogsToArguments, web3Wrapper } from '@0x/contracts-test-utils';
|
import { filterLogsToArguments, web3Wrapper } from '@0x/contracts-test-utils';
|
||||||
import { BigNumber } from '@0x/utils';
|
import { BigNumber } from '@0x/utils';
|
||||||
import { BlockParamLiteral, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { BlockParamLiteral, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
|
||||||
|
import { validEndEpochAssertion } from '../assertions/endEpoch';
|
||||||
|
import { validFinalizePoolAssertion } from '../assertions/finalizePool';
|
||||||
|
import { AssertionResult } from '../assertions/function_assertion';
|
||||||
|
import { Pseudorandom } from '../utils/pseudorandom';
|
||||||
|
|
||||||
import { Actor, Constructor } from './base';
|
import { Actor, Constructor } from './base';
|
||||||
|
|
||||||
export interface KeeperInterface {
|
export interface KeeperInterface {
|
||||||
@@ -14,17 +19,6 @@ export interface KeeperInterface {
|
|||||||
finalizePoolsAsync: (poolIds?: string[]) => Promise<TransactionReceiptWithDecodedLogs[]>;
|
finalizePoolsAsync: (poolIds?: string[]) => Promise<TransactionReceiptWithDecodedLogs[]>;
|
||||||
}
|
}
|
||||||
|
|
||||||
async function fastForwardToNextEpochAsync(stakingContract: TestStakingContract): Promise<void> {
|
|
||||||
// increase timestamp of next block by how many seconds we need to
|
|
||||||
// get to the next epoch.
|
|
||||||
const epochEndTime = await stakingContract.getCurrentEpochEarliestEndTimeInSeconds().callAsync();
|
|
||||||
const lastBlockTime = await web3Wrapper.getBlockTimestampAsync('latest');
|
|
||||||
const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber());
|
|
||||||
await web3Wrapper.increaseTimeAsync(dt);
|
|
||||||
// mine next block
|
|
||||||
await web3Wrapper.mineBlockAsync();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This mixin encapsulates functionality associated with keepers within the 0x ecosystem.
|
* This mixin encapsulates functionality associated with keepers within the 0x ecosystem.
|
||||||
* This includes ending epochs sand finalizing pools in the staking system.
|
* This includes ending epochs sand finalizing pools in the staking system.
|
||||||
@@ -42,6 +36,13 @@ export function KeeperMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
// tslint:disable-next-line:no-inferred-empty-object-type
|
// tslint:disable-next-line:no-inferred-empty-object-type
|
||||||
super(...args);
|
super(...args);
|
||||||
this.actor = (this as any) as Actor;
|
this.actor = (this as any) as Actor;
|
||||||
|
|
||||||
|
// Register this mixin's assertion generators
|
||||||
|
this.actor.simulationActions = {
|
||||||
|
...this.actor.simulationActions,
|
||||||
|
validFinalizePool: this._validFinalizePool(),
|
||||||
|
validEndEpoch: this._validEndEpoch(),
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -50,7 +51,7 @@ export function KeeperMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
public async endEpochAsync(shouldFastForward: boolean = true): Promise<TransactionReceiptWithDecodedLogs> {
|
public async endEpochAsync(shouldFastForward: boolean = true): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
const { stakingWrapper } = this.actor.deployment.staking;
|
const { stakingWrapper } = this.actor.deployment.staking;
|
||||||
if (shouldFastForward) {
|
if (shouldFastForward) {
|
||||||
await fastForwardToNextEpochAsync(stakingWrapper);
|
await this._fastForwardToNextEpochAsync();
|
||||||
}
|
}
|
||||||
return stakingWrapper.endEpoch().awaitTransactionSuccessAsync({ from: this.actor.address });
|
return stakingWrapper.endEpoch().awaitTransactionSuccessAsync({ from: this.actor.address });
|
||||||
}
|
}
|
||||||
@@ -83,6 +84,50 @@ export function KeeperMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
),
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async *_validFinalizePool(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
|
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||||
|
const assertion = validFinalizePoolAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
||||||
|
while (true) {
|
||||||
|
const poolId = Pseudorandom.sample(Object.keys(stakingPools));
|
||||||
|
if (poolId === undefined) {
|
||||||
|
yield;
|
||||||
|
} else {
|
||||||
|
yield assertion.executeAsync([poolId], { from: this.actor.address });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async *_validEndEpoch(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
|
const assertion = validEndEpochAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
||||||
|
const { currentEpoch } = this.actor.simulationEnvironment!;
|
||||||
|
const { stakingWrapper } = this.actor.deployment.staking;
|
||||||
|
while (true) {
|
||||||
|
const aggregatedStats = AggregatedStats.fromArray(
|
||||||
|
await stakingWrapper.aggregatedStatsByEpoch(currentEpoch.minus(1)).callAsync(),
|
||||||
|
);
|
||||||
|
if (aggregatedStats.numPoolsToFinalize.isGreaterThan(0)) {
|
||||||
|
// Can't end the epoch if the previous epoch is not fully finalized.
|
||||||
|
yield;
|
||||||
|
} else {
|
||||||
|
await this._fastForwardToNextEpochAsync();
|
||||||
|
yield assertion.executeAsync([], { from: this.actor.address });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private async _fastForwardToNextEpochAsync(): Promise<void> {
|
||||||
|
const { stakingWrapper } = this.actor.deployment.staking;
|
||||||
|
|
||||||
|
// increase timestamp of next block by how many seconds we need to
|
||||||
|
// get to the next epoch.
|
||||||
|
const epochEndTime = await stakingWrapper.getCurrentEpochEarliestEndTimeInSeconds().callAsync();
|
||||||
|
const lastBlockTime = await web3Wrapper.getBlockTimestampAsync('latest');
|
||||||
|
const dt = Math.max(0, epochEndTime.minus(lastBlockTime).toNumber());
|
||||||
|
await web3Wrapper.increaseTimeAsync(dt);
|
||||||
|
// mine next block
|
||||||
|
await web3Wrapper.mineBlockAsync();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { AssertionResult } from '../assertions/function_assertion';
|
|||||||
import { validMoveStakeAssertion } from '../assertions/moveStake';
|
import { validMoveStakeAssertion } from '../assertions/moveStake';
|
||||||
import { validStakeAssertion } from '../assertions/stake';
|
import { validStakeAssertion } from '../assertions/stake';
|
||||||
import { validUnstakeAssertion } from '../assertions/unstake';
|
import { validUnstakeAssertion } from '../assertions/unstake';
|
||||||
|
import { validWithdrawDelegatorRewardsAssertion } from '../assertions/withdrawDelegatorRewards';
|
||||||
import { Pseudorandom } from '../utils/pseudorandom';
|
import { Pseudorandom } from '../utils/pseudorandom';
|
||||||
|
|
||||||
import { Actor, Constructor } from './base';
|
import { Actor, Constructor } from './base';
|
||||||
@@ -44,6 +45,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
validStake: this._validStake(),
|
validStake: this._validStake(),
|
||||||
validUnstake: this._validUnstake(),
|
validUnstake: this._validUnstake(),
|
||||||
validMoveStake: this._validMoveStake(),
|
validMoveStake: this._validMoveStake(),
|
||||||
|
validWithdrawDelegatorRewards: this._validWithdrawDelegatorRewards(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -129,6 +131,19 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
yield assertion.executeAsync([from, to, amount], { from: this.actor.address });
|
yield assertion.executeAsync([from, to, amount], { from: this.actor.address });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async *_validWithdrawDelegatorRewards(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
|
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||||
|
const assertion = validWithdrawDelegatorRewardsAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
|
||||||
|
while (true) {
|
||||||
|
const poolId = Pseudorandom.sample(Object.keys(stakingPools));
|
||||||
|
if (poolId === undefined) {
|
||||||
|
yield;
|
||||||
|
} else {
|
||||||
|
yield assertion.executeAsync([poolId], { from: this.actor.address });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -126,6 +126,7 @@ export function TakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
|
|||||||
yield assertion.executeAsync([order, fillAmount, order.signature], {
|
yield assertion.executeAsync([order, fillAmount, order.signature], {
|
||||||
from: this.actor.address,
|
from: this.actor.address,
|
||||||
});
|
});
|
||||||
|
// TODO: Randomly choose msg.value
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user