@0x/contract-staking: Update CHANGELOG.
`@0x/contract-staking`: Add `DEFAULT_HYPER_PARAMETERS` to test constants. `@0x/contract-staking`: Appease linter gods. `@0x/contract-staking`: Remove `setCobbDouglasAlpha()` tests. `@0x/contract-staking`: Add `tune()` tests.
This commit is contained in:
@@ -33,6 +33,14 @@
|
||||
{
|
||||
"note": "Tests for new stake management mechanics.",
|
||||
"pr": 2126
|
||||
},
|
||||
{
|
||||
"note": "Add `init()` pattern to contracts.",
|
||||
"pr": 2131
|
||||
},
|
||||
{
|
||||
"note": "Replace `MixinDeploymentConstants` with `MixinHyperParameters`.",
|
||||
"pr": 2131
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -49,6 +49,13 @@ contract Staking is
|
||||
MixinStakingPool,
|
||||
MixinExchangeFees
|
||||
{
|
||||
// this contract can receive ETH
|
||||
// solhint-disable no-empty-blocks
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{}
|
||||
|
||||
/// @dev Initialize storage owned by this contract.
|
||||
/// This function should not be called directly.
|
||||
/// The StakingProxy contract will call it in `attachStakingContract()`.
|
||||
@@ -60,11 +67,4 @@ contract Staking is
|
||||
// not to accidentally overwrite existing state.
|
||||
_initMixinScheduler();
|
||||
}
|
||||
|
||||
// this contract can receive ETH
|
||||
// solhint-disable no-empty-blocks
|
||||
function ()
|
||||
external
|
||||
payable
|
||||
{}
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ import "./immutable/MixinHyperParameters.sol";
|
||||
import "./interfaces/IStorageInit.sol";
|
||||
import "./interfaces/IStakingProxy.sol";
|
||||
|
||||
|
||||
contract StakingProxy is
|
||||
IStakingEvents,
|
||||
IStakingProxy,
|
||||
|
||||
@@ -38,8 +38,6 @@ contract MixinConstants
|
||||
|
||||
uint64 constant internal INITIAL_EPOCH = 0;
|
||||
|
||||
uint64 constant internal INITIAL_TIMELOCK_PERIOD = INITIAL_EPOCH;
|
||||
|
||||
uint256 constant internal MIN_TOKEN_VALUE = 10**18;
|
||||
|
||||
// TODO(dorothy-zbornak): Remove when signatures are removed from maker handshake.
|
||||
|
||||
@@ -24,6 +24,7 @@ import "../interfaces/IStakingEvents.sol";
|
||||
import "../libs/LibStakingRichErrors.sol";
|
||||
import "./MixinConstants.sol";
|
||||
|
||||
|
||||
contract MixinHyperParameters is
|
||||
IStakingEvents,
|
||||
MixinConstants,
|
||||
@@ -40,30 +41,6 @@ contract MixinHyperParameters is
|
||||
// Denominator for cobb douglas alpha factor.
|
||||
uint256 internal cobbDouglasAlphaDenomintor = 2;
|
||||
|
||||
/// @dev Retrives all tuned values.
|
||||
/// @return _epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
/// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
|
||||
/// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
|
||||
/// @return _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor.
|
||||
function getHyperParameters()
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256 _epochDurationInSeconds,
|
||||
uint32 _rewardDelegatedStakeWeight,
|
||||
uint256 _minimumPoolStake,
|
||||
uint256 _cobbDouglasAlphaNumerator,
|
||||
uint256 _cobbDouglasAlphaDenomintor
|
||||
)
|
||||
{
|
||||
_epochDurationInSeconds = epochDurationInSeconds;
|
||||
_rewardDelegatedStakeWeight = rewardDelegatedStakeWeight;
|
||||
_minimumPoolStake = minimumPoolStake;
|
||||
_cobbDouglasAlphaNumerator = cobbDouglasAlphaNumerator;
|
||||
_cobbDouglasAlphaDenomintor = cobbDouglasAlphaDenomintor;
|
||||
}
|
||||
|
||||
/// @dev Set all hyperparameters at once.
|
||||
/// @param _epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
@@ -100,6 +77,30 @@ contract MixinHyperParameters is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Retrives all tuned values.
|
||||
/// @return _epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
/// @return _minimumPoolStake Minimum amount of stake required in a pool to collect rewards.
|
||||
/// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
|
||||
/// @return _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor.
|
||||
function getHyperParameters()
|
||||
external
|
||||
view
|
||||
returns (
|
||||
uint256 _epochDurationInSeconds,
|
||||
uint32 _rewardDelegatedStakeWeight,
|
||||
uint256 _minimumPoolStake,
|
||||
uint256 _cobbDouglasAlphaNumerator,
|
||||
uint256 _cobbDouglasAlphaDenomintor
|
||||
)
|
||||
{
|
||||
_epochDurationInSeconds = epochDurationInSeconds;
|
||||
_rewardDelegatedStakeWeight = rewardDelegatedStakeWeight;
|
||||
_minimumPoolStake = minimumPoolStake;
|
||||
_cobbDouglasAlphaNumerator = cobbDouglasAlphaNumerator;
|
||||
_cobbDouglasAlphaDenomintor = cobbDouglasAlphaDenomintor;
|
||||
}
|
||||
|
||||
/// @dev Asserts that cobb douglas alpha values are valid.
|
||||
function _assertValidCobbDouglasAlpha(
|
||||
uint256 numerator,
|
||||
|
||||
@@ -88,6 +88,7 @@ contract MixinScheduler is
|
||||
)
|
||||
);
|
||||
}
|
||||
// solhint-disable-next-line
|
||||
currentEpochStartTimeInSeconds = block.timestamp;
|
||||
}
|
||||
|
||||
|
||||
@@ -11,6 +11,7 @@ import * as IStaking from '../generated-artifacts/IStaking.json';
|
||||
import * as IStakingEvents from '../generated-artifacts/IStakingEvents.json';
|
||||
import * as IStakingPoolRewardVault from '../generated-artifacts/IStakingPoolRewardVault.json';
|
||||
import * as IStakingProxy from '../generated-artifacts/IStakingProxy.json';
|
||||
import * as IStorageInit from '../generated-artifacts/IStorageInit.json';
|
||||
import * as IStructs from '../generated-artifacts/IStructs.json';
|
||||
import * as IVaultCore from '../generated-artifacts/IVaultCore.json';
|
||||
import * as IZrxVault from '../generated-artifacts/IZrxVault.json';
|
||||
@@ -59,6 +60,7 @@ export const artifacts = {
|
||||
IStakingEvents: IStakingEvents as ContractArtifact,
|
||||
IStakingPoolRewardVault: IStakingPoolRewardVault as ContractArtifact,
|
||||
IStakingProxy: IStakingProxy as ContractArtifact,
|
||||
IStorageInit: IStorageInit as ContractArtifact,
|
||||
IStructs: IStructs as ContractArtifact,
|
||||
IVaultCore: IVaultCore as ContractArtifact,
|
||||
IZrxVault: IZrxVault as ContractArtifact,
|
||||
|
||||
@@ -9,6 +9,7 @@ export * from '../generated-wrappers/i_staking';
|
||||
export * from '../generated-wrappers/i_staking_events';
|
||||
export * from '../generated-wrappers/i_staking_pool_reward_vault';
|
||||
export * from '../generated-wrappers/i_staking_proxy';
|
||||
export * from '../generated-wrappers/i_storage_init';
|
||||
export * from '../generated-wrappers/i_structs';
|
||||
export * from '../generated-wrappers/i_vault_core';
|
||||
export * from '../generated-wrappers/i_zrx_vault';
|
||||
|
||||
@@ -1,16 +1,10 @@
|
||||
import { blockchainTests, constants, expect, filterLogsToArguments } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber, OwnableRevertErrors } from '@0x/utils';
|
||||
import { blockchainTests, Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
TestCobbDouglasCobbDouglasAlphaChangedEventArgs,
|
||||
TestCobbDouglasContract,
|
||||
TestCobbDouglasEvents,
|
||||
} from '../src/';
|
||||
import { artifacts, TestCobbDouglasContract } from '../src/';
|
||||
|
||||
import { assertRoughlyEquals, getRandomInteger, getRandomPortion, Numberish, toDecimal } from './utils/number_utils';
|
||||
import { assertRoughlyEquals, getRandomInteger, getRandomPortion, toDecimal } from './utils/number_utils';
|
||||
|
||||
// tslint:disable: no-unnecessary-type-assertion
|
||||
blockchainTests('Cobb-Douglas', env => {
|
||||
@@ -31,72 +25,6 @@ blockchainTests('Cobb-Douglas', env => {
|
||||
);
|
||||
});
|
||||
|
||||
blockchainTests.resets('setCobbDouglasAlpha()', () => {
|
||||
const NEGATIVE_ONE = constants.MAX_UINT256.minus(1);
|
||||
|
||||
it('throws if not called by owner', async () => {
|
||||
const [n, d] = [new BigNumber(1), new BigNumber(2)];
|
||||
const tx = testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(n, d, { from: notOwnerAddress });
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with int256(numerator) < 0', async () => {
|
||||
const [n, d] = [NEGATIVE_ONE, NEGATIVE_ONE];
|
||||
const tx = testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(n, d);
|
||||
const expectedError = new StakingRevertErrors.InvalidCobbDouglasAlphaError(n, d);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with int256(denominator) < 0', async () => {
|
||||
const [n, d] = [new BigNumber(1), NEGATIVE_ONE];
|
||||
const tx = testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(n, d);
|
||||
const expectedError = new StakingRevertErrors.InvalidCobbDouglasAlphaError(n, d);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with denominator == 0', async () => {
|
||||
const [n, d] = [new BigNumber(0), new BigNumber(0)];
|
||||
const tx = testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(n, d);
|
||||
const expectedError = new StakingRevertErrors.InvalidCobbDouglasAlphaError(n, d);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with numerator > denominator', async () => {
|
||||
const [n, d] = [new BigNumber(2), new BigNumber(1)];
|
||||
const tx = testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(n, d);
|
||||
const expectedError = new StakingRevertErrors.InvalidCobbDouglasAlphaError(n, d);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
async function setCobbDouglasAlphaAndAssertEffectsAsync(n: Numberish, d: Numberish): Promise<void> {
|
||||
const [_n, _d] = [new BigNumber(n), new BigNumber(d)];
|
||||
const receipt = await testContract.setCobbDouglasAlpha.awaitTransactionSuccessAsync(_n, _d);
|
||||
const logs = filterLogsToArguments<TestCobbDouglasCobbDouglasAlphaChangedEventArgs>(
|
||||
receipt.logs,
|
||||
TestCobbDouglasEvents.CobbDouglasAlphaChanged,
|
||||
);
|
||||
expect(logs.length).to.eq(1);
|
||||
expect(logs[0].numerator).to.bignumber.eq(_n);
|
||||
expect(logs[0].denominator).to.bignumber.eq(_d);
|
||||
const [actualNumerator, actualDenominator] = await testContract.getCobbDouglasAlpha.callAsync();
|
||||
expect(actualNumerator).to.bignumber.eq(_n);
|
||||
expect(actualDenominator).to.bignumber.eq(_d);
|
||||
}
|
||||
|
||||
it('accepts numerator == denominator', async () => {
|
||||
return setCobbDouglasAlphaAndAssertEffectsAsync(1, 1);
|
||||
});
|
||||
|
||||
it('accepts numerator < denominator', async () => {
|
||||
return setCobbDouglasAlphaAndAssertEffectsAsync(1, 2);
|
||||
});
|
||||
|
||||
it('accepts numerator == 0', async () => {
|
||||
return setCobbDouglasAlphaAndAssertEffectsAsync(0, 1);
|
||||
});
|
||||
});
|
||||
|
||||
describe('cobbDouglas()', () => {
|
||||
interface CobbDouglasParams {
|
||||
totalRewards: Numberish;
|
||||
|
||||
@@ -29,7 +29,7 @@ blockchainTests('Epochs', env => {
|
||||
it('basic epochs & timeLock periods', async () => {
|
||||
///// 1/3 Validate Assumptions /////
|
||||
expect(await stakingApiWrapper.stakingContract.getEpochDurationInSeconds.callAsync()).to.be.bignumber.equal(
|
||||
stakingConstants.EPOCH_DURATION_IN_SECONDS,
|
||||
stakingConstants.DEFAULT_HYPER_PARAMETERS.epochDurationInSeconds,
|
||||
);
|
||||
///// 2/3 Validate Initial Epoch & TimeLock Period /////
|
||||
{
|
||||
|
||||
159
contracts/staking/test/hyper_parameters.ts
Normal file
159
contracts/staking/test/hyper_parameters.ts
Normal file
@@ -0,0 +1,159 @@
|
||||
import { blockchainTests, constants, expect, filterLogsToArguments, Numberish } from '@0x/contracts-test-utils';
|
||||
import { StakingRevertErrors } from '@0x/order-utils';
|
||||
import { BigNumber, OwnableRevertErrors } from '@0x/utils';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, IStakingEventsTunedEventArgs, MixinHyperParametersContract } from '../src/';
|
||||
|
||||
blockchainTests('Hyper-Parameters', env => {
|
||||
let testContract: MixinHyperParametersContract;
|
||||
let ownerAddress: string;
|
||||
let notOwnerAddress: string;
|
||||
|
||||
before(async () => {
|
||||
[ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync();
|
||||
testContract = await MixinHyperParametersContract.deployFrom0xArtifactAsync(
|
||||
artifacts.MixinHyperParameters,
|
||||
env.provider,
|
||||
env.txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
});
|
||||
|
||||
blockchainTests.resets('tune()', () => {
|
||||
interface HyperParameters {
|
||||
epochDurationInSeconds: Numberish;
|
||||
rewardDelegatedStakeWeight: Numberish;
|
||||
minimumPoolStake: Numberish;
|
||||
cobbDouglasAlphaNumerator: Numberish;
|
||||
cobbDouglasAlphaDenomintor: Numberish;
|
||||
}
|
||||
|
||||
const TWO_WEEKS = 14 * 24 * 60 * 60;
|
||||
const PPM_90_PERCENT = 10 ** 6 * 0.9;
|
||||
const DEFAULT_HYPER_PARAMETERS = {
|
||||
epochDurationInSeconds: TWO_WEEKS,
|
||||
rewardDelegatedStakeWeight: PPM_90_PERCENT,
|
||||
minimumPoolStake: '100e18',
|
||||
cobbDouglasAlphaNumerator: 1,
|
||||
cobbDouglasAlphaDenomintor: 2,
|
||||
};
|
||||
|
||||
async function tuneAndAssertAsync(params: Partial<HyperParameters>, from?: string): Promise<void> {
|
||||
const _params = {
|
||||
...DEFAULT_HYPER_PARAMETERS,
|
||||
...params,
|
||||
};
|
||||
const receipt = await testContract.tune.awaitTransactionSuccessAsync(
|
||||
new BigNumber(_params.epochDurationInSeconds),
|
||||
new BigNumber(_params.rewardDelegatedStakeWeight),
|
||||
new BigNumber(_params.minimumPoolStake),
|
||||
new BigNumber(_params.cobbDouglasAlphaNumerator),
|
||||
new BigNumber(_params.cobbDouglasAlphaDenomintor),
|
||||
{ from },
|
||||
);
|
||||
// Assert event.
|
||||
expect(receipt.logs.length).to.eq(1);
|
||||
const event = filterLogsToArguments<IStakingEventsTunedEventArgs>(receipt.logs, 'Tuned')[0];
|
||||
expect(event.epochDurationInSeconds).to.bignumber.eq(_params.epochDurationInSeconds);
|
||||
expect(event.rewardDelegatedStakeWeight).to.bignumber.eq(_params.rewardDelegatedStakeWeight);
|
||||
expect(event.minimumPoolStake).to.bignumber.eq(_params.minimumPoolStake);
|
||||
expect(event.cobbDouglasAlphaNumerator).to.bignumber.eq(_params.cobbDouglasAlphaNumerator);
|
||||
expect(event.cobbDouglasAlphaDenomintor).to.bignumber.eq(_params.cobbDouglasAlphaDenomintor);
|
||||
// Assert `getHyperParameters()`.
|
||||
const actual = await testContract.getHyperParameters.callAsync();
|
||||
expect(actual[0]).to.bignumber.eq(_params.epochDurationInSeconds);
|
||||
expect(actual[1]).to.bignumber.eq(_params.rewardDelegatedStakeWeight);
|
||||
expect(actual[2]).to.bignumber.eq(_params.minimumPoolStake);
|
||||
expect(actual[3]).to.bignumber.eq(_params.cobbDouglasAlphaNumerator);
|
||||
expect(actual[4]).to.bignumber.eq(_params.cobbDouglasAlphaDenomintor);
|
||||
}
|
||||
|
||||
it('throws if not called by owner', async () => {
|
||||
const tx = tuneAndAssertAsync({}, notOwnerAddress);
|
||||
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('works if called by owner', async () => {
|
||||
return tuneAndAssertAsync({});
|
||||
});
|
||||
|
||||
describe('cobb-douglas alpha', () => {
|
||||
const NEGATIVE_ONE = constants.MAX_UINT256.minus(1);
|
||||
|
||||
it('throws with int256(numerator) < 0', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: NEGATIVE_ONE,
|
||||
cobbDouglasAlphaDenomintor: NEGATIVE_ONE,
|
||||
};
|
||||
const tx = tuneAndAssertAsync(params);
|
||||
const expectedError = new StakingRevertErrors.InvalidTuningValueError(
|
||||
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with int256(denominator) < 0', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 1,
|
||||
cobbDouglasAlphaDenomintor: NEGATIVE_ONE,
|
||||
};
|
||||
const tx = tuneAndAssertAsync(params);
|
||||
const expectedError = new StakingRevertErrors.InvalidTuningValueError(
|
||||
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with denominator == 0', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 0,
|
||||
cobbDouglasAlphaDenomintor: 0,
|
||||
};
|
||||
const tx = tuneAndAssertAsync(params);
|
||||
const expectedError = new StakingRevertErrors.InvalidTuningValueError(
|
||||
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('throws with numerator > denominator', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 2,
|
||||
cobbDouglasAlphaDenomintor: 1,
|
||||
};
|
||||
const tx = tuneAndAssertAsync(params);
|
||||
const expectedError = new StakingRevertErrors.InvalidTuningValueError(
|
||||
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha,
|
||||
);
|
||||
return expect(tx).to.revertWith(expectedError);
|
||||
});
|
||||
|
||||
it('accepts numerator == denominator', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 1,
|
||||
cobbDouglasAlphaDenomintor: 1,
|
||||
};
|
||||
return tuneAndAssertAsync(params);
|
||||
});
|
||||
|
||||
it('accepts numerator < denominator', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 1,
|
||||
cobbDouglasAlphaDenomintor: 2,
|
||||
};
|
||||
return tuneAndAssertAsync(params);
|
||||
});
|
||||
|
||||
it('accepts numerator == 0', async () => {
|
||||
const params = {
|
||||
cobbDouglasAlphaNumerator: 0,
|
||||
cobbDouglasAlphaDenomintor: 1,
|
||||
};
|
||||
return tuneAndAssertAsync(params);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
// tslint:enable:no-unnecessary-type-assertion
|
||||
@@ -1,11 +1,11 @@
|
||||
import { blockchainTests, expect, hexRandom } from '@0x/contracts-test-utils';
|
||||
import { blockchainTests, expect, hexRandom, Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, FixedMathRevertErrors } from '@0x/utils';
|
||||
import { Decimal } from 'decimal.js';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import { artifacts, TestLibFixedMathContract } from '../src/';
|
||||
|
||||
import { assertRoughlyEquals, fromFixed, Numberish, toDecimal, toFixed } from './utils/number_utils';
|
||||
import { assertRoughlyEquals, fromFixed, toDecimal, toFixed } from './utils/number_utils';
|
||||
|
||||
blockchainTests('LibFixedMath', env => {
|
||||
let testContract: TestLibFixedMathContract;
|
||||
|
||||
@@ -41,7 +41,12 @@ blockchainTests.resets('Testing Rewards', env => {
|
||||
erc20Wrapper = new ERC20Wrapper(env.provider, accounts, owner);
|
||||
// deploy staking contracts
|
||||
stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper, artifacts.TestStaking);
|
||||
|
||||
// set up hyper-parameters
|
||||
await stakingWrapper.stakingContract.tuneAsync({
|
||||
minimumPoolStake: new BigNumber(0),
|
||||
cobbDouglasAlphaNumerator: new BigNumber(1),
|
||||
cobbDouglasAlphaDenomintor: new BigNumber(6),
|
||||
});
|
||||
// setup stakers
|
||||
stakers = [new StakerActor(actors[0], stakingApiWrapper), new StakerActor(actors[1], stakingApiWrapper)];
|
||||
// setup pools
|
||||
|
||||
@@ -1,16 +1,22 @@
|
||||
import { constants as testConstants } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
|
||||
const TWO_WEEKS = 14 * 24 * 60 * 60;
|
||||
export const constants = {
|
||||
MAX_UINT_64: new BigNumber(2).pow(256).minus(1),
|
||||
TOKEN_MULTIPLIER: new BigNumber(10).pow(18),
|
||||
TOKEN_MULTIPLIER: testConstants.DUMMY_TOKEN_DECIMALS,
|
||||
INITIAL_POOL_ID: '0x0000000000000000000000000000000100000000000000000000000000000000',
|
||||
SECOND_POOL_ID: '0x0000000000000000000000000000000200000000000000000000000000000000',
|
||||
NIL_POOL_ID: '0x0000000000000000000000000000000000000000000000000000000000000000',
|
||||
NIL_ADDRESS: '0x0000000000000000000000000000000000000000',
|
||||
INITIAL_EPOCH: new BigNumber(0),
|
||||
INITIAL_TIMELOCK_PERIOD: new BigNumber(0),
|
||||
EPOCH_DURATION_IN_SECONDS: new BigNumber(1000), // @TODO SET FOR DEPLOYMENT*/
|
||||
TIMELOCK_DURATION_IN_EPOCHS: new BigNumber(3), // @TODO SET FOR DEPLOYMENT
|
||||
CHAIN_ID: 1,
|
||||
MAX_MAKERS_IN_POOL: 10, // @TODO SET FOR DEPLOYMENT,
|
||||
DEFAULT_HYPER_PARAMETERS: {
|
||||
epochDurationInSeconds: new BigNumber(TWO_WEEKS),
|
||||
rewardDelegatedStakeWeight: new BigNumber(0.9 * 1e6), // 90%
|
||||
minimumPoolStake: testConstants.DUMMY_TOKEN_DECIMALS.times(100), // 100 ZRX
|
||||
maxMakersInPool: new BigNumber(10),
|
||||
cobbDouglasAlphaNumerator: new BigNumber(1),
|
||||
cobbDouglasAlphaDenomintor: new BigNumber(2),
|
||||
},
|
||||
};
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { expect } from '@0x/contracts-test-utils';
|
||||
import { expect, Numberish } from '@0x/contracts-test-utils';
|
||||
import { BigNumber } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import * as crypto from 'crypto';
|
||||
@@ -6,8 +6,6 @@ import { Decimal } from 'decimal.js';
|
||||
|
||||
Decimal.set({ precision: 80 });
|
||||
|
||||
export type Numberish = BigNumber | string | number;
|
||||
|
||||
/**
|
||||
* Convert `x` to a `Decimal` type.
|
||||
*/
|
||||
|
||||
544
contracts/staking/test/utils/staking_wrapper.ts
Normal file
544
contracts/staking/test/utils/staking_wrapper.ts
Normal file
@@ -0,0 +1,544 @@
|
||||
import { ERC20ProxyContract } from '@0x/contracts-asset-proxy';
|
||||
import { artifacts as erc20Artifacts, DummyERC20TokenContract } from '@0x/contracts-erc20';
|
||||
import { LogDecoder, txDefaults } from '@0x/contracts-test-utils';
|
||||
import { BigNumber, logUtils } from '@0x/utils';
|
||||
import { Web3Wrapper } from '@0x/web3-wrapper';
|
||||
import { Provider, TransactionReceiptWithDecodedLogs } from 'ethereum-types';
|
||||
import * as _ from 'lodash';
|
||||
|
||||
import {
|
||||
artifacts,
|
||||
EthVaultContract,
|
||||
ReadOnlyProxyContract,
|
||||
StakingContract,
|
||||
StakingPoolRewardVaultContract,
|
||||
StakingProxyContract,
|
||||
ZrxVaultContract,
|
||||
} from '../../src';
|
||||
|
||||
import { constants } from './constants';
|
||||
import { HyperParameters, SignedStakingPoolApproval, StakeBalance } from './types';
|
||||
|
||||
export class StakingWrapper {
|
||||
private readonly _web3Wrapper: Web3Wrapper;
|
||||
private readonly _provider: Provider;
|
||||
private readonly _logDecoder: LogDecoder;
|
||||
private readonly _ownerAddress: string;
|
||||
private readonly _erc20ProxyContract: ERC20ProxyContract;
|
||||
private readonly _zrxTokenContract: DummyERC20TokenContract;
|
||||
private _stakingContractIfExists?: StakingContract;
|
||||
private _stakingProxyContractIfExists?: StakingProxyContract;
|
||||
private _zrxVaultContractIfExists?: ZrxVaultContract;
|
||||
private _ethVaultContractIfExists?: EthVaultContract;
|
||||
private _rewardVaultContractIfExists?: StakingPoolRewardVaultContract;
|
||||
private _readOnlyProxyContractIfExists?: ReadOnlyProxyContract;
|
||||
public static toBaseUnitAmount(amount: BigNumber | number): BigNumber {
|
||||
const decimals = 18;
|
||||
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
|
||||
const baseUnitAmount = Web3Wrapper.toBaseUnitAmount(amountAsBigNumber, decimals);
|
||||
return baseUnitAmount;
|
||||
}
|
||||
public static toFixedPoint(amount: BigNumber | number, decimals: number): BigNumber {
|
||||
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
|
||||
const scalar = Math.pow(10, decimals);
|
||||
const amountAsFixedPoint = amountAsBigNumber.times(scalar);
|
||||
return amountAsFixedPoint;
|
||||
}
|
||||
public static toFloatingPoint(amount: BigNumber | number, decimals: number): BigNumber {
|
||||
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
|
||||
const scalar = Math.pow(10, decimals);
|
||||
const amountAsFloatingPoint = amountAsBigNumber.dividedBy(scalar);
|
||||
return amountAsFloatingPoint;
|
||||
}
|
||||
public static trimFloat(amount: BigNumber | number, decimals: number): BigNumber {
|
||||
const amountAsBigNumber = typeof amount === 'number' ? new BigNumber(amount) : amount;
|
||||
const scalar = Math.pow(10, decimals);
|
||||
const amountAsFloatingPoint = amountAsBigNumber
|
||||
.multipliedBy(scalar)
|
||||
.dividedToIntegerBy(1)
|
||||
.dividedBy(scalar);
|
||||
return amountAsFloatingPoint;
|
||||
}
|
||||
constructor(
|
||||
provider: Provider,
|
||||
ownerAddres: string,
|
||||
erc20ProxyContract: ERC20ProxyContract,
|
||||
zrxTokenContract: DummyERC20TokenContract,
|
||||
) {
|
||||
this._web3Wrapper = new Web3Wrapper(provider);
|
||||
this._provider = provider;
|
||||
const decoderArtifacts = _.merge(artifacts, erc20Artifacts);
|
||||
this._logDecoder = new LogDecoder(this._web3Wrapper, decoderArtifacts);
|
||||
this._ownerAddress = ownerAddres;
|
||||
this._erc20ProxyContract = erc20ProxyContract;
|
||||
this._zrxTokenContract = zrxTokenContract;
|
||||
}
|
||||
public getStakingContract(): StakingContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._stakingContractIfExists as StakingContract;
|
||||
}
|
||||
public getStakingProxyContract(): StakingProxyContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._stakingProxyContractIfExists as StakingProxyContract;
|
||||
}
|
||||
public getZrxVaultContract(): ZrxVaultContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._zrxVaultContractIfExists as ZrxVaultContract;
|
||||
}
|
||||
public getEthVaultContract(): EthVaultContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._ethVaultContractIfExists as EthVaultContract;
|
||||
}
|
||||
public getStakingPoolRewardVaultContract(): StakingPoolRewardVaultContract {
|
||||
this._validateDeployedOrThrow();
|
||||
return this._rewardVaultContractIfExists as StakingPoolRewardVaultContract;
|
||||
}
|
||||
public async deployAndConfigureContractsAsync(): Promise<void> {
|
||||
// deploy read-only proxy
|
||||
this._readOnlyProxyContractIfExists = await ReadOnlyProxyContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ReadOnlyProxy,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
// deploy zrx vault
|
||||
this._zrxVaultContractIfExists = await ZrxVaultContract.deployFrom0xArtifactAsync(
|
||||
artifacts.ZrxVault,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
this._erc20ProxyContract.address,
|
||||
this._zrxTokenContract.address,
|
||||
);
|
||||
// deploy eth vault
|
||||
this._ethVaultContractIfExists = await EthVaultContract.deployFrom0xArtifactAsync(
|
||||
artifacts.EthVault,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
// deploy reward vault
|
||||
this._rewardVaultContractIfExists = await StakingPoolRewardVaultContract.deployFrom0xArtifactAsync(
|
||||
artifacts.StakingPoolRewardVault,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
// set eth vault in reward vault
|
||||
await this._rewardVaultContractIfExists.setEthVault.sendTransactionAsync(
|
||||
this._ethVaultContractIfExists.address,
|
||||
);
|
||||
// configure erc20 proxy to accept calls from zrx vault
|
||||
await this._erc20ProxyContract.addAuthorizedAddress.awaitTransactionSuccessAsync(
|
||||
this._zrxVaultContractIfExists.address,
|
||||
);
|
||||
// deploy staking contract
|
||||
this._stakingContractIfExists = await StakingContract.deployFrom0xArtifactAsync(
|
||||
artifacts.Staking,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
);
|
||||
// deploy staking proxy
|
||||
this._stakingProxyContractIfExists = await StakingProxyContract.deployFrom0xArtifactAsync(
|
||||
artifacts.StakingProxy,
|
||||
this._provider,
|
||||
txDefaults,
|
||||
artifacts,
|
||||
this._stakingContractIfExists.address,
|
||||
this._readOnlyProxyContractIfExists.address,
|
||||
);
|
||||
// set staking proxy contract in zrx vault
|
||||
await this._zrxVaultContractIfExists.setStakingContract.awaitTransactionSuccessAsync(
|
||||
this._stakingProxyContractIfExists.address,
|
||||
);
|
||||
// set zrx vault in staking contract
|
||||
const setZrxVaultCalldata = this._stakingContractIfExists.setZrxVault.getABIEncodedTransactionData(
|
||||
this._zrxVaultContractIfExists.address,
|
||||
);
|
||||
const setZrxVaultTxData = {
|
||||
from: this._ownerAddress,
|
||||
to: this._stakingProxyContractIfExists.address,
|
||||
data: setZrxVaultCalldata,
|
||||
};
|
||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await this._web3Wrapper.sendTransactionAsync(setZrxVaultTxData),
|
||||
);
|
||||
// set staking proxy contract in reward vault
|
||||
await this._rewardVaultContractIfExists.setStakingContract.awaitTransactionSuccessAsync(
|
||||
this._stakingProxyContractIfExists.address,
|
||||
);
|
||||
// set reward vault in staking contract
|
||||
const setStakingPoolRewardVaultCalldata = this._stakingContractIfExists.setStakingPoolRewardVault.getABIEncodedTransactionData(
|
||||
this._rewardVaultContractIfExists.address,
|
||||
);
|
||||
const setStakingPoolRewardVaultTxData = {
|
||||
from: this._ownerAddress,
|
||||
to: this._stakingProxyContractIfExists.address,
|
||||
data: setStakingPoolRewardVaultCalldata,
|
||||
};
|
||||
await this._web3Wrapper.awaitTransactionSuccessAsync(
|
||||
await this._web3Wrapper.sendTransactionAsync(setStakingPoolRewardVaultTxData),
|
||||
);
|
||||
}
|
||||
public async setReadOnlyModeAsync(readOnlyMode: boolean): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const txReceipt = await this.getStakingProxyContract().setReadOnlyMode.awaitTransactionSuccessAsync(
|
||||
readOnlyMode,
|
||||
);
|
||||
return txReceipt;
|
||||
}
|
||||
public async getEthBalanceAsync(owner: string): Promise<BigNumber> {
|
||||
const balance = this._web3Wrapper.getBalanceInWeiAsync(owner);
|
||||
return balance;
|
||||
}
|
||||
public async tuneAsync(params: Partial<HyperParameters>): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const _params = {
|
||||
...constants.DEFAULT_HYPER_PARAMETERS,
|
||||
...params,
|
||||
};
|
||||
const calldata = this.getStakingContract().tune.getABIEncodedTransactionData(
|
||||
_params.epochDurationInSeconds,
|
||||
_params.rewardDelegatedStakeWeight,
|
||||
_params.minimumPoolStake,
|
||||
_params.cobbDouglasAlphaNumerator,
|
||||
_params.cobbDouglasAlphaDenomintor,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata);
|
||||
return txReceipt;
|
||||
}
|
||||
///// STAKE /////
|
||||
public async stakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().stake.getABIEncodedTransactionData(amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
public async unstakeAsync(owner: string, amount: BigNumber): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().unstake.getABIEncodedTransactionData(amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
public async moveStakeAsync(
|
||||
owner: string,
|
||||
_fromStatus: {
|
||||
status: number;
|
||||
poolId?: string;
|
||||
},
|
||||
_toStatus: {
|
||||
status: number;
|
||||
poolId?: string;
|
||||
},
|
||||
amount: BigNumber,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const fromStatus = {
|
||||
status: _fromStatus.status,
|
||||
poolId: _fromStatus.poolId !== undefined ? _fromStatus.poolId : constants.NIL_POOL_ID,
|
||||
};
|
||||
const toStatus = {
|
||||
status: _toStatus.status,
|
||||
poolId: _toStatus.poolId !== undefined ? _toStatus.poolId : constants.NIL_POOL_ID,
|
||||
};
|
||||
const calldata = this.getStakingContract().moveStake.getABIEncodedTransactionData(fromStatus, toStatus, amount);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, owner);
|
||||
return txReceipt;
|
||||
}
|
||||
///// STAKE BALANCES /////
|
||||
public async getTotalStakeAsync(owner: string): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getTotalStake.getABIEncodedTransactionData(owner);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getTotalStake.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getActiveStakeAsync(owner: string): Promise<StakeBalance> {
|
||||
const calldata = this.getStakingContract().getActiveStake.getABIEncodedTransactionData(owner);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getActiveStake.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getInactiveStakeAsync(owner: string): Promise<StakeBalance> {
|
||||
const calldata = this.getStakingContract().getInactiveStake.getABIEncodedTransactionData(owner);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getInactiveStake.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getWithdrawableStakeAsync(owner: string): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getWithdrawableStake.getABIEncodedTransactionData(owner);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getWithdrawableStake.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getStakeDelegatedByOwnerAsync(owner: string): Promise<StakeBalance> {
|
||||
const calldata = this.getStakingContract().getStakeDelegatedByOwner.getABIEncodedTransactionData(owner);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getStakeDelegatedByOwner.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getStakeDelegatedToPoolByOwnerAsync(poolId: string, owner: string): Promise<StakeBalance> {
|
||||
const calldata = this.getStakingContract().getStakeDelegatedToPoolByOwner.getABIEncodedTransactionData(
|
||||
owner,
|
||||
poolId,
|
||||
);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getStakeDelegatedToPoolByOwner.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getTotalStakeDelegatedToPoolAsync(poolId: string): Promise<StakeBalance> {
|
||||
const calldata = this.getStakingContract().getTotalStakeDelegatedToPool.getABIEncodedTransactionData(poolId);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getTotalStakeDelegatedToPool.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
///// POOLS /////
|
||||
public async getNextStakingPoolIdAsync(): Promise<string> {
|
||||
const calldata = this.getStakingContract().getNextStakingPoolId.getABIEncodedTransactionData();
|
||||
const nextPoolId = await this._callAsync(calldata);
|
||||
return nextPoolId;
|
||||
}
|
||||
public async createStakingPoolAsync(
|
||||
operatorAddress: string,
|
||||
operatorShare: number,
|
||||
addOperatorAsMaker: boolean,
|
||||
): Promise<string> {
|
||||
const calldata = this.getStakingContract().createStakingPool.getABIEncodedTransactionData(
|
||||
operatorShare,
|
||||
addOperatorAsMaker,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
|
||||
const createStakingPoolLog = this._logDecoder.decodeLogOrThrow(txReceipt.logs[0]);
|
||||
const poolId = (createStakingPoolLog as any).args.poolId;
|
||||
return poolId;
|
||||
}
|
||||
public async joinStakingPoolAsMakerAsync(
|
||||
poolId: string,
|
||||
makerAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().joinStakingPoolAsMaker.getABIEncodedTransactionData(poolId);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, makerAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
public async addMakerToStakingPoolAsync(
|
||||
poolId: string,
|
||||
makerAddress: string,
|
||||
operatorAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().addMakerToStakingPool.getABIEncodedTransactionData(
|
||||
poolId,
|
||||
makerAddress,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
public async removeMakerFromStakingPoolAsync(
|
||||
poolId: string,
|
||||
makerAddress: string,
|
||||
operatorAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().removeMakerFromStakingPool.getABIEncodedTransactionData(
|
||||
poolId,
|
||||
makerAddress,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, operatorAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
public async getStakingPoolIdOfMakerAsync(makerAddress: string): Promise<string> {
|
||||
const calldata = this.getStakingContract().getStakingPoolIdOfMaker.getABIEncodedTransactionData(makerAddress);
|
||||
const poolId = await this._callAsync(calldata);
|
||||
return poolId;
|
||||
}
|
||||
public async getNumberOfMakersInStakingPoolAsync(poolId: string): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getNumberOfMakersInStakingPool.getABIEncodedTransactionData(poolId);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getNumberOfMakersInStakingPool.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
///// EPOCHS /////
|
||||
public async goToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().finalizeFees.getABIEncodedTransactionData();
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, undefined, new BigNumber(0), true);
|
||||
logUtils.log(`Finalization costed ${txReceipt.gasUsed} gas`);
|
||||
return txReceipt;
|
||||
}
|
||||
public async fastForwardToNextEpochAsync(): Promise<void> {
|
||||
// increase timestamp of next block
|
||||
const epochDurationInSeconds = await this.getEpochDurationInSecondsAsync();
|
||||
await this._web3Wrapper.increaseTimeAsync(epochDurationInSeconds.toNumber());
|
||||
// mine next block
|
||||
await this._web3Wrapper.mineBlockAsync();
|
||||
}
|
||||
public async skipToNextEpochAsync(): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
await this.fastForwardToNextEpochAsync();
|
||||
// increment epoch in contracts
|
||||
const txReceipt = await this.goToNextEpochAsync();
|
||||
await this._web3Wrapper.mineBlockAsync();
|
||||
return txReceipt;
|
||||
}
|
||||
public async getEpochDurationInSecondsAsync(): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getHyperParameters.getABIEncodedTransactionData();
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const params = this.getStakingContract().getHyperParameters.getABIDecodedReturnData(returnData);
|
||||
return params[0];
|
||||
}
|
||||
public async getCurrentEpochStartTimeInSecondsAsync(): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getCurrentEpochStartTimeInSeconds.getABIEncodedTransactionData();
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getCurrentEpochStartTimeInSeconds.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getCurrentEpochEarliestEndTimeInSecondsAsync(): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getCurrentEpochEarliestEndTimeInSeconds.getABIEncodedTransactionData();
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getCurrentEpochEarliestEndTimeInSeconds.getABIDecodedReturnData(
|
||||
returnData,
|
||||
);
|
||||
return value;
|
||||
}
|
||||
public async getCurrentEpochAsync(): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getCurrentEpoch.getABIEncodedTransactionData();
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getCurrentEpoch.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
///// PROTOCOL FEES /////
|
||||
public async payProtocolFeeAsync(
|
||||
makerAddress: string,
|
||||
payerAddress: string,
|
||||
protocolFeePaid: BigNumber,
|
||||
amount: BigNumber,
|
||||
exchangeAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().payProtocolFee.getABIEncodedTransactionData(
|
||||
makerAddress,
|
||||
payerAddress,
|
||||
protocolFeePaid,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, exchangeAddress, amount);
|
||||
return txReceipt;
|
||||
}
|
||||
public async getProtocolFeesThisEpochByPoolAsync(poolId: string): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getProtocolFeesThisEpochByPool.getABIEncodedTransactionData(poolId);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getProtocolFeesThisEpochByPool.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
public async getTotalProtocolFeesThisEpochAsync(): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().getTotalProtocolFeesThisEpoch.getABIEncodedTransactionData();
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().getTotalProtocolFeesThisEpoch.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
///// EXCHANGES /////
|
||||
public async isValidExchangeAddressAsync(exchangeAddress: string): Promise<boolean> {
|
||||
const calldata = this.getStakingContract().isValidExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const isValid = this.getStakingContract().isValidExchangeAddress.getABIDecodedReturnData(returnData);
|
||||
return isValid;
|
||||
}
|
||||
public async addExchangeAddressAsync(
|
||||
exchangeAddress: string,
|
||||
ownerAddressIfExists?: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().addExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
|
||||
const ownerAddress = ownerAddressIfExists !== undefined ? ownerAddressIfExists : this._ownerAddress;
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, ownerAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
public async removeExchangeAddressAsync(
|
||||
exchangeAddress: string,
|
||||
ownerAddressIfExists?: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingContract().removeExchangeAddress.getABIEncodedTransactionData(exchangeAddress);
|
||||
const ownerAddress = ownerAddressIfExists !== undefined ? ownerAddressIfExists : this._ownerAddress;
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, ownerAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
///// REWARDS /////
|
||||
public async computeRewardBalanceOfStakingPoolMemberAsync(poolId: string, owner: string): Promise<BigNumber> {
|
||||
const calldata = this.getStakingContract().computeRewardBalanceOfDelegator.getABIEncodedTransactionData(
|
||||
poolId,
|
||||
owner,
|
||||
);
|
||||
const returnData = await this._callAsync(calldata);
|
||||
const value = this.getStakingContract().computeRewardBalanceOfDelegator.getABIDecodedReturnData(returnData);
|
||||
return value;
|
||||
}
|
||||
///// REWARD VAULT /////
|
||||
public async rewardVaultEnterCatastrophicFailureModeAsync(
|
||||
zeroExMultisigAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingPoolRewardVaultContract().enterCatastrophicFailure.getABIEncodedTransactionData();
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, zeroExMultisigAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
public async rewardVaultBalanceOfAsync(poolId: string): Promise<BigNumber> {
|
||||
const balance = await this.getStakingPoolRewardVaultContract().balanceOf.callAsync(poolId);
|
||||
return balance;
|
||||
}
|
||||
public async rewardVaultBalanceOfOperatorAsync(poolId: string): Promise<BigNumber> {
|
||||
const balance = await this.getStakingPoolRewardVaultContract().balanceOfOperator.callAsync(poolId);
|
||||
return balance;
|
||||
}
|
||||
public async rewardVaultBalanceOfMembersAsync(poolId: string): Promise<BigNumber> {
|
||||
const balance = await this.getStakingPoolRewardVaultContract().balanceOfMembers.callAsync(poolId);
|
||||
return balance;
|
||||
}
|
||||
public async rewardVaultRegisterPoolAsync(
|
||||
poolId: string,
|
||||
poolOperatorShare: number,
|
||||
stakingContractAddress: string,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const calldata = this.getStakingPoolRewardVaultContract().registerStakingPool.getABIEncodedTransactionData(
|
||||
poolId,
|
||||
poolOperatorShare,
|
||||
);
|
||||
const txReceipt = await this._executeTransactionAsync(calldata, stakingContractAddress);
|
||||
return txReceipt;
|
||||
}
|
||||
///// ZRX VAULT /////
|
||||
public async getZrxVaultBalanceAsync(holder: string): Promise<BigNumber> {
|
||||
const balance = await this.getZrxVaultContract().balanceOf.callAsync(holder);
|
||||
return balance;
|
||||
}
|
||||
public async getZrxTokenBalanceAsync(holder: string): Promise<BigNumber> {
|
||||
const balance = await this._zrxTokenContract.balanceOf.callAsync(holder);
|
||||
return balance;
|
||||
}
|
||||
public async getZrxTokenBalanceOfZrxVaultAsync(): Promise<BigNumber> {
|
||||
const balance = await this._zrxTokenContract.balanceOf.callAsync(this.getZrxVaultContract().address);
|
||||
return balance;
|
||||
}
|
||||
private async _executeTransactionAsync(
|
||||
calldata: string,
|
||||
from?: string,
|
||||
value?: BigNumber,
|
||||
includeLogs?: boolean,
|
||||
): Promise<TransactionReceiptWithDecodedLogs> {
|
||||
const txData = {
|
||||
from: from ? from : this._ownerAddress,
|
||||
to: this.getStakingProxyContract().address,
|
||||
data: calldata,
|
||||
gas: 3000000,
|
||||
gasPrice: 0,
|
||||
value,
|
||||
};
|
||||
const txHash = await this._web3Wrapper.sendTransactionAsync(txData);
|
||||
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._ownerAddress,
|
||||
to: this.getStakingProxyContract().address,
|
||||
data: calldata,
|
||||
gas: 3000000,
|
||||
};
|
||||
const returnValue = await this._web3Wrapper.callAsync(txData);
|
||||
return returnValue;
|
||||
}
|
||||
private _validateDeployedOrThrow(): void {
|
||||
if (this._stakingContractIfExists === undefined) {
|
||||
throw new Error('Staking contracts are not deployed. Call `deployStakingContracts`');
|
||||
}
|
||||
}
|
||||
}
|
||||
// tslint:disable-line:max-file-line-count
|
||||
@@ -2,6 +2,15 @@ import { BigNumber } from '@0x/utils';
|
||||
|
||||
import { constants } from './constants';
|
||||
|
||||
export interface HyperParameters {
|
||||
epochDurationInSeconds: BigNumber;
|
||||
rewardDelegatedStakeWeight: BigNumber;
|
||||
minimumPoolStake: BigNumber;
|
||||
maxMakersInPool: BigNumber;
|
||||
cobbDouglasAlphaNumerator: BigNumber;
|
||||
cobbDouglasAlphaDenomintor: BigNumber;
|
||||
}
|
||||
|
||||
export interface StakerBalances {
|
||||
zrxBalance: BigNumber;
|
||||
stakeBalance: BigNumber;
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"generated-artifacts/IStakingEvents.json",
|
||||
"generated-artifacts/IStakingPoolRewardVault.json",
|
||||
"generated-artifacts/IStakingProxy.json",
|
||||
"generated-artifacts/IStorageInit.json",
|
||||
"generated-artifacts/IStructs.json",
|
||||
"generated-artifacts/IVaultCore.json",
|
||||
"generated-artifacts/IZrxVault.json",
|
||||
|
||||
Reference in New Issue
Block a user