ran prettier

This commit is contained in:
Greg Hysen 2019-06-26 14:01:24 -07:00
parent b756e723ea
commit a02f96c913
20 changed files with 657 additions and 433 deletions

View File

@ -5,7 +5,7 @@ import {
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils'
} from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
@ -19,21 +19,21 @@ import { StakerActor } from './staker_actor';
const expect = chai.expect;
export class DelegatorActor extends StakerActor {
constructor(owner: string, stakingWrapper: StakingWrapper) {
super(owner, stakingWrapper);
}
public async depositAndDelegateAsync(poolId: string, amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async depositAndDelegateAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
): Promise<void> {
// query init balances
const initZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVault();
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
// deposit stake
const txReceiptPromise = this._stakingWrapper.depositAndDelegateAsync(this._owner, poolId, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -45,23 +45,26 @@ export class DelegatorActor extends StakerActor {
expectedDelegatorBalances.stakeBalanceInVault = initDelegatorBalances.stakeBalanceInVault.plus(amount);
expectedDelegatorBalances.activatedStakeBalance = initDelegatorBalances.activatedStakeBalance.plus(amount);
expectedDelegatorBalances.delegatedStakeBalance = initDelegatorBalances.delegatedStakeBalance.plus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].plus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].plus(
amount,
);
expectedDelegatorBalances.stakeDelegatedToPool[0] = initDelegatorBalances.stakeDelegatedToPool[0].plus(amount);
await this.assertBalancesAsync(expectedDelegatorBalances, [poolId]);
// check zrx balance of vault
const finalZrxBalanceOfVault = await this._stakingWrapper.getZrxTokenBalanceOfZrxVault();
expect(finalZrxBalanceOfVault).to.be.bignumber.equal(initZrxBalanceOfVault.plus(amount));
}
public async activateAndDelegateStakeAsync(poolId: string, amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async activateAndDelegateStakeAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
): Promise<void> {
// query init balances
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
// activate and delegate
const txReceiptPromise = this._stakingWrapper.activateAndDelegateStakeAsync(this._owner, poolId, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -70,24 +73,37 @@ export class DelegatorActor extends StakerActor {
// check balances
let expectedDelegatorBalances = initDelegatorBalances;
expectedDelegatorBalances.activatedStakeBalance = initDelegatorBalances.activatedStakeBalance.plus(amount);
expectedDelegatorBalances.withdrawableStakeBalance = expectedDelegatorBalances.withdrawableStakeBalance.minus(amount);
expectedDelegatorBalances.activatableStakeBalance = expectedDelegatorBalances.activatableStakeBalance.minus(amount);
expectedDelegatorBalances.deactivatedStakeBalance = expectedDelegatorBalances.deactivatedStakeBalance.minus(amount);
expectedDelegatorBalances.withdrawableStakeBalance = expectedDelegatorBalances.withdrawableStakeBalance.minus(
amount,
);
expectedDelegatorBalances.activatableStakeBalance = expectedDelegatorBalances.activatableStakeBalance.minus(
amount,
);
expectedDelegatorBalances.deactivatedStakeBalance = expectedDelegatorBalances.deactivatedStakeBalance.minus(
amount,
);
expectedDelegatorBalances.delegatedStakeBalance = initDelegatorBalances.delegatedStakeBalance.plus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].plus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].plus(
amount,
);
expectedDelegatorBalances.stakeDelegatedToPool[0] = initDelegatorBalances.stakeDelegatedToPool[0].plus(amount);
await this.assertBalancesAsync(expectedDelegatorBalances, [poolId]);
}
public async deactivateAndTimelockDelegatedStakeAsync(poolId: string, amount: BigNumber, revertReason?: RevertReason): Promise<void> {
public async deactivateAndTimelockDelegatedStakeAsync(
poolId: string,
amount: BigNumber,
revertReason?: RevertReason,
): Promise<void> {
// query init balances
const initDelegatorBalances = await this.getBalancesAsync([poolId]);
// deactivate and timelock
const txReceiptPromise = this._stakingWrapper.deactivateAndTimelockDelegatedStakeAsync(this._owner, poolId, amount);
const txReceiptPromise = this._stakingWrapper.deactivateAndTimelockDelegatedStakeAsync(
this._owner,
poolId,
amount,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -95,10 +111,16 @@ export class DelegatorActor extends StakerActor {
// check balances
let expectedDelegatorBalances = initDelegatorBalances;
expectedDelegatorBalances.activatedStakeBalance = initDelegatorBalances.activatedStakeBalance.minus(amount);
expectedDelegatorBalances.timelockedStakeBalance = expectedDelegatorBalances.timelockedStakeBalance.plus(amount);
expectedDelegatorBalances.deactivatedStakeBalance = expectedDelegatorBalances.deactivatedStakeBalance.plus(amount);
expectedDelegatorBalances.timelockedStakeBalance = expectedDelegatorBalances.timelockedStakeBalance.plus(
amount,
);
expectedDelegatorBalances.deactivatedStakeBalance = expectedDelegatorBalances.deactivatedStakeBalance.plus(
amount,
);
expectedDelegatorBalances.delegatedStakeBalance = initDelegatorBalances.delegatedStakeBalance.minus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].minus(amount);
expectedDelegatorBalances.stakeDelegatedToPoolByOwner[0] = initDelegatorBalances.stakeDelegatedToPoolByOwner[0].minus(
amount,
);
expectedDelegatorBalances.stakeDelegatedToPool[0] = initDelegatorBalances.stakeDelegatedToPool[0].minus(amount);
await this.assertBalancesAsync(expectedDelegatorBalances, [poolId]);
}
@ -112,7 +134,10 @@ export class DelegatorActor extends StakerActor {
};
const poolIds = maybePoolIds !== undefined ? maybePoolIds : [];
for (const poolId of poolIds) {
const stakeDelegatedToPoolByOwner = await this._stakingWrapper.getStakeDelegatedToPoolByOwnerAsync(poolId, this._owner);
const stakeDelegatedToPoolByOwner = await this._stakingWrapper.getStakeDelegatedToPoolByOwnerAsync(
poolId,
this._owner,
);
delegatorBalances.stakeDelegatedToPoolByOwner.push(stakeDelegatedToPoolByOwner);
const stakeDelegatedToPool = await this._stakingWrapper.getStakeDelegatedToPoolAsync(poolId);
delegatorBalances.stakeDelegatedToPool.push(stakeDelegatedToPool);
@ -122,11 +147,19 @@ export class DelegatorActor extends StakerActor {
public async assertBalancesAsync(expectedBalances: DelegatorBalances, maybePoolIds?: string[]): Promise<void> {
await super.assertBalancesAsync(expectedBalances);
const balances = await this.getBalancesAsync(maybePoolIds);
expect(balances.delegatedStakeBalance, 'delegated stake balance').to.be.bignumber.equal(expectedBalances.delegatedStakeBalance);
expect(balances.delegatedStakeBalance, 'delegated stake balance').to.be.bignumber.equal(
expectedBalances.delegatedStakeBalance,
);
const poolIds = maybePoolIds !== undefined ? maybePoolIds : [];
for (let i = 0; i < poolIds.length; i++) {
expect(balances.stakeDelegatedToPoolByOwner[i], `stake delegated to pool ${poolIds[i]} by owner`).to.be.bignumber.equal(expectedBalances.stakeDelegatedToPoolByOwner[i]);
expect(balances.stakeDelegatedToPool[i], `total stake delegated to pool ${poolIds[i]}`).to.be.bignumber.equal(expectedBalances.stakeDelegatedToPool[i]);
expect(
balances.stakeDelegatedToPoolByOwner[i],
`stake delegated to pool ${poolIds[i]} by owner`,
).to.be.bignumber.equal(expectedBalances.stakeDelegatedToPoolByOwner[i]);
expect(
balances.stakeDelegatedToPool[i],
`total stake delegated to pool ${poolIds[i]}`,
).to.be.bignumber.equal(expectedBalances.stakeDelegatedToPool[i]);
}
}
}
}

View File

@ -5,7 +5,7 @@ import {
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils'
} from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
@ -25,7 +25,13 @@ export class MakerActor extends BaseActor {
private readonly _signatureVerifierIfExists?: string;
private readonly _chainIdIfExists?: number;
constructor(owner: string, stakingWrapper: StakingWrapper, ownerPrivateKey?: Buffer, signatureVerifier?: string, chainId?: number) {
constructor(
owner: string,
stakingWrapper: StakingWrapper,
ownerPrivateKey?: Buffer,
signatureVerifier?: string,
chainId?: number,
) {
super(owner, stakingWrapper);
this._ownerPrivateKeyIfExists = ownerPrivateKey;
this._signatureVerifierIfExists = signatureVerifier;
@ -42,8 +48,8 @@ export class MakerActor extends BaseActor {
this._ownerPrivateKeyIfExists,
this._signatureVerifierIfExists,
this._chainIdIfExists,
signatureType
signatureType,
);
return approval;
}
}
}

View File

@ -5,7 +5,7 @@ import {
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils'
} from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
@ -20,7 +20,6 @@ import { constants as stakingConstants } from '../utils/constants';
const expect = chai.expect;
export class PoolOperatorActor extends BaseActor {
constructor(owner: string, stakingWrapper: StakingWrapper) {
super(owner, stakingWrapper);
}
@ -31,25 +30,29 @@ export class PoolOperatorActor extends BaseActor {
// create pool
const poolIdPromise = this._stakingWrapper.createPoolAsync(this._owner, operatorShare);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
poolIdPromise,
revertReason
);
return "";
await expectTransactionFailedAsync(poolIdPromise, revertReason);
return '';
}
const poolId = await poolIdPromise;
// validate pool id
expect(poolId, 'pool id').to.be.bignumber.equal(nextPoolId);
return poolId;
}
public async addMakerToPoolAsync(poolId: string, makerAddress: string, makerSignature: string, revertReason?: RevertReason): Promise<void> {
public async addMakerToPoolAsync(
poolId: string,
makerAddress: string,
makerSignature: string,
revertReason?: RevertReason,
): Promise<void> {
// add maker
const txReceiptPromise = this._stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, makerSignature, this._owner);
const txReceiptPromise = this._stakingWrapper.addMakerToPoolAsync(
poolId,
makerAddress,
makerSignature,
this._owner,
);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -60,22 +63,23 @@ export class PoolOperatorActor extends BaseActor {
const makerAddressesForPool = await this._stakingWrapper.getMakerAddressesForPool(poolId);
expect(makerAddressesForPool, 'maker addresses for pool').to.include(makerAddress);
}
public async removeMakerFromPoolAsync(poolId: string, makerAddress: string, revertReason?: RevertReason): Promise<void> {
public async removeMakerFromPoolAsync(
poolId: string,
makerAddress: string,
revertReason?: RevertReason,
): Promise<void> {
// remove maker
const txReceiptPromise = this._stakingWrapper.removeMakerFromPoolAsync(poolId, makerAddress, this._owner);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
// check the pool id of the maker
const poolIdOfMakerAfterRemoving = await this._stakingWrapper.getMakerPoolId(makerAddress);
expect(poolIdOfMakerAfterRemoving, 'pool id of maker').to.be.equal(stakingConstants.NIL_POOL_ID);
// check the list of makers for the pool
const makerAddressesForPoolAfterRemoving = await this._stakingWrapper.getMakerAddressesForPool(poolId);
expect(makerAddressesForPoolAfterRemoving, 'maker addresses for pool').to.not.include(makerAddress);
// check the pool id of the maker
const poolIdOfMakerAfterRemoving = await this._stakingWrapper.getMakerPoolId(makerAddress);
expect(poolIdOfMakerAfterRemoving, 'pool id of maker').to.be.equal(stakingConstants.NIL_POOL_ID);
// check the list of makers for the pool
const makerAddressesForPoolAfterRemoving = await this._stakingWrapper.getMakerAddressesForPool(poolId);
expect(makerAddressesForPoolAfterRemoving, 'maker addresses for pool').to.not.include(makerAddress);
}
}
}

View File

@ -5,7 +5,7 @@ import {
provider,
txDefaults,
web3Wrapper,
} from '@0x/contracts-test-utils'
} from '@0x/contracts-test-utils';
import { RevertReason } from '@0x/types';
import { BigNumber } from '@0x/utils';
import * as chai from 'chai';
@ -18,7 +18,6 @@ import { BaseActor } from './base_actor';
const expect = chai.expect;
export class StakerActor extends BaseActor {
constructor(owner: string, stakingWrapper: StakingWrapper) {
super(owner, stakingWrapper);
}
@ -33,10 +32,7 @@ export class StakerActor extends BaseActor {
// deposit stake
const txReceiptPromise = this._stakingWrapper.depositAndStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -58,10 +54,7 @@ export class StakerActor extends BaseActor {
// activate stake
const txReceiptPromise = this._stakingWrapper.activateStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -80,10 +73,7 @@ export class StakerActor extends BaseActor {
// deactivate and timelock stake
const txReceiptPromise = this._stakingWrapper.deactivateAndTimelockStakeAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -102,10 +92,7 @@ export class StakerActor extends BaseActor {
// withdraw stake
const txReceiptPromise = this._stakingWrapper.withdrawAsync(this._owner, amount);
if (revertReason !== undefined) {
await expectTransactionFailedAsync(
txReceiptPromise,
revertReason
);
await expectTransactionFailedAsync(txReceiptPromise, revertReason);
return;
}
const txReceipt = await txReceiptPromise;
@ -133,19 +120,31 @@ export class StakerActor extends BaseActor {
activatedStakeBalance: await this._stakingWrapper.getActivatedStakeAsync(this._owner),
timelockedStakeBalance: await this._stakingWrapper.getTimelockedStakeAsync(this._owner),
deactivatedStakeBalance: await this._stakingWrapper.getDeactivatedStakeAsync(this._owner),
}
};
return stakerBalances;
}
public async assertBalancesAsync(expectedBalances: StakerBalances): Promise<void> {
const balances = await this.getBalancesAsync();
expect(balances.zrxBalance, 'zrx balance').to.be.bignumber.equal(expectedBalances.zrxBalance);
expect(balances.stakeBalance, 'stake balance').to.be.bignumber.equal(expectedBalances.stakeBalance);
expect(balances.stakeBalanceInVault, 'stake balance, recorded in vault').to.be.bignumber.equal(expectedBalances.stakeBalanceInVault);
expect(balances.withdrawableStakeBalance, 'withdrawable stake balance').to.be.bignumber.equal(expectedBalances.withdrawableStakeBalance);
expect(balances.activatableStakeBalance, 'activatable stake balance').to.be.bignumber.equal(expectedBalances.activatableStakeBalance);
expect(balances.activatedStakeBalance, 'activated stake balance').to.be.bignumber.equal(expectedBalances.activatedStakeBalance);
expect(balances.timelockedStakeBalance, 'timelocked stake balance').to.be.bignumber.equal(expectedBalances.timelockedStakeBalance);
expect(balances.deactivatedStakeBalance, 'deactivated stake balance').to.be.bignumber.equal(expectedBalances.deactivatedStakeBalance);
expect(balances.stakeBalanceInVault, 'stake balance, recorded in vault').to.be.bignumber.equal(
expectedBalances.stakeBalanceInVault,
);
expect(balances.withdrawableStakeBalance, 'withdrawable stake balance').to.be.bignumber.equal(
expectedBalances.withdrawableStakeBalance,
);
expect(balances.activatableStakeBalance, 'activatable stake balance').to.be.bignumber.equal(
expectedBalances.activatableStakeBalance,
);
expect(balances.activatedStakeBalance, 'activated stake balance').to.be.bignumber.equal(
expectedBalances.activatedStakeBalance,
);
expect(balances.timelockedStakeBalance, 'timelocked stake balance').to.be.bignumber.equal(
expectedBalances.timelockedStakeBalance,
);
expect(balances.deactivatedStakeBalance, 'deactivated stake balance').to.be.bignumber.equal(
expectedBalances.deactivatedStakeBalance,
);
}
public async forceTimelockSyncAsync(): Promise<void> {
const initBalances = await this.getBalancesAsync();
@ -162,7 +161,9 @@ export class StakerActor extends BaseActor {
let expectedBalances = initBalances;
const currentTimelockPeriod = await this._stakingWrapper.getCurrentTimelockPeriodAsync();
if (currentTimelockPeriod.minus(timelockStart).isGreaterThan(1)) {
expectedBalances.activatableStakeBalance = initBalances.activatableStakeBalance.plus(initBalances.timelockedStakeBalance);
expectedBalances.activatableStakeBalance = initBalances.activatableStakeBalance.plus(
initBalances.timelockedStakeBalance,
);
expectedBalances.withdrawableStakeBalance = expectedBalances.activatableStakeBalance;
expectedBalances.timelockedStakeBalance = new BigNumber(0);
}

View File

@ -72,9 +72,13 @@ describe('Epochs', () => {
describe('Epochs & Timelocks', () => {
it('basic epochs & timelock periods', async () => {
///// 0/3 Validate Assumptions /////
expect(await stakingWrapper.getEpochPeriodInSecondsAsync()).to.be.bignumber.equal(stakingConstants.EPOCH_PERIOD_IN_SECONDS);
expect(await stakingWrapper.getTimelockPeriodInEpochsAsync()).to.be.bignumber.equal(stakingConstants.TIMELOCK_PERIOD_IN_EPOCHS);
expect(await stakingWrapper.getEpochPeriodInSecondsAsync()).to.be.bignumber.equal(
stakingConstants.EPOCH_PERIOD_IN_SECONDS,
);
expect(await stakingWrapper.getTimelockPeriodInEpochsAsync()).to.be.bignumber.equal(
stakingConstants.TIMELOCK_PERIOD_IN_EPOCHS,
);
///// 1/3 Validate Initial Epoch & Timelock Period /////
{
// epoch

View File

@ -21,7 +21,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import { StakingContract } from '../src';
import { StakerActor } from './actors/staker_actor';
import { DelegatorActor } from './actors/delegator_actor';
@ -77,7 +76,7 @@ describe('Exchange Integrations', () => {
describe('Exchange Tracking in Staking Contract', () => {
it('basic exchange tracking', async () => {
// 1 try querying an invalid addresses
const invalidAddress = "0x0000000000000000000000000000000000000001";
const invalidAddress = '0x0000000000000000000000000000000000000001';
const isInvalidAddressValid = await stakingWrapper.isValidExchangeAddressAsync(invalidAddress);
expect(isInvalidAddressValid).to.be.false();
// 2 add valid address
@ -87,7 +86,7 @@ describe('Exchange Integrations', () => {
// 3 try adding valid address again
await expectTransactionFailedAsync(
stakingWrapper.addExchangeAddressAsync(exchange),
RevertReason.ExchangeAddressAlreadyRegistered
RevertReason.ExchangeAddressAlreadyRegistered,
);
// 4 remove valid address
await stakingWrapper.removeExchangeAddressAsync(exchange);
@ -96,7 +95,7 @@ describe('Exchange Integrations', () => {
// 5 try removing valid address again
await expectTransactionFailedAsync(
stakingWrapper.removeExchangeAddressAsync(exchange),
RevertReason.ExchangeAddressNotRegistered
RevertReason.ExchangeAddressNotRegistered,
);
});
});

View File

@ -16,7 +16,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
chaiSetup.configure();
const expect = chai.expect;
const blockchainLifecycle = new BlockchainLifecycle(web3Wrapper);
@ -107,7 +106,7 @@ describe('Math Libraries', () => {
expect(rootAsFloatingPoint).to.be.bignumber.equal(expectedResult);
});
it('cobb douglas - approximate', async() => {
it('cobb douglas - approximate', async () => {
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
const totalFees = stakingWrapper.toBaseUnitAmount(29.00679);
@ -126,14 +125,17 @@ describe('Math Libraries', () => {
ownerStake,
totalStake,
alphaNumerator,
alphaDenominator
alphaDenominator,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(
stakingWrapper.toFloatingPoint(ownerReward, 18),
4,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 4);
// validation
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
});
it('cobb douglas - simplified (alpha = 1/x)', async() => {
it('cobb douglas - simplified (alpha = 1/x)', async () => {
// setup test parameters
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
@ -151,14 +153,17 @@ describe('Math Libraries', () => {
totalFees,
ownerStake,
totalStake,
alphaDenominator
alphaDenominator,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(
stakingWrapper.toFloatingPoint(ownerReward, 18),
14,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 14);
// validation
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
});
it('cobb douglas - simplified inverse (1 - alpha = 1/x)', async() => {
it('cobb douglas - simplified inverse (1 - alpha = 1/x)', async () => {
const totalRewards = stakingWrapper.toBaseUnitAmount(57.154398);
const ownerFees = stakingWrapper.toBaseUnitAmount(5.64375);
const totalFees = stakingWrapper.toBaseUnitAmount(29.00679);
@ -175,9 +180,12 @@ describe('Math Libraries', () => {
totalFees,
ownerStake,
totalStake,
inverseAlphaDenominator
inverseAlphaDenominator,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(
stakingWrapper.toFloatingPoint(ownerReward, 18),
12,
);
const ownerRewardFloatingPoint = stakingWrapper.trimFloat(stakingWrapper.toFloatingPoint(ownerReward, 18), 12);
// validation
expect(ownerRewardFloatingPoint).to.be.bignumber.equal(expectedOwnerReward);
});

View File

@ -22,7 +22,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import { StakingContract } from '../src';
import { StakerActor } from './actors/staker_actor';
import { DelegatorActor } from './actors/delegator_actor';
import { PoolOperatorActor } from './actors/pool_operator_actor';
@ -75,7 +74,7 @@ describe('Staking Pool Management', () => {
await blockchainLifecycle.revertAsync();
});
describe('Staking Pool Management', () => {
it('Should successfully create a pool', async() => {
it('Should successfully create a pool', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -84,11 +83,11 @@ describe('Staking Pool Management', () => {
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// check that the next pool id was incremented
const expectedNextPoolId = "0x0000000000000000000000000000000200000000000000000000000000000000";
const expectedNextPoolId = '0x0000000000000000000000000000000200000000000000000000000000000000';
const nextPoolId = await stakingWrapper.getNextPoolIdAsync();
expect(nextPoolId).to.be.equal(expectedNextPoolId);
});
it('Should successfully add/remove a maker to a pool', async() => {
it('Should successfully add/remove a maker to a pool', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -104,7 +103,7 @@ describe('Staking Pool Management', () => {
// remove maker from pool
await poolOperator.removeMakerFromPoolAsync(poolId, makerAddress);
});
it('Should successfully add/remove multipler makers to the same pool', async() => {
it('Should successfully add/remove multipler makers to the same pool', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -133,7 +132,7 @@ describe('Staking Pool Management', () => {
// @TODO - this fails with `RuntimeError: VM Exception while processing transaction: revert` on Ganache
// await poolOperator.removeMakerFromPoolAsync(poolId, makerAddresses[2]);
});
it('Should fail to add the same maker twice', async() => {
it('Should fail to add the same maker twice', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -147,9 +146,14 @@ describe('Staking Pool Management', () => {
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature);
// add same maker to pool again
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, RevertReason.MakerAddressAlreadyRegistered);
await poolOperator.addMakerToPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.MakerAddressAlreadyRegistered,
);
});
it('Should fail to remove a maker that does not exist', async() => {
it('Should fail to remove a maker that does not exist', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -162,22 +166,29 @@ describe('Staking Pool Management', () => {
// remove non-existent maker from pool
await poolOperator.removeMakerFromPoolAsync(poolId, makerAddress, RevertReason.MakerAddressNotRegistered);
});
it('Should fail to add a maker who signed with the wrong private key', async() => {
it('Should fail to add a maker who signed with the wrong private key', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingWrapper);
const makerAddress = users[1];
const badMakerPrivateKey = ethUtil.toBuffer('0x0000000000000000000000000000000000000000000000000000000000000001');
const badMakerPrivateKey = ethUtil.toBuffer(
'0x0000000000000000000000000000000000000000000000000000000000000001',
);
const maker = new MakerActor(makerAddress, stakingWrapper, badMakerPrivateKey);
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, RevertReason.InvalidMakerSignature);
await poolOperator.addMakerToPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
);
});
it('Should fail to add a maker who signed with the wrong staking contract address', async() => {
it('Should fail to add a maker who signed with the wrong staking contract address', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -191,9 +202,14 @@ describe('Staking Pool Management', () => {
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, RevertReason.InvalidMakerSignature);
await poolOperator.addMakerToPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
);
});
it('Should fail to add a maker who signed with the wrong chain id', async() => {
it('Should fail to add a maker who signed with the wrong chain id', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
@ -202,50 +218,61 @@ describe('Staking Pool Management', () => {
const forceMakerKeyLookup = undefined;
const forceStakingContractLookup = undefined;
const badChainId = 209348;
const maker = new MakerActor(makerAddress, stakingWrapper, forceMakerKeyLookup, forceStakingContractLookup, badChainId);
const maker = new MakerActor(
makerAddress,
stakingWrapper,
forceMakerKeyLookup,
forceStakingContractLookup,
badChainId,
);
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, RevertReason.InvalidMakerSignature);
});
it('Should fail to add a maker when called by someone other than the pool operator', async() => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingWrapper);
const makerAddress = users[1];
const maker = new MakerActor(makerAddress, stakingWrapper);
const notOperatorAddress = users[2];
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await expectTransactionFailedAsync(
stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, notOperatorAddress),
RevertReason.OnlyCallableByPoolOperator
await poolOperator.addMakerToPoolAsync(
poolId,
makerAddress,
makerApproval.signature,
RevertReason.InvalidMakerSignature,
);
});
it('Should fail to remove a maker when called by someone other than the pool operator', async() => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingWrapper);
const makerAddress = users[1];
const maker = new MakerActor(makerAddress, stakingWrapper);
const notOperatorAddress = users[2];
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature);
// try to remove the maker address from an address other than the operator
it('Should fail to add a maker when called by someone other than the pool operator', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingWrapper);
const makerAddress = users[1];
const maker = new MakerActor(makerAddress, stakingWrapper);
const notOperatorAddress = users[2];
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await expectTransactionFailedAsync(
stakingWrapper.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature, notOperatorAddress),
RevertReason.OnlyCallableByPoolOperator,
);
});
it('Should fail to remove a maker when called by someone other than the pool operator', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = 39;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingWrapper);
const makerAddress = users[1];
const maker = new MakerActor(makerAddress, stakingWrapper);
const notOperatorAddress = users[2];
// create pool
const poolId = await poolOperator.createPoolAsync(operatorShare);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
// add maker to pool
const makerApproval = maker.signApprovalForStakingPool(poolId);
await poolOperator.addMakerToPoolAsync(poolId, makerAddress, makerApproval.signature);
// try to remove the maker address from an address other than the operator
await expectTransactionFailedAsync(
stakingWrapper.removeMakerFromPoolAsync(poolId, makerAddress, notOperatorAddress),
RevertReason.OnlyCallableByPoolOperator
RevertReason.OnlyCallableByPoolOperator,
);
});
});

View File

@ -21,7 +21,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import { StakingContract } from '../src';
import { StakerActor } from './actors/staker_actor';
import { DelegatorActor } from './actors/delegator_actor';
@ -43,11 +42,10 @@ describe('End-To-End Simulations', () => {
let zrxTokenContract: DummyERC20TokenContract;
let erc20ProxyContract: ERC20ProxyContract;
let stakers: string[];
let stakers: string[];
let makers: string[];
let delegators: string[];
// wrappers
let stakingWrapper: StakingWrapper;
let erc20Wrapper: ERC20Wrapper;
@ -69,7 +67,6 @@ describe('End-To-End Simulations', () => {
makers = accounts.slice(4, 10);
users = [...users, ...users]; // maybe this'll work? Not sure lol.
// deploy erc20 proxy
erc20Wrapper = new ERC20Wrapper(provider, accounts, owner);
erc20ProxyContract = await erc20Wrapper.deployProxyAsync();
@ -89,64 +86,59 @@ describe('End-To-End Simulations', () => {
describe('Simulations', () => {
it('Should successfully simulate (no delegators / no shadow balances)', async () => {
// @TODO - get computations more accurate
const simulationParams = {
users,
numberOfPools: 3,
poolOperatorShares: [100, 100, 100],
const simulationParams = {
users,
numberOfPools: 3,
poolOperatorShares: [100, 100, 100],
stakeByPoolOperator: [
stakingWrapper.toBaseUnitAmount(42),
stakingWrapper.toBaseUnitAmount(84),
stakingWrapper.toBaseUnitAmount(97),
],
numberOfMakers: 6,
numberOfMakersPerPool: [1, 2, 3],
protocolFeesByMaker: [
// pool 1
stakingWrapper.toBaseUnitAmount(0.304958),
// pool 2
stakingWrapper.toBaseUnitAmount(3.2),
stakingWrapper.toBaseUnitAmount(12.123258),
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0)
],
numberOfDelegators: 0,
numberOfDelegatorsPerPool: [0, 0, 0],
stakeByDelegator: [],
delegateInNextEpoch: false, // no shadow eth
withdrawByUndelegating: false, // profits are withdrawn without undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedPayoutByPoolOperator: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedMembersPayoutByPool: [
new BigNumber('0'),
new BigNumber('0'),
new BigNumber('0'),
],
expectedPayoutByDelegator: [],
exchangeAddress: exchange,
};
const simulator = new Simulation(stakingWrapper, simulationParams);
await simulator.runAsync();
});
numberOfMakers: 6,
numberOfMakersPerPool: [1, 2, 3],
protocolFeesByMaker: [
// pool 1
stakingWrapper.toBaseUnitAmount(0.304958),
// pool 2
stakingWrapper.toBaseUnitAmount(3.2),
stakingWrapper.toBaseUnitAmount(12.123258),
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0),
],
numberOfDelegators: 0,
numberOfDelegatorsPerPool: [0, 0, 0],
stakeByDelegator: [],
delegateInNextEpoch: false, // no shadow eth
withdrawByUndelegating: false, // profits are withdrawn without undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedPayoutByPoolOperator: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedMembersPayoutByPool: [new BigNumber('0'), new BigNumber('0'), new BigNumber('0')],
expectedPayoutByDelegator: [],
exchangeAddress: exchange,
};
const simulator = new Simulation(stakingWrapper, simulationParams);
await simulator.runAsync();
});
it('Should successfully simulate (delegators withdraw by undeleating / no shadow balances)', async () => {
// @TODO - get computations more accurate
/*
it('Should successfully simulate (delegators withdraw by undeleating / no shadow balances)', async () => {
// @TODO - get computations more accurate
/*
\ // the expected payouts were computed by hand
// @TODO - get computations more accurate
Pool | Total Fees | Total Stake | Total Delegated Stake | Total Stake (Scaled)
@ -158,70 +150,70 @@ describe('End-To-End Simulations', () => {
Cumulative Stake = 405
Total Rewards = 43.75043836
*/
const simulationParams = {
users,
numberOfPools: 3,
poolOperatorShares: [39, 59, 43],
stakeByPoolOperator: [
stakingWrapper.toBaseUnitAmount(42),
stakingWrapper.toBaseUnitAmount(84),
stakingWrapper.toBaseUnitAmount(97),
],
numberOfMakers: 6,
numberOfMakersPerPool: [1, 2, 3],
protocolFeesByMaker: [
// pool 1
stakingWrapper.toBaseUnitAmount(0.304958),
// pool 2
stakingWrapper.toBaseUnitAmount(3.2),
stakingWrapper.toBaseUnitAmount(12.123258),
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0)
],
numberOfDelegators: 3,
numberOfDelegatorsPerPool: [0, 0, 3],
stakeByDelegator: [
stakingWrapper.toBaseUnitAmount(17),
stakingWrapper.toBaseUnitAmount(75),
stakingWrapper.toBaseUnitAmount(90),
],
delegateInNextEpoch: false, // delegated stake is included in payout computation + no shadow ether
withdrawByUndelegating: false, // profits are withdrawn without undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('2.89303'), // 2.8930364057678784829875695710382241749912199174798475
new BigNumber('9.90218'), // 9.9021783083174087034787071054543342142019746753770943
new BigNumber('28.16463'), // 28.164631904035798614670299155719067954180760345463798
],
expectedPayoutByPoolOperator: [
new BigNumber('1.12828'), // 0.39 * 2.89303
new BigNumber('5.84228'), // 0.59 * 9.90218
new BigNumber('12.11079') // 0.43 * 28.16463
],
expectedMembersPayoutByPool: [
new BigNumber('1.76475'), // (1 - 0.39) * 2.89303
new BigNumber('4.05989'), // (1 - 0.59) * 9.90218
new BigNumber('16.05383'), // (1 - 0.43) * 28.16463
],
expectedPayoutByDelegator: [
// note that the on-chain values may be slightly different due to rounding down on each entry
// there is a carry over between calls, which we account for here. the result is that delegators
// who withdraw later on will scoop up any rounding spillover from those who have already withdrawn.
new BigNumber('1.49953'), // (17 / 182) * 16.05383
new BigNumber('6.61559'), // (75 / 182) * 16.05383
new BigNumber('7.93871'), // (90 / 182) * 16.05383
],
exchangeAddress: exchange,
};
const simulator = new Simulation(stakingWrapper, simulationParams);
await simulator.runAsync();
});
const simulationParams = {
users,
numberOfPools: 3,
poolOperatorShares: [39, 59, 43],
stakeByPoolOperator: [
stakingWrapper.toBaseUnitAmount(42),
stakingWrapper.toBaseUnitAmount(84),
stakingWrapper.toBaseUnitAmount(97),
],
numberOfMakers: 6,
numberOfMakersPerPool: [1, 2, 3],
protocolFeesByMaker: [
// pool 1
stakingWrapper.toBaseUnitAmount(0.304958),
// pool 2
stakingWrapper.toBaseUnitAmount(3.2),
stakingWrapper.toBaseUnitAmount(12.123258),
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0),
],
numberOfDelegators: 3,
numberOfDelegatorsPerPool: [0, 0, 3],
stakeByDelegator: [
stakingWrapper.toBaseUnitAmount(17),
stakingWrapper.toBaseUnitAmount(75),
stakingWrapper.toBaseUnitAmount(90),
],
delegateInNextEpoch: false, // delegated stake is included in payout computation + no shadow ether
withdrawByUndelegating: false, // profits are withdrawn without undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('2.89303'), // 2.8930364057678784829875695710382241749912199174798475
new BigNumber('9.90218'), // 9.9021783083174087034787071054543342142019746753770943
new BigNumber('28.16463'), // 28.164631904035798614670299155719067954180760345463798
],
expectedPayoutByPoolOperator: [
new BigNumber('1.12828'), // 0.39 * 2.89303
new BigNumber('5.84228'), // 0.59 * 9.90218
new BigNumber('12.11079'), // 0.43 * 28.16463
],
expectedMembersPayoutByPool: [
new BigNumber('1.76475'), // (1 - 0.39) * 2.89303
new BigNumber('4.05989'), // (1 - 0.59) * 9.90218
new BigNumber('16.05383'), // (1 - 0.43) * 28.16463
],
expectedPayoutByDelegator: [
// note that the on-chain values may be slightly different due to rounding down on each entry
// there is a carry over between calls, which we account for here. the result is that delegators
// who withdraw later on will scoop up any rounding spillover from those who have already withdrawn.
new BigNumber('1.49953'), // (17 / 182) * 16.05383
new BigNumber('6.61559'), // (75 / 182) * 16.05383
new BigNumber('7.93871'), // (90 / 182) * 16.05383
],
exchangeAddress: exchange,
};
const simulator = new Simulation(stakingWrapper, simulationParams);
await simulator.runAsync();
});
it('Should successfully simulate (delegators withdraw by undelegating / includes shadow balances / delegators enter after reward payouts)', async () => {
// @TODO - get computations more accurate
@ -260,7 +252,7 @@ describe('End-To-End Simulations', () => {
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0)
stakingWrapper.toBaseUnitAmount(0),
],
numberOfDelegators: 3,
numberOfDelegatorsPerPool: [0, 0, 3],
@ -269,30 +261,30 @@ describe('End-To-End Simulations', () => {
stakingWrapper.toBaseUnitAmount(75),
stakingWrapper.toBaseUnitAmount(90),
],
delegateInNextEpoch: true, // delegated stake is included in payout computation + forces shadow eth
withdrawByUndelegating: true, // profits are withdrawn as result of undelegating
delegateInNextEpoch: true, // delegated stake is included in payout computation + forces shadow eth
withdrawByUndelegating: true, // profits are withdrawn as result of undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedPayoutByPoolOperator: [
new BigNumber('1.85514'), // 0.39 * 4.75677
new BigNumber('9.60597'), // 0.59 * 16.28130
new BigNumber('8.73342') // 0.43 * 20.31028
new BigNumber('1.85514'), // 0.39 * 4.75677
new BigNumber('9.60597'), // 0.59 * 16.28130
new BigNumber('8.73342'), // 0.43 * 20.31028
],
expectedMembersPayoutByPool: [
new BigNumber('2.90163'), // (1 - 0.39) * 4.75677
new BigNumber('6.67533'), // (1 - 0.59) * 16.28130
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber('2.90163'), // (1 - 0.39) * 4.75677
new BigNumber('6.67533'), // (1 - 0.59) * 16.28130
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
],
expectedPayoutByDelegator: [
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber(0),
new BigNumber(0),
],
@ -303,7 +295,7 @@ describe('End-To-End Simulations', () => {
});
it('Should successfully simulate (delegators withdraw without undelegating / includes shadow balances / delegators enter after reward payouts)', async () => {
// @TODO - get computations more accurate
// @TODO - get computations more accurate
/*
Pool | Total Fees | Total Stake | Total Delegated Stake | Total Stake (Scaled)
0 | 0.304958 | 42 | 0 | 42
@ -339,7 +331,7 @@ describe('End-To-End Simulations', () => {
// pool 3
stakingWrapper.toBaseUnitAmount(23.577),
stakingWrapper.toBaseUnitAmount(4.54522236),
stakingWrapper.toBaseUnitAmount(0)
stakingWrapper.toBaseUnitAmount(0),
],
numberOfDelegators: 3,
numberOfDelegatorsPerPool: [0, 0, 3],
@ -348,35 +340,34 @@ describe('End-To-End Simulations', () => {
stakingWrapper.toBaseUnitAmount(75),
stakingWrapper.toBaseUnitAmount(90),
],
delegateInNextEpoch: true, // delegated stake is included in payout computation + forces shadow eth
withdrawByUndelegating: false, // profits are withdrawn without undelegating
delegateInNextEpoch: true, // delegated stake is included in payout computation + forces shadow eth
withdrawByUndelegating: false, // profits are withdrawn without undelegating
expectedFeesByPool: [
stakingWrapper.toBaseUnitAmount(0.304958),
stakingWrapper.toBaseUnitAmount(15.323258),
stakingWrapper.toBaseUnitAmount(28.12222236),
],
expectedPayoutByPool: [
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
new BigNumber('4.75677'), // 4.756772362932728793619590327361600155564384201215274334070
new BigNumber('16.28130'), // 16.28130500394935316563988584956596823402223838026190634525
new BigNumber('20.31028'), // 20.31028447343014834523983759032242063760612769662934308289
],
expectedPayoutByPoolOperator: [
new BigNumber('1.85514'), // 0.39 * 4.75677
new BigNumber('9.60597'), // 0.59 * 16.28130
new BigNumber('8.73342') // 0.43 * 20.31028
new BigNumber('1.85514'), // 0.39 * 4.75677
new BigNumber('9.60597'), // 0.59 * 16.28130
new BigNumber('8.73342'), // 0.43 * 20.31028
],
expectedMembersPayoutByPool: [
new BigNumber('2.90163'), // (1 - 0.39) * 4.75677
new BigNumber('6.67533'), // (1 - 0.59) * 16.28130
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber('2.90163'), // (1 - 0.39) * 4.75677
new BigNumber('6.67533'), // (1 - 0.59) * 16.28130
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
],
expectedPayoutByDelegator: [
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber('11.57686'), // (1 - 0.43) * 20.31028
new BigNumber(0),
new BigNumber(0),
],
exchangeAddress: exchange,
};
const simulator = new Simulation(stakingWrapper, simulationParams);
await simulator.runAsync();
@ -387,7 +378,7 @@ describe('End-To-End Simulations', () => {
const protocolFee = new BigNumber(1);
await expectTransactionFailedAsync(
stakingWrapper.payProtocolFeeAsync(makerAddress, protocolFee, owner),
RevertReason.OnlyCallableByExchange
RevertReason.OnlyCallableByExchange,
);
});
});

View File

@ -21,7 +21,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import { StakingContract } from '../src';
import { StakerActor } from './actors/staker_actor';
import { DelegatorActor } from './actors/delegator_actor';

View File

@ -26,7 +26,7 @@ export class ApprovalFactory {
poolId,
makerAddress,
this._verifyingContractAddress,
this._chainId
this._chainId,
);
const signatureBuff = signingUtils.signMessage(approvalHashBuff, this._privateKey, signatureType);
const signedApproval = {

View File

@ -1,6 +1,4 @@
import {
chaiSetup,
} from '@0x/contracts-test-utils';
import { chaiSetup } from '@0x/contracts-test-utils';
import * as _ from 'lodash';
import * as chai from 'chai';
@ -12,7 +10,6 @@ import { StakingWrapper } from './staking_wrapper';
import { Queue } from './queue';
import { DelegatorActor } from '../actors/delegator_actor';
chaiSetup.configure();
const expect = chai.expect;
@ -25,7 +22,7 @@ export class Simulation {
private _poolIds: string[];
private _makers: MakerActor[];
private _delegators: DelegatorActor[];
constructor(stakingWrapper: StakingWrapper, simulationParams: SimulationParams) {
this._stakingWrapper = stakingWrapper;
this._p = simulationParams;
@ -57,7 +54,7 @@ export class Simulation {
} else {
await this._withdrawRewardForDelegatorsByUndelegating(this._p);
}
// @TODO cleanup state and verify the staking contract is empty
}
@ -73,10 +70,16 @@ export class Simulation {
const initEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress);
await delegator.deactivateAndTimelockDelegatedStakeAsync(poolId, amountOfStakeDelegated);
const finalEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress);
const reward = finalEthBalance.minus(initEthBalance);
const rewardTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(reward, 18), 5);
const reward = finalEthBalance.minus(initEthBalance);
const rewardTrimmed = this._stakingWrapper.trimFloat(
this._stakingWrapper.toFloatingPoint(reward, 18),
5,
);
const expectedReward = p.expectedPayoutByDelegator[delegatorIdx];
expect(rewardTrimmed, `reward withdrawn from pool ${poolId} for delegator ${delegatorAddress}`).to.be.bignumber.equal(expectedReward);
expect(
rewardTrimmed,
`reward withdrawn from pool ${poolId} for delegator ${delegatorAddress}`,
).to.be.bignumber.equal(expectedReward);
delegatorIdx += 1;
}
poolIdx += 1;
@ -94,10 +97,16 @@ export class Simulation {
const initEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress);
await this._stakingWrapper.withdrawTotalRewardAsync(poolId, delegatorAddress);
const finalEthBalance = await this._stakingWrapper.getEthBalanceAsync(delegatorAddress);
const reward = finalEthBalance.minus(initEthBalance);
const rewardTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(reward, 18), 5);
const reward = finalEthBalance.minus(initEthBalance);
const rewardTrimmed = this._stakingWrapper.trimFloat(
this._stakingWrapper.toFloatingPoint(reward, 18),
5,
);
const expectedReward = p.expectedPayoutByDelegator[delegatorIdx];
expect(rewardTrimmed, `reward withdrawn from pool ${poolId} for delegator ${delegatorAddress}`).to.be.bignumber.equal(expectedReward);
expect(
rewardTrimmed,
`reward withdrawn from pool ${poolId} for delegator ${delegatorAddress}`,
).to.be.bignumber.equal(expectedReward);
delegatorIdx += 1;
}
poolIdx += 1;
@ -198,19 +207,37 @@ export class Simulation {
// check pool balance in vault
const poolId = this._poolIds[i];
const rewardVaultBalance = await this._stakingWrapper.rewardVaultBalanceOfAsync(poolId);
const rewardVaultBalanceTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(rewardVaultBalance, 18), 5);
const rewardVaultBalanceTrimmed = this._stakingWrapper.trimFloat(
this._stakingWrapper.toFloatingPoint(rewardVaultBalance, 18),
5,
);
const expectedRewardBalance = p.expectedPayoutByPool[i];
expect(rewardVaultBalanceTrimmed, `expected balance in vault for pool with id ${poolId}`).to.be.bignumber.equal(expectedRewardBalance);
expect(
rewardVaultBalanceTrimmed,
`expected balance in vault for pool with id ${poolId}`,
).to.be.bignumber.equal(expectedRewardBalance);
// check operator's balance
const poolOperatorVaultBalance = await this._stakingWrapper.getRewardBalanceOfOperatorAsync(poolId);
const poolOperatorVaultBalanceTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(poolOperatorVaultBalance, 18), 5);
const poolOperatorVaultBalanceTrimmed = this._stakingWrapper.trimFloat(
this._stakingWrapper.toFloatingPoint(poolOperatorVaultBalance, 18),
5,
);
const expectedPoolOperatorVaultBalance = p.expectedPayoutByPoolOperator[i];
expect(poolOperatorVaultBalanceTrimmed, `operator balance in vault for pool with id ${poolId}`).to.be.bignumber.equal(expectedPoolOperatorVaultBalance);
expect(
poolOperatorVaultBalanceTrimmed,
`operator balance in vault for pool with id ${poolId}`,
).to.be.bignumber.equal(expectedPoolOperatorVaultBalance);
// check balance of pool members
const membersVaultBalance = await this._stakingWrapper.getRewardBalanceOfPoolAsync(poolId);
const membersVaultBalanceTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(membersVaultBalance, 18), 5);
const membersVaultBalanceTrimmed = this._stakingWrapper.trimFloat(
this._stakingWrapper.toFloatingPoint(membersVaultBalance, 18),
5,
);
const expectedMembersVaultBalance = p.expectedMembersPayoutByPool[i];
expect(membersVaultBalanceTrimmed, `members balance in vault for pool with id ${poolId}`).to.be.bignumber.equal(expectedMembersVaultBalance);
expect(
membersVaultBalanceTrimmed,
`members balance in vault for pool with id ${poolId}`,
).to.be.bignumber.equal(expectedMembersVaultBalance);
// @TODO compute balance of each member
}
}
@ -226,10 +253,12 @@ export class Simulation {
const initEthBalance = await this._stakingWrapper.getEthBalanceAsync(poolOperatorAddress);
await this._stakingWrapper.withdrawTotalOperatorRewardAsync(poolId, poolOperatorAddress);
const finalEthBalance = await this._stakingWrapper.getEthBalanceAsync(poolOperatorAddress);
const reward = finalEthBalance.minus(initEthBalance);
const reward = finalEthBalance.minus(initEthBalance);
const rewardTrimmed = this._stakingWrapper.trimFloat(this._stakingWrapper.toFloatingPoint(reward, 18), 5);
const expectedReward = p.expectedPayoutByPoolOperator[i];
expect(rewardTrimmed, `reward withdrawn from pool ${poolId} for operator`).to.be.bignumber.equal(expectedReward);
expect(rewardTrimmed, `reward withdrawn from pool ${poolId} for operator`).to.be.bignumber.equal(
expectedReward,
);
}
}
}
}

View File

@ -1,14 +1,14 @@
import { BigNumber } from '@0x/utils';
export const constants = {
MAX_UINT_64: (new BigNumber(2)).pow(256).minus(1),
TOKEN_MULTIPLIER: (new BigNumber(10)).pow(18),
INITIAL_POOL_ID: "0x0000000000000000000000000000000100000000000000000000000000000000",
NIL_POOL_ID: "0x0000000000000000000000000000000000000000000000000000000000000000",
NIL_ADDRESS: "0x0000000000000000000000000000000000000000",
INITIAL_EPOCH: (new BigNumber(0)),
MAX_UINT_64: new BigNumber(2).pow(256).minus(1),
TOKEN_MULTIPLIER: new BigNumber(10).pow(18),
INITIAL_POOL_ID: '0x0000000000000000000000000000000100000000000000000000000000000000',
NIL_POOL_ID: '0x0000000000000000000000000000000000000000000000000000000000000000',
NIL_ADDRESS: '0x0000000000000000000000000000000000000000',
INITIAL_EPOCH: new BigNumber(0),
INITIAL_TIMELOCK_PERIOD: new BigNumber(0),
EPOCH_PERIOD_IN_SECONDS: new BigNumber(1000), // @TODO SET FOR DEPLOYMENT*/
TIMELOCK_PERIOD_IN_EPOCHS: new BigNumber(3), // @TODO SET FOR DEPLOYMENT
CHAIN_ID: 1,
};
};

View File

@ -7,13 +7,13 @@ export const hashUtils = {
poolId: string,
makerAddress: string,
verifyingContractAddress: string,
chainId: number
chainId: number,
): Buffer {
const typedData = eip712Utils.createStakingPoolApprovalTypedData(
poolId,
makerAddress,
verifyingContractAddress,
chainId
chainId,
);
const hashBuffer = signTypedDataUtils.generateTypedDataHash(typedData);
return hashBuffer;
@ -22,7 +22,7 @@ export const hashUtils = {
poolId: string,
makerAddress: string,
verifyingContractAddress: string,
chainId: number
chainId: number,
): string {
const hashHex = `0x${hashUtils
.getStakingPoolApprovalHashBuffer(poolId, makerAddress, verifyingContractAddress, chainId)

View File

@ -2,7 +2,7 @@ import * as _ from 'lodash';
export class Queue<T> {
private _store: T[] = [];
constructor (store?: T[]) {
constructor(store?: T[]) {
this._store = store !== undefined ? _.cloneDeep(store) : [];
}
public pushBack(val: T): void {

View File

@ -9,7 +9,14 @@ import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contra
import { ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import * as _ from 'lodash';
import { artifacts, StakingContract, StakingProxyContract, ZrxVaultContract, RewardVaultContract, LibFeeMathTestContract } from '../../src';
import {
artifacts,
StakingContract,
StakingProxyContract,
ZrxVaultContract,
RewardVaultContract,
LibFeeMathTestContract,
} from '../../src';
import { ApprovalFactory } from './ApprovalFactory';
import { SignedStakingPoolApproval } from './types';
import { constants } from './constants';
@ -30,12 +37,18 @@ export class StakingWrapper {
private _rewardVaultContractIfExists?: RewardVaultContract;
private _LibFeeMathTestContractIfExists?: LibFeeMathTestContract;
constructor(provider: Provider, ownerAddres: string, erc20ProxyContract: ERC20ProxyContract, zrxTokenContract: DummyERC20TokenContract, accounts: string[]) {
constructor(
provider: Provider,
ownerAddres: string,
erc20ProxyContract: ERC20ProxyContract,
zrxTokenContract: DummyERC20TokenContract,
accounts: string[],
) {
this._web3Wrapper = new Web3Wrapper(provider);
this._provider = provider;
const decoderArtifacts = _.merge(artifacts, erc20Artifacts);
this._logDecoder = new LogDecoder(this._web3Wrapper, decoderArtifacts);
this._ownerAddres= ownerAddres;
this._ownerAddres = ownerAddres;
this._erc20ProxyContract = erc20ProxyContract;
this._zrxTokenContract = zrxTokenContract;
this._accounts = accounts;
@ -69,7 +82,7 @@ export class StakingWrapper {
txDefaults,
this._erc20ProxyContract.address,
this._zrxTokenContract.address,
zrxAssetData
zrxAssetData,
);
// deploy reward vault
this._rewardVaultContractIfExists = await RewardVaultContract.deployFrom0xArtifactAsync(
@ -78,43 +91,57 @@ export class StakingWrapper {
txDefaults,
);
// configure erc20 proxy to accept calls from zrx vault
await this._erc20ProxyContract.addAuthorizedAddress.awaitTransactionSuccessAsync((this._zrxVaultContractIfExists as ZrxVaultContract).address);
await this._erc20ProxyContract.addAuthorizedAddress.awaitTransactionSuccessAsync(
(this._zrxVaultContractIfExists as ZrxVaultContract).address,
);
// deploy staking contract
this._stakingContractIfExists = await StakingContract.deployFrom0xArtifactAsync(
artifacts.Staking,
this._provider,
txDefaults
txDefaults,
);
// deploy staking proxy
this._stakingProxyContractIfExists = await StakingProxyContract.deployFrom0xArtifactAsync(
artifacts.StakingProxy,
this._provider,
txDefaults,
(this._stakingContractIfExists as StakingContract).address
(this._stakingContractIfExists as StakingContract).address,
);
// set staking proxy contract in zrx vault
await (this._zrxVaultContractIfExists as ZrxVaultContract).setStakingContractAddrsess.awaitTransactionSuccessAsync((this._stakingProxyContractIfExists as StakingProxyContract).address);
await (this
._zrxVaultContractIfExists as ZrxVaultContract).setStakingContractAddrsess.awaitTransactionSuccessAsync(
(this._stakingProxyContractIfExists as StakingProxyContract).address,
);
// set zrx vault in staking contract
const setZrxVaultCalldata = await (this._stakingContractIfExists as StakingContract).setZrxVault.getABIEncodedTransactionData((this._zrxVaultContractIfExists as ZrxVaultContract).address);
const setZrxVaultCalldata = await (this
._stakingContractIfExists as StakingContract).setZrxVault.getABIEncodedTransactionData(
(this._zrxVaultContractIfExists as ZrxVaultContract).address,
);
const setZrxVaultTxData = {
from: this._ownerAddres,
to: (this._stakingProxyContractIfExists as StakingProxyContract).address,
data: setZrxVaultCalldata
}
data: setZrxVaultCalldata,
};
await this._web3Wrapper.awaitTransactionSuccessAsync(
await this._web3Wrapper.sendTransactionAsync(setZrxVaultTxData)
await this._web3Wrapper.sendTransactionAsync(setZrxVaultTxData),
);
// set staking proxy contract in reward vault
await (this._rewardVaultContractIfExists as RewardVaultContract).setStakingContractAddrsess.awaitTransactionSuccessAsync((this._stakingProxyContractIfExists as StakingProxyContract).address);
await (this
._rewardVaultContractIfExists as RewardVaultContract).setStakingContractAddrsess.awaitTransactionSuccessAsync(
(this._stakingProxyContractIfExists as StakingProxyContract).address,
);
// set reward vault in staking contract
const setRewardVaultCalldata = await (this._stakingContractIfExists as StakingContract).setRewardVault.getABIEncodedTransactionData((this._rewardVaultContractIfExists as RewardVaultContract).address);
const setRewardVaultCalldata = await (this
._stakingContractIfExists as StakingContract).setRewardVault.getABIEncodedTransactionData(
(this._rewardVaultContractIfExists as RewardVaultContract).address,
);
const setRewardVaultTxData = {
from: this._ownerAddres,
to: (this._stakingProxyContractIfExists as StakingProxyContract).address,
data: setRewardVaultCalldata
}
data: setRewardVaultCalldata,
};
await this._web3Wrapper.awaitTransactionSuccessAsync(
await this._web3Wrapper.sendTransactionAsync(setRewardVaultTxData)
await this._web3Wrapper.sendTransactionAsync(setRewardVaultTxData),
);
// deploy libmath test
this._LibFeeMathTestContractIfExists = await LibFeeMathTestContract.deployFrom0xArtifactAsync(
@ -123,26 +150,33 @@ export class StakingWrapper {
txDefaults,
);
}
private async _executeTransactionAsync(calldata: string, from?: string, value?: BigNumber, includeLogs?: boolean): Promise<TransactionReceiptWithDecodedLogs> {
private async _executeTransactionAsync(
calldata: string,
from?: string,
value?: BigNumber,
includeLogs?: boolean,
): Promise<TransactionReceiptWithDecodedLogs> {
const txData = {
from: (from ? from : this._ownerAddres),
from: from ? from : this._ownerAddres,
to: this.getStakingProxyContract().address,
data: calldata,
gas: 3000000,
gasPrice: 0,
value
}
value,
};
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
const txReceipt = await (includeLogs ? this._logDecoder.getTxWithDecodedLogsAsync(txHash) : this._web3Wrapper.awaitTransactionSuccessAsync(txHash));
const txReceipt = await (includeLogs
? this._logDecoder.getTxWithDecodedLogsAsync(txHash)
: this._web3Wrapper.awaitTransactionSuccessAsync(txHash));
return txReceipt;
}
private async _callAsync(calldata: string, from?: string): Promise<any> {
const txData = {
from: (from ? from : this._ownerAddres),
from: from ? from : this._ownerAddres,
to: this.getStakingProxyContract().address,
data: calldata,
gas: 3000000
}
gas: 3000000,
};
const returnValue = await this._web3Wrapper.callAsync(txData);
return returnValue;
}
@ -161,7 +195,11 @@ export class StakingWrapper {
const txReceipt = await this._executeTransactionAsync(calldata, owner);
return txReceipt;
}
public async depositAndDelegateAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
public async depositAndDelegateAsync(
owner: string,
poolId: string,
amount: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().depositAndDelegate.getABIEncodedTransactionData(poolId, amount);
const txReceipt = await this._executeTransactionAsync(calldata, owner, new BigNumber(0), true);
return txReceipt;
@ -171,18 +209,35 @@ export class StakingWrapper {
const txReceipt = await this._executeTransactionAsync(calldata, owner);
return txReceipt;
}
public async activateAndDelegateStakeAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().activateAndDelegateStake.getABIEncodedTransactionData(poolId, amount);
public async activateAndDelegateStakeAsync(
owner: string,
poolId: string,
amount: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().activateAndDelegateStake.getABIEncodedTransactionData(
poolId,
amount,
);
const txReceipt = await this._executeTransactionAsync(calldata, owner);
return txReceipt;
}
public async deactivateAndTimelockStakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
public async deactivateAndTimelockStakeAsync(
owner: string,
amount: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().deactivateAndTimelockStake.getABIEncodedTransactionData(amount);
const txReceipt = await this._executeTransactionAsync(calldata, owner);
return txReceipt;
}
public async deactivateAndTimelockDelegatedStakeAsync(owner: string, poolId: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().deactivateAndTimelockDelegatedStake.getABIEncodedTransactionData(poolId, amount);
public async deactivateAndTimelockDelegatedStakeAsync(
owner: string,
poolId: string,
amount: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().deactivateAndTimelockDelegatedStake.getABIEncodedTransactionData(
poolId,
amount,
);
const txReceipt = await this._executeTransactionAsync(calldata, owner, new BigNumber(0), true);
return txReceipt;
}
@ -246,7 +301,10 @@ export class StakingWrapper {
return value;
}
public async getStakeDelegatedToPoolByOwnerAsync(poolId: string, owner: string): Promise<BigNumber> {
const calldata = this.getStakingContract().getStakeDelegatedToPoolByOwner.getABIEncodedTransactionData(owner, poolId);
const calldata = this.getStakingContract().getStakeDelegatedToPoolByOwner.getABIEncodedTransactionData(
owner,
poolId,
);
const returnData = await this._callAsync(calldata);
const value = this.getStakingContract().getStakeDelegatedToPoolByOwner.getABIDecodedReturnData(returnData);
return value;
@ -270,13 +328,29 @@ export class StakingWrapper {
const poolId = (createPoolLog as any).args.poolId;
return poolId;
}
public async addMakerToPoolAsync(poolId: string, makerAddress: string, makerSignature: string, operatorAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().addMakerToPool.getABIEncodedTransactionData(poolId, makerAddress, makerSignature);
public async addMakerToPoolAsync(
poolId: string,
makerAddress: string,
makerSignature: string,
operatorAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().addMakerToPool.getABIEncodedTransactionData(
poolId,
makerAddress,
makerSignature,
);
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
return txReceipt;
}
public async removeMakerFromPoolAsync(poolId: string, makerAddress: string, operatorAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().removeMakerFromPool.getABIEncodedTransactionData(poolId, makerAddress);
public async removeMakerFromPoolAsync(
poolId: string,
makerAddress: string,
operatorAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().removeMakerFromPool.getABIEncodedTransactionData(
poolId,
makerAddress,
);
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
return txReceipt;
}
@ -291,16 +365,29 @@ export class StakingWrapper {
const makerAddresses = this.getStakingContract().getMakerAddressesForPool.getABIDecodedReturnData(returndata);
return makerAddresses;
}
public async isValidMakerSignatureAsync(poolId: string, makerAddress: string, makerSignature: string): Promise<Boolean> {
const calldata = this.getStakingContract().isValidMakerSignature.getABIEncodedTransactionData(poolId, makerAddress, makerSignature);
public async isValidMakerSignatureAsync(
poolId: string,
makerAddress: string,
makerSignature: string,
): Promise<Boolean> {
const calldata = this.getStakingContract().isValidMakerSignature.getABIEncodedTransactionData(
poolId,
makerAddress,
makerSignature,
);
const returndata = await this._callAsync(calldata);
const isValid = this.getStakingContract().isValidMakerSignature.getABIDecodedReturnData(returndata);
return isValid;
}
public async getStakingPoolApprovalMessageHashAsync(poolId: string, makerAddress: string): Promise<string> {
const calldata = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIEncodedTransactionData(poolId, makerAddress);
const calldata = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIEncodedTransactionData(
poolId,
makerAddress,
);
const returndata = await this._callAsync(calldata);
const messageHash = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIDecodedReturnData(returndata);
const messageHash = this.getStakingContract().getStakingPoolApprovalMessageHash.getABIDecodedReturnData(
returndata,
);
return messageHash;
}
public signApprovalForStakingPool(
@ -311,8 +398,12 @@ export class StakingWrapper {
chainIdIfExists?: number,
signatureType: SignatureType = SignatureType.EthSign,
): SignedStakingPoolApproval {
const makerPrivateKey = makerPrivateKeyIfExists !== undefined ? makerPrivateKeyIfExists : testUtilsConstants.TESTRPC_PRIVATE_KEYS[this._accounts.indexOf(makerAddress)];
const verifierAddress = verifierAddressIfExists !== undefined ? verifierAddressIfExists : this.getStakingProxyContract().address;
const makerPrivateKey =
makerPrivateKeyIfExists !== undefined
? makerPrivateKeyIfExists
: testUtilsConstants.TESTRPC_PRIVATE_KEYS[this._accounts.indexOf(makerAddress)];
const verifierAddress =
verifierAddressIfExists !== undefined ? verifierAddressIfExists : this.getStakingProxyContract().address;
const chainId = chainIdIfExists !== undefined ? chainIdIfExists : constants.CHAIN_ID;
const approvalFactory = new ApprovalFactory(makerPrivateKey, verifierAddress, chainId);
const signedStakingPoolApproval = approvalFactory.newSignedApproval(poolId, makerAddress, signatureType);
@ -322,7 +413,9 @@ export class StakingWrapper {
public async goToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().finalizeFees.getABIEncodedTransactionData();
const txReceipt = await this._executeTransactionAsync(calldata, undefined, new BigNumber(0), true);
console.log(`finalization: gasUsed = ${txReceipt.gasUsed} / cumulativeGasUsed = ${txReceipt.cumulativeGasUsed}`);
console.log(
`finalization: gasUsed = ${txReceipt.gasUsed} / cumulativeGasUsed = ${txReceipt.cumulativeGasUsed}`,
);
return txReceipt;
}
public async skipToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
@ -395,7 +488,11 @@ export class StakingWrapper {
return value;
}
///// PROTOCOL FEES /////
public async payProtocolFeeAsync(makerAddress: string, amount: BigNumber, exchangeAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
public async payProtocolFeeAsync(
makerAddress: string,
amount: BigNumber,
exchangeAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().payProtocolFee.getABIEncodedTransactionData(makerAddress);
const txReceipt = await this._executeTransactionAsync(calldata, exchangeAddress, amount);
return txReceipt;
@ -461,22 +558,36 @@ export class StakingWrapper {
return value;
}
public async getShadowBalanceInPoolByOwnerAsync(owner: string, poolId: string): Promise<BigNumber> {
const calldata = this.getStakingContract().getShadowBalanceInPoolByOwner.getABIEncodedTransactionData(owner, poolId);
const calldata = this.getStakingContract().getShadowBalanceInPoolByOwner.getABIEncodedTransactionData(
owner,
poolId,
);
const returnData = await this._callAsync(calldata);
const value = this.getStakingContract().getShadowBalanceInPoolByOwner.getABIDecodedReturnData(returnData);
return value;
}
public async withdrawOperatorRewardAsync(poolId: string, amount: BigNumber, operatorAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
public async withdrawOperatorRewardAsync(
poolId: string,
amount: BigNumber,
operatorAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().withdrawOperatorReward.getABIEncodedTransactionData(poolId, amount);
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
return txReceipt;
}
public async withdrawRewardAsync(poolId: string, amount: BigNumber, owner: string): Promise<TransactionReceiptWithDecodedLogs> {
public async withdrawRewardAsync(
poolId: string,
amount: BigNumber,
owner: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().withdrawReward.getABIEncodedTransactionData(poolId, amount);
const txReceipt = await this._executeTransactionAsync(calldata, owner);
return txReceipt;
}
public async withdrawTotalOperatorRewardAsync(poolId: string, operatorAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
public async withdrawTotalOperatorRewardAsync(
poolId: string,
operatorAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getStakingContract().withdrawTotalOperatorReward.getABIEncodedTransactionData(poolId);
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
return txReceipt;
@ -487,12 +598,18 @@ export class StakingWrapper {
return txReceipt;
}
///// REWARD VAULT /////
public async rewardVaultDepositForAsync(poolId: string, amount: BigNumber, stakingContractAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
public async rewardVaultDepositForAsync(
poolId: string,
amount: BigNumber,
stakingContractAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getRewardVaultContract().depositFor.getABIEncodedTransactionData(poolId);
const txReceipt = await this._executeTransactionAsync(calldata, stakingContractAddress, amount);
return txReceipt;
}
public async rewardVaultEnterCatastrophicFailureModeAsync(zeroExMultisigAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
public async rewardVaultEnterCatastrophicFailureModeAsync(
zeroExMultisigAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getRewardVaultContract().enterCatostrophicFailure.getABIEncodedTransactionData();
const txReceipt = await this._executeTransactionAsync(calldata, zeroExMultisigAddress);
return txReceipt;
@ -509,8 +626,15 @@ export class StakingWrapper {
const balance = await this.getRewardVaultContract().balanceOfPool.callAsync(poolId);
return balance;
}
public async rewardVaultCreatePoolAsync(poolId: string, poolOperatorShare: number, stakingContractAddress: string): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getRewardVaultContract().createPool.getABIEncodedTransactionData(poolId, poolOperatorShare);
public async rewardVaultCreatePoolAsync(
poolId: string,
poolOperatorShare: number,
stakingContractAddress: string,
): Promise<TransactionReceiptWithDecodedLogs> {
const calldata = this.getRewardVaultContract().createPool.getABIEncodedTransactionData(
poolId,
poolOperatorShare,
);
const txReceipt = await this._executeTransactionAsync(calldata, stakingContractAddress);
return txReceipt;
}
@ -544,7 +668,7 @@ export class StakingWrapper {
ownerStake: BigNumber,
totalStake: BigNumber,
alphaNumerator: BigNumber,
alphaDenominator: BigNumber
alphaDenominator: BigNumber,
) {
const output = await this.getLibFeeMathTestContract().cobbDouglas.callAsync(
totalRewards,
@ -553,7 +677,7 @@ export class StakingWrapper {
ownerStake,
totalStake,
alphaNumerator,
alphaDenominator
alphaDenominator,
);
return output;
}
@ -563,7 +687,7 @@ export class StakingWrapper {
totalFees: BigNumber,
ownerStake: BigNumber,
totalStake: BigNumber,
alphaDenominator: BigNumber
alphaDenominator: BigNumber,
) {
const txReceipt = await this.getLibFeeMathTestContract().cobbDouglasSimplifiedInverse.awaitTransactionSuccessAsync(
totalRewards,
@ -571,7 +695,7 @@ export class StakingWrapper {
totalFees,
ownerStake,
totalStake,
alphaDenominator
alphaDenominator,
);
const output = await this.getLibFeeMathTestContract().cobbDouglasSimplified.callAsync(
totalRewards,
@ -579,7 +703,7 @@ export class StakingWrapper {
totalFees,
ownerStake,
totalStake,
alphaDenominator
alphaDenominator,
);
return output;
}
@ -589,7 +713,7 @@ export class StakingWrapper {
totalFees: BigNumber,
ownerStake: BigNumber,
totalStake: BigNumber,
alphaDenominator: BigNumber
alphaDenominator: BigNumber,
) {
const txReceipt = await this.getLibFeeMathTestContract().cobbDouglasSimplifiedInverse.awaitTransactionSuccessAsync(
totalRewards,
@ -597,7 +721,7 @@ export class StakingWrapper {
totalFees,
ownerStake,
totalStake,
alphaDenominator
alphaDenominator,
);
const output = await this.getLibFeeMathTestContract().cobbDouglasSimplifiedInverse.callAsync(
@ -606,32 +730,35 @@ export class StakingWrapper {
totalFees,
ownerStake,
totalStake,
alphaDenominator
alphaDenominator,
);
return output;
}
public toBaseUnitAmount(amount: BigNumber | number): BigNumber {
const decimals = 18;
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountAsBigNumber, decimals);
return baseUnitAmount;
}
public toFixedPoint(amount: BigNumber | number, decimals: number): BigNumber {
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
const scalar = Math.pow(10, decimals);
const amountAsFixedPoint = amountAsBigNumber.times(scalar);
return amountAsFixedPoint;
}
public toFloatingPoint(amount: BigNumber | number, decimals: number): BigNumber {
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
const scalar = Math.pow(10, decimals);
const amountAsFloatingPoint = amountAsBigNumber.dividedBy(scalar);
return amountAsFloatingPoint;
}
public trimFloat(amount: BigNumber | number, decimals: number): BigNumber {
const amountAsBigNumber = typeof(amount) === 'number' ? new BigNumber(amount) : amount;
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
const scalar = Math.pow(10, decimals);
const amountAsFloatingPoint = ((amountAsBigNumber.multipliedBy(scalar)).dividedToIntegerBy(1)).dividedBy(scalar);
const amountAsFloatingPoint = amountAsBigNumber
.multipliedBy(scalar)
.dividedToIntegerBy(1)
.dividedBy(scalar);
return amountAsFloatingPoint;
}
private _validateDeployedOrThrow() {

View File

@ -1,10 +1,10 @@
import { BigNumber } from '@0x/utils';
export interface StakingPoolApproval {
makerAddress: string,
poolId: string,
verifyingContractAddress: string,
chainId: number
makerAddress: string;
poolId: string;
verifyingContractAddress: string;
chainId: number;
}
export interface SignedStakingPoolApproval extends StakingPoolApproval {
@ -29,22 +29,22 @@ export interface DelegatorBalances extends StakerBalances {
}
export interface SimulationParams {
users: string[],
numberOfPools: number,
poolOperatorShares: number[],
stakeByPoolOperator: BigNumber[],
numberOfMakers: number,
numberOfMakersPerPool: number[],
protocolFeesByMaker: BigNumber[],
numberOfDelegators: number,
numberOfDelegatorsPerPool: number[],
stakeByDelegator: BigNumber[],
expectedFeesByPool: BigNumber[],
expectedPayoutByPool: BigNumber[],
expectedPayoutByPoolOperator: BigNumber[],
expectedMembersPayoutByPool: BigNumber[],
expectedPayoutByDelegator: BigNumber[],
exchangeAddress: string,
delegateInNextEpoch: Boolean,
withdrawByUndelegating: Boolean,
}
users: string[];
numberOfPools: number;
poolOperatorShares: number[];
stakeByPoolOperator: BigNumber[];
numberOfMakers: number;
numberOfMakersPerPool: number[];
protocolFeesByMaker: BigNumber[];
numberOfDelegators: number;
numberOfDelegatorsPerPool: number[];
stakeByDelegator: BigNumber[];
expectedFeesByPool: BigNumber[];
expectedPayoutByPool: BigNumber[];
expectedPayoutByPoolOperator: BigNumber[];
expectedMembersPayoutByPool: BigNumber[];
expectedPayoutByDelegator: BigNumber[];
exchangeAddress: string;
delegateInNextEpoch: Boolean;
withdrawByUndelegating: Boolean;
}

View File

@ -21,7 +21,6 @@ import { StakingWrapper } from './utils/staking_wrapper';
import { ERC20Wrapper, ERC20ProxyContract } from '@0x/contracts-asset-proxy';
import { StakingContract } from '../src';
import { StakerActor } from './actors/staker_actor';
import { DelegatorActor } from './actors/delegator_actor';
@ -87,12 +86,12 @@ describe('Staking Vaults', () => {
// should fail to create pool if it already exists
await expectTransactionFailedAsync(
stakingWrapper.rewardVaultCreatePoolAsync(poolId, operatorShare, stakingContractAddress),
RevertReason.PoolAlreadyExists
RevertReason.PoolAlreadyExists,
);
// should fail to create a pool from an address other than the staking contract
await expectTransactionFailedAsync(
stakingWrapper.rewardVaultCreatePoolAsync(poolId, operatorShare, notStakingContractAddress),
RevertReason.OnlyCallableByStakingContract
stakingWrapper.rewardVaultCreatePoolAsync(poolId, operatorShare, notStakingContractAddress),
RevertReason.OnlyCallableByStakingContract,
);
});
});

View File

@ -153,10 +153,7 @@ export const constants = {
STAKING_DOMAIN_VERSION: '1.0.0',
STAKING_POOL_APPROVAL_SCHEMA: {
name: 'StakingPoolApproval',
parameters: [
{ name: 'poolId', type: 'bytes32' },
{ name: 'makerAddress', type: 'address' },
],
parameters: [{ name: 'poolId', type: 'bytes32' }, { name: 'makerAddress', type: 'address' }],
},
ERC20_METHOD_ABI,
ERC721_METHOD_ABI,

View File

@ -133,13 +133,13 @@ export const eip712Utils = {
poolId: string,
makerAddress: string,
verifyingContractAddress: string,
chainId: number
chainId: number,
): EIP712TypedData => {
const domain = {
name: constants.STAKING_DOMAIN_NAME,
version: constants.STAKING_DOMAIN_VERSION,
verifyingContractAddress,
chainId
chainId,
};
const approval = {
poolId,