diff --git a/contracts/integrations/test/framework/actors/hybrids.ts b/contracts/integrations/test/framework/actors/hybrids.ts index 7265b0fb93..51a73a43b2 100644 --- a/contracts/integrations/test/framework/actors/hybrids.ts +++ b/contracts/integrations/test/framework/actors/hybrids.ts @@ -3,9 +3,11 @@ import { KeeperMixin } from './keeper'; import { MakerMixin } from './maker'; import { PoolOperatorMixin } from './pool_operator'; import { StakerMixin } from './staker'; +import { TakerMixin } from './taker'; export class OperatorMaker extends PoolOperatorMixin(MakerMixin(Actor)) {} export class StakerMaker extends StakerMixin(MakerMixin(Actor)) {} export class StakerOperator extends StakerMixin(PoolOperatorMixin(Actor)) {} export class OperatorStakerMaker extends PoolOperatorMixin(StakerMixin(MakerMixin(Actor))) {} export class StakerKeeper extends StakerMixin(KeeperMixin(Actor)) {} +export class MakerTaker extends MakerMixin(TakerMixin(Actor)) {} diff --git a/contracts/integrations/test/framework/actors/maker.ts b/contracts/integrations/test/framework/actors/maker.ts index e701e29306..b0dbdf9077 100644 --- a/contracts/integrations/test/framework/actors/maker.ts +++ b/contracts/integrations/test/framework/actors/maker.ts @@ -1,6 +1,10 @@ import { constants, OrderFactory } from '@0x/contracts-test-utils'; import { Order, SignedOrder } from '@0x/types'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import * as _ from 'lodash'; + +import { AssertionResult } from '../assertions/function_assertion'; +import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool'; import { Actor, ActorConfig, Constructor } from './base'; @@ -45,6 +49,12 @@ export function MakerMixin(Base: TBase): TBase & Cons ...orderConfig, }; this.orderFactory = new OrderFactory(this.actor.privateKey, defaultOrderParams); + + // Register this mixin's assertion generators + this.actor.simulationActions = { + ...this.actor.simulationActions, + validJoinStakingPool: this._validJoinStakingPool(), + }; } /** @@ -73,6 +83,19 @@ export function MakerMixin(Base: TBase): TBase & Cons from: this.actor.address, }); } + + private async *_validJoinStakingPool(): AsyncIterableIterator { + 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 { + yield assertion.executeAsync([poolId], { from: this.actor.address }); + } + } + } }; } diff --git a/contracts/integrations/test/framework/actors/pool_member.ts b/contracts/integrations/test/framework/actors/pool_member.ts deleted file mode 100644 index 160eb7371e..0000000000 --- a/contracts/integrations/test/framework/actors/pool_member.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { constants, getRandomInteger } from '@0x/contracts-test-utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; -import * as _ from 'lodash'; - -import { validFillOrderCompleteFillAssertion } from '../assertions/fillOrder'; -import { AssertionResult } from '../assertions/function_assertion'; -import { validJoinStakingPoolAssertion } from '../assertions/joinStakingPool'; - -import { Actor, Constructor } from './base'; - -interface PoolMemberInterface { - joinStakingPoolAsync: (poolId: string) => Promise; -} - -/** - * 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(Base: TBase): TBase & Constructor { - 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(), - validFillOrderCompleteFill: this._validFillOrderCompleteFill(), - }; - } - - /** - * Joins a new staking pool. - */ - public async joinStakingPoolAsync(poolId: string): Promise { - const stakingContract = this.actor.deployment.staking.stakingWrapper; - return stakingContract - .joinStakingPoolAsMaker(poolId) - .awaitTransactionSuccessAsync({ from: this.actor.address }); - } - - private async *_validJoinStakingPool(): AsyncIterableIterator { - 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 { - yield assertion.executeAsync({ args: [poolId], txData: { from: this.actor.address } }); - } - } - } - - private async *_validFillOrderCompleteFill(): AsyncIterableIterator { - const { marketMakers } = this.actor.simulationEnvironment!; - const assertion = validFillOrderCompleteFillAssertion(this.actor.deployment); - while (true) { - const maker = _.sample(marketMakers); - if (maker === undefined) { - yield undefined; - } else { - // Configure the maker's token balances so that the order will definitely be fillable. - await Promise.all([ - ...this.actor.deployment.tokens.erc20.map(async token => maker.configureERC20TokenAsync(token)), - ...this.actor.deployment.tokens.erc20.map(async token => - this.actor.configureERC20TokenAsync(token), - ), - this.actor.configureERC20TokenAsync( - this.actor.deployment.tokens.weth, - this.actor.deployment.staking.stakingProxy.address, - ), - ]); - - const order = await maker.signOrderAsync({ - makerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE), - takerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE), - }); - yield assertion.executeAsync({ - args: [order, order.takerAssetAmount, order.signature], - txData: { from: this.actor.address }, - }); - } - } - } - }; -} - -export class PoolMember extends PoolMemberMixin(Actor) {} diff --git a/contracts/integrations/test/framework/actors/pool_operator.ts b/contracts/integrations/test/framework/actors/pool_operator.ts index b888ead533..176e26fd06 100644 --- a/contracts/integrations/test/framework/actors/pool_operator.ts +++ b/contracts/integrations/test/framework/actors/pool_operator.ts @@ -84,7 +84,7 @@ export function PoolOperatorMixin(Base: TBase): TBase const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools); while (true) { const operatorShare = getRandomInteger(0, constants.PPM).toNumber(); - yield assertion.executeAsync({ args: [operatorShare, false], txData: { from: this.actor.address } }); + yield assertion.executeAsync([operatorShare, false], { from: this.actor.address }); } } @@ -97,10 +97,7 @@ export function PoolOperatorMixin(Base: TBase): TBase yield undefined; } else { const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare).toNumber(); - yield assertion.executeAsync({ - args: [poolId, operatorShare], - txData: { from: this.actor.address }, - }); + yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address }); } } } diff --git a/contracts/integrations/test/framework/actors/staker.ts b/contracts/integrations/test/framework/actors/staker.ts index 4898a4804e..b92f98475d 100644 --- a/contracts/integrations/test/framework/actors/staker.ts +++ b/contracts/integrations/test/framework/actors/staker.ts @@ -76,7 +76,7 @@ export function StakerMixin(Base: TBase): TBase & Con await balanceStore.updateErc20BalancesAsync(); const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address]; const amount = getRandomInteger(0, zrxBalance); - yield assertion.executeAsync({ args: [amount], txData: { from: this.actor.address } }); + yield assertion.executeAsync([amount], { from: this.actor.address }); } } @@ -95,7 +95,7 @@ export function StakerMixin(Base: TBase): TBase & Con undelegatedStake.nextEpochBalance, ); const amount = getRandomInteger(0, withdrawableStake); - yield assertion.executeAsync({ args: [amount], txData: { from: this.actor.address } }); + yield assertion.executeAsync([amount], { from: this.actor.address }); } } @@ -124,7 +124,7 @@ export function StakerMixin(Base: TBase): TBase & Con : this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance; const amount = getRandomInteger(0, moveableStake); - yield assertion.executeAsync({ args: [from, to, amount], txData: { from: this.actor.address } }); + yield assertion.executeAsync([from, to, amount], { from: this.actor.address }); } } }; diff --git a/contracts/integrations/test/framework/actors/taker.ts b/contracts/integrations/test/framework/actors/taker.ts index 65672f9a52..ca545966cd 100644 --- a/contracts/integrations/test/framework/actors/taker.ts +++ b/contracts/integrations/test/framework/actors/taker.ts @@ -1,7 +1,11 @@ +import { constants, getRandomInteger } from '@0x/contracts-test-utils'; import { SignedOrder } from '@0x/types'; import { BigNumber } from '@0x/utils'; import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; +import * as _ from 'lodash'; +import { validFillOrderCompleteFillAssertion } from '../assertions/fillOrder'; +import { AssertionResult } from '../assertions/function_assertion'; import { DeploymentManager } from '../deployment_manager'; import { Actor, Constructor } from './base'; @@ -31,6 +35,12 @@ export function TakerMixin(Base: TBase): TBase & Cons // 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, + validFillOrderCompleteFill: this._validFillOrderCompleteFill(), + }; } /** @@ -50,6 +60,37 @@ export function TakerMixin(Base: TBase): TBase & Cons ...txData, }); } + + private async *_validFillOrderCompleteFill(): AsyncIterableIterator { + const { marketMakers } = this.actor.simulationEnvironment!; + const assertion = validFillOrderCompleteFillAssertion(this.actor.deployment); + while (true) { + const maker = _.sample(marketMakers); + if (maker === undefined) { + yield undefined; + } else { + // Configure the maker's token balances so that the order will definitely be fillable. + await Promise.all([ + ...this.actor.deployment.tokens.erc20.map(async token => maker.configureERC20TokenAsync(token)), + ...this.actor.deployment.tokens.erc20.map(async token => + this.actor.configureERC20TokenAsync(token), + ), + this.actor.configureERC20TokenAsync( + this.actor.deployment.tokens.weth, + this.actor.deployment.staking.stakingProxy.address, + ), + ]); + + const order = await maker.signOrderAsync({ + makerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE), + takerAssetAmount: getRandomInteger(constants.ZERO_AMOUNT, constants.INITIAL_ERC20_BALANCE), + }); + yield assertion.executeAsync([order, order.takerAssetAmount, order.signature], { + from: this.actor.address, + }); + } + } + } }; } diff --git a/contracts/integrations/test/framework/assertions/createStakingPool.ts b/contracts/integrations/test/framework/assertions/createStakingPool.ts index 5f781151e8..6748b44271 100644 --- a/contracts/integrations/test/framework/assertions/createStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/createStakingPool.ts @@ -13,6 +13,7 @@ import { FunctionAssertion, FunctionResult } from './function_assertion'; * Returns a FunctionAssertion for `createStakingPool` which assumes valid input is provided. The * FunctionAssertion checks that the new poolId is one more than the last poolId. */ +/* tslint:disable:no-non-null-assertion */ export function validCreateStakingPoolAssertion( deployment: DeploymentManager, pools: StakingPoolById, @@ -34,25 +35,26 @@ export function validCreateStakingPoolAssertion( after: async ( expectedPoolId: string, result: FunctionResult, - args: { - args: [number, boolean]; - txData: Partial; - }, + args: [number, boolean], + txData: Partial, ) => { - logUtils.log(`createStakingPool(${args.args[0]}, ${args.args[1]}) => ${expectedPoolId}`); + const [operatorShare, shouldAddMakerAsOperator] = args; + + logUtils.log(`createStakingPool(${operatorShare}, ${shouldAddMakerAsOperator}) => ${expectedPoolId}`); // Checks the logs for the new poolId, verifies that it is as expected - const log = result.receipt!.logs[0]; // tslint:disable-line:no-non-null-assertion + const log = result.receipt!.logs[0]; const actualPoolId = (log as any).args.poolId; expect(actualPoolId).to.equal(expectedPoolId); // Adds the new pool to local state pools[actualPoolId] = { - operator: args.txData.from as string, - operatorShare: args.args[0], + operator: txData.from!, + operatorShare, delegatedStake: new StoredBalance(), }; }, }, ); } +/* tslint:enable:no-non-null-assertion*/ diff --git a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts index 90ffa60c12..9a6ff1a0c4 100644 --- a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts +++ b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts @@ -1,6 +1,7 @@ import { StakingPoolById } from '@0x/contracts-staking'; import { expect } from '@0x/contracts-test-utils'; import { logUtils } from '@0x/utils'; +import { TxData } from 'ethereum-types'; import { DeploymentManager } from '../deployment_manager'; @@ -19,15 +20,15 @@ export function validDecreaseStakingPoolOperatorShareAssertion( return new FunctionAssertion<[string, number], {}, void>( stakingWrapper.decreaseStakingPoolOperatorShare.bind(stakingWrapper), { - after: async (_beforeInfo, _result: FunctionResult, args: { args: [string, number] }) => { - const poolId = args.args[0]; - const expectedOperatorShare = args.args[1]; + after: async (_beforeInfo, _result: FunctionResult, args: [string, number], txData: Partial) => { + const [poolId, expectedOperatorShare] = args; logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`); // Checks that the on-chain pool's operator share has been updated. const { operatorShare } = await stakingWrapper.getStakingPool(poolId).callAsync(); expect(operatorShare).to.bignumber.equal(expectedOperatorShare); + // Updates the pool in local state. pools[poolId].operatorShare = operatorShare; }, diff --git a/contracts/integrations/test/framework/assertions/fillOrder.ts b/contracts/integrations/test/framework/assertions/fillOrder.ts index 1b54d628aa..cb34ed4f43 100644 --- a/contracts/integrations/test/framework/assertions/fillOrder.ts +++ b/contracts/integrations/test/framework/assertions/fillOrder.ts @@ -3,12 +3,12 @@ import { ExchangeEvents, ExchangeFillEventArgs } from '@0x/contracts-exchange'; import { constants, expect, orderHashUtils, verifyEvents } from '@0x/contracts-test-utils'; import { FillResults, Order } from '@0x/types'; import { BigNumber, logUtils } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; import * as _ from 'lodash'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionAssertion, FunctionResult } from './function_assertion'; function verifyFillEvents( takerAddress: string, @@ -68,23 +68,30 @@ function verifyFillEvents( * A function assertion that verifies that a complete and valid fill succeeded and emitted the correct logs. */ /* tslint:disable:no-unnecessary-type-assertion */ +/* tslint:disable:no-non-null-assertion */ export function validFillOrderCompleteFillAssertion( deployment: DeploymentManager, ): FunctionAssertion<[Order, BigNumber, string], {}, FillResults> { const exchange = deployment.exchange; return new FunctionAssertion<[Order, BigNumber, string], {}, FillResults>(exchange.fillOrder.bind(exchange), { - after: async (_beforeInfo, result: FunctionResult, args: FunctionArguments<[Order, BigNumber, string]>) => { - const [order] = args.args; + after: async ( + _beforeInfo, + result: FunctionResult, + args: [Order, BigNumber, string], + txData: Partial, + ) => { + const [order] = args; // Ensure that the tx succeeded. expect(result.success).to.be.true(); // Ensure that the correct events were emitted. - verifyFillEvents(args.txData.from!, order, result.receipt!, deployment); // tslint:disable-line:no-non-null-assertion + verifyFillEvents(txData.from!, order, result.receipt!, deployment); - logUtils.log(`Order filled by ${args.txData.from}`); + logUtils.log(`Order filled by ${txData.from}`); }, }); } +/* tslint:enable:no-non-null-assertion */ /* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/function_assertion.ts b/contracts/integrations/test/framework/assertions/function_assertion.ts index 411ad3acf9..ff810da3f5 100644 --- a/contracts/integrations/test/framework/assertions/function_assertion.ts +++ b/contracts/integrations/test/framework/assertions/function_assertion.ts @@ -5,11 +5,6 @@ import * as _ from 'lodash'; // tslint:disable:max-classes-per-file export type GenericContractFunction = (...args: any[]) => ContractFunctionObj; -export interface FunctionArguments { - args: TArgs; - txData: Partial; -} - export interface FunctionResult { data?: any; success: boolean; @@ -27,8 +22,8 @@ export interface FunctionResult { * function. */ export interface Condition { - before: (args: FunctionArguments) => Promise; - after: (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments) => Promise; + before: (args: TArgs, txData: Partial) => Promise; + after: (beforeInfo: TBefore, result: FunctionResult, args: TArgs, txData: Partial) => Promise; } /** @@ -39,7 +34,7 @@ export interface Condition { * @param runAsync The function to execute for the assertion. */ export interface Assertion { - executeAsync: (args: FunctionArguments) => Promise; + executeAsync: (args: TArgs, txData: TxData) => Promise; } export interface AssertionResult { @@ -67,10 +62,10 @@ export class FunctionAssertion imp condition: Partial> = {}, ) { this.condition = { - before: async (args: FunctionArguments) => { + before: async (args: TArgs, txData: Partial) => { return ({} as any) as TBefore; }, - after: async (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments) => { + after: async (beforeInfo: TBefore, result: FunctionResult, args: TArgs, txData: Partial) => { return ({} as any) as TBefore; }, ...condition, @@ -82,9 +77,9 @@ export class FunctionAssertion imp * Runs the wrapped function and fails if the before or after assertions fail. * @param ...args The args to the contract wrapper function. */ - public async executeAsync(args: FunctionArguments): Promise> { + public async executeAsync(args: TArgs, txData: Partial): Promise> { // Call the before condition. - const beforeInfo = await this.condition.before(args); + const beforeInfo = await this.condition.before(args, txData); // Initialize the callResult so that the default success value is true. const callResult: FunctionResult = { success: true }; @@ -92,11 +87,11 @@ export class FunctionAssertion imp // Try to make the call to the function. If it is successful, pass the // result and receipt to the after condition. try { - const functionWithArgs = this.wrapperFunction(...args.args) as ContractTxFunctionObj; - callResult.data = await functionWithArgs.callAsync(args.txData); + const functionWithArgs = this.wrapperFunction(...args) as ContractTxFunctionObj; + callResult.data = await functionWithArgs.callAsync(txData); callResult.receipt = functionWithArgs.awaitTransactionSuccessAsync !== undefined - ? await functionWithArgs.awaitTransactionSuccessAsync(args.txData) // tslint:disable-line:await-promise + ? await functionWithArgs.awaitTransactionSuccessAsync(txData) // tslint:disable-line:await-promise : undefined; // tslint:enable:await-promise } catch (error) { @@ -106,7 +101,7 @@ export class FunctionAssertion imp } // Call the after condition. - const afterInfo = await this.condition.after(beforeInfo, callResult, args); + const afterInfo = await this.condition.after(beforeInfo, callResult, args, txData); return { beforeInfo, diff --git a/contracts/integrations/test/framework/assertions/joinStakingPool.ts b/contracts/integrations/test/framework/assertions/joinStakingPool.ts index 6f9db95acd..478268ca63 100644 --- a/contracts/integrations/test/framework/assertions/joinStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/joinStakingPool.ts @@ -1,50 +1,43 @@ import { StakingEvents, StakingMakerStakingPoolSetEventArgs } from '@0x/contracts-staking'; import { expect, filterLogsToArguments } from '@0x/contracts-test-utils'; import { logUtils } from '@0x/utils'; +import { TxData } from 'ethereum-types'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionAssertion, FunctionResult } from './function_assertion'; /** * Returns a function assertion that verifies valid pool joining. */ +/* tslint:disable:no-unnecessary-type-assertion */ +/* tslint:disable:no-non-null-assertion */ export function validJoinStakingPoolAssertion(deployment: DeploymentManager): FunctionAssertion<[string], {}, void> { const { stakingWrapper } = deployment.staking; return new FunctionAssertion<[string], {}, void>(stakingWrapper.joinStakingPoolAsMaker.bind(stakingWrapper), { - 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'); - } + after: async (_beforeInfo, _result: FunctionResult, args: [string], txData: Partial) => { + const [poolId] = args; expect(_result.success).to.be.true(); - const logs = _result.receipt.logs; + const logs = _result.receipt!.logs; const logArgs = filterLogsToArguments( logs, StakingEvents.MakerStakingPoolSet, ); expect(logArgs).to.be.deep.eq([ { - makerAddress: args.txData.from, + makerAddress: txData.from!, poolId, }, ]); - const joinedPoolId = await deployment.staking.stakingWrapper.poolIdByMaker(args.txData.from).callAsync(); + const joinedPoolId = await deployment.staking.stakingWrapper.poolIdByMaker(txData.from!).callAsync(); expect(joinedPoolId).to.be.eq(poolId); - logUtils.log(`Pool ${poolId} joined by ${args.txData.from}`); /* tslint:disable-line:no-console */ + logUtils.log(`Pool ${poolId} joined by ${txData.from}`); }, }); } +/* tslint:enable:no-non-null-assertion */ +/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/moveStake.ts b/contracts/integrations/test/framework/assertions/moveStake.ts index 3b464e59dd..f65d98ab41 100644 --- a/contracts/integrations/test/framework/assertions/moveStake.ts +++ b/contracts/integrations/test/framework/assertions/moveStake.ts @@ -8,11 +8,12 @@ import { } from '@0x/contracts-staking'; import { constants, expect } from '@0x/contracts-test-utils'; import { BigNumber, logUtils } from '@0x/utils'; +import { TxData } from 'ethereum-types'; import * as _ from 'lodash'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionAssertion, FunctionResult } from './function_assertion'; function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void { _.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount)); @@ -76,6 +77,7 @@ function updateNextEpochBalances( * Returns a FunctionAssertion for `moveStake` which assumes valid input is provided. The * FunctionAssertion checks that the staker's */ +/* tslint:disable:no-unnecessary-type-assertion */ export function validMoveStakeAssertion( deployment: DeploymentManager, globalStake: GlobalStakeByStatus, @@ -90,9 +92,10 @@ export function validMoveStakeAssertion( after: async ( _beforeInfo: {}, _result: FunctionResult, - args: FunctionArguments<[StakeInfo, StakeInfo, BigNumber]>, + args: [StakeInfo, StakeInfo, BigNumber], + txData: Partial, ) => { - const [from, to, amount] = args.args; + const [from, to, amount] = args; logUtils.log( `moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${ @@ -100,7 +103,7 @@ export function validMoveStakeAssertion( }, poolId: ${to.poolId} }, ${amount})`, ); - const owner = args.txData.from as string; + const owner = txData.from!; // tslint:disable-line:no-non-null-assertion // Update local balances to match the expected result of this `moveStake` operation const updatedPools = updateNextEpochBalances(globalStake, ownerStake, pools, from, to, amount); @@ -140,3 +143,4 @@ export function validMoveStakeAssertion( }, ); } +/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/stake.ts b/contracts/integrations/test/framework/assertions/stake.ts index 76c5fff406..ac88003f0c 100644 --- a/contracts/integrations/test/framework/assertions/stake.ts +++ b/contracts/integrations/test/framework/assertions/stake.ts @@ -1,12 +1,13 @@ import { GlobalStakeByStatus, OwnerStakeByStatus, StakeStatus, StoredBalance } from '@0x/contracts-staking'; import { expect } from '@0x/contracts-test-utils'; import { BigNumber, logUtils } from '@0x/utils'; +import { TxData } from 'ethereum-types'; import { BlockchainBalanceStore } from '../balances/blockchain_balance_store'; import { LocalBalanceStore } from '../balances/local_balance_store'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionAssertion, FunctionResult } from './function_assertion'; function expectedUndelegatedStake( initStake: OwnerStakeByStatus | GlobalStakeByStatus, @@ -24,6 +25,7 @@ function expectedUndelegatedStake( * FunctionAssertion checks that the staker and zrxVault's balances of ZRX decrease and increase, * respectively, by the input amount. */ +/* tslint:disable:no-unnecessary-type-assertion */ export function validStakeAssertion( deployment: DeploymentManager, balanceStore: BlockchainBalanceStore, @@ -33,13 +35,13 @@ export function validStakeAssertion( const { stakingWrapper, zrxVault } = deployment.staking; return new FunctionAssertion(stakingWrapper.stake.bind(stakingWrapper), { - before: async (args: FunctionArguments<[BigNumber]>) => { - const [amount] = args.args; + before: async (args: [BigNumber], txData: Partial) => { + const [amount] = args; // Simulates the transfer of ZRX from staker to vault const expectedBalances = LocalBalanceStore.create(balanceStore); expectedBalances.transferAsset( - args.txData.from as string, + txData.from!, // tslint:disable-line:no-non-null-assertion zrxVault.address, amount, deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(), @@ -49,9 +51,10 @@ export function validStakeAssertion( after: async ( expectedBalances: LocalBalanceStore, _result: FunctionResult, - args: FunctionArguments<[BigNumber]>, + args: [BigNumber], + txData: Partial, ) => { - const [amount] = args.args; + const [amount] = args; logUtils.log(`stake(${amount})`); @@ -61,7 +64,7 @@ export function validStakeAssertion( // Checks that the owner's undelegated stake has increased by the stake amount const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated) + .getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated) // tslint:disable-line:no-non-null-assertion .callAsync(); const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount); expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake); @@ -79,3 +82,4 @@ export function validStakeAssertion( }, }); } +/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/unstake.ts b/contracts/integrations/test/framework/assertions/unstake.ts index 4308160b7e..6bfc6363fe 100644 --- a/contracts/integrations/test/framework/assertions/unstake.ts +++ b/contracts/integrations/test/framework/assertions/unstake.ts @@ -1,12 +1,13 @@ import { GlobalStakeByStatus, OwnerStakeByStatus, StakeStatus, StoredBalance } from '@0x/contracts-staking'; import { expect } from '@0x/contracts-test-utils'; import { BigNumber, logUtils } from '@0x/utils'; +import { TxData } from 'ethereum-types'; import { BlockchainBalanceStore } from '../balances/blockchain_balance_store'; import { LocalBalanceStore } from '../balances/local_balance_store'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionAssertion, FunctionResult } from './function_assertion'; function expectedUndelegatedStake( initStake: OwnerStakeByStatus | GlobalStakeByStatus, @@ -24,6 +25,8 @@ function expectedUndelegatedStake( * FunctionAssertion checks that the staker and zrxVault's balances of ZRX increase and decrease, * respectively, by the input amount. */ +/* tslint:disable:no-unnecessary-type-assertion */ +/* tslint:disable:no-non-null-assertion */ export function validUnstakeAssertion( deployment: DeploymentManager, balanceStore: BlockchainBalanceStore, @@ -33,14 +36,14 @@ export function validUnstakeAssertion( const { stakingWrapper, zrxVault } = deployment.staking; return new FunctionAssertion(stakingWrapper.unstake.bind(stakingWrapper), { - before: async (args: FunctionArguments<[BigNumber]>) => { - const [amount] = args.args; + before: async (args: [BigNumber], txData: Partial) => { + const [amount] = args; // Simulates the transfer of ZRX from vault to staker const expectedBalances = LocalBalanceStore.create(balanceStore); expectedBalances.transferAsset( zrxVault.address, - args.txData.from as string, + txData.from!, amount, deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(), ); @@ -49,9 +52,10 @@ export function validUnstakeAssertion( after: async ( expectedBalances: LocalBalanceStore, _result: FunctionResult, - args: FunctionArguments<[BigNumber]>, + args: [BigNumber], + txData: Partial, ) => { - const [amount] = args.args; + const [amount] = args; logUtils.log(`unstake(${amount})`); @@ -61,7 +65,7 @@ export function validUnstakeAssertion( // Checks that the owner's undelegated stake has decreased by the stake amount const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated) + .getOwnerStakeByStatus(txData.from!, StakeStatus.Undelegated) .callAsync(); const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount); expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake); @@ -79,3 +83,5 @@ export function validUnstakeAssertion( }, }); } +/* tslint:enable:no-non-null-assertion */ +/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/tests/function_assertion_test.ts b/contracts/integrations/test/framework/tests/function_assertion_test.ts index 72664611a6..9e9e746b46 100644 --- a/contracts/integrations/test/framework/tests/function_assertion_test.ts +++ b/contracts/integrations/test/framework/tests/function_assertion_test.ts @@ -1,10 +1,10 @@ import { blockchainTests, constants, expect, filterLogsToArguments, getRandomInteger } from '@0x/contracts-test-utils'; import { BigNumber, StringRevertError } from '@0x/utils'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; import { artifacts } from '../../artifacts'; import { TestFrameworkContract, TestFrameworkEventEventArgs, TestFrameworkEvents } from '../../wrappers'; -import { FunctionArguments, FunctionAssertion, FunctionResult } from '../assertions/function_assertion'; +import { FunctionAssertion, FunctionResult } from '../assertions/function_assertion'; const { ZERO_AMOUNT, MAX_UINT256 } = constants; @@ -26,13 +26,13 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - before: async (args: { args: [BigNumber] }) => { + before: async (args: [BigNumber], txData: Partial) => { sideEffectTarget = randomInput; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync({ args: [randomInput], txData: {} }); + await assertion.executeAsync([randomInput], {}); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); @@ -41,19 +41,24 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - after: async (_beforeInfo: any, _result: FunctionResult, args: FunctionArguments<[BigNumber]>) => { - sideEffectTarget = args.args[0]; + after: async ( + _beforeInfo: any, + _result: FunctionResult, + args: [BigNumber], + txData: Partial, + ) => { + [sideEffectTarget] = args; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync({ args: [randomInput], txData: {} }); + await assertion.executeAsync([randomInput], {}); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); it('should not fail immediately if the wrapped function fails', async () => { const assertion = new FunctionAssertion<[], {}, void>(exampleContract.emptyRevert.bind(exampleContract)); - await assertion.executeAsync({ args: [], txData: {} }); + await assertion.executeAsync([], {}); }); it('should pass the return value of "before" to "after"', async () => { @@ -62,15 +67,20 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[BigNumber], BigNumber, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - before: async (_args: FunctionArguments<[BigNumber]>) => { + before: async (_args: [BigNumber], _txData: Partial) => { return randomInput; }, - after: async (beforeInfo: any, _result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => { + after: async ( + beforeInfo: any, + _result: FunctionResult, + _args: [BigNumber], + _txData: Partial, + ) => { sideEffectTarget = beforeInfo; }, }, ); - await assertion.executeAsync({ args: [randomInput], txData: {} }); + await assertion.executeAsync([randomInput], {}); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); @@ -79,13 +89,18 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => { + after: async ( + _beforeInfo: any, + result: FunctionResult, + _args: [BigNumber], + _txData: Partial, + ) => { sideEffectTarget = result.data; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync({ args: [randomInput], txData: {} }); + await assertion.executeAsync([randomInput], {}); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); @@ -94,7 +109,12 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[string], void, void>( exampleContract.emitEvent.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => { + after: async ( + _beforeInfo: any, + result: FunctionResult, + _args: [string], + _txData: Partial, + ) => { if (result.receipt) { sideEffectTarget = result.receipt; } @@ -103,7 +123,7 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { ); const input = 'emitted data'; - await assertion.executeAsync({ args: [input], txData: {} }); + await assertion.executeAsync([input], {}); // Ensure that the correct events were emitted. const [event] = filterLogsToArguments( @@ -118,13 +138,18 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { const assertion = new FunctionAssertion<[string], void, void>( exampleContract.stringRevert.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => { + after: async ( + _beforeInfo: any, + result: FunctionResult, + _args: [string], + _txData: Partial, + ) => { sideEffectTarget = result.data; }, }, ); const message = 'error message'; - await assertion.executeAsync({ args: [message], txData: {} }); + await assertion.executeAsync([message], {}); const expectedError = new StringRevertError(message); return expect(Promise.reject(sideEffectTarget!)).to.revertWith(expectedError); // tslint:disable-line diff --git a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts index edce353084..00670f18d9 100644 --- a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts +++ b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts @@ -1,24 +1,22 @@ import { blockchainTests, constants } from '@0x/contracts-test-utils'; import * as _ from 'lodash'; +import { MakerTaker } from '../framework/actors/hybrids'; import { Maker } from '../framework/actors/maker'; -import { PoolMember } from '../framework/actors/pool_member'; 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'; import { PoolManagementSimulation } from './pool_management_test'; -import { StakeManagementSimulation } from './stake_management_test'; class PoolMembershipSimulation extends Simulation { protected async *_assertionGenerator(): AsyncIterableIterator { const { deployment } = this.environment; const poolManagement = new PoolManagementSimulation(this.environment); - const stakeManagement = new StakeManagementSimulation(this.environment); - const member = new PoolMember({ + const member = new MakerTaker({ name: 'member', deployment, simulationEnvironment: this.environment, @@ -28,7 +26,6 @@ class PoolMembershipSimulation extends Simulation { member.simulationActions.validJoinStakingPool, member.simulationActions.validFillOrderCompleteFill, poolManagement.generator, - stakeManagement.generator, ]; while (true) { @@ -38,7 +35,7 @@ class PoolMembershipSimulation extends Simulation { } } -blockchainTests.only('pool membership fuzz test', env => { +blockchainTests.skip('pool membership fuzz test', env => { let deployment: DeploymentManager; let maker: Maker;