Made function assertions work with the new wrappers
This commit is contained in:
parent
8685cf9036
commit
1e44a9c942
66
contracts/integrations/test/framework/actors/pool_member.ts
Normal file
66
contracts/integrations/test/framework/actors/pool_member.ts
Normal file
@ -0,0 +1,66 @@
|
|||||||
|
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { AssertionResult } from '../assertions/function_assertion';
|
||||||
|
import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool';
|
||||||
|
|
||||||
|
import { Actor, Constructor } from './base';
|
||||||
|
import { PoolOperatorMixin } from './pool_operator';
|
||||||
|
|
||||||
|
interface PoolMemberInterface {
|
||||||
|
joinStakingPoolAsync: (poolId: string) => Promise<TransactionReceiptWithDecodedLogs>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mixin encapsulates functionaltiy associated with pool operators within the 0x ecosystem.
|
||||||
|
* This includes creating staking pools and decreasing the operator share of a pool.
|
||||||
|
*/
|
||||||
|
export function PoolMemberMixin<TBase extends Constructor>(Base: TBase): TBase & Constructor<PoolMemberInterface> {
|
||||||
|
return class extends Base {
|
||||||
|
public readonly actor: Actor;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The mixin pattern requires that this constructor uses `...args: any[]`, but this class
|
||||||
|
* really expects a single `ActorConfig` parameter (assuming `Actor` is used as the
|
||||||
|
* base class).
|
||||||
|
*/
|
||||||
|
constructor(...args: any[]) {
|
||||||
|
// tslint:disable-next-line:no-inferred-empty-object-type
|
||||||
|
super(...args);
|
||||||
|
this.actor = (this as any) as Actor;
|
||||||
|
|
||||||
|
// Register this mixin's assertion generators
|
||||||
|
this.actor.simulationActions = {
|
||||||
|
...this.actor.simulationActions,
|
||||||
|
validJoinStakingPool: this._validJoinStakingPool(),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Joins a new staking pool.
|
||||||
|
*/
|
||||||
|
public async joinStakingPoolAsync(poolId: string): Promise<TransactionReceiptWithDecodedLogs> {
|
||||||
|
const stakingContract = this.actor.deployment.staking.stakingWrapper;
|
||||||
|
return stakingContract
|
||||||
|
.joinStakingPoolAsMaker(poolId)
|
||||||
|
.awaitTransactionSuccessAsync({ from: this.actor.address });
|
||||||
|
}
|
||||||
|
|
||||||
|
// FIXME(jalextowle): I need to make sure that this is being sent from the actor's address
|
||||||
|
private async *_validJoinStakingPool(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
|
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||||
|
const assertion = validJoinStakingPoolAssertion(this.actor.deployment);
|
||||||
|
while (true) {
|
||||||
|
const poolId = _.sample(Object.keys(stakingPools));
|
||||||
|
if (poolId === undefined) {
|
||||||
|
yield undefined;
|
||||||
|
} else {
|
||||||
|
console.log('Attempting to join pool');
|
||||||
|
yield assertion.executeAsync({ args: [poolId], txData: {} });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export class PoolMember extends PoolOperatorMixin(PoolMemberMixin(Actor)) {}
|
@ -80,11 +80,16 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
|||||||
}
|
}
|
||||||
|
|
||||||
private async *_validCreateStakingPool(): AsyncIterableIterator<AssertionResult> {
|
private async *_validCreateStakingPool(): AsyncIterableIterator<AssertionResult> {
|
||||||
|
console.log(10);
|
||||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||||
|
console.log(11);
|
||||||
const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools);
|
const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools);
|
||||||
|
console.log(12);
|
||||||
while (true) {
|
while (true) {
|
||||||
const operatorShare = getRandomInteger(0, constants.PPM);
|
const operatorShare = getRandomInteger(0, constants.PPM).toNumber();
|
||||||
yield assertion.executeAsync(operatorShare, false, { from: this.actor.address });
|
console.log(13);
|
||||||
|
yield assertion.executeAsync({ args: [operatorShare, false], txData: { from: this.actor.address } });
|
||||||
|
console.log(14);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -96,8 +101,11 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
|||||||
if (poolId === undefined) {
|
if (poolId === undefined) {
|
||||||
yield undefined;
|
yield undefined;
|
||||||
} else {
|
} else {
|
||||||
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare);
|
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare).toNumber();
|
||||||
yield assertion.executeAsync(poolId, operatorShare, { from: this.actor.address });
|
yield assertion.executeAsync({
|
||||||
|
args: [poolId, operatorShare],
|
||||||
|
txData: { from: this.actor.address },
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
await balanceStore.updateErc20BalancesAsync();
|
await balanceStore.updateErc20BalancesAsync();
|
||||||
const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address];
|
const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address];
|
||||||
const amount = getRandomInteger(0, zrxBalance);
|
const amount = getRandomInteger(0, zrxBalance);
|
||||||
yield assertion.executeAsync(amount, { from: this.actor.address });
|
yield assertion.executeAsync({ args: [amount], txData: { from: this.actor.address } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -95,7 +95,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
undelegatedStake.nextEpochBalance,
|
undelegatedStake.nextEpochBalance,
|
||||||
);
|
);
|
||||||
const amount = getRandomInteger(0, withdrawableStake);
|
const amount = getRandomInteger(0, withdrawableStake);
|
||||||
yield assertion.executeAsync(amount, { from: this.actor.address });
|
yield assertion.executeAsync({ args: [amount], txData: { from: this.actor.address } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,7 +124,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
|||||||
: this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance;
|
: this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance;
|
||||||
const amount = getRandomInteger(0, moveableStake);
|
const amount = getRandomInteger(0, moveableStake);
|
||||||
|
|
||||||
yield assertion.executeAsync(from, to, amount, { from: this.actor.address });
|
yield assertion.executeAsync({ args: [from, to, amount], txData: { from: this.actor.address } });
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
@ -16,10 +16,10 @@ import { FunctionAssertion, FunctionResult } from './function_assertion';
|
|||||||
export function validCreateStakingPoolAssertion(
|
export function validCreateStakingPoolAssertion(
|
||||||
deployment: DeploymentManager,
|
deployment: DeploymentManager,
|
||||||
pools: StakingPoolById,
|
pools: StakingPoolById,
|
||||||
): FunctionAssertion<string, string> {
|
): FunctionAssertion<[number, boolean], string, string> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion(stakingWrapper.createStakingPool, {
|
return new FunctionAssertion<[number, boolean], string, string>(stakingWrapper.createStakingPool, {
|
||||||
// Returns the expected ID of th created pool
|
// Returns the expected ID of th created pool
|
||||||
before: async () => {
|
before: async () => {
|
||||||
const lastPoolId = await stakingWrapper.lastPoolId().callAsync();
|
const lastPoolId = await stakingWrapper.lastPoolId().callAsync();
|
||||||
@ -32,23 +32,31 @@ export function validCreateStakingPoolAssertion(
|
|||||||
after: async (
|
after: async (
|
||||||
expectedPoolId: string,
|
expectedPoolId: string,
|
||||||
result: FunctionResult,
|
result: FunctionResult,
|
||||||
operatorShare: number,
|
args: {
|
||||||
addOperatorAsMaker: boolean,
|
args: [number, boolean];
|
||||||
txData: Partial<TxData>,
|
txData: Partial<TxData>;
|
||||||
|
},
|
||||||
) => {
|
) => {
|
||||||
logUtils.log(`createStakingPool(${operatorShare}, ${addOperatorAsMaker}) => ${expectedPoolId}`);
|
console.log(100);
|
||||||
|
logUtils.log(`createStakingPool(${args.args[0]}, ${args.args[1]}) => ${expectedPoolId}`);
|
||||||
|
console.log(101);
|
||||||
|
|
||||||
// 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
|
||||||
|
console.log(result.receipt);
|
||||||
const log = result.receipt!.logs[0]; // tslint:disable-line:no-non-null-assertion
|
const log = result.receipt!.logs[0]; // tslint:disable-line:no-non-null-assertion
|
||||||
|
console.log(102);
|
||||||
const actualPoolId = (log as any).args.poolId;
|
const actualPoolId = (log as any).args.poolId;
|
||||||
|
console.log(103);
|
||||||
expect(actualPoolId).to.equal(expectedPoolId);
|
expect(actualPoolId).to.equal(expectedPoolId);
|
||||||
|
console.log(104);
|
||||||
|
|
||||||
// Adds the new pool to local state
|
// Adds the new pool to local state
|
||||||
pools[actualPoolId] = {
|
pools[actualPoolId] = {
|
||||||
operator: txData.from as string,
|
operator: args.txData.from as string,
|
||||||
operatorShare,
|
operatorShare: args.args[0],
|
||||||
delegatedStake: new StoredBalance(),
|
delegatedStake: new StoredBalance(),
|
||||||
};
|
};
|
||||||
|
console.log(105);
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -13,11 +13,14 @@ import { FunctionAssertion, FunctionResult } from './function_assertion';
|
|||||||
export function validDecreaseStakingPoolOperatorShareAssertion(
|
export function validDecreaseStakingPoolOperatorShareAssertion(
|
||||||
deployment: DeploymentManager,
|
deployment: DeploymentManager,
|
||||||
pools: StakingPoolById,
|
pools: StakingPoolById,
|
||||||
): FunctionAssertion<{}, void> {
|
): FunctionAssertion<[string, number], {}, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion<{}, void>(stakingWrapper.decreaseStakingPoolOperatorShare, {
|
return new FunctionAssertion<[string, number], {}, void>(stakingWrapper.decreaseStakingPoolOperatorShare, {
|
||||||
after: async (_beforeInfo, _result: FunctionResult, poolId: string, expectedOperatorShare: number) => {
|
after: async (_beforeInfo, _result: FunctionResult, args: { args: [string, number] }) => {
|
||||||
|
const poolId = args.args[0];
|
||||||
|
const expectedOperatorShare = args.args[1];
|
||||||
|
|
||||||
logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`);
|
logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`);
|
||||||
|
|
||||||
// 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,11 +1,16 @@
|
|||||||
import { ContractFunctionObj, ContractTxFunctionObj } from '@0x/base-contract';
|
import { ContractFunctionObj, ContractTxFunctionObj } from '@0x/base-contract';
|
||||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types';
|
||||||
import * as _ from 'lodash';
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
// tslint:disable:max-classes-per-file
|
// tslint:disable:max-classes-per-file
|
||||||
|
|
||||||
export type GenericContractFunction<T> = (...args: any[]) => ContractFunctionObj<T>;
|
export type GenericContractFunction<T> = (...args: any[]) => ContractFunctionObj<T>;
|
||||||
|
|
||||||
|
export interface FunctionArguments<TArgs extends any[]> {
|
||||||
|
args: TArgs;
|
||||||
|
txData: Partial<TxData>;
|
||||||
|
}
|
||||||
|
|
||||||
export interface FunctionResult {
|
export interface FunctionResult {
|
||||||
data?: any;
|
data?: any;
|
||||||
success: boolean;
|
success: boolean;
|
||||||
@ -22,9 +27,9 @@ export interface FunctionResult {
|
|||||||
* @param after A function that will be run after a call to the contract wrapper
|
* @param after A function that will be run after a call to the contract wrapper
|
||||||
* function.
|
* function.
|
||||||
*/
|
*/
|
||||||
export interface Condition<TBefore> {
|
export interface Condition<TArgs extends any[], TBefore> {
|
||||||
before: (...args: any[]) => Promise<TBefore>;
|
before: (args: FunctionArguments<TArgs>) => Promise<TBefore>;
|
||||||
after: (beforeInfo: TBefore, result: FunctionResult, ...args: any[]) => Promise<any>;
|
after: (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments<TArgs>) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,8 +39,8 @@ export interface Condition<TBefore> {
|
|||||||
* our `Assertion` implementations will do in practice).
|
* our `Assertion` implementations will do in practice).
|
||||||
* @param runAsync The function to execute for the assertion.
|
* @param runAsync The function to execute for the assertion.
|
||||||
*/
|
*/
|
||||||
export interface Assertion {
|
export interface Assertion<TArgs extends any[]> {
|
||||||
executeAsync: (...args: any[]) => Promise<any>;
|
executeAsync: (args: FunctionArguments<TArgs>) => Promise<any>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface AssertionResult<TBefore = unknown> {
|
export interface AssertionResult<TBefore = unknown> {
|
||||||
@ -47,9 +52,9 @@ export interface AssertionResult<TBefore = unknown> {
|
|||||||
* This class implements `Assertion` and represents a "Hoare Triple" that can be
|
* This class implements `Assertion` and represents a "Hoare Triple" that can be
|
||||||
* executed.
|
* executed.
|
||||||
*/
|
*/
|
||||||
export class FunctionAssertion<TBefore, ReturnDataType> implements Assertion {
|
export class FunctionAssertion<TArgs extends any[], TBefore, ReturnDataType> implements Assertion<TArgs> {
|
||||||
// A condition that will be applied to `wrapperFunction`.
|
// A condition that will be applied to `wrapperFunction`.
|
||||||
public condition: Condition<TBefore>;
|
public condition: Condition<TArgs, TBefore>;
|
||||||
|
|
||||||
// The wrapper function that will be wrapped in assertions.
|
// The wrapper function that will be wrapped in assertions.
|
||||||
public wrapperFunction: (
|
public wrapperFunction: (
|
||||||
@ -60,11 +65,15 @@ export class FunctionAssertion<TBefore, ReturnDataType> implements Assertion {
|
|||||||
wrapperFunction: (
|
wrapperFunction: (
|
||||||
...args: any[] // tslint:disable-line:trailing-comma
|
...args: any[] // tslint:disable-line:trailing-comma
|
||||||
) => ContractTxFunctionObj<ReturnDataType> | ContractFunctionObj<ReturnDataType>,
|
) => ContractTxFunctionObj<ReturnDataType> | ContractFunctionObj<ReturnDataType>,
|
||||||
condition: Partial<Condition<TBefore>> = {},
|
condition: Partial<Condition<TArgs, TBefore>> = {},
|
||||||
) {
|
) {
|
||||||
this.condition = {
|
this.condition = {
|
||||||
before: _.noop.bind(this),
|
before: async (args: FunctionArguments<TArgs>) => {
|
||||||
after: _.noop.bind(this),
|
return ({} as any) as TBefore;
|
||||||
|
},
|
||||||
|
after: async (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments<TArgs>) => {
|
||||||
|
return ({} as any) as TBefore;
|
||||||
|
},
|
||||||
...condition,
|
...condition,
|
||||||
};
|
};
|
||||||
this.wrapperFunction = wrapperFunction;
|
this.wrapperFunction = wrapperFunction;
|
||||||
@ -74,9 +83,9 @@ export class FunctionAssertion<TBefore, ReturnDataType> implements Assertion {
|
|||||||
* Runs the wrapped function and fails if the before or after assertions fail.
|
* Runs the wrapped function and fails if the before or after assertions fail.
|
||||||
* @param ...args The args to the contract wrapper function.
|
* @param ...args The args to the contract wrapper function.
|
||||||
*/
|
*/
|
||||||
public async executeAsync(...args: any[]): Promise<AssertionResult<TBefore>> {
|
public async executeAsync(args: FunctionArguments<TArgs>): Promise<AssertionResult<TBefore>> {
|
||||||
// Call the before condition.
|
// Call the before condition.
|
||||||
const beforeInfo = await this.condition.before(...args);
|
const beforeInfo = await this.condition.before(args);
|
||||||
|
|
||||||
// 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 };
|
||||||
@ -84,21 +93,27 @@ export class FunctionAssertion<TBefore, ReturnDataType> implements Assertion {
|
|||||||
// 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.wrapperFunction(...args) as ContractTxFunctionObj<ReturnDataType>;
|
const functionWithArgs = this.wrapperFunction(...args.args) as ContractTxFunctionObj<ReturnDataType>;
|
||||||
callResult.data = await functionWithArgs.callAsync();
|
callResult.data = await functionWithArgs.callAsync(args.txData);
|
||||||
|
|
||||||
|
console.log(functionWithArgs);
|
||||||
|
|
||||||
callResult.receipt =
|
callResult.receipt =
|
||||||
functionWithArgs.awaitTransactionSuccessAsync !== undefined
|
functionWithArgs.awaitTransactionSuccessAsync !== undefined
|
||||||
? await functionWithArgs.awaitTransactionSuccessAsync() // tslint:disable-line:await-promise
|
? await functionWithArgs.awaitTransactionSuccessAsync(args.txData) // tslint:disable-line:await-promise
|
||||||
: undefined;
|
: undefined;
|
||||||
// tslint:enable:await-promise
|
// tslint:enable:await-promise
|
||||||
} catch (error) {
|
} catch (error) {
|
||||||
|
console.log('got here');
|
||||||
|
console.log(error);
|
||||||
|
|
||||||
callResult.data = error;
|
callResult.data = error;
|
||||||
callResult.success = false;
|
callResult.success = false;
|
||||||
callResult.receipt = undefined;
|
callResult.receipt = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call the after condition.
|
// Call the after condition.
|
||||||
const afterInfo = await this.condition.after(beforeInfo, callResult, ...args);
|
const afterInfo = await this.condition.after(beforeInfo, callResult, args);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
beforeInfo,
|
beforeInfo,
|
||||||
|
@ -0,0 +1,45 @@
|
|||||||
|
import { StakingEvents, StakingMakerStakingPoolSetEventArgs, StakingPoolById } from '@0x/contracts-staking';
|
||||||
|
import { constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils';
|
||||||
|
import { logUtils } from '@0x/utils';
|
||||||
|
|
||||||
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
|
|
||||||
|
import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
|
export function validJoinStakingPoolAssertion(deployment: DeploymentManager): FunctionAssertion<[string], {}, void> {
|
||||||
|
return new FunctionAssertion<[string], {}, void>(deployment.staking.stakingWrapper.joinStakingPoolAsMaker, {
|
||||||
|
after: async (_beforeInfo, _result: FunctionResult, args: FunctionArguments<[string]>) => {
|
||||||
|
const poolId = args.args[0];
|
||||||
|
|
||||||
|
if (args.txData === undefined) {
|
||||||
|
throw new Error('Undefined transaction data');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (args.txData.from === undefined) {
|
||||||
|
throw new Error('Undefined from address');
|
||||||
|
}
|
||||||
|
|
||||||
|
if (_result.receipt === undefined) {
|
||||||
|
throw new Error('Undefined transaction receipt');
|
||||||
|
}
|
||||||
|
|
||||||
|
expect(_result.success).to.be.true();
|
||||||
|
|
||||||
|
const logs = _result.receipt.logs;
|
||||||
|
const logArgs = filterLogsToArguments<StakingMakerStakingPoolSetEventArgs>(
|
||||||
|
logs,
|
||||||
|
StakingEvents.MakerStakingPoolSet,
|
||||||
|
);
|
||||||
|
expect(logArgs).to.be.deep.eq([
|
||||||
|
{
|
||||||
|
maker: args.txData.from,
|
||||||
|
poolId,
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
const joinedPoolId = deployment.staking.stakingWrapper.poolIdByMaker(args.txData.from);
|
||||||
|
expect(joinedPoolId).to.be.eq(poolId);
|
||||||
|
|
||||||
|
console.log(`Pool ${poolId} joined by ${args.txData.from}`); /* tslint:disable-line:no-console */
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
@ -13,7 +13,7 @@ import * as _ from 'lodash';
|
|||||||
|
|
||||||
import { DeploymentManager } from '../deployment_manager';
|
import { DeploymentManager } from '../deployment_manager';
|
||||||
|
|
||||||
import { FunctionAssertion } from './function_assertion';
|
import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void {
|
function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void {
|
||||||
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount));
|
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount));
|
||||||
@ -82,25 +82,24 @@ export function validMoveStakeAssertion(
|
|||||||
globalStake: GlobalStakeByStatus,
|
globalStake: GlobalStakeByStatus,
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
pools: StakingPoolById,
|
pools: StakingPoolById,
|
||||||
): FunctionAssertion<{}, void> {
|
): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void> {
|
||||||
const { stakingWrapper } = deployment.staking;
|
const { stakingWrapper } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion<{}, void>(stakingWrapper.moveStake, {
|
return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>(stakingWrapper.moveStake, {
|
||||||
after: async (
|
after: async (
|
||||||
_beforeInfo,
|
_beforeInfo: {},
|
||||||
_result,
|
_result: FunctionResult,
|
||||||
from: StakeInfo,
|
args: FunctionArguments<[StakeInfo, StakeInfo, BigNumber]>,
|
||||||
to: StakeInfo,
|
|
||||||
amount: BigNumber,
|
|
||||||
txData: Partial<TxData>,
|
|
||||||
) => {
|
) => {
|
||||||
|
const [from, to, amount] = args.args;
|
||||||
|
|
||||||
logUtils.log(
|
logUtils.log(
|
||||||
`moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${
|
`moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${
|
||||||
StakeStatus[to.status]
|
StakeStatus[to.status]
|
||||||
}, poolId: ${to.poolId} }, ${amount})`,
|
}, poolId: ${to.poolId} }, ${amount})`,
|
||||||
);
|
);
|
||||||
|
|
||||||
const owner = txData.from as string;
|
const owner = args.txData.from as string;
|
||||||
|
|
||||||
// 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(globalStake, ownerStake, pools, from, to, amount);
|
||||||
|
@ -7,7 +7,7 @@ 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 { FunctionAssertion, FunctionResult } from './function_assertion';
|
import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function expectedUndelegatedStake(
|
function expectedUndelegatedStake(
|
||||||
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
||||||
@ -30,15 +30,17 @@ export function validStakeAssertion(
|
|||||||
balanceStore: BlockchainBalanceStore,
|
balanceStore: BlockchainBalanceStore,
|
||||||
globalStake: GlobalStakeByStatus,
|
globalStake: GlobalStakeByStatus,
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
): FunctionAssertion<LocalBalanceStore, void> {
|
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
||||||
const { stakingWrapper, zrxVault } = deployment.staking;
|
const { stakingWrapper, zrxVault } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion(stakingWrapper.stake, {
|
return new FunctionAssertion(stakingWrapper.stake, {
|
||||||
before: async (amount: BigNumber, txData: Partial<TxData>) => {
|
before: async (args: FunctionArguments<[BigNumber]>) => {
|
||||||
|
const [amount] = args.args;
|
||||||
|
|
||||||
// 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);
|
||||||
expectedBalances.transferAsset(
|
expectedBalances.transferAsset(
|
||||||
txData.from as string,
|
args.txData.from as string,
|
||||||
zrxVault.address,
|
zrxVault.address,
|
||||||
amount,
|
amount,
|
||||||
deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(),
|
deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(),
|
||||||
@ -48,9 +50,10 @@ export function validStakeAssertion(
|
|||||||
after: async (
|
after: async (
|
||||||
expectedBalances: LocalBalanceStore,
|
expectedBalances: LocalBalanceStore,
|
||||||
_result: FunctionResult,
|
_result: FunctionResult,
|
||||||
amount: BigNumber,
|
args: FunctionArguments<[BigNumber]>,
|
||||||
txData: Partial<TxData>,
|
|
||||||
) => {
|
) => {
|
||||||
|
const [amount] = args.args;
|
||||||
|
|
||||||
logUtils.log(`stake(${amount})`);
|
logUtils.log(`stake(${amount})`);
|
||||||
|
|
||||||
// Checks that the ZRX transfer updated balances as expected.
|
// Checks that the ZRX transfer updated balances as expected.
|
||||||
@ -59,7 +62,7 @@ export function validStakeAssertion(
|
|||||||
|
|
||||||
// Checks that the owner's undelegated stake has increased by the stake amount
|
// Checks that the owner's undelegated stake has increased by the stake amount
|
||||||
const ownerUndelegatedStake = await stakingWrapper
|
const ownerUndelegatedStake = await stakingWrapper
|
||||||
.getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated)
|
.getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
||||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||||
|
@ -7,7 +7,7 @@ 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 { FunctionAssertion, FunctionResult } from './function_assertion';
|
import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion';
|
||||||
|
|
||||||
function expectedUndelegatedStake(
|
function expectedUndelegatedStake(
|
||||||
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
initStake: OwnerStakeByStatus | GlobalStakeByStatus,
|
||||||
@ -30,16 +30,18 @@ export function validUnstakeAssertion(
|
|||||||
balanceStore: BlockchainBalanceStore,
|
balanceStore: BlockchainBalanceStore,
|
||||||
globalStake: GlobalStakeByStatus,
|
globalStake: GlobalStakeByStatus,
|
||||||
ownerStake: OwnerStakeByStatus,
|
ownerStake: OwnerStakeByStatus,
|
||||||
): FunctionAssertion<LocalBalanceStore, void> {
|
): FunctionAssertion<[BigNumber], LocalBalanceStore, void> {
|
||||||
const { stakingWrapper, zrxVault } = deployment.staking;
|
const { stakingWrapper, zrxVault } = deployment.staking;
|
||||||
|
|
||||||
return new FunctionAssertion(stakingWrapper.unstake, {
|
return new FunctionAssertion(stakingWrapper.unstake, {
|
||||||
before: async (amount: BigNumber, txData: Partial<TxData>) => {
|
before: async (args: FunctionArguments<[BigNumber]>) => {
|
||||||
|
const [amount] = args.args;
|
||||||
|
|
||||||
// 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);
|
||||||
expectedBalances.transferAsset(
|
expectedBalances.transferAsset(
|
||||||
zrxVault.address,
|
zrxVault.address,
|
||||||
txData.from as string,
|
args.txData.from as string,
|
||||||
amount,
|
amount,
|
||||||
deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(),
|
deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(),
|
||||||
);
|
);
|
||||||
@ -48,9 +50,10 @@ export function validUnstakeAssertion(
|
|||||||
after: async (
|
after: async (
|
||||||
expectedBalances: LocalBalanceStore,
|
expectedBalances: LocalBalanceStore,
|
||||||
_result: FunctionResult,
|
_result: FunctionResult,
|
||||||
amount: BigNumber,
|
args: FunctionArguments<[BigNumber]>,
|
||||||
txData: Partial<TxData>,
|
|
||||||
) => {
|
) => {
|
||||||
|
const [amount] = args.args;
|
||||||
|
|
||||||
logUtils.log(`unstake(${amount})`);
|
logUtils.log(`unstake(${amount})`);
|
||||||
|
|
||||||
// Checks that the ZRX transfer updated balances as expected.
|
// Checks that the ZRX transfer updated balances as expected.
|
||||||
@ -59,7 +62,7 @@ export function validUnstakeAssertion(
|
|||||||
|
|
||||||
// Checks that the owner's undelegated stake has decreased by the stake amount
|
// Checks that the owner's undelegated stake has decreased by the stake amount
|
||||||
const ownerUndelegatedStake = await stakingWrapper
|
const ownerUndelegatedStake = await stakingWrapper
|
||||||
.getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated)
|
.getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated)
|
||||||
.callAsync();
|
.callAsync();
|
||||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
||||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||||
|
@ -4,11 +4,11 @@ import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
|||||||
|
|
||||||
import { artifacts } from '../../artifacts';
|
import { artifacts } from '../../artifacts';
|
||||||
import { TestFrameworkContract, TestFrameworkEventEventArgs, TestFrameworkEvents } from '../../wrappers';
|
import { TestFrameworkContract, TestFrameworkEventEventArgs, TestFrameworkEvents } from '../../wrappers';
|
||||||
import { FunctionAssertion, FunctionResult } from '../assertions/function_assertion';
|
import { FunctionArguments, FunctionAssertion, FunctionResult } from '../assertions/function_assertion';
|
||||||
|
|
||||||
const { ZERO_AMOUNT, MAX_UINT256 } = constants;
|
const { ZERO_AMOUNT, MAX_UINT256 } = constants;
|
||||||
|
|
||||||
blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
blockchainTests.resets.only('FunctionAssertion Unit Tests', env => {
|
||||||
let exampleContract: TestFrameworkContract;
|
let exampleContract: TestFrameworkContract;
|
||||||
|
|
||||||
before(async () => {
|
before(async () => {
|
||||||
@ -23,84 +23,87 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
|||||||
describe('executeAsync', () => {
|
describe('executeAsync', () => {
|
||||||
it('should call the before function with the provided arguments', async () => {
|
it('should call the before function with the provided arguments', async () => {
|
||||||
let sideEffectTarget = ZERO_AMOUNT;
|
let sideEffectTarget = ZERO_AMOUNT;
|
||||||
const assertion = new FunctionAssertion<void, BigNumber>(
|
const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(
|
||||||
exampleContract.returnInteger.bind(exampleContract),
|
exampleContract.returnInteger.bind(exampleContract),
|
||||||
{
|
{
|
||||||
before: async (_input: BigNumber) => {
|
before: async (args: { args: [BigNumber] }) => {
|
||||||
sideEffectTarget = randomInput;
|
sideEffectTarget = randomInput;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
||||||
await assertion.executeAsync(randomInput);
|
await assertion.executeAsync({ args: [randomInput], txData: {} });
|
||||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should call the after function with the provided arguments', async () => {
|
it('should call the after function with the provided arguments', async () => {
|
||||||
let sideEffectTarget = ZERO_AMOUNT;
|
let sideEffectTarget = ZERO_AMOUNT;
|
||||||
const assertion = new FunctionAssertion<void, BigNumber>(
|
const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(
|
||||||
exampleContract.returnInteger.bind(exampleContract),
|
exampleContract.returnInteger.bind(exampleContract),
|
||||||
{
|
{
|
||||||
after: async (_beforeInfo: any, _result: FunctionResult, input: BigNumber) => {
|
after: async (_beforeInfo: any, _result: FunctionResult, args: FunctionArguments<[BigNumber]>) => {
|
||||||
sideEffectTarget = input;
|
sideEffectTarget = args.args[0];
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
||||||
await assertion.executeAsync(randomInput);
|
await assertion.executeAsync({ args: [randomInput], txData: {} });
|
||||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should not fail immediately if the wrapped function fails', async () => {
|
it('should not fail immediately if the wrapped function fails', async () => {
|
||||||
const assertion = new FunctionAssertion<{}, void>(exampleContract.emptyRevert.bind(exampleContract));
|
const assertion = new FunctionAssertion<[], {}, void>(exampleContract.emptyRevert.bind(exampleContract));
|
||||||
await assertion.executeAsync();
|
await assertion.executeAsync({ args: [], txData: {} });
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass the return value of "before" to "after"', async () => {
|
it('should pass the return value of "before" to "after"', async () => {
|
||||||
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
||||||
let sideEffectTarget = ZERO_AMOUNT;
|
let sideEffectTarget = ZERO_AMOUNT;
|
||||||
const assertion = new FunctionAssertion<BigNumber, BigNumber>(
|
const assertion = new FunctionAssertion<[BigNumber], BigNumber, BigNumber>(
|
||||||
exampleContract.returnInteger.bind(exampleContract),
|
exampleContract.returnInteger.bind(exampleContract),
|
||||||
{
|
{
|
||||||
before: async (_input: BigNumber) => {
|
before: async (_args: FunctionArguments<[BigNumber]>) => {
|
||||||
return randomInput;
|
return randomInput;
|
||||||
},
|
},
|
||||||
after: async (beforeInfo: any, _result: FunctionResult, _input: BigNumber) => {
|
after: async (beforeInfo: any, _result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => {
|
||||||
sideEffectTarget = beforeInfo;
|
sideEffectTarget = beforeInfo;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
await assertion.executeAsync(randomInput);
|
await assertion.executeAsync({ args: [randomInput], txData: {} });
|
||||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass the result from the function call to "after"', async () => {
|
it('should pass the result from the function call to "after"', async () => {
|
||||||
let sideEffectTarget = ZERO_AMOUNT;
|
let sideEffectTarget = ZERO_AMOUNT;
|
||||||
const assertion = new FunctionAssertion<void, BigNumber>(
|
const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>(
|
||||||
exampleContract.returnInteger.bind(exampleContract),
|
exampleContract.returnInteger.bind(exampleContract),
|
||||||
{
|
{
|
||||||
after: async (_beforeInfo: any, result: FunctionResult, _input: BigNumber) => {
|
after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => {
|
||||||
sideEffectTarget = result.data;
|
sideEffectTarget = result.data;
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256);
|
||||||
await assertion.executeAsync(randomInput);
|
await assertion.executeAsync({ args: [randomInput], txData: {} });
|
||||||
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
expect(sideEffectTarget).bignumber.to.be.eq(randomInput);
|
||||||
});
|
});
|
||||||
|
|
||||||
it('should pass the receipt from the function call to "after"', async () => {
|
it('should pass the receipt from the function call to "after"', async () => {
|
||||||
let sideEffectTarget: TransactionReceiptWithDecodedLogs;
|
let sideEffectTarget: TransactionReceiptWithDecodedLogs;
|
||||||
const assertion = new FunctionAssertion<void, void>(exampleContract.emitEvent.bind(exampleContract), {
|
const assertion = new FunctionAssertion<[string], void, void>(
|
||||||
after: async (_beforeInfo: any, result: FunctionResult, _input: string) => {
|
exampleContract.emitEvent.bind(exampleContract),
|
||||||
|
{
|
||||||
|
after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => {
|
||||||
if (result.receipt) {
|
if (result.receipt) {
|
||||||
sideEffectTarget = result.receipt;
|
sideEffectTarget = result.receipt;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
|
|
||||||
const input = 'emitted data';
|
const input = 'emitted data';
|
||||||
await assertion.executeAsync(input);
|
await assertion.executeAsync({ args: [input], txData: {} });
|
||||||
|
|
||||||
// Ensure that the correct events were emitted.
|
// Ensure that the correct events were emitted.
|
||||||
const [event] = filterLogsToArguments<TestFrameworkEventEventArgs>(
|
const [event] = filterLogsToArguments<TestFrameworkEventEventArgs>(
|
||||||
@ -112,13 +115,16 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => {
|
|||||||
|
|
||||||
it('should pass the error to "after" if the function call fails', async () => {
|
it('should pass the error to "after" if the function call fails', async () => {
|
||||||
let sideEffectTarget: Error;
|
let sideEffectTarget: Error;
|
||||||
const assertion = new FunctionAssertion<void, void>(exampleContract.stringRevert.bind(exampleContract), {
|
const assertion = new FunctionAssertion<[string], void, void>(
|
||||||
after: async (_beforeInfo: any, result: FunctionResult, _input: string) => {
|
exampleContract.stringRevert.bind(exampleContract),
|
||||||
|
{
|
||||||
|
after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => {
|
||||||
sideEffectTarget = result.data;
|
sideEffectTarget = result.data;
|
||||||
},
|
},
|
||||||
});
|
},
|
||||||
|
);
|
||||||
const message = 'error message';
|
const message = 'error message';
|
||||||
await assertion.executeAsync(message);
|
await assertion.executeAsync({ args: [message], txData: {} });
|
||||||
|
|
||||||
const expectedError = new StringRevertError(message);
|
const expectedError = new StringRevertError(message);
|
||||||
return expect(Promise.reject(sideEffectTarget!)).to.revertWith(expectedError); // tslint:disable-line
|
return expect(Promise.reject(sideEffectTarget!)).to.revertWith(expectedError); // tslint:disable-line
|
||||||
|
@ -0,0 +1,53 @@
|
|||||||
|
import { blockchainTests } from '@0x/contracts-test-utils';
|
||||||
|
import * as _ from 'lodash';
|
||||||
|
|
||||||
|
import { PoolMember } from '../framework/actors/pool_member';
|
||||||
|
import { PoolOperator } from '../framework/actors/pool_operator';
|
||||||
|
import { AssertionResult } from '../framework/assertions/function_assertion';
|
||||||
|
import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance_store';
|
||||||
|
import { DeploymentManager } from '../framework/deployment_manager';
|
||||||
|
import { Simulation, SimulationEnvironment } from '../framework/simulation';
|
||||||
|
|
||||||
|
class PoolMembershipSimulation extends Simulation {
|
||||||
|
protected async *_assertionGenerator(): AsyncIterableIterator<AssertionResult | void> {
|
||||||
|
const { deployment } = this.environment;
|
||||||
|
|
||||||
|
const operator = new PoolOperator({
|
||||||
|
name: 'operator',
|
||||||
|
deployment,
|
||||||
|
simulationEnvironment: this.environment,
|
||||||
|
});
|
||||||
|
|
||||||
|
const member = new PoolMember({
|
||||||
|
name: 'member',
|
||||||
|
deployment,
|
||||||
|
simulationEnvironment: this.environment,
|
||||||
|
});
|
||||||
|
|
||||||
|
const actions = [
|
||||||
|
operator.simulationActions.validCreateStakingPool,
|
||||||
|
member.simulationActions.validJoinStakingPool,
|
||||||
|
];
|
||||||
|
|
||||||
|
while (true) {
|
||||||
|
const action = _.sample(actions);
|
||||||
|
yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
blockchainTests('pool membership fuzz test', env => {
|
||||||
|
it('fuzz', async () => {
|
||||||
|
const deployment = await DeploymentManager.deployAsync(env, {
|
||||||
|
numErc20TokensToDeploy: 0,
|
||||||
|
numErc721TokensToDeploy: 0,
|
||||||
|
numErc1155TokensToDeploy: 0,
|
||||||
|
});
|
||||||
|
|
||||||
|
const balanceStore = new BlockchainBalanceStore({}, {});
|
||||||
|
|
||||||
|
const simulationEnv = new SimulationEnvironment(deployment, balanceStore);
|
||||||
|
const simulation = new PoolMembershipSimulation(simulationEnv);
|
||||||
|
return simulation.fuzzAsync();
|
||||||
|
});
|
||||||
|
});
|
Loading…
x
Reference in New Issue
Block a user