From 1e44a9c9423c9e3ae183b63b13c4760cfb6d543c Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Fri, 22 Nov 2019 14:14:45 -0600 Subject: [PATCH 1/7] Made function assertions work with the new wrappers --- .../test/framework/actors/pool_member.ts | 66 +++++++++++++++++++ .../test/framework/actors/pool_operator.ts | 16 +++-- .../test/framework/actors/staker.ts | 6 +- .../framework/assertions/createStakingPool.ts | 24 ++++--- .../decreaseStakingPoolOperatorShare.ts | 9 ++- .../assertions/function_assertion.ts | 49 +++++++++----- .../framework/assertions/joinStakingPool.ts | 45 +++++++++++++ .../test/framework/assertions/moveStake.ts | 19 +++--- .../test/framework/assertions/stake.ts | 17 +++-- .../test/framework/assertions/unstake.ts | 17 +++-- .../tests/function_assertion_test.ts | 66 ++++++++++--------- .../test/fuzz_tests/pool_membership_test.ts | 53 +++++++++++++++ 12 files changed, 298 insertions(+), 89 deletions(-) create mode 100644 contracts/integrations/test/framework/actors/pool_member.ts create mode 100644 contracts/integrations/test/framework/assertions/joinStakingPool.ts create mode 100644 contracts/integrations/test/fuzz_tests/pool_membership_test.ts diff --git a/contracts/integrations/test/framework/actors/pool_member.ts b/contracts/integrations/test/framework/actors/pool_member.ts new file mode 100644 index 0000000000..5588137f7d --- /dev/null +++ b/contracts/integrations/test/framework/actors/pool_member.ts @@ -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; +} + +/** + * 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(), + }; + } + + /** + * 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 }); + } + + // FIXME(jalextowle): I need to make sure that this is being sent from the actor's 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 { + console.log('Attempting to join pool'); + yield assertion.executeAsync({ args: [poolId], txData: {} }); + } + } + } + }; +} + +export class PoolMember extends PoolOperatorMixin(PoolMemberMixin(Actor)) {} diff --git a/contracts/integrations/test/framework/actors/pool_operator.ts b/contracts/integrations/test/framework/actors/pool_operator.ts index 19d9e06d12..31b7dc7e6b 100644 --- a/contracts/integrations/test/framework/actors/pool_operator.ts +++ b/contracts/integrations/test/framework/actors/pool_operator.ts @@ -80,11 +80,16 @@ export function PoolOperatorMixin(Base: TBase): TBase } private async *_validCreateStakingPool(): AsyncIterableIterator { + console.log(10); const { stakingPools } = this.actor.simulationEnvironment!; + console.log(11); const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools); + console.log(12); while (true) { - const operatorShare = getRandomInteger(0, constants.PPM); - yield assertion.executeAsync(operatorShare, false, { from: this.actor.address }); + const operatorShare = getRandomInteger(0, constants.PPM).toNumber(); + console.log(13); + yield assertion.executeAsync({ args: [operatorShare, false], txData: { from: this.actor.address } }); + console.log(14); } } @@ -96,8 +101,11 @@ export function PoolOperatorMixin(Base: TBase): TBase if (poolId === undefined) { yield undefined; } else { - const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare); - yield assertion.executeAsync(poolId, operatorShare, { from: this.actor.address }); + const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare).toNumber(); + yield assertion.executeAsync({ + args: [poolId, operatorShare], + txData: { from: this.actor.address }, + }); } } } diff --git a/contracts/integrations/test/framework/actors/staker.ts b/contracts/integrations/test/framework/actors/staker.ts index 1261933b85..4898a4804e 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(amount, { from: this.actor.address }); + yield assertion.executeAsync({ args: [amount], txData: { 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(amount, { from: this.actor.address }); + yield assertion.executeAsync({ args: [amount], txData: { 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(from, to, amount, { from: this.actor.address }); + yield assertion.executeAsync({ args: [from, to, amount], txData: { from: this.actor.address } }); } } }; diff --git a/contracts/integrations/test/framework/assertions/createStakingPool.ts b/contracts/integrations/test/framework/assertions/createStakingPool.ts index a1829a0e62..d3bfebf2cd 100644 --- a/contracts/integrations/test/framework/assertions/createStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/createStakingPool.ts @@ -16,10 +16,10 @@ import { FunctionAssertion, FunctionResult } from './function_assertion'; export function validCreateStakingPoolAssertion( deployment: DeploymentManager, pools: StakingPoolById, -): FunctionAssertion { +): FunctionAssertion<[number, boolean], string, string> { 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 before: async () => { const lastPoolId = await stakingWrapper.lastPoolId().callAsync(); @@ -32,23 +32,31 @@ export function validCreateStakingPoolAssertion( after: async ( expectedPoolId: string, result: FunctionResult, - operatorShare: number, - addOperatorAsMaker: boolean, - txData: Partial, + args: { + args: [number, boolean]; + txData: Partial; + }, ) => { - 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 + console.log(result.receipt); const log = result.receipt!.logs[0]; // tslint:disable-line:no-non-null-assertion + console.log(102); const actualPoolId = (log as any).args.poolId; + console.log(103); expect(actualPoolId).to.equal(expectedPoolId); + console.log(104); // Adds the new pool to local state pools[actualPoolId] = { - operator: txData.from as string, - operatorShare, + operator: args.txData.from as string, + operatorShare: args.args[0], delegatedStake: new StoredBalance(), }; + console.log(105); }, }); } diff --git a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts index dfcee98ad2..5633524e81 100644 --- a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts +++ b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts @@ -13,11 +13,14 @@ import { FunctionAssertion, FunctionResult } from './function_assertion'; export function validDecreaseStakingPoolOperatorShareAssertion( deployment: DeploymentManager, pools: StakingPoolById, -): FunctionAssertion<{}, void> { +): FunctionAssertion<[string, number], {}, void> { const { stakingWrapper } = deployment.staking; - return new FunctionAssertion<{}, void>(stakingWrapper.decreaseStakingPoolOperatorShare, { - after: async (_beforeInfo, _result: FunctionResult, poolId: string, expectedOperatorShare: number) => { + return new FunctionAssertion<[string, number], {}, void>(stakingWrapper.decreaseStakingPoolOperatorShare, { + after: async (_beforeInfo, _result: FunctionResult, args: { args: [string, number] }) => { + const poolId = args.args[0]; + const expectedOperatorShare = args.args[1]; + logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`); // Checks that the on-chain pool's operator share has been updated. diff --git a/contracts/integrations/test/framework/assertions/function_assertion.ts b/contracts/integrations/test/framework/assertions/function_assertion.ts index 541e57ce12..6bdd7141ec 100644 --- a/contracts/integrations/test/framework/assertions/function_assertion.ts +++ b/contracts/integrations/test/framework/assertions/function_assertion.ts @@ -1,11 +1,16 @@ import { ContractFunctionObj, ContractTxFunctionObj } from '@0x/base-contract'; -import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; +import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; 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; @@ -22,9 +27,9 @@ export interface FunctionResult { * @param after A function that will be run after a call to the contract wrapper * function. */ -export interface Condition { - before: (...args: any[]) => Promise; - after: (beforeInfo: TBefore, result: FunctionResult, ...args: any[]) => Promise; +export interface Condition { + before: (args: FunctionArguments) => Promise; + after: (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments) => Promise; } /** @@ -34,8 +39,8 @@ export interface Condition { * our `Assertion` implementations will do in practice). * @param runAsync The function to execute for the assertion. */ -export interface Assertion { - executeAsync: (...args: any[]) => Promise; +export interface Assertion { + executeAsync: (args: FunctionArguments) => Promise; } export interface AssertionResult { @@ -47,9 +52,9 @@ export interface AssertionResult { * This class implements `Assertion` and represents a "Hoare Triple" that can be * executed. */ -export class FunctionAssertion implements Assertion { +export class FunctionAssertion implements Assertion { // A condition that will be applied to `wrapperFunction`. - public condition: Condition; + public condition: Condition; // The wrapper function that will be wrapped in assertions. public wrapperFunction: ( @@ -60,11 +65,15 @@ export class FunctionAssertion implements Assertion { wrapperFunction: ( ...args: any[] // tslint:disable-line:trailing-comma ) => ContractTxFunctionObj | ContractFunctionObj, - condition: Partial> = {}, + condition: Partial> = {}, ) { this.condition = { - before: _.noop.bind(this), - after: _.noop.bind(this), + before: async (args: FunctionArguments) => { + return ({} as any) as TBefore; + }, + after: async (beforeInfo: TBefore, result: FunctionResult, args: FunctionArguments) => { + return ({} as any) as TBefore; + }, ...condition, }; this.wrapperFunction = wrapperFunction; @@ -74,9 +83,9 @@ export class FunctionAssertion implements Assertion { * 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: any[]): Promise> { + public async executeAsync(args: FunctionArguments): Promise> { // 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. const callResult: FunctionResult = { success: true }; @@ -84,21 +93,27 @@ export class FunctionAssertion implements Assertion { // 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) as ContractTxFunctionObj; - callResult.data = await functionWithArgs.callAsync(); + const functionWithArgs = this.wrapperFunction(...args.args) as ContractTxFunctionObj; + callResult.data = await functionWithArgs.callAsync(args.txData); + + console.log(functionWithArgs); + callResult.receipt = functionWithArgs.awaitTransactionSuccessAsync !== undefined - ? await functionWithArgs.awaitTransactionSuccessAsync() // tslint:disable-line:await-promise + ? await functionWithArgs.awaitTransactionSuccessAsync(args.txData) // tslint:disable-line:await-promise : undefined; // tslint:enable:await-promise } catch (error) { + console.log('got here'); + console.log(error); + callResult.data = error; callResult.success = false; callResult.receipt = undefined; } // Call the after condition. - const afterInfo = await this.condition.after(beforeInfo, callResult, ...args); + const afterInfo = await this.condition.after(beforeInfo, callResult, args); return { beforeInfo, diff --git a/contracts/integrations/test/framework/assertions/joinStakingPool.ts b/contracts/integrations/test/framework/assertions/joinStakingPool.ts new file mode 100644 index 0000000000..6263ea1222 --- /dev/null +++ b/contracts/integrations/test/framework/assertions/joinStakingPool.ts @@ -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( + 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 */ + }, + }); +} diff --git a/contracts/integrations/test/framework/assertions/moveStake.ts b/contracts/integrations/test/framework/assertions/moveStake.ts index 08d27627fe..e640a554fc 100644 --- a/contracts/integrations/test/framework/assertions/moveStake.ts +++ b/contracts/integrations/test/framework/assertions/moveStake.ts @@ -13,7 +13,7 @@ import * as _ from 'lodash'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionAssertion } from './function_assertion'; +import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; function incrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumber): void { _.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).plus(amount)); @@ -82,25 +82,24 @@ export function validMoveStakeAssertion( globalStake: GlobalStakeByStatus, ownerStake: OwnerStakeByStatus, pools: StakingPoolById, -): FunctionAssertion<{}, void> { +): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void> { const { stakingWrapper } = deployment.staking; - return new FunctionAssertion<{}, void>(stakingWrapper.moveStake, { + return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>(stakingWrapper.moveStake, { after: async ( - _beforeInfo, - _result, - from: StakeInfo, - to: StakeInfo, - amount: BigNumber, - txData: Partial, + _beforeInfo: {}, + _result: FunctionResult, + args: FunctionArguments<[StakeInfo, StakeInfo, BigNumber]>, ) => { + const [from, to, amount] = args.args; + logUtils.log( `moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${ StakeStatus[to.status] }, 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 const updatedPools = updateNextEpochBalances(globalStake, ownerStake, pools, from, to, amount); diff --git a/contracts/integrations/test/framework/assertions/stake.ts b/contracts/integrations/test/framework/assertions/stake.ts index 2affd8a194..5b03302eb8 100644 --- a/contracts/integrations/test/framework/assertions/stake.ts +++ b/contracts/integrations/test/framework/assertions/stake.ts @@ -7,7 +7,7 @@ import { BlockchainBalanceStore } from '../balances/blockchain_balance_store'; import { LocalBalanceStore } from '../balances/local_balance_store'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; function expectedUndelegatedStake( initStake: OwnerStakeByStatus | GlobalStakeByStatus, @@ -30,15 +30,17 @@ export function validStakeAssertion( balanceStore: BlockchainBalanceStore, globalStake: GlobalStakeByStatus, ownerStake: OwnerStakeByStatus, -): FunctionAssertion { +): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { const { stakingWrapper, zrxVault } = deployment.staking; return new FunctionAssertion(stakingWrapper.stake, { - before: async (amount: BigNumber, txData: Partial) => { + before: async (args: FunctionArguments<[BigNumber]>) => { + const [amount] = args.args; + // Simulates the transfer of ZRX from staker to vault const expectedBalances = LocalBalanceStore.create(balanceStore); expectedBalances.transferAsset( - txData.from as string, + args.txData.from as string, zrxVault.address, amount, deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(), @@ -48,9 +50,10 @@ export function validStakeAssertion( after: async ( expectedBalances: LocalBalanceStore, _result: FunctionResult, - amount: BigNumber, - txData: Partial, + args: FunctionArguments<[BigNumber]>, ) => { + const [amount] = args.args; + logUtils.log(`stake(${amount})`); // 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 const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated) + .getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated) .callAsync(); const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount); expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake); diff --git a/contracts/integrations/test/framework/assertions/unstake.ts b/contracts/integrations/test/framework/assertions/unstake.ts index 5644ba5e39..9473124bf2 100644 --- a/contracts/integrations/test/framework/assertions/unstake.ts +++ b/contracts/integrations/test/framework/assertions/unstake.ts @@ -7,7 +7,7 @@ import { BlockchainBalanceStore } from '../balances/blockchain_balance_store'; import { LocalBalanceStore } from '../balances/local_balance_store'; import { DeploymentManager } from '../deployment_manager'; -import { FunctionAssertion, FunctionResult } from './function_assertion'; +import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; function expectedUndelegatedStake( initStake: OwnerStakeByStatus | GlobalStakeByStatus, @@ -30,16 +30,18 @@ export function validUnstakeAssertion( balanceStore: BlockchainBalanceStore, globalStake: GlobalStakeByStatus, ownerStake: OwnerStakeByStatus, -): FunctionAssertion { +): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { const { stakingWrapper, zrxVault } = deployment.staking; return new FunctionAssertion(stakingWrapper.unstake, { - before: async (amount: BigNumber, txData: Partial) => { + before: async (args: FunctionArguments<[BigNumber]>) => { + const [amount] = args.args; + // Simulates the transfer of ZRX from vault to staker const expectedBalances = LocalBalanceStore.create(balanceStore); expectedBalances.transferAsset( zrxVault.address, - txData.from as string, + args.txData.from as string, amount, deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(), ); @@ -48,9 +50,10 @@ export function validUnstakeAssertion( after: async ( expectedBalances: LocalBalanceStore, _result: FunctionResult, - amount: BigNumber, - txData: Partial, + args: FunctionArguments<[BigNumber]>, ) => { + const [amount] = args.args; + logUtils.log(`unstake(${amount})`); // 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 const ownerUndelegatedStake = await stakingWrapper - .getOwnerStakeByStatus(txData.from as string, StakeStatus.Undelegated) + .getOwnerStakeByStatus(args.txData.from as string, StakeStatus.Undelegated) .callAsync(); const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount); expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake); diff --git a/contracts/integrations/test/framework/tests/function_assertion_test.ts b/contracts/integrations/test/framework/tests/function_assertion_test.ts index e585d17d1c..0f2e5deb46 100644 --- a/contracts/integrations/test/framework/tests/function_assertion_test.ts +++ b/contracts/integrations/test/framework/tests/function_assertion_test.ts @@ -4,11 +4,11 @@ import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import { artifacts } from '../../artifacts'; 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; -blockchainTests.resets('FunctionAssertion Unit Tests', env => { +blockchainTests.resets.only('FunctionAssertion Unit Tests', env => { let exampleContract: TestFrameworkContract; before(async () => { @@ -23,84 +23,87 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { describe('executeAsync', () => { it('should call the before function with the provided arguments', async () => { let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion( + const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - before: async (_input: BigNumber) => { + before: async (args: { args: [BigNumber] }) => { sideEffectTarget = randomInput; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync(randomInput); + await assertion.executeAsync({ args: [randomInput], txData: {} }); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); it('should call the after function with the provided arguments', async () => { let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion( + const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - after: async (_beforeInfo: any, _result: FunctionResult, input: BigNumber) => { - sideEffectTarget = input; + after: async (_beforeInfo: any, _result: FunctionResult, args: FunctionArguments<[BigNumber]>) => { + sideEffectTarget = args.args[0]; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync(randomInput); + await assertion.executeAsync({ args: [randomInput], txData: {} }); 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(); + const assertion = new FunctionAssertion<[], {}, void>(exampleContract.emptyRevert.bind(exampleContract)); + await assertion.executeAsync({ args: [], txData: {} }); }); it('should pass the return value of "before" to "after"', async () => { const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion( + const assertion = new FunctionAssertion<[BigNumber], BigNumber, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - before: async (_input: BigNumber) => { + before: async (_args: FunctionArguments<[BigNumber]>) => { return randomInput; }, - after: async (beforeInfo: any, _result: FunctionResult, _input: BigNumber) => { + after: async (beforeInfo: any, _result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => { sideEffectTarget = beforeInfo; }, }, ); - await assertion.executeAsync(randomInput); + await assertion.executeAsync({ args: [randomInput], txData: {} }); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); it('should pass the result from the function call to "after"', async () => { let sideEffectTarget = ZERO_AMOUNT; - const assertion = new FunctionAssertion( + const assertion = new FunctionAssertion<[BigNumber], void, BigNumber>( exampleContract.returnInteger.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _input: BigNumber) => { + after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[BigNumber]>) => { sideEffectTarget = result.data; }, }, ); const randomInput = getRandomInteger(ZERO_AMOUNT, MAX_UINT256); - await assertion.executeAsync(randomInput); + await assertion.executeAsync({ args: [randomInput], txData: {} }); expect(sideEffectTarget).bignumber.to.be.eq(randomInput); }); it('should pass the receipt from the function call to "after"', async () => { let sideEffectTarget: TransactionReceiptWithDecodedLogs; - const assertion = new FunctionAssertion(exampleContract.emitEvent.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _input: string) => { - if (result.receipt) { - sideEffectTarget = result.receipt; - } + const assertion = new FunctionAssertion<[string], void, void>( + exampleContract.emitEvent.bind(exampleContract), + { + after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => { + if (result.receipt) { + sideEffectTarget = result.receipt; + } + }, }, - }); + ); const input = 'emitted data'; - await assertion.executeAsync(input); + await assertion.executeAsync({ args: [input], txData: {} }); // Ensure that the correct events were emitted. const [event] = filterLogsToArguments( @@ -112,13 +115,16 @@ blockchainTests.resets('FunctionAssertion Unit Tests', env => { it('should pass the error to "after" if the function call fails', async () => { let sideEffectTarget: Error; - const assertion = new FunctionAssertion(exampleContract.stringRevert.bind(exampleContract), { - after: async (_beforeInfo: any, result: FunctionResult, _input: string) => { - sideEffectTarget = result.data; + const assertion = new FunctionAssertion<[string], void, void>( + exampleContract.stringRevert.bind(exampleContract), + { + after: async (_beforeInfo: any, result: FunctionResult, _args: FunctionArguments<[string]>) => { + sideEffectTarget = result.data; + }, }, - }); + ); const message = 'error message'; - await assertion.executeAsync(message); + await assertion.executeAsync({ args: [message], txData: {} }); 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 new file mode 100644 index 0000000000..73930a6f1d --- /dev/null +++ b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts @@ -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 { + 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(); + }); +}); From 36df5dc72151c22c91cabfc8ed8bb97fc84a4a5a Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Fri, 22 Nov 2019 17:45:24 -0600 Subject: [PATCH 2/7] Implemented a hacky version of the `fillOrder` fuzz tests --- .../test/framework/actors/pool_member.ts | 40 +++++++- .../test/framework/actors/pool_operator.ts | 5 - .../framework/assertions/createStakingPool.ts | 68 +++++++------- .../decreaseStakingPoolOperatorShare.ts | 25 ++--- .../test/framework/assertions/fillOrder.ts | 22 +++++ .../assertions/function_assertion.ts | 11 +-- .../framework/assertions/joinStakingPool.ts | 8 +- .../test/framework/assertions/moveStake.ts | 91 ++++++++++--------- .../test/framework/assertions/stake.ts | 2 +- .../test/framework/assertions/unstake.ts | 2 +- .../integrations/test/framework/simulation.ts | 7 +- .../tests/function_assertion_test.ts | 2 +- .../test/fuzz_tests/pool_membership_test.ts | 42 +++++++-- 13 files changed, 205 insertions(+), 120 deletions(-) create mode 100644 contracts/integrations/test/framework/assertions/fillOrder.ts diff --git a/contracts/integrations/test/framework/actors/pool_member.ts b/contracts/integrations/test/framework/actors/pool_member.ts index 5588137f7d..ed8c730843 100644 --- a/contracts/integrations/test/framework/actors/pool_member.ts +++ b/contracts/integrations/test/framework/actors/pool_member.ts @@ -1,6 +1,9 @@ +import { constants, getRandomInteger, hexRandom } from '@0x/contracts-test-utils'; +import { Order } from '@0x/types'; 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'; @@ -33,6 +36,7 @@ export function PoolMemberMixin(Base: TBase): TBase & this.actor.simulationActions = { ...this.actor.simulationActions, validJoinStakingPool: this._validJoinStakingPool(), + validFillOrderCompleteFill: this._validFillOrderCompleteFill(), }; } @@ -46,7 +50,6 @@ export function PoolMemberMixin(Base: TBase): TBase & .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 { const { stakingPools } = this.actor.simulationEnvironment!; const assertion = validJoinStakingPoolAssertion(this.actor.deployment); @@ -55,8 +58,39 @@ export function PoolMemberMixin(Base: TBase): TBase & if (poolId === undefined) { yield undefined; } else { - console.log('Attempting to join pool'); - yield assertion.executeAsync({ args: [poolId], txData: {} }); + 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 }, + }); } } } diff --git a/contracts/integrations/test/framework/actors/pool_operator.ts b/contracts/integrations/test/framework/actors/pool_operator.ts index 31b7dc7e6b..b888ead533 100644 --- a/contracts/integrations/test/framework/actors/pool_operator.ts +++ b/contracts/integrations/test/framework/actors/pool_operator.ts @@ -80,16 +80,11 @@ export function PoolOperatorMixin(Base: TBase): TBase } private async *_validCreateStakingPool(): AsyncIterableIterator { - console.log(10); const { stakingPools } = this.actor.simulationEnvironment!; - console.log(11); const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools); - console.log(12); while (true) { const operatorShare = getRandomInteger(0, constants.PPM).toNumber(); - console.log(13); yield assertion.executeAsync({ args: [operatorShare, false], txData: { from: this.actor.address } }); - console.log(14); } } diff --git a/contracts/integrations/test/framework/assertions/createStakingPool.ts b/contracts/integrations/test/framework/assertions/createStakingPool.ts index d3bfebf2cd..5f781151e8 100644 --- a/contracts/integrations/test/framework/assertions/createStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/createStakingPool.ts @@ -19,44 +19,40 @@ export function validCreateStakingPoolAssertion( ): FunctionAssertion<[number, boolean], string, string> { const { stakingWrapper } = deployment.staking; - return new FunctionAssertion<[number, boolean], string, string>(stakingWrapper.createStakingPool, { - // Returns the expected ID of th created pool - before: async () => { - const lastPoolId = await stakingWrapper.lastPoolId().callAsync(); - // Effectively the last poolId + 1, but as a bytestring - return `0x${new BigNumber(lastPoolId) - .plus(1) - .toString(16) - .padStart(64, '0')}`; - }, - after: async ( - expectedPoolId: string, - result: FunctionResult, - args: { - args: [number, boolean]; - txData: Partial; + return new FunctionAssertion<[number, boolean], string, string>( + stakingWrapper.createStakingPool.bind(stakingWrapper), + { + // Returns the expected ID of th created pool + before: async () => { + const lastPoolId = await stakingWrapper.lastPoolId().callAsync(); + // Effectively the last poolId + 1, but as a bytestring + return `0x${new BigNumber(lastPoolId) + .plus(1) + .toString(16) + .padStart(64, '0')}`; }, - ) => { - console.log(100); - logUtils.log(`createStakingPool(${args.args[0]}, ${args.args[1]}) => ${expectedPoolId}`); - console.log(101); + after: async ( + expectedPoolId: string, + result: FunctionResult, + args: { + args: [number, boolean]; + txData: Partial; + }, + ) => { + logUtils.log(`createStakingPool(${args.args[0]}, ${args.args[1]}) => ${expectedPoolId}`); - // 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 - console.log(102); - const actualPoolId = (log as any).args.poolId; - console.log(103); - expect(actualPoolId).to.equal(expectedPoolId); - console.log(104); + // 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 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], - delegatedStake: new StoredBalance(), - }; - console.log(105); + // Adds the new pool to local state + pools[actualPoolId] = { + operator: args.txData.from as string, + operatorShare: args.args[0], + delegatedStake: new StoredBalance(), + }; + }, }, - }); + ); } diff --git a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts index 5633524e81..90ffa60c12 100644 --- a/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts +++ b/contracts/integrations/test/framework/assertions/decreaseStakingPoolOperatorShare.ts @@ -16,18 +16,21 @@ export function validDecreaseStakingPoolOperatorShareAssertion( ): FunctionAssertion<[string, number], {}, void> { const { stakingWrapper } = deployment.staking; - return new FunctionAssertion<[string, number], {}, void>(stakingWrapper.decreaseStakingPoolOperatorShare, { - after: async (_beforeInfo, _result: FunctionResult, args: { args: [string, number] }) => { - const poolId = args.args[0]; - const expectedOperatorShare = args.args[1]; + 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]; - logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`); + 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; + // 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 new file mode 100644 index 0000000000..ccbccfbbaf --- /dev/null +++ b/contracts/integrations/test/framework/assertions/fillOrder.ts @@ -0,0 +1,22 @@ +import { constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; +import { FillResults, Order } from '@0x/types'; +import { BigNumber, logUtils } from '@0x/utils'; +import * as _ from 'lodash'; + +import { Maker } from '../actors/maker'; +import { DeploymentManager } from '../deployment_manager'; + +import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_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]>) => { + expect(result.success).to.be.true(); + logUtils.log(`Order filled by ${args.txData.from}`); + }, + }); +} diff --git a/contracts/integrations/test/framework/assertions/function_assertion.ts b/contracts/integrations/test/framework/assertions/function_assertion.ts index 6bdd7141ec..411ad3acf9 100644 --- a/contracts/integrations/test/framework/assertions/function_assertion.ts +++ b/contracts/integrations/test/framework/assertions/function_assertion.ts @@ -3,7 +3,6 @@ import { TransactionReceiptWithDecodedLogs, TxData } from 'ethereum-types'; import * as _ from 'lodash'; // tslint:disable:max-classes-per-file - export type GenericContractFunction = (...args: any[]) => ContractFunctionObj; export interface FunctionArguments { @@ -58,12 +57,12 @@ export class FunctionAssertion imp // The wrapper function that will be wrapped in assertions. public wrapperFunction: ( - ...args: any[] // tslint:disable-line:trailing-comma + ...args: TArgs // tslint:disable-line:trailing-comma ) => ContractTxFunctionObj | ContractFunctionObj; constructor( wrapperFunction: ( - ...args: any[] // tslint:disable-line:trailing-comma + ...args: TArgs // tslint:disable-line:trailing-comma ) => ContractTxFunctionObj | ContractFunctionObj, condition: Partial> = {}, ) { @@ -95,18 +94,12 @@ export class FunctionAssertion imp try { const functionWithArgs = this.wrapperFunction(...args.args) as ContractTxFunctionObj; callResult.data = await functionWithArgs.callAsync(args.txData); - - console.log(functionWithArgs); - callResult.receipt = functionWithArgs.awaitTransactionSuccessAsync !== undefined ? await functionWithArgs.awaitTransactionSuccessAsync(args.txData) // tslint:disable-line:await-promise : undefined; // tslint:enable:await-promise } catch (error) { - console.log('got here'); - console.log(error); - callResult.data = error; callResult.success = false; callResult.receipt = undefined; diff --git a/contracts/integrations/test/framework/assertions/joinStakingPool.ts b/contracts/integrations/test/framework/assertions/joinStakingPool.ts index 6263ea1222..522a6b58c0 100644 --- a/contracts/integrations/test/framework/assertions/joinStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/joinStakingPool.ts @@ -7,7 +7,9 @@ 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, { + 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]; @@ -32,11 +34,11 @@ export function validJoinStakingPoolAssertion(deployment: DeploymentManager): Fu ); expect(logArgs).to.be.deep.eq([ { - maker: args.txData.from, + makerAddress: args.txData.from, poolId, }, ]); - const joinedPoolId = deployment.staking.stakingWrapper.poolIdByMaker(args.txData.from); + const joinedPoolId = await deployment.staking.stakingWrapper.poolIdByMaker(args.txData.from).callAsync(); expect(joinedPoolId).to.be.eq(poolId); console.log(`Pool ${poolId} joined by ${args.txData.from}`); /* tslint:disable-line:no-console */ diff --git a/contracts/integrations/test/framework/assertions/moveStake.ts b/contracts/integrations/test/framework/assertions/moveStake.ts index e640a554fc..85fd1bbf81 100644 --- a/contracts/integrations/test/framework/assertions/moveStake.ts +++ b/contracts/integrations/test/framework/assertions/moveStake.ts @@ -85,54 +85,59 @@ export function validMoveStakeAssertion( ): FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void> { const { stakingWrapper } = deployment.staking; - return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>(stakingWrapper.moveStake, { - after: async ( - _beforeInfo: {}, - _result: FunctionResult, - args: FunctionArguments<[StakeInfo, StakeInfo, BigNumber]>, - ) => { - const [from, to, amount] = args.args; + return new FunctionAssertion<[StakeInfo, StakeInfo, BigNumber], {}, void>( + stakingWrapper.moveStake.bind(stakingWrapper), + { + after: async ( + _beforeInfo: {}, + _result: FunctionResult, + args: FunctionArguments<[StakeInfo, StakeInfo, BigNumber]>, + ) => { + const [from, to, amount] = args.args; - logUtils.log( - `moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${ - StakeStatus[to.status] - }, poolId: ${to.poolId} }, ${amount})`, - ); + logUtils.log( + `moveStake({status: ${StakeStatus[from.status]}, poolId: ${from.poolId} }, { status: ${ + StakeStatus[to.status] + }, poolId: ${to.poolId} }, ${amount})`, + ); - const owner = args.txData.from as string; + const owner = args.txData.from as string; - // Update local balances to match the expected result of this `moveStake` operation - const updatedPools = updateNextEpochBalances(globalStake, ownerStake, pools, from, to, amount); + // Update local balances to match the expected result of this `moveStake` operation + const updatedPools = updateNextEpochBalances(globalStake, ownerStake, pools, from, to, amount); - // Fetches on-chain owner stake balances and checks against local balances - const ownerUndelegatedStake = { - ...new StoredBalance(), - ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Undelegated).callAsync()), - }; - const ownerDelegatedStake = { - ...new StoredBalance(), - ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Delegated).callAsync()), - }; - expect(ownerUndelegatedStake).to.deep.equal(ownerStake[StakeStatus.Undelegated]); - expect(ownerDelegatedStake).to.deep.equal(ownerStake[StakeStatus.Delegated].total); + // Fetches on-chain owner stake balances and checks against local balances + const ownerUndelegatedStake = { + ...new StoredBalance(), + ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Undelegated).callAsync()), + }; + const ownerDelegatedStake = { + ...new StoredBalance(), + ...(await stakingWrapper.getOwnerStakeByStatus(owner, StakeStatus.Delegated).callAsync()), + }; + expect(ownerUndelegatedStake).to.deep.equal(ownerStake[StakeStatus.Undelegated]); + expect(ownerDelegatedStake).to.deep.equal(ownerStake[StakeStatus.Delegated].total); - // Fetches on-chain global stake balances and checks against local balances - const globalUndelegatedStake = await stakingWrapper - .getGlobalStakeByStatus(StakeStatus.Undelegated) - .callAsync(); - const globalDelegatedStake = await stakingWrapper.getGlobalStakeByStatus(StakeStatus.Delegated).callAsync(); - expect(globalUndelegatedStake).to.deep.equal(globalStake[StakeStatus.Undelegated]); - expect(globalDelegatedStake).to.deep.equal(globalStake[StakeStatus.Delegated]); - - // Fetches on-chain pool stake balances and checks against local balances - for (const poolId of updatedPools) { - const stakeDelegatedByOwner = await stakingWrapper - .getStakeDelegatedToPoolByOwner(owner, poolId) + // Fetches on-chain global stake balances and checks against local balances + const globalUndelegatedStake = await stakingWrapper + .getGlobalStakeByStatus(StakeStatus.Undelegated) .callAsync(); - const totalStakeDelegated = await stakingWrapper.getTotalStakeDelegatedToPool(poolId).callAsync(); - expect(stakeDelegatedByOwner).to.deep.equal(ownerStake[StakeStatus.Delegated][poolId]); - expect(totalStakeDelegated).to.deep.equal(pools[poolId].delegatedStake); - } + const globalDelegatedStake = await stakingWrapper + .getGlobalStakeByStatus(StakeStatus.Delegated) + .callAsync(); + expect(globalUndelegatedStake).to.deep.equal(globalStake[StakeStatus.Undelegated]); + expect(globalDelegatedStake).to.deep.equal(globalStake[StakeStatus.Delegated]); + + // Fetches on-chain pool stake balances and checks against local balances + for (const poolId of updatedPools) { + const stakeDelegatedByOwner = await stakingWrapper + .getStakeDelegatedToPoolByOwner(owner, poolId) + .callAsync(); + const totalStakeDelegated = await stakingWrapper.getTotalStakeDelegatedToPool(poolId).callAsync(); + expect(stakeDelegatedByOwner).to.deep.equal(ownerStake[StakeStatus.Delegated][poolId]); + expect(totalStakeDelegated).to.deep.equal(pools[poolId].delegatedStake); + } + }, }, - }); + ); } diff --git a/contracts/integrations/test/framework/assertions/stake.ts b/contracts/integrations/test/framework/assertions/stake.ts index 5b03302eb8..eaabab39d9 100644 --- a/contracts/integrations/test/framework/assertions/stake.ts +++ b/contracts/integrations/test/framework/assertions/stake.ts @@ -33,7 +33,7 @@ export function validStakeAssertion( ): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { const { stakingWrapper, zrxVault } = deployment.staking; - return new FunctionAssertion(stakingWrapper.stake, { + return new FunctionAssertion(stakingWrapper.stake.bind(stakingWrapper), { before: async (args: FunctionArguments<[BigNumber]>) => { const [amount] = args.args; diff --git a/contracts/integrations/test/framework/assertions/unstake.ts b/contracts/integrations/test/framework/assertions/unstake.ts index 9473124bf2..64e34b192f 100644 --- a/contracts/integrations/test/framework/assertions/unstake.ts +++ b/contracts/integrations/test/framework/assertions/unstake.ts @@ -33,7 +33,7 @@ export function validUnstakeAssertion( ): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { const { stakingWrapper, zrxVault } = deployment.staking; - return new FunctionAssertion(stakingWrapper.unstake, { + return new FunctionAssertion(stakingWrapper.unstake.bind(stakingWrapper), { before: async (args: FunctionArguments<[BigNumber]>) => { const [amount] = args.args; diff --git a/contracts/integrations/test/framework/simulation.ts b/contracts/integrations/test/framework/simulation.ts index 5bc94a6625..1ae337cb7f 100644 --- a/contracts/integrations/test/framework/simulation.ts +++ b/contracts/integrations/test/framework/simulation.ts @@ -1,6 +1,7 @@ import { GlobalStakeByStatus, StakeStatus, StakingPoolById, StoredBalance } from '@0x/contracts-staking'; import * as _ from 'lodash'; +import { Maker } from './actors/maker'; import { AssertionResult } from './assertions/function_assertion'; import { BlockchainBalanceStore } from './balances/blockchain_balance_store'; import { DeploymentManager } from './deployment_manager'; @@ -14,7 +15,11 @@ export class SimulationEnvironment { }; public stakingPools: StakingPoolById = {}; - public constructor(public readonly deployment: DeploymentManager, public balanceStore: BlockchainBalanceStore) {} + public constructor( + public readonly deployment: DeploymentManager, + public balanceStore: BlockchainBalanceStore, + public marketMakers: Maker[] = [], + ) {} } export abstract class Simulation { diff --git a/contracts/integrations/test/framework/tests/function_assertion_test.ts b/contracts/integrations/test/framework/tests/function_assertion_test.ts index 0f2e5deb46..72664611a6 100644 --- a/contracts/integrations/test/framework/tests/function_assertion_test.ts +++ b/contracts/integrations/test/framework/tests/function_assertion_test.ts @@ -8,7 +8,7 @@ import { FunctionArguments, FunctionAssertion, FunctionResult } from '../asserti const { ZERO_AMOUNT, MAX_UINT256 } = constants; -blockchainTests.resets.only('FunctionAssertion Unit Tests', env => { +blockchainTests.resets('FunctionAssertion Unit Tests', env => { let exampleContract: TestFrameworkContract; before(async () => { diff --git a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts index 73930a6f1d..6f7005b456 100644 --- a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts +++ b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts @@ -1,6 +1,7 @@ -import { blockchainTests } from '@0x/contracts-test-utils'; +import { blockchainTests, constants } from '@0x/contracts-test-utils'; import * as _ from 'lodash'; +import { Maker } from '../framework/actors/maker'; import { PoolMember } from '../framework/actors/pool_member'; import { PoolOperator } from '../framework/actors/pool_operator'; import { AssertionResult } from '../framework/assertions/function_assertion'; @@ -27,6 +28,7 @@ class PoolMembershipSimulation extends Simulation { const actions = [ operator.simulationActions.validCreateStakingPool, member.simulationActions.validJoinStakingPool, + member.simulationActions.validFillOrderCompleteFill, ]; while (true) { @@ -36,17 +38,45 @@ class PoolMembershipSimulation extends Simulation { } } -blockchainTests('pool membership fuzz test', env => { - it('fuzz', async () => { - const deployment = await DeploymentManager.deployAsync(env, { - numErc20TokensToDeploy: 0, +blockchainTests.skip('pool membership fuzz test', env => { + let deployment: DeploymentManager; + let maker: Maker; + + before(async () => { + deployment = await DeploymentManager.deployAsync(env, { + numErc20TokensToDeploy: 2, numErc721TokensToDeploy: 0, numErc1155TokensToDeploy: 0, }); + const makerToken = deployment.tokens.erc20[0]; + const takerToken = deployment.tokens.erc20[1]; + + const orderConfig = { + feeRecipientAddress: constants.NULL_ADDRESS, + makerAssetData: deployment.assetDataEncoder.ERC20Token(makerToken.address).getABIEncodedTransactionData(), + takerAssetData: deployment.assetDataEncoder.ERC20Token(takerToken.address).getABIEncodedTransactionData(), + makerFeeAssetData: deployment.assetDataEncoder + .ERC20Token(makerToken.address) + .getABIEncodedTransactionData(), + takerFeeAssetData: deployment.assetDataEncoder + .ERC20Token(takerToken.address) + .getABIEncodedTransactionData(), + makerFee: constants.ZERO_AMOUNT, + takerFee: constants.ZERO_AMOUNT, + }; + + maker = new Maker({ + name: 'maker', + deployment, + orderConfig, + }); + }); + + it('fuzz', async () => { const balanceStore = new BlockchainBalanceStore({}, {}); - const simulationEnv = new SimulationEnvironment(deployment, balanceStore); + const simulationEnv = new SimulationEnvironment(deployment, balanceStore, [maker]); const simulation = new PoolMembershipSimulation(simulationEnv); return simulation.fuzzAsync(); }); From 86cf353296d1c0a97366b1e89a517c22a6b61459 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Fri, 22 Nov 2019 19:08:46 -0600 Subject: [PATCH 3/7] Improved the fuzz test --- .../test/framework/actors/pool_member.ts | 3 +- .../test/framework/assertions/fillOrder.ts | 66 ++++++++++++++++++- .../test/fuzz_tests/pool_membership_test.ts | 23 ++++--- 3 files changed, 81 insertions(+), 11 deletions(-) diff --git a/contracts/integrations/test/framework/actors/pool_member.ts b/contracts/integrations/test/framework/actors/pool_member.ts index ed8c730843..611f316262 100644 --- a/contracts/integrations/test/framework/actors/pool_member.ts +++ b/contracts/integrations/test/framework/actors/pool_member.ts @@ -8,7 +8,6 @@ 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; @@ -97,4 +96,4 @@ export function PoolMemberMixin(Base: TBase): TBase & }; } -export class PoolMember extends PoolOperatorMixin(PoolMemberMixin(Actor)) {} +export class PoolMember extends PoolMemberMixin(Actor) {} diff --git a/contracts/integrations/test/framework/assertions/fillOrder.ts b/contracts/integrations/test/framework/assertions/fillOrder.ts index ccbccfbbaf..aeb18f1fd9 100644 --- a/contracts/integrations/test/framework/assertions/fillOrder.ts +++ b/contracts/integrations/test/framework/assertions/fillOrder.ts @@ -1,6 +1,9 @@ -import { constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; +import { ERC20TokenEvents, ERC20TokenTransferEventArgs } from '@0x/contracts-erc20'; +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 * as _ from 'lodash'; import { Maker } from '../actors/maker'; @@ -8,6 +11,60 @@ import { DeploymentManager } from '../deployment_manager'; import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +function verifyFillEvents( + takerAddress: string, + order: Order, + receipt: TransactionReceiptWithDecodedLogs, + deployment: DeploymentManager, +): void { + // Ensure that the fill event was correct. + verifyEvents( + receipt, + [ + { + makerAddress: order.makerAddress, + feeRecipientAddress: order.feeRecipientAddress, + makerAssetData: order.makerAssetData, + takerAssetData: order.takerAssetData, + makerFeeAssetData: order.makerFeeAssetData, + takerFeeAssetData: order.takerFeeAssetData, + orderHash: orderHashUtils.getOrderHashHex(order), + takerAddress, + senderAddress: takerAddress, + makerAssetFilledAmount: order.makerAssetAmount, + takerAssetFilledAmount: order.takerAssetAmount, + makerFeePaid: constants.ZERO_AMOUNT, + takerFeePaid: constants.ZERO_AMOUNT, + protocolFeePaid: DeploymentManager.protocolFee, + }, + ], + ExchangeEvents.Fill, + ); + + // Ensure that the transfer events were correctly emitted. + verifyEvents( + receipt, + [ + { + _from: takerAddress, + _to: order.makerAddress, + _value: order.takerAssetAmount, + }, + { + _from: order.makerAddress, + _to: takerAddress, + _value: order.makerAssetAmount, + }, + { + _from: takerAddress, + _to: deployment.staking.stakingProxy.address, + _value: DeploymentManager.protocolFee, + }, + ], + ERC20TokenEvents.Transfer, + ); +} + export function validFillOrderCompleteFillAssertion( deployment: DeploymentManager, ): FunctionAssertion<[Order, BigNumber, string], {}, FillResults> { @@ -15,7 +72,14 @@ export function validFillOrderCompleteFillAssertion( return new FunctionAssertion<[Order, BigNumber, string], {}, FillResults>(exchange.fillOrder.bind(exchange), { after: async (_beforeInfo, result: FunctionResult, args: FunctionArguments<[Order, BigNumber, string]>) => { + const [order, takerAssetFilledAmount, signature] = args.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 + logUtils.log(`Order filled by ${args.txData.from}`); }, }); diff --git a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts index 6f7005b456..2657f763ea 100644 --- a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts +++ b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts @@ -9,15 +9,15 @@ import { BlockchainBalanceStore } from '../framework/balances/blockchain_balance 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 operator = new PoolOperator({ - name: 'operator', - deployment, - simulationEnvironment: this.environment, - }); + const poolManagement = new PoolManagementSimulation(this.environment); + const stakeManagement = new StakeManagementSimulation(this.environment); const member = new PoolMember({ name: 'member', @@ -26,9 +26,10 @@ class PoolMembershipSimulation extends Simulation { }); const actions = [ - operator.simulationActions.validCreateStakingPool, member.simulationActions.validJoinStakingPool, member.simulationActions.validFillOrderCompleteFill, + poolManagement.generator, + stakeManagement.generator, ]; while (true) { @@ -38,7 +39,7 @@ class PoolMembershipSimulation extends Simulation { } } -blockchainTests.skip('pool membership fuzz test', env => { +blockchainTests.only('pool membership fuzz test', env => { let deployment: DeploymentManager; let maker: Maker; @@ -74,7 +75,13 @@ blockchainTests.skip('pool membership fuzz test', env => { }); it('fuzz', async () => { - const balanceStore = new BlockchainBalanceStore({}, {}); + const balanceStore = new BlockchainBalanceStore( + { + StakingProxy: deployment.staking.stakingProxy.address, + ZRXVault: deployment.staking.zrxVault.address, + }, + { erc20: { ZRX: deployment.tokens.zrx } }, + ); const simulationEnv = new SimulationEnvironment(deployment, balanceStore, [maker]); const simulation = new PoolMembershipSimulation(simulationEnv); From ce112718668ef0cd976ac7bdf57479c235cca344 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Fri, 22 Nov 2019 19:15:33 -0600 Subject: [PATCH 4/7] Appease the linter --- .../integrations/test/framework/actors/pool_member.ts | 3 +-- .../integrations/test/framework/assertions/fillOrder.ts | 8 ++++++-- .../test/framework/assertions/joinStakingPool.ts | 9 ++++++--- .../integrations/test/framework/assertions/moveStake.ts | 1 - .../integrations/test/framework/assertions/stake.ts | 1 - .../integrations/test/framework/assertions/unstake.ts | 1 - .../integrations/test/fuzz_tests/pool_membership_test.ts | 1 - 7 files changed, 13 insertions(+), 11 deletions(-) diff --git a/contracts/integrations/test/framework/actors/pool_member.ts b/contracts/integrations/test/framework/actors/pool_member.ts index 611f316262..160eb7371e 100644 --- a/contracts/integrations/test/framework/actors/pool_member.ts +++ b/contracts/integrations/test/framework/actors/pool_member.ts @@ -1,5 +1,4 @@ -import { constants, getRandomInteger, hexRandom } from '@0x/contracts-test-utils'; -import { Order } from '@0x/types'; +import { constants, getRandomInteger } from '@0x/contracts-test-utils'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; diff --git a/contracts/integrations/test/framework/assertions/fillOrder.ts b/contracts/integrations/test/framework/assertions/fillOrder.ts index aeb18f1fd9..1b54d628aa 100644 --- a/contracts/integrations/test/framework/assertions/fillOrder.ts +++ b/contracts/integrations/test/framework/assertions/fillOrder.ts @@ -6,7 +6,6 @@ import { BigNumber, logUtils } from '@0x/utils'; import { TransactionReceiptWithDecodedLogs } from 'ethereum-types'; import * as _ from 'lodash'; -import { Maker } from '../actors/maker'; import { DeploymentManager } from '../deployment_manager'; import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; @@ -65,6 +64,10 @@ 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 */ export function validFillOrderCompleteFillAssertion( deployment: DeploymentManager, ): FunctionAssertion<[Order, BigNumber, string], {}, FillResults> { @@ -72,7 +75,7 @@ export function validFillOrderCompleteFillAssertion( return new FunctionAssertion<[Order, BigNumber, string], {}, FillResults>(exchange.fillOrder.bind(exchange), { after: async (_beforeInfo, result: FunctionResult, args: FunctionArguments<[Order, BigNumber, string]>) => { - const [order, takerAssetFilledAmount, signature] = args.args; + const [order] = args.args; // Ensure that the tx succeeded. expect(result.success).to.be.true(); @@ -84,3 +87,4 @@ export function validFillOrderCompleteFillAssertion( }, }); } +/* tslint:enable:no-unnecessary-type-assertion */ diff --git a/contracts/integrations/test/framework/assertions/joinStakingPool.ts b/contracts/integrations/test/framework/assertions/joinStakingPool.ts index 522a6b58c0..6f9db95acd 100644 --- a/contracts/integrations/test/framework/assertions/joinStakingPool.ts +++ b/contracts/integrations/test/framework/assertions/joinStakingPool.ts @@ -1,11 +1,14 @@ -import { StakingEvents, StakingMakerStakingPoolSetEventArgs, StakingPoolById } from '@0x/contracts-staking'; -import { constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils'; +import { StakingEvents, StakingMakerStakingPoolSetEventArgs } from '@0x/contracts-staking'; +import { expect, filterLogsToArguments } from '@0x/contracts-test-utils'; import { logUtils } from '@0x/utils'; import { DeploymentManager } from '../deployment_manager'; import { FunctionArguments, FunctionAssertion, FunctionResult } from './function_assertion'; +/** + * Returns a function assertion that verifies valid pool joining. + */ export function validJoinStakingPoolAssertion(deployment: DeploymentManager): FunctionAssertion<[string], {}, void> { const { stakingWrapper } = deployment.staking; @@ -41,7 +44,7 @@ export function validJoinStakingPoolAssertion(deployment: DeploymentManager): Fu const joinedPoolId = await deployment.staking.stakingWrapper.poolIdByMaker(args.txData.from).callAsync(); expect(joinedPoolId).to.be.eq(poolId); - console.log(`Pool ${poolId} joined by ${args.txData.from}`); /* tslint:disable-line:no-console */ + logUtils.log(`Pool ${poolId} joined by ${args.txData.from}`); /* tslint:disable-line:no-console */ }, }); } diff --git a/contracts/integrations/test/framework/assertions/moveStake.ts b/contracts/integrations/test/framework/assertions/moveStake.ts index 85fd1bbf81..3b464e59dd 100644 --- a/contracts/integrations/test/framework/assertions/moveStake.ts +++ b/contracts/integrations/test/framework/assertions/moveStake.ts @@ -8,7 +8,6 @@ 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'; diff --git a/contracts/integrations/test/framework/assertions/stake.ts b/contracts/integrations/test/framework/assertions/stake.ts index eaabab39d9..76c5fff406 100644 --- a/contracts/integrations/test/framework/assertions/stake.ts +++ b/contracts/integrations/test/framework/assertions/stake.ts @@ -1,7 +1,6 @@ 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'; diff --git a/contracts/integrations/test/framework/assertions/unstake.ts b/contracts/integrations/test/framework/assertions/unstake.ts index 64e34b192f..4308160b7e 100644 --- a/contracts/integrations/test/framework/assertions/unstake.ts +++ b/contracts/integrations/test/framework/assertions/unstake.ts @@ -1,7 +1,6 @@ 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'; diff --git a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts index 2657f763ea..edce353084 100644 --- a/contracts/integrations/test/fuzz_tests/pool_membership_test.ts +++ b/contracts/integrations/test/fuzz_tests/pool_membership_test.ts @@ -3,7 +3,6 @@ import * as _ from 'lodash'; import { Maker } from '../framework/actors/maker'; 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'; From 19f5153d0eb669dec47ee035694acdb975f9d5c4 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Sat, 23 Nov 2019 21:43:41 -0600 Subject: [PATCH 5/7] Addressed some review feedback --- .../test/framework/actors/hybrids.ts | 2 + .../test/framework/actors/maker.ts | 23 +++++ .../test/framework/actors/pool_member.ts | 98 ------------------- .../test/framework/actors/pool_operator.ts | 7 +- .../test/framework/actors/staker.ts | 6 +- .../test/framework/actors/taker.ts | 41 ++++++++ .../framework/assertions/createStakingPool.ts | 18 ++-- .../decreaseStakingPoolOperatorShare.ts | 7 +- .../test/framework/assertions/fillOrder.ts | 19 ++-- .../assertions/function_assertion.ts | 27 +++-- .../framework/assertions/joinStakingPool.ts | 31 +++--- .../test/framework/assertions/moveStake.ts | 12 ++- .../test/framework/assertions/stake.ts | 18 ++-- .../test/framework/assertions/unstake.ts | 20 ++-- .../tests/function_assertion_test.ts | 59 +++++++---- .../test/fuzz_tests/pool_membership_test.ts | 9 +- 16 files changed, 198 insertions(+), 199 deletions(-) delete mode 100644 contracts/integrations/test/framework/actors/pool_member.ts 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; From 474399154f1d08a1b566617da89c91dd5fd0cab8 Mon Sep 17 00:00:00 2001 From: Alex Towle Date: Mon, 2 Dec 2019 16:38:25 -0600 Subject: [PATCH 6/7] Addressed last review comment --- contracts/integrations/test/framework/assertions/fillOrder.ts | 2 ++ 1 file changed, 2 insertions(+) diff --git a/contracts/integrations/test/framework/assertions/fillOrder.ts b/contracts/integrations/test/framework/assertions/fillOrder.ts index cb34ed4f43..a2db06e2c0 100644 --- a/contracts/integrations/test/framework/assertions/fillOrder.ts +++ b/contracts/integrations/test/framework/assertions/fillOrder.ts @@ -90,6 +90,8 @@ export function validFillOrderCompleteFillAssertion( verifyFillEvents(txData.from!, order, result.receipt!, deployment); logUtils.log(`Order filled by ${txData.from}`); + + // TODO: Add validation for on-chain state (like balances) }, }); } From 3d79fe2bf484228ece54ea901f105c159245f16e Mon Sep 17 00:00:00 2001 From: Michael Zhu Date: Tue, 3 Dec 2019 15:34:59 -0800 Subject: [PATCH 7/7] post-rebase lockfile update --- yarn.lock | 147 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 147 insertions(+) diff --git a/yarn.lock b/yarn.lock index ad0359a900..699f0e744f 100644 --- a/yarn.lock +++ b/yarn.lock @@ -668,12 +668,52 @@ lodash "^4.17.11" valid-url "^1.0.9" +"@0x/assert@^2.2.0-beta.2", "@0x/assert@^2.2.0-beta.3": + version "2.2.0-beta.3" + resolved "https://registry.yarnpkg.com/@0x/assert/-/assert-2.2.0-beta.3.tgz#8fb95c265000532cd8dced44d44d29ca544b2bfc" + integrity sha512-ShENc8QJU4ur/5TkRl3l7J3Yt7WaxHAbuoTRm/djcA0iwYyUVlP5yN9Ab9ua+VLizQQTNw1n+kF1mJWg5lQXuA== + dependencies: + "@0x/json-schemas" "^4.1.0-beta.3" + "@0x/typescript-typings" "^4.4.0-beta.2" + "@0x/utils" "^4.6.0-beta.3" + lodash "^4.17.11" + valid-url "^1.0.9" + +"@0x/base-contract@^5.5.0-beta.2", "@0x/base-contract@^5.5.0-beta.3", "@0x/base-contract@^5.5.0-beta.4": + version "5.5.0-beta.4" + resolved "https://registry.yarnpkg.com/@0x/base-contract/-/base-contract-5.5.0-beta.4.tgz#eb26473e033e1a305a9fa87ab9e26325c9face59" + integrity sha512-6OC3Rg2ESoi1k4wABLt67aMGxqdb6FraeEHdAGb07VuPElpyH9jT8dl2aJFAI8tVcnrUQTXeDYJjuK7rimNReg== + dependencies: + "@0x/assert" "^2.2.0-beta.3" + "@0x/json-schemas" "^4.1.0-beta.3" + "@0x/utils" "^4.6.0-beta.3" + "@0x/web3-wrapper" "^6.1.0-beta.3" + ethereumjs-account "^3.0.0" + ethereumjs-blockstream "^7.0.0" + ethereumjs-util "^5.1.1" + ethereumjs-vm "^4.0.0" + ethers "~4.0.4" + js-sha3 "^0.7.0" + uuid "^3.3.2" + "@0x/contract-addresses@3.3.0-beta.3": version "3.3.0-beta.3" resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-3.3.0-beta.3.tgz#0fa8ad47e22aecdb99f9a044ba3c705c4173b61e" dependencies: lodash "^4.17.11" +"@0x/contract-addresses@^3.3.0-beta.3", "@0x/contract-addresses@^3.3.0-beta.4", "@0x/contract-addresses@^3.3.0-beta.5": + version "3.3.0-beta.5" + resolved "https://registry.yarnpkg.com/@0x/contract-addresses/-/contract-addresses-3.3.0-beta.5.tgz#9d5f80a258f1d103b127159c237f9bcdad182e80" + integrity sha512-/8de6W1MnVc2zElnCGjK3zgWabBAJZck+zCmNRIMiGtPJIWEW+F3EkAFPfMX6bSZIyrUBlYJIr0xVIWLPU45Aw== + dependencies: + lodash "^4.17.11" + +"@0x/contract-artifacts@^2.3.0-beta.3": + version "2.3.0-beta.4" + resolved "https://registry.yarnpkg.com/@0x/contract-artifacts/-/contract-artifacts-2.3.0-beta.4.tgz#ca056885be387344aaccf5c69fe80aec248df37d" + integrity sha512-NpZk3PVE9c2g5kolCcZej2i1l1XlvCFm9FXAny0tCz+/vNb3RhI0m6ecoiS7b1nFEFZ9q6jjsCCb5OEsxMudnw== + "@0x/contract-wrappers@12.2.0-beta.2": version "12.2.0-beta.2" resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-12.2.0-beta.2.tgz#62b3c13e35282df14734d1f6b1a617ed51901a27" @@ -686,6 +726,28 @@ ethers "~4.0.4" http-status-codes "^1.3.2" +"@0x/contract-wrappers@^12.2.0-beta.4": + version "12.2.0-beta.4" + resolved "https://registry.yarnpkg.com/@0x/contract-wrappers/-/contract-wrappers-12.2.0-beta.4.tgz#7a7301dd50c28887879df4d385e80a49e040748d" + integrity sha512-JVoYG3Rd430fZw9ogBSqeLOaJXkqp9N7g614X5/bzzuG/dSDdwXl48X02m66aGFWcNofx/iMsT4tpOZrJ2bDBg== + dependencies: + "@0x/assert" "^2.2.0-beta.3" + "@0x/base-contract" "^5.5.0-beta.4" + "@0x/contract-addresses" "^3.3.0-beta.5" + "@0x/json-schemas" "^4.1.0-beta.3" + "@0x/types" "^2.5.0-beta.3" + "@0x/utils" "^4.6.0-beta.3" + "@0x/web3-wrapper" "^6.1.0-beta.3" + ethereum-types "^2.2.0-beta.2" + ethers "~4.0.4" + +"@0x/contracts-dev-utils@^0.1.0-beta.2": + version "0.1.0-beta.4" + resolved "https://registry.yarnpkg.com/@0x/contracts-dev-utils/-/contracts-dev-utils-0.1.0-beta.4.tgz#87f51a7ed778b619beb8b32bf08ea6b3e4495d4e" + integrity sha512-6fQ13/L8aKKnO/vs2WIg0D7FXz3QpMKBHrTYdzvpwFrOcd6MPavQEj0KCQdT/4aplMvWnWDSVAOqn8i/lJJ8jQ== + dependencies: + "@0x/base-contract" "^5.5.0-beta.4" + "@0x/contracts-erc20@2.3.0-beta.2": version "2.3.0-beta.2" resolved "https://registry.yarnpkg.com/@0x/contracts-erc20/-/contracts-erc20-2.3.0-beta.2.tgz#218239f5594fdbbf8c1ff757a6356ac6fb787421" @@ -734,6 +796,16 @@ jsonschema "^1.2.0" lodash.values "^4.3.0" +"@0x/json-schemas@^4.1.0-beta.2", "@0x/json-schemas@^4.1.0-beta.3": + version "4.1.0-beta.3" + resolved "https://registry.yarnpkg.com/@0x/json-schemas/-/json-schemas-4.1.0-beta.3.tgz#af70a35691108ea162140640bae93a7fc84ca6ee" + integrity sha512-vcgzSeaOXiUQ4KjqdLTTBHbkWnp4IE7cXbUblRy8Y0XYPQsPywhs9mtjY4lBVNmm1DDpLhreo1mwrvPS3HW5YA== + dependencies: + "@0x/typescript-typings" "^4.4.0-beta.2" + "@types/node" "*" + jsonschema "^1.2.0" + lodash.values "^4.3.0" + "@0x/mesh-rpc-client@^7.0.4-beta-0xv3": version "7.0.4-beta-0xv3" resolved "https://registry.yarnpkg.com/@0x/mesh-rpc-client/-/mesh-rpc-client-7.0.4-beta-0xv3.tgz#5e933a0b9cf20ca900f309fc4adee03b081eb335" @@ -769,6 +841,20 @@ ethers "~4.0.4" lodash "^4.17.11" +"@0x/order-utils@^8.5.0-beta.2": + version "8.5.0-beta.4" + resolved "https://registry.yarnpkg.com/@0x/order-utils/-/order-utils-8.5.0-beta.4.tgz#900387631008cc9dc9ece125d28450d2beaea462" + integrity sha512-a3vFDAETaPVo/hN5iFr1gxgshfSzAO23NnaUSjeEhs4Ff8eKxuISc6UARFaNzdQeXygDWHMjwlmZ7iegBHe93g== + dependencies: + "@0x/assert" "^2.2.0-beta.3" + "@0x/contract-wrappers" "^12.2.0-beta.4" + "@0x/json-schemas" "^4.1.0-beta.3" + "@0x/utils" "^4.6.0-beta.3" + "@0x/web3-wrapper" "^6.1.0-beta.3" + ethereumjs-util "^5.1.1" + ethers "~4.0.4" + lodash "^4.17.11" + "@0x/subproviders@5.1.0-beta.2": version "5.1.0-beta.2" resolved "https://registry.yarnpkg.com/@0x/subproviders/-/subproviders-5.1.0-beta.2.tgz#020369711330755448397b3b8cecf2868ae7c54c" @@ -827,6 +913,26 @@ bignumber.js "~8.0.2" ethereum-types "^2.1.6" +"@0x/types@^2.5.0-beta.2", "@0x/types@^2.5.0-beta.3": + version "2.5.0-beta.3" + resolved "https://registry.yarnpkg.com/@0x/types/-/types-2.5.0-beta.3.tgz#e010e9dbf62e37e59177c1d6df8d1acf3a9ea1b4" + integrity sha512-5wJs4/EZGPcU6W5IZ87zuya9vQUPD4DchyP29bXyguGHg9dOxuUOF4WauJZExWlPCS7eivviiUHpZD9DZhni+w== + dependencies: + "@types/node" "*" + bignumber.js "~9.0.0" + ethereum-types "^2.2.0-beta.2" + +"@0x/typescript-typings@4.4.0-beta.2", "@0x/typescript-typings@^4.4.0-beta.2": + version "4.4.0-beta.2" + resolved "https://registry.yarnpkg.com/@0x/typescript-typings/-/typescript-typings-4.4.0-beta.2.tgz#67c621252f162914186b8f684ac5e306206c1cf2" + integrity sha512-Fq2nOKvopdLMEjuPiKqomGog06bxAXGjqnodCwv9OKr11V5W1twFTUM3c1TENfHeGvcqf1aMl1hsH3fuVP61jg== + dependencies: + "@types/bn.js" "^4.11.0" + "@types/react" "*" + bignumber.js "~9.0.0" + ethereum-types "^2.2.0-beta.2" + popper.js "1.14.3" + "@0x/typescript-typings@^4.2.2", "@0x/typescript-typings@^4.3.0": version "4.3.0" resolved "https://registry.npmjs.org/@0x/typescript-typings/-/typescript-typings-4.3.0.tgz#4813a996ac5101841d1c22f4aa1738ab56168857" @@ -874,6 +980,25 @@ js-sha3 "^0.7.0" lodash "^4.17.11" +"@0x/utils@^4.6.0-beta.2", "@0x/utils@^4.6.0-beta.3": + version "4.6.0-beta.3" + resolved "https://registry.yarnpkg.com/@0x/utils/-/utils-4.6.0-beta.3.tgz#d40278916d98c48ea05821ae4987c88f032c7bff" + integrity sha512-aPIUgfhaDhwgddJAlIQJ2Ki87A60ovatBLCjareLUbsQSvFS5i3iujUBQHgFxZAv9tgl35fyg2ISEJ1YkQyubA== + dependencies: + "@0x/types" "^2.5.0-beta.3" + "@0x/typescript-typings" "^4.4.0-beta.2" + "@types/node" "*" + abortcontroller-polyfill "^1.1.9" + bignumber.js "~9.0.0" + chalk "^2.3.0" + detect-node "2.0.3" + ethereum-types "^2.2.0-beta.2" + ethereumjs-util "^5.1.1" + ethers "~4.0.4" + isomorphic-fetch "2.2.1" + js-sha3 "^0.7.0" + lodash "^4.17.11" + "@0x/web3-providers-fork@0.0.7": version "0.0.7" resolved "https://registry.yarnpkg.com/@0x/web3-providers-fork/-/web3-providers-fork-0.0.7.tgz#9cf40ebb6a2aa230283c5accb195d92594bb0aa7" @@ -904,6 +1029,20 @@ ethers "~4.0.4" lodash "^4.17.11" +"@0x/web3-wrapper@^6.1.0-beta.2", "@0x/web3-wrapper@^6.1.0-beta.3": + version "6.1.0-beta.3" + resolved "https://registry.yarnpkg.com/@0x/web3-wrapper/-/web3-wrapper-6.1.0-beta.3.tgz#82161147e9283391e0c7cd6027c971749c5a2f77" + integrity sha512-mc8120n8w88gICbDm8pkmC83Ul3RgE4BGsjY5BRBFefmKbv/XLeBZiWdhsaWYmkk8v4f+ZxAQ+HHTBDsRH87Og== + dependencies: + "@0x/assert" "^2.2.0-beta.3" + "@0x/json-schemas" "^4.1.0-beta.3" + "@0x/typescript-typings" "^4.4.0-beta.2" + "@0x/utils" "^4.6.0-beta.3" + ethereum-types "^2.2.0-beta.2" + ethereumjs-util "^5.1.1" + ethers "~4.0.4" + lodash "^4.17.11" + "@0xproject/npm-cli-login@^0.0.11": version "0.0.11" resolved "https://registry.yarnpkg.com/@0xproject/npm-cli-login/-/npm-cli-login-0.0.11.tgz#3f1ec06112ce62aad300ff0575358f68aeecde2e" @@ -6626,6 +6765,14 @@ ethereum-types@^2.1.6: "@types/node" "*" bignumber.js "~8.0.2" +ethereum-types@^2.2.0-beta.2: + version "2.2.0-beta.2" + resolved "https://registry.yarnpkg.com/ethereum-types/-/ethereum-types-2.2.0-beta.2.tgz#0b446842474c2afacd351258ed4a2d0841f2608f" + integrity sha512-5ANYHI/InHqf4Nt8oYrpvcph9/D6gi3sbM7Rlr8r0QjXb2mqocqEvOH460Zkf1robc7WDqurp9baeMy+um8kww== + dependencies: + "@types/node" "*" + bignumber.js "~9.0.0" + ethereumjs-abi@0.6.5: version "0.6.5" resolved "https://registry.yarnpkg.com/ethereumjs-abi/-/ethereumjs-abi-0.6.5.tgz#5a637ef16ab43473fa72a29ad90871405b3f5241"