diff --git a/contracts/staking/contracts/src/StakingProxy.sol b/contracts/staking/contracts/src/StakingProxy.sol index 72d732b41d..5e53b32d49 100644 --- a/contracts/staking/contracts/src/StakingProxy.sol +++ b/contracts/staking/contracts/src/StakingProxy.sol @@ -164,52 +164,13 @@ contract StakingProxy is return batchReturnData; } - /// @dev Attach a staking contract; future calls will be delegated to the staking contract. - /// @param _stakingContract Address of staking contract. - /// @param _wethProxyAddress The address that can transfer WETH for fees. - /// @param _ethVaultAddress Address of the EthVault contract. - /// @param _rewardVaultAddress Address of the StakingPoolRewardVault contract. - /// @param _zrxVaultAddress Address of the ZrxVault contract. - function _attachStakingContract( - address _stakingContract, - address _wethProxyAddress, - address _ethVaultAddress, - address _rewardVaultAddress, - address _zrxVaultAddress - ) - private - { - // Attach the staking contract - stakingContract = readOnlyProxyCallee = _stakingContract; - emit StakingContractAttachedToProxy(_stakingContract); - - // Call `init()` on the staking contract to initialize storage. - (bool didInitSucceed, bytes memory initReturnData) = stakingContract.delegatecall( - abi.encodeWithSelector( - IStorageInit(0).init.selector, - _wethProxyAddress, - _ethVaultAddress, - _rewardVaultAddress, - _zrxVaultAddress - ) - ); - if (!didInitSucceed) { - assembly { - revert(add(initReturnData, 0x20), mload(initReturnData)) - } - } - - // Assert initialized storage values are valid - _assertValidStorageParams(); - } - /// @dev Asserts that an epoch is between 5 and 30 days long. - // Asserts that cobb douglas alpha value is between 0 and 1. + // Asserts that 0 < cobb douglas alpha value <= 1. // Asserts that a stake weight is <= 100%. // Asserts that pools allow >= 1 maker. // Asserts that all addresses are initialized. function _assertValidStorageParams() - private + internal view { // Epoch length must be between 5 and 30 days long @@ -221,7 +182,7 @@ contract StakingProxy is )); } - // Alpha must be 0 < x < 1 + // Alpha must be 0 < x <= 1 uint32 _cobbDouglasAlphaDenominator = cobbDouglasAlphaDenominator; if (cobbDouglasAlphaNumerator > _cobbDouglasAlphaDenominator || _cobbDouglasAlphaDenominator == 0) { LibRichErrors.rrevert( @@ -275,4 +236,43 @@ contract StakingProxy is )); } } + + /// @dev Attach a staking contract; future calls will be delegated to the staking contract. + /// @param _stakingContract Address of staking contract. + /// @param _wethProxyAddress The address that can transfer WETH for fees. + /// @param _ethVaultAddress Address of the EthVault contract. + /// @param _rewardVaultAddress Address of the StakingPoolRewardVault contract. + /// @param _zrxVaultAddress Address of the ZrxVault contract. + function _attachStakingContract( + address _stakingContract, + address _wethProxyAddress, + address _ethVaultAddress, + address _rewardVaultAddress, + address _zrxVaultAddress + ) + internal + { + // Attach the staking contract + stakingContract = readOnlyProxyCallee = _stakingContract; + emit StakingContractAttachedToProxy(_stakingContract); + + // Call `init()` on the staking contract to initialize storage. + (bool didInitSucceed, bytes memory initReturnData) = stakingContract.delegatecall( + abi.encodeWithSelector( + IStorageInit(0).init.selector, + _wethProxyAddress, + _ethVaultAddress, + _rewardVaultAddress, + _zrxVaultAddress + ) + ); + if (!didInitSucceed) { + assembly { + revert(add(initReturnData, 0x20), mload(initReturnData)) + } + } + + // Assert initialized storage values are valid + _assertValidStorageParams(); + } } diff --git a/contracts/staking/contracts/test/TestAssertStorageParams.sol b/contracts/staking/contracts/test/TestAssertStorageParams.sol new file mode 100644 index 0000000000..5773511b55 --- /dev/null +++ b/contracts/staking/contracts/test/TestAssertStorageParams.sol @@ -0,0 +1,71 @@ +/* + + Copyright 2019 ZeroEx Intl. + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ +pragma solidity ^0.5.9; +pragma experimental ABIEncoderV2; + +import "../src/StakingProxy.sol"; + + +contract TestAssertStorageParams is + StakingProxy +{ + struct StorageParams { + uint256 epochDurationInSeconds; + uint32 rewardDelegatedStakeWeight; + uint256 minimumPoolStake; + uint256 maximumMakersInPool; + uint32 cobbDouglasAlphaNumerator; + uint32 cobbDouglasAlphaDenominator; + address wethProxyAddress; + address ethVaultAddress; + address rewardVaultAddress; + address zrxVaultAddress; + } + + constructor() + public + StakingProxy( + NIL_ADDRESS, + NIL_ADDRESS, + NIL_ADDRESS, + NIL_ADDRESS, + NIL_ADDRESS, + NIL_ADDRESS + ) + {} + + function setAndAssertParams(StorageParams memory params) + public + { + epochDurationInSeconds = params.epochDurationInSeconds; + rewardDelegatedStakeWeight = params.rewardDelegatedStakeWeight; + minimumPoolStake = params.minimumPoolStake; + maximumMakersInPool = params.maximumMakersInPool; + cobbDouglasAlphaNumerator = params.cobbDouglasAlphaNumerator; + cobbDouglasAlphaDenominator = params.cobbDouglasAlphaDenominator; + wethAssetProxy = IAssetProxy(params.wethProxyAddress); + ethVault = IEthVault(params.ethVaultAddress); + rewardVault = IStakingPoolRewardVault(params.rewardVaultAddress); + zrxVault = IZrxVault(params.zrxVaultAddress); + _assertValidStorageParams(); + } + + function _attachStakingContract(address, address, address, address, address) + internal + {} +} diff --git a/contracts/staking/contracts/test/TestInitTarget.sol b/contracts/staking/contracts/test/TestInitTarget.sol index b64a2f076e..e3ee74ed25 100644 --- a/contracts/staking/contracts/test/TestInitTarget.sol +++ b/contracts/staking/contracts/test/TestInitTarget.sol @@ -51,7 +51,7 @@ contract TestInitTarget is external { if (SHOULD_REVERT_ADDRESS.balance != 0) { - revert("FORCED_REVERT"); + revert("FORCED_INIT_REVERT"); } _initCounter += 1; _initSender = msg.sender; diff --git a/contracts/staking/contracts/test/TestStakingProxy.sol b/contracts/staking/contracts/test/TestStakingProxy.sol index 9e4c2d9bca..b15e846489 100644 --- a/contracts/staking/contracts/test/TestStakingProxy.sol +++ b/contracts/staking/contracts/test/TestStakingProxy.sol @@ -24,6 +24,8 @@ import "../src/StakingProxy.sol"; contract TestStakingProxy is StakingProxy { + address public constant SHOULD_REVERT_STAKING_ADDRESS = 0x5ed6A38c6bEcEd15b0AB58566b6fD7A00463d2F7; + // solhint-disable no-empty-blocks constructor(address _stakingContract) public @@ -50,4 +52,14 @@ contract TestStakingProxy is rewardVault = IStakingPoolRewardVault(_rewardVaultAddress); zrxVault = IZrxVault(_zrxVaultAddress); } + + function _assertValidStorageParams() + internal + view + { + require( + stakingContract != SHOULD_REVERT_STAKING_ADDRESS, + "FORCED_STORAGE_PARAMS_REVERT" + ); + } } diff --git a/contracts/staking/package.json b/contracts/staking/package.json index f380eec6e1..227554959c 100644 --- a/contracts/staking/package.json +++ b/contracts/staking/package.json @@ -37,7 +37,7 @@ }, "config": { "abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.", - "abis": "./generated-artifacts/@(EthVault|IEthVault|IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStorage|IStorageInit|IStructs|IVaultCore|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolMakers|MixinStakingPoolModifiers|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|ReadOnlyProxy|Staking|StakingPoolRewardVault|StakingProxy|TestCobbDouglas|TestCumulativeRewardTracking|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinVaultCore|TestProtocolFees|TestProtocolFeesERC20Proxy|TestStaking|TestStakingProxy|TestStorageLayout|ZrxVault).json" + "abis": "./generated-artifacts/@(EthVault|IEthVault|IStaking|IStakingEvents|IStakingPoolRewardVault|IStakingProxy|IStorage|IStorageInit|IStructs|IVaultCore|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolMakers|MixinStakingPoolModifiers|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|ReadOnlyProxy|Staking|StakingPoolRewardVault|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinVaultCore|TestProtocolFees|TestProtocolFeesERC20Proxy|TestStaking|TestStakingProxy|TestStorageLayout|ZrxVault).json" }, "repository": { "type": "git", diff --git a/contracts/staking/src/artifacts.ts b/contracts/staking/src/artifacts.ts index 27b72dabb5..247f09fdb4 100644 --- a/contracts/staking/src/artifacts.ts +++ b/contracts/staking/src/artifacts.ts @@ -42,6 +42,7 @@ import * as ReadOnlyProxy from '../generated-artifacts/ReadOnlyProxy.json'; import * as Staking from '../generated-artifacts/Staking.json'; import * as StakingPoolRewardVault from '../generated-artifacts/StakingPoolRewardVault.json'; import * as StakingProxy from '../generated-artifacts/StakingProxy.json'; +import * as TestAssertStorageParams from '../generated-artifacts/TestAssertStorageParams.json'; import * as TestCobbDouglas from '../generated-artifacts/TestCobbDouglas.json'; import * as TestCumulativeRewardTracking from '../generated-artifacts/TestCumulativeRewardTracking.json'; import * as TestInitTarget from '../generated-artifacts/TestInitTarget.json'; @@ -95,6 +96,7 @@ export const artifacts = { MixinVaultCore: MixinVaultCore as ContractArtifact, StakingPoolRewardVault: StakingPoolRewardVault as ContractArtifact, ZrxVault: ZrxVault as ContractArtifact, + TestAssertStorageParams: TestAssertStorageParams as ContractArtifact, TestCobbDouglas: TestCobbDouglas as ContractArtifact, TestCumulativeRewardTracking: TestCumulativeRewardTracking as ContractArtifact, TestInitTarget: TestInitTarget as ContractArtifact, diff --git a/contracts/staking/src/wrappers.ts b/contracts/staking/src/wrappers.ts index 5a4ecca61c..b0cadd3c4c 100644 --- a/contracts/staking/src/wrappers.ts +++ b/contracts/staking/src/wrappers.ts @@ -40,6 +40,7 @@ export * from '../generated-wrappers/read_only_proxy'; export * from '../generated-wrappers/staking'; export * from '../generated-wrappers/staking_pool_reward_vault'; export * from '../generated-wrappers/staking_proxy'; +export * from '../generated-wrappers/test_assert_storage_params'; export * from '../generated-wrappers/test_cobb_douglas'; export * from '../generated-wrappers/test_cumulative_reward_tracking'; export * from '../generated-wrappers/test_init_target'; diff --git a/contracts/staking/test/migration.ts b/contracts/staking/test/migration.ts index e8cba2a780..13a9673399 100644 --- a/contracts/staking/test/migration.ts +++ b/contracts/staking/test/migration.ts @@ -5,23 +5,37 @@ import { BigNumber, OwnableRevertErrors, StringRevertError } from '@0x/utils'; import { artifacts, StakingContract, + StakingProxyContract, + TestAssertStorageParamsContract, TestInitTargetContract, TestInitTargetInitAddressesEventArgs, TestStakingProxyContract, TestStakingProxyStakingContractAttachedToProxyEventArgs, } from '../src/'; +import { constants as stakingConstants } from './utils/constants'; + blockchainTests('Migration tests', env => { let ownerAddress: string; let notOwnerAddress: string; + let stakingContract: StakingContract; + before(async () => { [ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync(); + stakingContract = await StakingContract.deployFrom0xArtifactAsync( + artifacts.Staking, + env.provider, + env.txDefaults, + artifacts, + ); }); describe('StakingProxy', () => { - const REVERT_ERROR = new StringRevertError('FORCED_REVERT'); + const INIT_REVERT_ERROR = new StringRevertError('FORCED_INIT_REVERT'); + const STORAGE_PARAMS_REVERT_ERROR = new StringRevertError('FORCED_STORAGE_PARAMS_REVERT'); let initTargetContract: TestInitTargetContract; + let revertAddress: string; async function deployStakingProxyAsync(stakingContractAddress?: string): Promise { return TestStakingProxyContract.deployFrom0xArtifactAsync( @@ -41,10 +55,10 @@ blockchainTests('Migration tests', env => { env.txDefaults, artifacts, ); + revertAddress = await initTargetContract.SHOULD_REVERT_ADDRESS.callAsync(); }); async function enableInitRevertsAsync(): Promise { - const revertAddress = await initTargetContract.SHOULD_REVERT_ADDRESS.callAsync(); // Deposit some ether into `revertAddress` to signal `initTargetContract` // to fail. await env.web3Wrapper.awaitTransactionMinedAsync( @@ -77,7 +91,49 @@ blockchainTests('Migration tests', env => { it('reverts if init() reverts', async () => { await enableInitRevertsAsync(); const tx = deployStakingProxyAsync(initTargetContract.address); - return expect(tx).to.revertWith(REVERT_ERROR); + return expect(tx).to.revertWith(INIT_REVERT_ERROR); + }); + + it('reverts if assertValidStorageParams() fails', async () => { + const tx = deployStakingProxyAsync(revertAddress); + return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR); + }); + + it('should set the correct initial params', async () => { + const wethProxyAddress = randomAddress(); + const ethVaultAddress = randomAddress(); + const rewardVaultAddress = randomAddress(); + const zrxVaultAddress = randomAddress(); + + const stakingProxyContractAddress = (await StakingProxyContract.deployFrom0xArtifactAsync( + artifacts.StakingProxy, + env.provider, + env.txDefaults, + artifacts, + stakingContract.address, + stakingContract.address, + wethProxyAddress, + ethVaultAddress, + rewardVaultAddress, + zrxVaultAddress, + )).address; + + const stakingProxyContract = new StakingContract( + stakingProxyContractAddress, + env.provider, + env.txDefaults, + ); + const params = await stakingProxyContract.getParams.callAsync(); + expect(params[0]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.epochDurationInSeconds); + expect(params[1]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.rewardDelegatedStakeWeight); + expect(params[2]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.minimumPoolStake); + expect(params[3]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.maximumMakersInPool); + expect(params[4]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaNumerator); + expect(params[5]).to.bignumber.eq(stakingConstants.DEFAULT_PARAMS.cobbDouglasAlphaDenominator); + expect(params[6]).to.eq(wethProxyAddress); + expect(params[7]).to.eq(ethVaultAddress); + expect(params[8]).to.eq(rewardVaultAddress); + expect(params[9]).to.eq(zrxVaultAddress); }); }); @@ -142,7 +198,7 @@ blockchainTests('Migration tests', env => { constants.NULL_ADDRESS, constants.NULL_ADDRESS, ); - return expect(tx).to.revertWith(REVERT_ERROR); + return expect(tx).to.revertWith(INIT_REVERT_ERROR); }); it('calls init with initialized addresses if passed in args are null', async () => { @@ -197,6 +253,17 @@ blockchainTests('Migration tests', env => { expect(args.zrxVaultAddress).to.eq(zrxVaultAddress); } }); + + it('reverts if assertValidStorageParams() fails', async () => { + const tx = proxyContract.attachStakingContract.awaitTransactionSuccessAsync( + revertAddress, + constants.NULL_ADDRESS, + constants.NULL_ADDRESS, + constants.NULL_ADDRESS, + constants.NULL_ADDRESS, + ); + return expect(tx).to.revertWith(STORAGE_PARAMS_REVERT_ERROR); + }); }); blockchainTests.resets('upgrades', async () => { @@ -216,17 +283,6 @@ blockchainTests('Migration tests', env => { }); blockchainTests.resets('Staking.init()', async () => { - let stakingContract: StakingContract; - - before(async () => { - stakingContract = await StakingContract.deployFrom0xArtifactAsync( - artifacts.Staking, - env.provider, - env.txDefaults, - artifacts, - ); - }); - it('throws if not called by owner', async () => { const tx = stakingContract.init.awaitTransactionSuccessAsync( randomAddress(), @@ -258,5 +314,163 @@ blockchainTests('Migration tests', env => { return expect(tx).to.revertWith(expectedError); }); }); + + blockchainTests.resets('assertValidStorageParams', async () => { + let proxyContract: TestAssertStorageParamsContract; + const fiveDays = new BigNumber(5 * 24 * 60 * 60); + const thirtyDays = new BigNumber(30 * 24 * 60 * 60); + before(async () => { + proxyContract = await TestAssertStorageParamsContract.deployFrom0xArtifactAsync( + artifacts.TestAssertStorageParams, + env.provider, + env.txDefaults, + artifacts, + ); + }); + + it('succeeds if all params are valid', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync(stakingConstants.DEFAULT_PARAMS); + expect(tx).to.be.fulfilled(''); + }); + + it('reverts if epoch duration is < 5 days', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + epochDurationInSeconds: fiveDays.minus(1), + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidEpochDuration, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if epoch duration is > 30 days', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + epochDurationInSeconds: thirtyDays.plus(1), + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidEpochDuration, + ); + expect(tx).to.revertWith(expectedError); + }); + it('succeeds if epoch duration is 5 days', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + epochDurationInSeconds: fiveDays, + }); + expect(tx).to.be.fulfilled(''); + }); + it('succeeds if epoch duration is 30 days', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + epochDurationInSeconds: thirtyDays, + }); + expect(tx).to.be.fulfilled(''); + }); + it('reverts if alpha denominator is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + cobbDouglasAlphaDenominator: constants.ZERO_AMOUNT, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if alpha > 1', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + cobbDouglasAlphaNumerator: new BigNumber(101), + cobbDouglasAlphaDenominator: new BigNumber(100), + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, + ); + expect(tx).to.revertWith(expectedError); + }); + it('succeeds if alpha == 1', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + cobbDouglasAlphaNumerator: new BigNumber(1), + cobbDouglasAlphaDenominator: new BigNumber(1), + }); + expect(tx).to.be.fulfilled(''); + }); + it('succeeds if alpha == 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + cobbDouglasAlphaNumerator: constants.ZERO_AMOUNT, + cobbDouglasAlphaDenominator: new BigNumber(1), + }); + expect(tx).to.be.fulfilled(''); + }); + it('reverts if delegation weight is > 100%', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM).plus(1), + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight, + ); + expect(tx).to.revertWith(expectedError); + }); + it('succeeds if delegation weight is 100%', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + rewardDelegatedStakeWeight: new BigNumber(stakingConstants.PPM), + }); + expect(tx).to.be.fulfilled(''); + }); + it('reverts if max makers in pool is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + maximumMakersInPool: constants.ZERO_AMOUNT, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if wethAssetProxy is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + wethProxyAddress: constants.NULL_ADDRESS, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidWethProxyAddress, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if ethVault is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + ethVaultAddress: constants.NULL_ADDRESS, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidEthVaultAddress, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if rewardVault is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + rewardVaultAddress: constants.NULL_ADDRESS, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidRewardVaultAddress, + ); + expect(tx).to.revertWith(expectedError); + }); + it('reverts if zrxVault is 0', async () => { + const tx = proxyContract.setAndAssertParams.awaitTransactionSuccessAsync({ + ...stakingConstants.DEFAULT_PARAMS, + zrxVaultAddress: constants.NULL_ADDRESS, + }); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidZrxVaultAddress, + ); + expect(tx).to.revertWith(expectedError); + }); + }); }); // tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/params.ts b/contracts/staking/test/params.ts index 4e7ac700f9..17110b6d35 100644 --- a/contracts/staking/test/params.ts +++ b/contracts/staking/test/params.ts @@ -77,82 +77,6 @@ blockchainTests('Configurable Parameters', env => { it('works if called by owner', async () => { return setParamsAndAssertAsync({}); }); - - describe('rewardDelegatedStakeWeight', () => { - it('throws when > PPM_100_PERCENT', async () => { - const params = { - rewardDelegatedStakeWeight: constants.PPM_100_PERCENT + 1, - }; - const tx = setParamsAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('maximumMakersInPool', () => { - it('throws when == 0', async () => { - const params = { - maximumMakersInPool: constants.ZERO_AMOUNT, - }; - const tx = setParamsAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool, - ); - return expect(tx).to.revertWith(expectedError); - }); - }); - - describe('cobb-douglas alpha', () => { - it('throws with denominator == 0', async () => { - const params = { - cobbDouglasAlphaNumerator: 0, - cobbDouglasAlphaDenominator: 0, - }; - const tx = setParamsAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('throws with numerator > denominator', async () => { - const params = { - cobbDouglasAlphaNumerator: 2, - cobbDouglasAlphaDenominator: 1, - }; - const tx = setParamsAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidParamValueError( - StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, - ); - return expect(tx).to.revertWith(expectedError); - }); - - it('accepts numerator == denominator', async () => { - const params = { - cobbDouglasAlphaNumerator: 1, - cobbDouglasAlphaDenominator: 1, - }; - return setParamsAndAssertAsync(params); - }); - - it('accepts numerator < denominator', async () => { - const params = { - cobbDouglasAlphaNumerator: 1, - cobbDouglasAlphaDenominator: 2, - }; - return setParamsAndAssertAsync(params); - }); - - it('accepts numerator == 0', async () => { - const params = { - cobbDouglasAlphaNumerator: 0, - cobbDouglasAlphaDenominator: 1, - }; - return setParamsAndAssertAsync(params); - }); - }); }); }); // tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/utils/constants.ts b/contracts/staking/test/utils/constants.ts index 3e2e9d4450..d9ce44ab29 100644 --- a/contracts/staking/test/utils/constants.ts +++ b/contracts/staking/test/utils/constants.ts @@ -1,8 +1,8 @@ import { constants as testConstants, randomAddress } from '@0x/contracts-test-utils'; import { BigNumber } from '@0x/utils'; -const TWO_WEEKS = 14 * 24 * 60 * 60; -const PPM_90_PERCENT = 10 ** 6 * 0.9; +const TEN_DAYS = 10 * 24 * 60 * 60; +const PPM = 10 ** 6; export const constants = { TOKEN_MULTIPLIER: testConstants.DUMMY_TOKEN_DECIMALS, INITIAL_POOL_ID: '0x0000000000000000000000000000000100000000000000000000000000000000', @@ -11,9 +11,9 @@ export const constants = { NIL_ADDRESS: '0x0000000000000000000000000000000000000000', INITIAL_EPOCH: new BigNumber(0), DEFAULT_PARAMS: { - epochDurationInSeconds: new BigNumber(TWO_WEEKS), - rewardDelegatedStakeWeight: new BigNumber(PPM_90_PERCENT), - minimumPoolStake: testConstants.DUMMY_TOKEN_DECIMALS.times(100), + epochDurationInSeconds: new BigNumber(TEN_DAYS), + rewardDelegatedStakeWeight: new BigNumber(PPM * 0.9), + minimumPoolStake: new BigNumber(10).pow(testConstants.DUMMY_TOKEN_DECIMALS).times(100), maximumMakersInPool: new BigNumber(10), cobbDouglasAlphaNumerator: new BigNumber(1), cobbDouglasAlphaDenominator: new BigNumber(2), @@ -22,4 +22,5 @@ export const constants = { rewardVaultAddress: randomAddress(), zrxVaultAddress: randomAddress(), }, + PPM, }; diff --git a/contracts/staking/tsconfig.json b/contracts/staking/tsconfig.json index 920fe86c67..09286c55b8 100644 --- a/contracts/staking/tsconfig.json +++ b/contracts/staking/tsconfig.json @@ -40,6 +40,7 @@ "generated-artifacts/Staking.json", "generated-artifacts/StakingPoolRewardVault.json", "generated-artifacts/StakingProxy.json", + "generated-artifacts/TestAssertStorageParams.json", "generated-artifacts/TestCobbDouglas.json", "generated-artifacts/TestCumulativeRewardTracking.json", "generated-artifacts/TestInitTarget.json",