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'; function expectedUndelegatedStake( initStake: OwnerStakeByStatus | GlobalStakeByStatus, amount: BigNumber, ): StoredBalance { return { currentEpoch: initStake[StakeStatus.Undelegated].currentEpoch, currentEpochBalance: initStake[StakeStatus.Undelegated].currentEpochBalance.plus(amount), nextEpochBalance: initStake[StakeStatus.Undelegated].nextEpochBalance.plus(amount), }; } /** * Returns a FunctionAssertion for `stake` which assumes valid input is provided. The * FunctionAssertion checks that the staker and zrxVault's balances of ZRX decrease and increase, * respectively, by the input amount. */ export function validStakeAssertion( deployment: DeploymentManager, balanceStore: BlockchainBalanceStore, globalStake: GlobalStakeByStatus, ownerStake: OwnerStakeByStatus, ): FunctionAssertion<[BigNumber], LocalBalanceStore, void> { const { stakingWrapper, zrxVault } = deployment.staking; return new FunctionAssertion(stakingWrapper.stake.bind(stakingWrapper), { 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( args.txData.from as string, zrxVault.address, amount, deployment.assetDataEncoder.ERC20Token(deployment.tokens.zrx.address).getABIEncodedTransactionData(), ); return expectedBalances; }, after: async ( expectedBalances: LocalBalanceStore, _result: FunctionResult, args: FunctionArguments<[BigNumber]>, ) => { const [amount] = args.args; 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(args.txData.from as string, StakeStatus.Undelegated) .callAsync(); 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(StakeStatus.Undelegated) .callAsync(); const expectedGlobalUndelegatedStake = expectedUndelegatedStake(globalStake, amount); expect(globalUndelegatedStake, 'Global undelegated stake').to.deep.equal(expectedGlobalUndelegatedStake); // Updates local state accordingly globalStake[StakeStatus.Undelegated] = expectedGlobalUndelegatedStake; }, }); }