Merge pull request #2392 from 0xProject/feature/fuzz/better-input-gen
`@0x/contracts-integrations`: Better input generation for fuzzing
This commit is contained in:
		@@ -111,7 +111,7 @@ export function MakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
 | 
				
			|||||||
                    await (owner as Actor).configureERC20TokenAsync(token as DummyERC20TokenContract);
 | 
					                    await (owner as Actor).configureERC20TokenAsync(token as DummyERC20TokenContract);
 | 
				
			||||||
                    balance = balanceStore.balances.erc20[owner.address][token.address] =
 | 
					                    balance = balanceStore.balances.erc20[owner.address][token.address] =
 | 
				
			||||||
                        constants.INITIAL_ERC20_BALANCE;
 | 
					                        constants.INITIAL_ERC20_BALANCE;
 | 
				
			||||||
                    return Pseudorandom.integer(balance.dividedToIntegerBy(2));
 | 
					                    return Pseudorandom.integer(0, balance.dividedToIntegerBy(2));
 | 
				
			||||||
                }),
 | 
					                }),
 | 
				
			||||||
            );
 | 
					            );
 | 
				
			||||||
            // Encode asset data
 | 
					            // Encode asset data
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -6,7 +6,7 @@ import * as _ from 'lodash';
 | 
				
			|||||||
import { validCreateStakingPoolAssertion } from '../assertions/createStakingPool';
 | 
					import { validCreateStakingPoolAssertion } from '../assertions/createStakingPool';
 | 
				
			||||||
import { validDecreaseStakingPoolOperatorShareAssertion } from '../assertions/decreaseStakingPoolOperatorShare';
 | 
					import { validDecreaseStakingPoolOperatorShareAssertion } from '../assertions/decreaseStakingPoolOperatorShare';
 | 
				
			||||||
import { AssertionResult } from '../assertions/function_assertion';
 | 
					import { AssertionResult } from '../assertions/function_assertion';
 | 
				
			||||||
import { Pseudorandom } from '../utils/pseudorandom';
 | 
					import { Distributions, Pseudorandom } from '../utils/pseudorandom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Actor, Constructor } from './base';
 | 
					import { Actor, Constructor } from './base';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -83,7 +83,11 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
 | 
				
			|||||||
        private async *_validCreateStakingPool(): AsyncIterableIterator<AssertionResult> {
 | 
					        private async *_validCreateStakingPool(): AsyncIterableIterator<AssertionResult> {
 | 
				
			||||||
            const assertion = validCreateStakingPoolAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
 | 
					            const assertion = validCreateStakingPoolAssertion(this.actor.deployment, this.actor.simulationEnvironment!);
 | 
				
			||||||
            while (true) {
 | 
					            while (true) {
 | 
				
			||||||
                const operatorShare = Pseudorandom.integer(constants.PPM).toNumber();
 | 
					                const operatorShare = Pseudorandom.integer(
 | 
				
			||||||
 | 
					                    0,
 | 
				
			||||||
 | 
					                    constants.PPM,
 | 
				
			||||||
 | 
					                    Distributions.Kumaraswamy(0.2, 0.2),
 | 
				
			||||||
 | 
					                ).toNumber();
 | 
				
			||||||
                yield assertion.executeAsync([operatorShare, false], { from: this.actor.address });
 | 
					                yield assertion.executeAsync([operatorShare, false], { from: this.actor.address });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -96,7 +100,11 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
 | 
				
			|||||||
                if (poolId === undefined) {
 | 
					                if (poolId === undefined) {
 | 
				
			||||||
                    yield undefined;
 | 
					                    yield undefined;
 | 
				
			||||||
                } else {
 | 
					                } else {
 | 
				
			||||||
                    const operatorShare = Pseudorandom.integer(stakingPools[poolId].operatorShare).toNumber();
 | 
					                    const operatorShare = Pseudorandom.integer(
 | 
				
			||||||
 | 
					                        0,
 | 
				
			||||||
 | 
					                        stakingPools[poolId].operatorShare,
 | 
				
			||||||
 | 
					                        Distributions.Kumaraswamy(0.2, 0.2),
 | 
				
			||||||
 | 
					                    ).toNumber();
 | 
				
			||||||
                    yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address });
 | 
					                    yield assertion.executeAsync([poolId, operatorShare], { from: this.actor.address });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -79,7 +79,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
 | 
				
			|||||||
            while (true) {
 | 
					            while (true) {
 | 
				
			||||||
                await balanceStore.updateErc20BalancesAsync();
 | 
					                await balanceStore.updateErc20BalancesAsync();
 | 
				
			||||||
                const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address];
 | 
					                const zrxBalance = balanceStore.balances.erc20[this.actor.address][zrx.address];
 | 
				
			||||||
                const amount = Pseudorandom.integer(zrxBalance);
 | 
					                const amount = Pseudorandom.integer(0, zrxBalance);
 | 
				
			||||||
                yield assertion.executeAsync([amount], { from: this.actor.address });
 | 
					                yield assertion.executeAsync([amount], { from: this.actor.address });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -98,7 +98,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
 | 
				
			|||||||
                    undelegatedStake.currentEpochBalance,
 | 
					                    undelegatedStake.currentEpochBalance,
 | 
				
			||||||
                    undelegatedStake.nextEpochBalance,
 | 
					                    undelegatedStake.nextEpochBalance,
 | 
				
			||||||
                );
 | 
					                );
 | 
				
			||||||
                const amount = Pseudorandom.integer(withdrawableStake);
 | 
					                const amount = Pseudorandom.integer(0, withdrawableStake);
 | 
				
			||||||
                yield assertion.executeAsync([amount], { from: this.actor.address });
 | 
					                yield assertion.executeAsync([amount], { from: this.actor.address });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
@@ -118,7 +118,10 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
 | 
				
			|||||||
                const fromStatus =
 | 
					                const fromStatus =
 | 
				
			||||||
                    fromPoolId === undefined || stakingPools[fromPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
 | 
					                    fromPoolId === undefined || stakingPools[fromPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
 | 
				
			||||||
                        ? StakeStatus.Undelegated
 | 
					                        ? StakeStatus.Undelegated
 | 
				
			||||||
                        : (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
 | 
					                        : (Pseudorandom.sample(
 | 
				
			||||||
 | 
					                              [StakeStatus.Undelegated, StakeStatus.Delegated],
 | 
				
			||||||
 | 
					                              [0.2, 0.8], // 20% chance of `Undelegated`, 80% chance of `Delegated`
 | 
				
			||||||
 | 
					                          ) as StakeStatus);
 | 
				
			||||||
                const from = new StakeInfo(fromStatus, fromPoolId);
 | 
					                const from = new StakeInfo(fromStatus, fromPoolId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // Pick a random pool to move the stake to
 | 
					                // Pick a random pool to move the stake to
 | 
				
			||||||
@@ -128,7 +131,10 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
 | 
				
			|||||||
                const toStatus =
 | 
					                const toStatus =
 | 
				
			||||||
                    toPoolId === undefined || stakingPools[toPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
 | 
					                    toPoolId === undefined || stakingPools[toPoolId].lastFinalized.isLessThan(currentEpoch.minus(1))
 | 
				
			||||||
                        ? StakeStatus.Undelegated
 | 
					                        ? StakeStatus.Undelegated
 | 
				
			||||||
                        : (Pseudorandom.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
 | 
					                        : (Pseudorandom.sample(
 | 
				
			||||||
 | 
					                              [StakeStatus.Undelegated, StakeStatus.Delegated],
 | 
				
			||||||
 | 
					                              [0.2, 0.8], // 20% chance of `Undelegated`, 80% chance of `Delegated`
 | 
				
			||||||
 | 
					                          ) as StakeStatus);
 | 
				
			||||||
                const to = new StakeInfo(toStatus, toPoolId);
 | 
					                const to = new StakeInfo(toStatus, toPoolId);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                // The next epoch balance of the `from` stake is the amount that can be moved
 | 
					                // The next epoch balance of the `from` stake is the amount that can be moved
 | 
				
			||||||
@@ -136,7 +142,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
 | 
				
			|||||||
                    from.status === StakeStatus.Undelegated
 | 
					                    from.status === StakeStatus.Undelegated
 | 
				
			||||||
                        ? this.stake[StakeStatus.Undelegated].nextEpochBalance
 | 
					                        ? this.stake[StakeStatus.Undelegated].nextEpochBalance
 | 
				
			||||||
                        : this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance;
 | 
					                        : this.stake[StakeStatus.Delegated][from.poolId].nextEpochBalance;
 | 
				
			||||||
                const amount = Pseudorandom.integer(moveableStake);
 | 
					                const amount = Pseudorandom.integer(0, moveableStake);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
                yield assertion.executeAsync([from, to, amount], { from: this.actor.address });
 | 
					                yield assertion.executeAsync([from, to, amount], { from: this.actor.address });
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -75,12 +75,12 @@ export function TakerMixin<TBase extends Constructor>(Base: TBase): TBase & Cons
 | 
				
			|||||||
                    // Maker creates and signs a fillable order
 | 
					                    // Maker creates and signs a fillable order
 | 
				
			||||||
                    const order = await maker.createFillableOrderAsync(this.actor);
 | 
					                    const order = await maker.createFillableOrderAsync(this.actor);
 | 
				
			||||||
                    // Taker fills the order by a random amount (up to the order's takerAssetAmount)
 | 
					                    // Taker fills the order by a random amount (up to the order's takerAssetAmount)
 | 
				
			||||||
                    const fillAmount = Pseudorandom.integer(order.takerAssetAmount);
 | 
					                    const fillAmount = Pseudorandom.integer(0, order.takerAssetAmount);
 | 
				
			||||||
                    // Taker executes the fill with a random msg.value, so that sometimes the
 | 
					                    // Taker executes the fill with a random msg.value, so that sometimes the
 | 
				
			||||||
                    // protocol fee is paid in ETH and other times it's paid in WETH.
 | 
					                    // protocol fee is paid in ETH and other times it's paid in WETH.
 | 
				
			||||||
                    yield assertion.executeAsync([order, fillAmount, order.signature], {
 | 
					                    yield assertion.executeAsync([order, fillAmount, order.signature], {
 | 
				
			||||||
                        from: this.actor.address,
 | 
					                        from: this.actor.address,
 | 
				
			||||||
                        value: Pseudorandom.integer(DeploymentManager.protocolFee.times(2)),
 | 
					                        value: Pseudorandom.integer(0, DeploymentManager.protocolFee.times(2)),
 | 
				
			||||||
                    });
 | 
					                    });
 | 
				
			||||||
                }
 | 
					                }
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -2,6 +2,7 @@
 | 
				
			|||||||
    "extends": ["@0x/tslint-config"],
 | 
					    "extends": ["@0x/tslint-config"],
 | 
				
			||||||
    "rules": {
 | 
					    "rules": {
 | 
				
			||||||
        "max-classes-per-file": false,
 | 
					        "max-classes-per-file": false,
 | 
				
			||||||
        "no-non-null-assertion": false
 | 
					        "no-non-null-assertion": false,
 | 
				
			||||||
 | 
					        "custom-no-magic-numbers": false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -13,11 +13,11 @@ import { FunctionAssertion, FunctionResult } from './function_assertion';
 | 
				
			|||||||
export function validDecreaseStakingPoolOperatorShareAssertion(
 | 
					export function validDecreaseStakingPoolOperatorShareAssertion(
 | 
				
			||||||
    deployment: DeploymentManager,
 | 
					    deployment: DeploymentManager,
 | 
				
			||||||
    pools: StakingPoolById,
 | 
					    pools: StakingPoolById,
 | 
				
			||||||
): FunctionAssertion<[string, number], {}, void> {
 | 
					): FunctionAssertion<[string, number], void, void> {
 | 
				
			||||||
    const { stakingWrapper } = deployment.staking;
 | 
					    const { stakingWrapper } = deployment.staking;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    return new FunctionAssertion<[string, number], {}, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', {
 | 
					    return new FunctionAssertion<[string, number], void, void>(stakingWrapper, 'decreaseStakingPoolOperatorShare', {
 | 
				
			||||||
        after: async (_beforeInfo, result: FunctionResult, args: [string, number], _txData: Partial<TxData>) => {
 | 
					        after: async (_beforeInfo: void, result: FunctionResult, args: [string, number], _txData: Partial<TxData>) => {
 | 
				
			||||||
            // Ensure that the tx succeeded.
 | 
					            // Ensure that the tx succeeded.
 | 
				
			||||||
            expect(result.success, `Error: ${result.data}`).to.be.true();
 | 
					            expect(result.success, `Error: ${result.data}`).to.be.true();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,54 +1,87 @@
 | 
				
			|||||||
import { Numberish } from '@0x/contracts-test-utils';
 | 
					import { Numberish } from '@0x/contracts-test-utils';
 | 
				
			||||||
import { BigNumber } from '@0x/utils';
 | 
					import { BigNumber } from '@0x/utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
import * as seedrandom from 'seedrandom';
 | 
					import * as seedrandom from 'seedrandom';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
class PRNGWrapper {
 | 
					class PRNGWrapper {
 | 
				
			||||||
    public readonly seed = process.env.SEED || Math.random().toString();
 | 
					    public readonly seed = process.env.SEED || Math.random().toString();
 | 
				
			||||||
    private readonly _rng = seedrandom(this.seed);
 | 
					    public readonly rng = seedrandom(this.seed);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Pseudorandom version of _.sample. Picks an element of the given array with uniform probability.
 | 
					     * Pseudorandom version of _.sample. Picks an element of the given array. If an array of weights
 | 
				
			||||||
     * Return undefined if the array is empty.
 | 
					     * is provided, elements of `arr` are weighted according to the value in the corresponding index
 | 
				
			||||||
 | 
					     * of `weights`. Otherwise, the samples are chosen uniformly at random. Return undefined if the
 | 
				
			||||||
 | 
					     * array is empty.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public sample<T>(arr: T[]): T | undefined {
 | 
					    public sample<T>(arr: T[], weights?: number[]): T | undefined {
 | 
				
			||||||
        if (arr.length === 0) {
 | 
					        if (arr.length === 0) {
 | 
				
			||||||
            return undefined;
 | 
					            return undefined;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const index = Math.abs(this._rng.int32()) % arr.length;
 | 
					
 | 
				
			||||||
 | 
					        let index: number;
 | 
				
			||||||
 | 
					        if (weights !== undefined) {
 | 
				
			||||||
 | 
					            const cdf = weights.map((_weight, i) => _.sum(weights.slice(0, i + 1)) / _.sum(weights));
 | 
				
			||||||
 | 
					            const x = this.rng();
 | 
				
			||||||
 | 
					            index = cdf.findIndex(value => value > x);
 | 
				
			||||||
 | 
					        } else {
 | 
				
			||||||
 | 
					            index = Math.abs(this.rng.int32()) % arr.length;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        return arr[index];
 | 
					        return arr[index];
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Pseudorandom version of _.sampleSize. Returns an array of `n` samples from the given array
 | 
					     * Pseudorandom version of _.sampleSize. Returns an array of `n` samples from the given array
 | 
				
			||||||
     * (with replacement), chosen with uniform probability. Return undefined if the array is empty.
 | 
					     * (with replacement). If an array of weights is provided, elements of `arr` are weighted
 | 
				
			||||||
 | 
					     * according to the value in the corresponding index of `weights`. Otherwise, the samples are
 | 
				
			||||||
 | 
					     * chosen uniformly at random. Return undefined if the array is empty.
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public sampleSize<T>(arr: T[], n: number): T[] | undefined {
 | 
					    public sampleSize<T>(arr: T[], n: number, weights?: number[]): T[] | undefined {
 | 
				
			||||||
        if (arr.length === 0) {
 | 
					        if (arr.length === 0) {
 | 
				
			||||||
            return undefined;
 | 
					            return undefined;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        const samples = [];
 | 
					        const samples = [];
 | 
				
			||||||
        for (let i = 0; i < n; i++) {
 | 
					        for (let i = 0; i < n; i++) {
 | 
				
			||||||
            samples.push(this.sample(arr) as T);
 | 
					            samples.push(this.sample(arr, weights) as T);
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        return samples;
 | 
					        return samples;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    // tslint:disable:unified-signatures
 | 
					 | 
				
			||||||
    /*
 | 
					    /*
 | 
				
			||||||
     * Pseudorandom version of getRandomPortion/getRandomInteger. If two arguments are provided,
 | 
					     * Pseudorandom version of getRandomPortion/getRandomInteger. If no distribution is provided,
 | 
				
			||||||
     * treats those arguments as the min and max (inclusive) of the desired range. If only one
 | 
					     * samples an integer between the min and max uniformly at random. If a distribution is
 | 
				
			||||||
     * argument is provided, picks an integer between 0 and the argument.
 | 
					     * provided, samples an integer from the given distribution (assumed to be defined on the
 | 
				
			||||||
 | 
					     * interval [0, 1]) scaled to [min, max].
 | 
				
			||||||
     */
 | 
					     */
 | 
				
			||||||
    public integer(max: Numberish): BigNumber;
 | 
					    public integer(min: Numberish, max: Numberish, distribution: () => Numberish = this.rng): BigNumber {
 | 
				
			||||||
    public integer(min: Numberish, max: Numberish): BigNumber;
 | 
					        const range = new BigNumber(max).minus(min);
 | 
				
			||||||
    public integer(a: Numberish, b?: Numberish): BigNumber {
 | 
					        return new BigNumber(distribution())
 | 
				
			||||||
        if (b === undefined) {
 | 
					            .times(range)
 | 
				
			||||||
            return new BigNumber(this._rng()).times(a).integerValue(BigNumber.ROUND_HALF_UP);
 | 
					            .integerValue(BigNumber.ROUND_HALF_UP)
 | 
				
			||||||
        } else {
 | 
					            .plus(min);
 | 
				
			||||||
            const range = new BigNumber(b).minus(a);
 | 
					    }
 | 
				
			||||||
            return this.integer(range).plus(a);
 | 
					
 | 
				
			||||||
        }
 | 
					    /*
 | 
				
			||||||
 | 
					     * Returns a function that produces samples from the Kumaraswamy distribution parameterized by
 | 
				
			||||||
 | 
					     * the given alpha and beta. The Kumaraswamy distribution is like the beta distribution, but
 | 
				
			||||||
 | 
					     * with a nice closed form. More info:
 | 
				
			||||||
 | 
					     * https://en.wikipedia.org/wiki/Kumaraswamy_distribution
 | 
				
			||||||
 | 
					     * https://www.johndcook.com/blog/2009/11/24/kumaraswamy-distribution/
 | 
				
			||||||
 | 
					     * Alpha and beta default to 0.2, so that the distribution favors the extremes of the domain.
 | 
				
			||||||
 | 
					     * The PDF for alpha=0.2, beta=0.2:
 | 
				
			||||||
 | 
					     * https://www.wolframalpha.com/input/?i=0.2*0.2*x%5E%280.2-1%29*%281-x%5E0.2%29%5E%280.2-1%29+from+0+to+1
 | 
				
			||||||
 | 
					     */
 | 
				
			||||||
 | 
					    public kumaraswamy(this: PRNGWrapper, alpha: Numberish = 0.2, beta: Numberish = 0.2): () => BigNumber {
 | 
				
			||||||
 | 
					        const ONE = new BigNumber(1);
 | 
				
			||||||
 | 
					        return () => {
 | 
				
			||||||
 | 
					            const u = new BigNumber(this.rng()).modulo(ONE); // u ~ Uniform(0, 1)
 | 
				
			||||||
 | 
					            // Evaluate the inverse CDF at `u` to obtain a sample from Kumaraswamy(alpha, beta)
 | 
				
			||||||
 | 
					            return ONE.minus(ONE.minus(u).exponentiatedBy(ONE.dividedBy(beta))).exponentiatedBy(ONE.dividedBy(alpha));
 | 
				
			||||||
 | 
					        };
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
export const Pseudorandom = new PRNGWrapper();
 | 
					export const Pseudorandom = new PRNGWrapper();
 | 
				
			||||||
 | 
					export const Distributions = {
 | 
				
			||||||
 | 
					    Uniform: Pseudorandom.rng,
 | 
				
			||||||
 | 
					    Kumaraswamy: Pseudorandom.kumaraswamy.bind(Pseudorandom),
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
 | 
					import { blockchainTests } from '@0x/contracts-test-utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Actor } from '../framework/actors/base';
 | 
					import { Actor } from '../framework/actors/base';
 | 
				
			||||||
import { PoolOperator } from '../framework/actors/pool_operator';
 | 
					import { PoolOperator } from '../framework/actors/pool_operator';
 | 
				
			||||||
@@ -14,12 +15,14 @@ export class PoolManagementSimulation extends Simulation {
 | 
				
			|||||||
        const { actors } = this.environment;
 | 
					        const { actors } = this.environment;
 | 
				
			||||||
        const operators = filterActorsByRole(actors, PoolOperator);
 | 
					        const operators = filterActorsByRole(actors, PoolOperator);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const actions = [
 | 
					        const [actions, weights] = _.unzip([
 | 
				
			||||||
            ...operators.map(operator => operator.simulationActions.validCreateStakingPool),
 | 
					            // 40% chance of executing validCreateStakingPool assertion for a random operator
 | 
				
			||||||
            ...operators.map(operator => operator.simulationActions.validDecreaseStakingPoolOperatorShare),
 | 
					            ...operators.map(operator => [operator.simulationActions.validCreateStakingPool, 0.4]),
 | 
				
			||||||
        ];
 | 
					            // 60% chance of executing validDecreaseStakingPoolOperatorShare for a random operator
 | 
				
			||||||
 | 
					            ...operators.map(operator => [operator.simulationActions.validDecreaseStakingPoolOperatorShare, 0.6]),
 | 
				
			||||||
 | 
					        ]) as [Array<AsyncIterableIterator<AssertionResult | void>>, number[]];
 | 
				
			||||||
        while (true) {
 | 
					        while (true) {
 | 
				
			||||||
            const action = Pseudorandom.sample(actions);
 | 
					            const action = Pseudorandom.sample(actions, weights);
 | 
				
			||||||
            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
					            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
 | 
					import { blockchainTests } from '@0x/contracts-test-utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Actor } from '../framework/actors/base';
 | 
					import { Actor } from '../framework/actors/base';
 | 
				
			||||||
import { MakerTaker } from '../framework/actors/hybrids';
 | 
					import { MakerTaker } from '../framework/actors/hybrids';
 | 
				
			||||||
@@ -22,14 +23,17 @@ export class PoolMembershipSimulation extends Simulation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const poolManagement = new PoolManagementSimulation(this.environment);
 | 
					        const poolManagement = new PoolManagementSimulation(this.environment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const actions = [
 | 
					        const [actions, weights] = _.unzip([
 | 
				
			||||||
            ...makers.map(maker => maker.simulationActions.validJoinStakingPool),
 | 
					            // 20% chance of executing validJoinStakingPool for a random maker
 | 
				
			||||||
            ...takers.map(taker => taker.simulationActions.validFillOrder),
 | 
					            ...makers.map(maker => [maker.simulationActions.validJoinStakingPool, 0.2 / makers.length]),
 | 
				
			||||||
            poolManagement.generator,
 | 
					            // 60% chance of executing validFillOrder for a random taker
 | 
				
			||||||
        ];
 | 
					            ...takers.map(taker => [taker.simulationActions.validFillOrder, 0.6 / takers.length]),
 | 
				
			||||||
 | 
					            // 20% chance of executing an assertion generated from the pool management simulation
 | 
				
			||||||
 | 
					            [poolManagement.generator, 0.2],
 | 
				
			||||||
 | 
					        ]) as [Array<AsyncIterableIterator<AssertionResult | void>>, number[]];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (true) {
 | 
					        while (true) {
 | 
				
			||||||
            const action = Pseudorandom.sample(actions);
 | 
					            const action = Pseudorandom.sample(actions, weights);
 | 
				
			||||||
            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
					            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
 | 
					import { blockchainTests } from '@0x/contracts-test-utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Actor } from '../framework/actors/base';
 | 
					import { Actor } from '../framework/actors/base';
 | 
				
			||||||
import { StakerOperator } from '../framework/actors/hybrids';
 | 
					import { StakerOperator } from '../framework/actors/hybrids';
 | 
				
			||||||
@@ -20,14 +21,19 @@ export class StakeManagementSimulation extends Simulation {
 | 
				
			|||||||
 | 
					
 | 
				
			||||||
        const poolManagement = new PoolManagementSimulation(this.environment);
 | 
					        const poolManagement = new PoolManagementSimulation(this.environment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const actions = [
 | 
					        const [actions, weights] = _.unzip([
 | 
				
			||||||
            ...stakers.map(staker => staker.simulationActions.validStake),
 | 
					            // 30% chance of executing validStake for a random staker
 | 
				
			||||||
            ...stakers.map(staker => staker.simulationActions.validUnstake),
 | 
					            ...stakers.map(staker => [staker.simulationActions.validStake, 0.3 / stakers.length]),
 | 
				
			||||||
            ...stakers.map(staker => staker.simulationActions.validMoveStake),
 | 
					            // 20% chance of executing validUnstake for a random staker
 | 
				
			||||||
            poolManagement.generator,
 | 
					            ...stakers.map(staker => [staker.simulationActions.validUnstake, 0.2 / stakers.length]),
 | 
				
			||||||
        ];
 | 
					            // 30% chance of executing validMoveStake for a random staker
 | 
				
			||||||
 | 
					            ...stakers.map(staker => [staker.simulationActions.validMoveStake, 0.3 / stakers.length]),
 | 
				
			||||||
 | 
					            // 20% chance of executing an assertion generated from the pool management simulation
 | 
				
			||||||
 | 
					            [poolManagement.generator, 0.2],
 | 
				
			||||||
 | 
					        ]) as [Array<AsyncIterableIterator<AssertionResult | void>>, number[]];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        while (true) {
 | 
					        while (true) {
 | 
				
			||||||
            const action = Pseudorandom.sample(actions);
 | 
					            const action = Pseudorandom.sample(actions, weights);
 | 
				
			||||||
            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
					            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,4 +1,5 @@
 | 
				
			|||||||
import { blockchainTests } from '@0x/contracts-test-utils';
 | 
					import { blockchainTests } from '@0x/contracts-test-utils';
 | 
				
			||||||
 | 
					import * as _ from 'lodash';
 | 
				
			||||||
 | 
					
 | 
				
			||||||
import { Actor } from '../framework/actors/base';
 | 
					import { Actor } from '../framework/actors/base';
 | 
				
			||||||
import {
 | 
					import {
 | 
				
			||||||
@@ -32,15 +33,20 @@ export class StakingRewardsSimulation extends Simulation {
 | 
				
			|||||||
        const poolMembership = new PoolMembershipSimulation(this.environment);
 | 
					        const poolMembership = new PoolMembershipSimulation(this.environment);
 | 
				
			||||||
        const stakeManagement = new StakeManagementSimulation(this.environment);
 | 
					        const stakeManagement = new StakeManagementSimulation(this.environment);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const actions = [
 | 
					        const [actions, weights] = _.unzip([
 | 
				
			||||||
            ...stakers.map(staker => staker.simulationActions.validWithdrawDelegatorRewards),
 | 
					            // 10% chance of executing validWithdrawDelegatorRewards for a random staker
 | 
				
			||||||
            ...keepers.map(keeper => keeper.simulationActions.validFinalizePool),
 | 
					            ...stakers.map(staker => [staker.simulationActions.validWithdrawDelegatorRewards, 0.1 / stakers.length]),
 | 
				
			||||||
            ...keepers.map(keeper => keeper.simulationActions.validEndEpoch),
 | 
					            // 10% chance of executing validFinalizePool for a random keeper
 | 
				
			||||||
            poolMembership.generator,
 | 
					            ...keepers.map(keeper => [keeper.simulationActions.validFinalizePool, 0.1 / keepers.length]),
 | 
				
			||||||
            stakeManagement.generator,
 | 
					            // 10% chance of executing validEndEpoch for a random keeper
 | 
				
			||||||
        ];
 | 
					            ...keepers.map(keeper => [keeper.simulationActions.validEndEpoch, 0.1 / keepers.length]),
 | 
				
			||||||
 | 
					            // 50% chance of executing an assertion generated from the pool membership simulation
 | 
				
			||||||
 | 
					            [poolMembership.generator, 0.5],
 | 
				
			||||||
 | 
					            // 20% chance of executing an assertion generated from the stake management simulation
 | 
				
			||||||
 | 
					            [stakeManagement.generator, 0.2],
 | 
				
			||||||
 | 
					        ]) as [Array<AsyncIterableIterator<AssertionResult | void>>, number[]];
 | 
				
			||||||
        while (true) {
 | 
					        while (true) {
 | 
				
			||||||
            const action = Pseudorandom.sample(actions);
 | 
					            const action = Pseudorandom.sample(actions, weights);
 | 
				
			||||||
            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
					            yield (await action!.next()).value; // tslint:disable-line:no-non-null-assertion
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -1,6 +1,7 @@
 | 
				
			|||||||
{
 | 
					{
 | 
				
			||||||
    "extends": ["@0x/tslint-config"],
 | 
					    "extends": ["@0x/tslint-config"],
 | 
				
			||||||
    "rules": {
 | 
					    "rules": {
 | 
				
			||||||
        "no-invalid-this": false
 | 
					        "no-invalid-this": false,
 | 
				
			||||||
 | 
					        "custom-no-magic-numbers": false
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 
 | 
				
			|||||||
@@ -83,9 +83,10 @@ export function loadCurrentBalance(balance: StoredBalance, epoch: BigNumber): St
 | 
				
			|||||||
 * Simulates _increaseNextBalance
 | 
					 * Simulates _increaseNextBalance
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function increaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance {
 | 
					export function increaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance {
 | 
				
			||||||
 | 
					    const newBalance = loadCurrentBalance(balance, epoch);
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        ...loadCurrentBalance(balance, epoch),
 | 
					        ...newBalance,
 | 
				
			||||||
        nextEpochBalance: balance.nextEpochBalance.plus(amount),
 | 
					        nextEpochBalance: newBalance.nextEpochBalance.plus(amount),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -93,9 +94,10 @@ export function increaseNextBalance(balance: StoredBalance, amount: Numberish, e
 | 
				
			|||||||
 * Simulates _decreaseNextBalance
 | 
					 * Simulates _decreaseNextBalance
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
export function decreaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance {
 | 
					export function decreaseNextBalance(balance: StoredBalance, amount: Numberish, epoch: BigNumber): StoredBalance {
 | 
				
			||||||
 | 
					    const newBalance = loadCurrentBalance(balance, epoch);
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        ...loadCurrentBalance(balance, epoch),
 | 
					        ...newBalance,
 | 
				
			||||||
        nextEpochBalance: balance.nextEpochBalance.minus(amount),
 | 
					        nextEpochBalance: newBalance.nextEpochBalance.minus(amount),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -107,10 +109,11 @@ export function increaseCurrentAndNextBalance(
 | 
				
			|||||||
    amount: Numberish,
 | 
					    amount: Numberish,
 | 
				
			||||||
    epoch: BigNumber,
 | 
					    epoch: BigNumber,
 | 
				
			||||||
): StoredBalance {
 | 
					): StoredBalance {
 | 
				
			||||||
 | 
					    const newBalance = loadCurrentBalance(balance, epoch);
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        ...loadCurrentBalance(balance, epoch),
 | 
					        ...newBalance,
 | 
				
			||||||
        currentEpochBalance: balance.currentEpochBalance.plus(amount),
 | 
					        currentEpochBalance: newBalance.currentEpochBalance.plus(amount),
 | 
				
			||||||
        nextEpochBalance: balance.nextEpochBalance.plus(amount),
 | 
					        nextEpochBalance: newBalance.nextEpochBalance.plus(amount),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -122,10 +125,11 @@ export function decreaseCurrentAndNextBalance(
 | 
				
			|||||||
    amount: Numberish,
 | 
					    amount: Numberish,
 | 
				
			||||||
    epoch: BigNumber,
 | 
					    epoch: BigNumber,
 | 
				
			||||||
): StoredBalance {
 | 
					): StoredBalance {
 | 
				
			||||||
 | 
					    const newBalance = loadCurrentBalance(balance, epoch);
 | 
				
			||||||
    return {
 | 
					    return {
 | 
				
			||||||
        ...loadCurrentBalance(balance, epoch),
 | 
					        ...newBalance,
 | 
				
			||||||
        currentEpochBalance: balance.currentEpochBalance.minus(amount),
 | 
					        currentEpochBalance: newBalance.currentEpochBalance.minus(amount),
 | 
				
			||||||
        nextEpochBalance: balance.nextEpochBalance.minus(amount),
 | 
					        nextEpochBalance: newBalance.nextEpochBalance.minus(amount),
 | 
				
			||||||
    };
 | 
					    };
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user