address comments
This commit is contained in:
parent
1f5a0987cb
commit
48ecd32d5d
@ -1,5 +1,5 @@
|
||||
import { BaseContract } from '@0x/base-contract';
|
||||
import { expect, TokenBalances } from '@0x/contracts-test-utils';
|
||||
import { constants, expect, TokenBalances } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
@ -37,7 +37,7 @@ export class BalanceStore {
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the given token owner in this balance store. The token owner's balane will be
|
||||
* Registers the given token owner in this balance store. The token owner's balance will be
|
||||
* tracked in subsequent operations.
|
||||
* @param address Address of the token owner
|
||||
* @param name Name of the token owner
|
||||
@ -83,8 +83,8 @@ export class BalanceStore {
|
||||
*/
|
||||
private _assertEthBalancesEqual(rhs: BalanceStore): void {
|
||||
for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) {
|
||||
const thisBalance = _.get(this.balances.eth, [ownerAddress], new BigNumber(0));
|
||||
const rhsBalance = _.get(rhs.balances.eth, [ownerAddress], new BigNumber(0));
|
||||
const thisBalance = _.get(this.balances.eth, [ownerAddress], constants.ZERO_AMOUNT);
|
||||
const rhsBalance = _.get(rhs.balances.eth, [ownerAddress], constants.ZERO_AMOUNT);
|
||||
expect(thisBalance, `${this._readableAddressName(ownerAddress)} ETH balance`).to.bignumber.equal(
|
||||
rhsBalance,
|
||||
);
|
||||
@ -98,8 +98,8 @@ export class BalanceStore {
|
||||
private _assertErc20BalancesEqual(rhs: BalanceStore): void {
|
||||
for (const ownerAddress of [...this._ownerAddresses, ...rhs._ownerAddresses]) {
|
||||
for (const tokenAddress of [...this._tokenAddresses.erc20, ...rhs._tokenAddresses.erc20]) {
|
||||
const thisBalance = _.get(this.balances.erc20, [ownerAddress, tokenAddress], new BigNumber(0));
|
||||
const rhsBalance = _.get(rhs.balances.erc20, [ownerAddress, tokenAddress], new BigNumber(0));
|
||||
const thisBalance = _.get(this.balances.erc20, [ownerAddress, tokenAddress], constants.ZERO_AMOUNT);
|
||||
const rhsBalance = _.get(rhs.balances.erc20, [ownerAddress, tokenAddress], constants.ZERO_AMOUNT);
|
||||
expect(
|
||||
thisBalance,
|
||||
`${this._readableAddressName(ownerAddress)} ${this._readableAddressName(tokenAddress)} balance`,
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { constants } from '@0x/contracts-staking';
|
||||
import { constants, StakingPoolById } from '@0x/contracts-staking';
|
||||
import { getRandomInteger } from '@0x/contracts-test-utils';
|
||||
import { TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
@ -7,7 +7,6 @@ import {
|
||||
validCreateStakingPoolAssertion,
|
||||
validDecreaseStakingPoolOperatorShareAssertion,
|
||||
} from '../function-assertions';
|
||||
import { SimulationEnvironment } from '../simulation/simulation';
|
||||
import { AssertionResult } from '../utils/function_assertions';
|
||||
|
||||
import { Actor, Constructor } from './base';
|
||||
@ -39,15 +38,11 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
this.actor = (this as any) as Actor;
|
||||
|
||||
// Register this mixin's assertion generators
|
||||
if (this.actor.simulationEnvironment !== undefined) {
|
||||
this.actor.simulationActions = {
|
||||
...this.actor.simulationActions,
|
||||
validCreateStakingPool: this._validCreateStakingPool(this.actor.simulationEnvironment),
|
||||
validDecreaseStakingPoolOperatorShare: this._validDecreaseStakingPoolOperatorShare(
|
||||
this.actor.simulationEnvironment,
|
||||
),
|
||||
};
|
||||
}
|
||||
this.actor.simulationActions = {
|
||||
...this.actor.simulationActions,
|
||||
validCreateStakingPool: this._validCreateStakingPool(),
|
||||
validDecreaseStakingPoolOperatorShare: this._validDecreaseStakingPoolOperatorShare(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -84,40 +79,29 @@ export function PoolOperatorMixin<TBase extends Constructor>(Base: TBase): TBase
|
||||
);
|
||||
}
|
||||
|
||||
private _getOperatorPoolIds(simulationEnvironment: SimulationEnvironment): string[] {
|
||||
const operatorPools = _.pickBy(
|
||||
simulationEnvironment.stakingPools,
|
||||
pool => pool.operator === this.actor.address,
|
||||
);
|
||||
private _getOperatorPoolIds(stakingPools: StakingPoolById): string[] {
|
||||
const operatorPools = _.pickBy(stakingPools, pool => pool.operator === this.actor.address);
|
||||
return Object.keys(operatorPools);
|
||||
}
|
||||
|
||||
private async *_validCreateStakingPool(
|
||||
simulationEnvironment: SimulationEnvironment,
|
||||
): AsyncIterableIterator<AssertionResult> {
|
||||
const assertion = validCreateStakingPoolAssertion(
|
||||
this.actor.deployment,
|
||||
simulationEnvironment.stakingPools,
|
||||
);
|
||||
private async *_validCreateStakingPool(): AsyncIterableIterator<AssertionResult> {
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validCreateStakingPoolAssertion(this.actor.deployment, stakingPools);
|
||||
while (true) {
|
||||
const operatorShare = getRandomInteger(0, constants.PPM);
|
||||
yield assertion.executeAsync(operatorShare, false, { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
|
||||
private async *_validDecreaseStakingPoolOperatorShare(
|
||||
simulationEnvironment: SimulationEnvironment,
|
||||
): AsyncIterableIterator<AssertionResult | void> {
|
||||
const assertion = validDecreaseStakingPoolOperatorShareAssertion(
|
||||
this.actor.deployment,
|
||||
simulationEnvironment.stakingPools,
|
||||
);
|
||||
private async *_validDecreaseStakingPoolOperatorShare(): AsyncIterableIterator<AssertionResult | void> {
|
||||
const { stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validDecreaseStakingPoolOperatorShareAssertion(this.actor.deployment, stakingPools);
|
||||
while (true) {
|
||||
const poolId = _.sample(this._getOperatorPoolIds(simulationEnvironment));
|
||||
const poolId = _.sample(this._getOperatorPoolIds(stakingPools));
|
||||
if (poolId === undefined) {
|
||||
yield undefined;
|
||||
} else {
|
||||
const operatorShare = getRandomInteger(0, simulationEnvironment.stakingPools[poolId].operatorShare);
|
||||
const operatorShare = getRandomInteger(0, stakingPools[poolId].operatorShare);
|
||||
yield assertion.executeAsync(poolId, operatorShare, { from: this.actor.address });
|
||||
}
|
||||
}
|
||||
|
@ -4,7 +4,6 @@ import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { validMoveStakeAssertion, validStakeAssertion, validUnstakeAssertion } from '../function-assertions';
|
||||
import { SimulationEnvironment } from '../simulation/simulation';
|
||||
import { AssertionResult } from '../utils/function_assertions';
|
||||
|
||||
import { Actor, Constructor } from './base';
|
||||
@ -37,14 +36,12 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
};
|
||||
|
||||
// Register this mixin's assertion generators
|
||||
if (this.actor.simulationEnvironment !== undefined) {
|
||||
this.actor.simulationActions = {
|
||||
...this.actor.simulationActions,
|
||||
validStake: this._validStake(this.actor.simulationEnvironment),
|
||||
validUnstake: this._validUnstake(this.actor.simulationEnvironment),
|
||||
validMoveStake: this._validMoveStake(this.actor.simulationEnvironment),
|
||||
};
|
||||
}
|
||||
this.actor.simulationActions = {
|
||||
...this.actor.simulationActions,
|
||||
validStake: this._validStake(),
|
||||
validUnstake: this._validUnstake(),
|
||||
validMoveStake: this._validMoveStake(),
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@ -66,30 +63,26 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
}
|
||||
}
|
||||
|
||||
private async *_validStake(
|
||||
simulationEnvironment: SimulationEnvironment,
|
||||
): AsyncIterableIterator<AssertionResult> {
|
||||
private async *_validStake(): AsyncIterableIterator<AssertionResult> {
|
||||
const { zrx } = this.actor.deployment.tokens;
|
||||
const { deployment, balanceStore, globalStake } = simulationEnvironment;
|
||||
const { deployment, balanceStore, globalStake } = this.actor.simulationEnvironment!;
|
||||
const assertion = validStakeAssertion(deployment, balanceStore, globalStake, this.stake);
|
||||
|
||||
while (true) {
|
||||
await simulationEnvironment.balanceStore.updateErc20BalancesAsync();
|
||||
const zrxBalance = simulationEnvironment.balanceStore.balances.erc20[this.actor.address][zrx.address];
|
||||
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 });
|
||||
}
|
||||
}
|
||||
|
||||
private async *_validUnstake(
|
||||
simulationEnvironment: SimulationEnvironment,
|
||||
): AsyncIterableIterator<AssertionResult> {
|
||||
private async *_validUnstake(): AsyncIterableIterator<AssertionResult> {
|
||||
const { stakingWrapper } = this.actor.deployment.staking;
|
||||
const { deployment, balanceStore, globalStake } = simulationEnvironment;
|
||||
const { deployment, balanceStore, globalStake } = this.actor.simulationEnvironment!;
|
||||
const assertion = validUnstakeAssertion(deployment, balanceStore, globalStake, this.stake);
|
||||
|
||||
while (true) {
|
||||
await simulationEnvironment.balanceStore.updateErc20BalancesAsync();
|
||||
await balanceStore.updateErc20BalancesAsync();
|
||||
const undelegatedStake = await stakingWrapper.getOwnerStakeByStatus.callAsync(
|
||||
this.actor.address,
|
||||
StakeStatus.Undelegated,
|
||||
@ -103,16 +96,9 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
}
|
||||
}
|
||||
|
||||
private async *_validMoveStake(
|
||||
simulationEnvironment: SimulationEnvironment,
|
||||
): AsyncIterableIterator<AssertionResult> {
|
||||
const { deployment, globalStake } = simulationEnvironment;
|
||||
const assertion = validMoveStakeAssertion(
|
||||
deployment,
|
||||
globalStake,
|
||||
this.stake,
|
||||
simulationEnvironment.stakingPools,
|
||||
);
|
||||
private async *_validMoveStake(): AsyncIterableIterator<AssertionResult> {
|
||||
const { deployment, globalStake, stakingPools } = this.actor.simulationEnvironment!;
|
||||
const assertion = validMoveStakeAssertion(deployment, globalStake, this.stake, stakingPools);
|
||||
|
||||
while (true) {
|
||||
const fromPoolId = _.sample(Object.keys(_.omit(this.stake[StakeStatus.Delegated], ['total'])));
|
||||
@ -122,7 +108,7 @@ export function StakerMixin<TBase extends Constructor>(Base: TBase): TBase & Con
|
||||
: (_.sample([StakeStatus.Undelegated, StakeStatus.Delegated]) as StakeStatus);
|
||||
const from = new StakeInfo(fromStatus, fromPoolId);
|
||||
|
||||
const toPoolId = _.sample(Object.keys(simulationEnvironment.stakingPools));
|
||||
const toPoolId = _.sample(Object.keys(stakingPools));
|
||||
const toStatus =
|
||||
toPoolId === undefined
|
||||
? StakeStatus.Undelegated
|
||||
|
@ -1,6 +1,7 @@
|
||||
{
|
||||
"extends": ["@0x/tslint-config"],
|
||||
"rules": {
|
||||
"max-classes-per-file": false
|
||||
"max-classes-per-file": false,
|
||||
"no-non-null-assertion": false
|
||||
}
|
||||
}
|
||||
|
@ -19,8 +19,10 @@ export function validCreateStakingPoolAssertion(
|
||||
const { stakingWrapper } = deployment.staking;
|
||||
|
||||
return new FunctionAssertion(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)
|
||||
@ -35,9 +37,12 @@ export function validCreateStakingPoolAssertion(
|
||||
) => {
|
||||
logUtils.log(`createStakingPool(${operatorShare}, ${addOperatorAsMaker}) => ${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 actualPoolId = (log as any).args.poolId;
|
||||
expect(actualPoolId).to.equal(expectedPoolId);
|
||||
|
||||
// Adds the new pool to local state
|
||||
pools[actualPoolId] = {
|
||||
operator: txData.from as string,
|
||||
operatorShare,
|
||||
|
@ -19,8 +19,10 @@ export function validDecreaseStakingPoolOperatorShareAssertion(
|
||||
after: async (_beforeInfo, _result: FunctionResult, poolId: string, expectedOperatorShare: number) => {
|
||||
logUtils.log(`decreaseStakingPoolOperatorShare(${poolId}, ${expectedOperatorShare})`);
|
||||
|
||||
// Checks that the on-chain pool's operator share has been updated.
|
||||
const { operatorShare } = await stakingWrapper.getStakingPool.callAsync(poolId);
|
||||
expect(operatorShare).to.bignumber.equal(expectedOperatorShare);
|
||||
// Updates the pool in local state.
|
||||
pools[poolId].operatorShare = operatorShare;
|
||||
},
|
||||
});
|
||||
|
@ -22,6 +22,56 @@ function decrementNextEpochBalance(stakeBalance: StoredBalance, amount: BigNumbe
|
||||
_.update(stakeBalance, ['nextEpochBalance'], balance => (balance || constants.ZERO_AMOUNT).minus(amount));
|
||||
}
|
||||
|
||||
function updateNextEpochBalances(
|
||||
globalStake: GlobalStakeByStatus,
|
||||
ownerStake: OwnerStakeByStatus,
|
||||
pools: StakingPoolById,
|
||||
from: StakeInfo,
|
||||
to: StakeInfo,
|
||||
amount: BigNumber,
|
||||
): string[] {
|
||||
// The on-chain state of these updated pools will be verified in the `after` of the assertion.
|
||||
const updatedPools = [];
|
||||
|
||||
// Decrement next epoch balances associated with the `from` stake
|
||||
if (from.status === StakeStatus.Undelegated) {
|
||||
// Decrement owner undelegated stake
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
||||
// Decrement global undelegated stake
|
||||
decrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
||||
} else if (from.status === StakeStatus.Delegated) {
|
||||
// Decrement owner's delegated stake to this pool
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated][from.poolId], amount);
|
||||
// Decrement owner's total delegated stake
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
||||
// Decrement global delegated stake
|
||||
decrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
||||
// Decrement pool's delegated stake
|
||||
decrementNextEpochBalance(pools[from.poolId].delegatedStake, amount);
|
||||
updatedPools.push(from.poolId);
|
||||
}
|
||||
|
||||
// Increment next epoch balances associated with the `to` stake
|
||||
if (to.status === StakeStatus.Undelegated) {
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
||||
incrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
||||
} else if (to.status === StakeStatus.Delegated) {
|
||||
// Initializes the balance for this pool if the user has not previously delegated to it
|
||||
_.defaults(ownerStake[StakeStatus.Delegated], {
|
||||
[to.poolId]: new StoredBalance(),
|
||||
});
|
||||
// Increment owner's delegated stake to this pool
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated][to.poolId], amount);
|
||||
// Increment owner's total delegated stake
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
||||
// Increment global delegated stake
|
||||
incrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
||||
// Increment pool's delegated stake
|
||||
incrementNextEpochBalance(pools[to.poolId].delegatedStake, amount);
|
||||
updatedPools.push(to.poolId);
|
||||
}
|
||||
return updatedPools;
|
||||
}
|
||||
/**
|
||||
* Returns a FunctionAssertion for `moveStake` which assumes valid input is provided. The
|
||||
* FunctionAssertion checks that the staker's
|
||||
@ -50,35 +100,11 @@ export function validMoveStakeAssertion(
|
||||
);
|
||||
|
||||
const owner = txData.from as string;
|
||||
const updatedPools = [];
|
||||
if (from.status === StakeStatus.Undelegated) {
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
||||
decrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
||||
} else if (from.status === StakeStatus.Delegated) {
|
||||
_.defaults(ownerStake[StakeStatus.Delegated], {
|
||||
[from.poolId]: new StoredBalance(),
|
||||
});
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated][from.poolId], amount);
|
||||
decrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
||||
decrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
||||
decrementNextEpochBalance(pools[from.poolId].delegatedStake, amount);
|
||||
updatedPools.push(from.poolId);
|
||||
}
|
||||
|
||||
if (to.status === StakeStatus.Undelegated) {
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Undelegated], amount);
|
||||
incrementNextEpochBalance(globalStake[StakeStatus.Undelegated], amount);
|
||||
} else if (to.status === StakeStatus.Delegated) {
|
||||
_.defaults(ownerStake[StakeStatus.Delegated], {
|
||||
[to.poolId]: new StoredBalance(),
|
||||
});
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated][to.poolId], amount);
|
||||
incrementNextEpochBalance(ownerStake[StakeStatus.Delegated].total, amount);
|
||||
incrementNextEpochBalance(globalStake[StakeStatus.Delegated], amount);
|
||||
incrementNextEpochBalance(pools[to.poolId].delegatedStake, amount);
|
||||
updatedPools.push(to.poolId);
|
||||
}
|
||||
// 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.callAsync(owner, StakeStatus.Undelegated)),
|
||||
@ -90,6 +116,7 @@ export function validMoveStakeAssertion(
|
||||
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.callAsync(
|
||||
StakeStatus.Undelegated,
|
||||
);
|
||||
@ -97,6 +124,7 @@ export function validMoveStakeAssertion(
|
||||
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.callAsync(
|
||||
owner,
|
||||
|
@ -35,6 +35,7 @@ export function validStakeAssertion(
|
||||
|
||||
return new FunctionAssertion(stakingWrapper.stake, {
|
||||
before: async (amount: BigNumber, txData: Partial<TxData>) => {
|
||||
// Simulates the transfer of ZRX from staker to vault
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.transferAsset(
|
||||
txData.from as string,
|
||||
@ -52,22 +53,27 @@ export function validStakeAssertion(
|
||||
) => {
|
||||
logUtils.log(`stake(${amount})`);
|
||||
|
||||
// Checks that the ZRX transfer updated balances as expected.
|
||||
await balanceStore.updateErc20BalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
|
||||
// Checks that the owner's undelegated stake has increased by the stake amount
|
||||
const ownerUndelegatedStake = await stakingWrapper.getOwnerStakeByStatus.callAsync(
|
||||
txData.from as string,
|
||||
StakeStatus.Undelegated,
|
||||
);
|
||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||
// Updates local state accordingly
|
||||
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
||||
|
||||
// Checks that the global undelegated stake has also increased by the stake amount
|
||||
const globalUndelegatedStake = await stakingWrapper.getGlobalStakeByStatus.callAsync(
|
||||
StakeStatus.Undelegated,
|
||||
);
|
||||
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount);
|
||||
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
||||
// Updates local state accordingly
|
||||
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
||||
},
|
||||
});
|
||||
|
@ -35,6 +35,7 @@ export function validUnstakeAssertion(
|
||||
|
||||
return new FunctionAssertion(stakingWrapper.unstake, {
|
||||
before: async (amount: BigNumber, txData: Partial<TxData>) => {
|
||||
// Simulates the transfer of ZRX from vault to staker
|
||||
const expectedBalances = LocalBalanceStore.create(balanceStore);
|
||||
expectedBalances.transferAsset(
|
||||
zrxVault.address,
|
||||
@ -52,22 +53,27 @@ export function validUnstakeAssertion(
|
||||
) => {
|
||||
logUtils.log(`unstake(${amount})`);
|
||||
|
||||
// Checks that the ZRX transfer updated balances as expected.
|
||||
await balanceStore.updateErc20BalancesAsync();
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
|
||||
// Checks that the owner's undelegated stake has decreased by the stake amount
|
||||
const ownerUndelegatedStake = await stakingWrapper.getOwnerStakeByStatus.callAsync(
|
||||
txData.from as string,
|
||||
StakeStatus.Undelegated,
|
||||
);
|
||||
const expectedOwnerUndelegatedStake = expectedUndelegatedStake(ownerStake, amount);
|
||||
expect(ownerUndelegatedStake, 'Owner undelegated stake').to.deep.equal(expectedOwnerUndelegatedStake);
|
||||
// Updates local state accordingly
|
||||
ownerStake[StakeStatus.Undelegated] = expectedOwnerUndelegatedStake;
|
||||
|
||||
// Checks that the global undelegated stake has also decreased by the stake amount
|
||||
const globalUndelegatedStake = await stakingWrapper.getGlobalStakeByStatus.callAsync(
|
||||
StakeStatus.Undelegated,
|
||||
);
|
||||
const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount);
|
||||
expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake);
|
||||
// Updates local state accordingly
|
||||
globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake;
|
||||
},
|
||||
});
|
||||
|
@ -6,6 +6,7 @@ import {
|
||||
ExchangeFillEventArgs,
|
||||
LocalBalanceStore,
|
||||
} from '@0x/contracts-exchange';
|
||||
import { ReferenceFunctions } from '@0x/contracts-exchange-libs';
|
||||
import {
|
||||
constants as stakingConstants,
|
||||
IStakingEventsEpochEndedEventArgs,
|
||||
@ -284,7 +285,11 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
);
|
||||
|
||||
// The rewards are split between the operator and delegator based on the pool's operatorShare
|
||||
const operatorReward = rewardsAvailable.times(operatorShare).dividedToIntegerBy(constants.PPM_DENOMINATOR);
|
||||
const operatorReward = ReferenceFunctions.getPartialAmountFloor(
|
||||
new BigNumber(operatorShare),
|
||||
new BigNumber(constants.PPM_DENOMINATOR),
|
||||
rewardsAvailable,
|
||||
);
|
||||
const delegatorReward = rewardsAvailable.minus(operatorReward);
|
||||
|
||||
// Finalize the pool. This should automatically pay the operator in WETH.
|
||||
@ -363,7 +368,11 @@ blockchainTests.resets('fillOrder integration tests', env => {
|
||||
balanceStore.assertEquals(expectedBalances);
|
||||
|
||||
// The rewards are split between the operator and delegator based on the pool's operatorShare
|
||||
const operatorReward = rewardsAvailable.times(operatorShare).dividedToIntegerBy(constants.PPM_DENOMINATOR);
|
||||
const operatorReward = ReferenceFunctions.getPartialAmountFloor(
|
||||
new BigNumber(operatorShare),
|
||||
new BigNumber(constants.PPM_DENOMINATOR),
|
||||
rewardsAvailable,
|
||||
);
|
||||
|
||||
// Finalize the pool. This should automatically pay the operator in WETH.
|
||||
const [finalizePoolReceipt] = await delegator.finalizePoolsAsync([poolId]);
|
||||
|
Loading…
x
Reference in New Issue
Block a user