* update abi-gen with new method interfaces * wip: get all packages to build * wip: get all packages to build * Fix two contract wrapper calls * Export necessary types part of the contract wrapper public interfaces * Revive and fix wrapper_unit_tests * Remove duplicate type * Fix lib_exchange_rich_error_decoder tests * Fix remaining test failures in contracts-* packages * Prettier fixes * remove transactionHelper * lint and update changelogs * Fix prettier * Revert changes to reference docs * Add back changelog already published and add revert changelog entry * Add missing CHANGELOG entries * Add missing comma * Update mesh-rpc-client dep * Update Mesh RPC logic in @0x/orderbook to v6.0.1-beta * Align package versions
209 lines
11 KiB
TypeScript
209 lines
11 KiB
TypeScript
import { ERC20Wrapper } from '@0x/contracts-asset-proxy';
|
|
import { blockchainTests, constants, expect } from '@0x/contracts-test-utils';
|
|
import { StakingRevertErrors } from '@0x/order-utils';
|
|
import * as _ from 'lodash';
|
|
|
|
import { constants as stakingConstants } from '../src/constants';
|
|
|
|
import { MakerActor } from './actors/maker_actor';
|
|
import { PoolOperatorActor } from './actors/pool_operator_actor';
|
|
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
|
|
|
|
// tslint:disable:no-unnecessary-type-assertion
|
|
// tslint:disable:max-file-line-count
|
|
blockchainTests('Staking Pool Management', env => {
|
|
// constants
|
|
const { PPM_100_PERCENT, PPM_DENOMINATOR } = constants;
|
|
// tokens & addresses
|
|
let accounts: string[];
|
|
let owner: string;
|
|
let users: string[];
|
|
// wrappers
|
|
let stakingApiWrapper: StakingApiWrapper;
|
|
let erc20Wrapper: ERC20Wrapper;
|
|
// tests
|
|
before(async () => {
|
|
// create accounts
|
|
accounts = await env.getAccountAddressesAsync();
|
|
[owner, ...users] = accounts;
|
|
// set up ERC20Wrapper
|
|
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
|
// deploy staking contracts
|
|
stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper);
|
|
});
|
|
blockchainTests.resets('Staking Pool Management', () => {
|
|
it('Should successfully create a pool', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
// check that the next pool id was incremented
|
|
const lastPoolId = await stakingApiWrapper.stakingContract.lastPoolId().callAsync();
|
|
expect(lastPoolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
});
|
|
it('Should successfully create several staking pools, as long as the operator is only a maker in one', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId1 = await poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
expect(poolId1).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
const poolId2 = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId2).to.be.equal(stakingConstants.SECOND_POOL_ID);
|
|
});
|
|
it('Should fail to create a pool with operator share > 100', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (101 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
|
|
const revertError = new StakingRevertErrors.OperatorShareError(
|
|
StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge,
|
|
stakingConstants.INITIAL_POOL_ID,
|
|
operatorShare,
|
|
);
|
|
// create pool
|
|
await poolOperator.createStakingPoolAsync(operatorShare, false, revertError);
|
|
});
|
|
it('Should successfully create a pool and add owner as a maker', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
// check that the next pool id was incremented
|
|
const lastPoolId = await stakingApiWrapper.stakingContract.lastPoolId().callAsync();
|
|
expect(lastPoolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
});
|
|
it('Should throw if operatorShare is > PPM_DENOMINATOR', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
// tslint:disable-next-line
|
|
const operatorShare = PPM_100_PERCENT + 1;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
// create pool
|
|
const tx = poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
const expectedPoolId = stakingConstants.INITIAL_POOL_ID;
|
|
const expectedError = new StakingRevertErrors.OperatorShareError(
|
|
StakingRevertErrors.OperatorShareErrorCodes.OperatorShareTooLarge,
|
|
expectedPoolId,
|
|
operatorShare,
|
|
);
|
|
return expect(tx).to.revertWith(expectedError);
|
|
});
|
|
it('Should successfully add a maker to a pool', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
const makerAddress = users[1];
|
|
const maker = new MakerActor(makerAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
// maker joins pool
|
|
await maker.joinStakingPoolAsMakerAsync(poolId);
|
|
});
|
|
it('Maker should successfully remove themselves from a pool', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
const makerAddress = users[1];
|
|
const maker = new MakerActor(makerAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
// maker joins pool
|
|
await maker.joinStakingPoolAsMakerAsync(poolId);
|
|
// maker removes themselves from pool
|
|
await maker.joinStakingPoolAsMakerAsync(stakingConstants.NIL_POOL_ID);
|
|
});
|
|
it('Should successfully add/remove multiple makers to the same pool', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
const makerAddresses = users.slice(1, 4);
|
|
const makers = makerAddresses.map(makerAddress => new MakerActor(makerAddress, stakingApiWrapper));
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
// add makers to pool
|
|
await Promise.all(makers.map(async maker => maker.joinStakingPoolAsMakerAsync(poolId)));
|
|
// remove makers to pool
|
|
await Promise.all(
|
|
makers.map(async maker => maker.joinStakingPoolAsMakerAsync(stakingConstants.NIL_POOL_ID)),
|
|
);
|
|
});
|
|
it('Operator should successfully decrease their share of rewards', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
|
|
// decrease operator share
|
|
await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, operatorShare - 1);
|
|
});
|
|
it('Should fail if operator tries to increase their share of rewards', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
|
|
const increasedOperatorShare = operatorShare + 1;
|
|
const revertError = new StakingRevertErrors.OperatorShareError(
|
|
StakingRevertErrors.OperatorShareErrorCodes.CanOnlyDecreaseOperatorShare,
|
|
poolId,
|
|
increasedOperatorShare,
|
|
);
|
|
// decrease operator share
|
|
await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, increasedOperatorShare, revertError);
|
|
});
|
|
it('Should be successful if operator calls decreaseStakingPoolOperatorShare and newOperatorShare == oldOperatorShare', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, false);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
|
|
// decrease operator share
|
|
await poolOperator.decreaseStakingPoolOperatorShareAsync(poolId, operatorShare);
|
|
});
|
|
it('should fail to decrease operator share if not called by operator', async () => {
|
|
// test parameters
|
|
const operatorAddress = users[0];
|
|
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
|
|
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
|
|
const makerAddress = users[1];
|
|
const maker = new MakerActor(makerAddress, stakingApiWrapper);
|
|
// create pool
|
|
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
|
|
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
|
|
await maker.decreaseStakingPoolOperatorShareAsync(
|
|
poolId,
|
|
operatorShare - 1,
|
|
new StakingRevertErrors.OnlyCallableByPoolOperatorError(makerAddress, poolId),
|
|
);
|
|
});
|
|
});
|
|
});
|
|
// tslint:enable:no-unnecessary-type-assertion
|