diff --git a/contracts/staking/contracts/src/Staking.sol b/contracts/staking/contracts/src/Staking.sol index dd45015ce9..aef1ddeb65 100644 --- a/contracts/staking/contracts/src/Staking.sol +++ b/contracts/staking/contracts/src/Staking.sol @@ -24,6 +24,7 @@ import "./fees/MixinExchangeManager.sol"; import "./stake/MixinZrxVault.sol"; import "./staking_pools/MixinStakingPoolRewardVault.sol"; import "./sys/MixinScheduler.sol"; +import "./sys/MixinParams.sol"; import "./stake/MixinStakeBalances.sol"; import "./stake/MixinStake.sol"; import "./staking_pools/MixinStakingPool.sol"; @@ -37,7 +38,7 @@ contract Staking is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, + MixinParams, MixinZrxVault, MixinExchangeManager, MixinStakingPoolRewardVault, @@ -64,7 +65,8 @@ contract Staking is onlyOwner { // DANGER! When performing upgrades, take care to modify this logic - // not to accidentally overwrite existing state. + // to prevent accidentally clearing prior state. _initMixinScheduler(); + _initMixinParams(); } } diff --git a/contracts/staking/contracts/src/StakingProxy.sol b/contracts/staking/contracts/src/StakingProxy.sol index 935f9a6272..5e8dda892b 100644 --- a/contracts/staking/contracts/src/StakingProxy.sol +++ b/contracts/staking/contracts/src/StakingProxy.sol @@ -21,8 +21,8 @@ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "./libs/LibProxy.sol"; import "./immutable/MixinStorage.sol"; -import "./immutable/MixinHyperParameters.sol"; import "./interfaces/IStorageInit.sol"; +import "./interfaces/IStakingEvents.sol"; import "./interfaces/IStakingProxy.sol"; @@ -31,8 +31,7 @@ contract StakingProxy is IStakingProxy, MixinConstants, Ownable, - MixinStorage, - MixinHyperParameters + MixinStorage { using LibProxy for address; diff --git a/contracts/staking/contracts/src/fees/MixinExchangeFees.sol b/contracts/staking/contracts/src/fees/MixinExchangeFees.sol index 04f0f60ada..4ecdb97420 100644 --- a/contracts/staking/contracts/src/fees/MixinExchangeFees.sol +++ b/contracts/staking/contracts/src/fees/MixinExchangeFees.sol @@ -49,7 +49,6 @@ contract MixinExchangeFees is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinZrxVault, MixinExchangeManager, MixinStakingPoolRewardVault, diff --git a/contracts/staking/contracts/src/immutable/MixinStorage.sol b/contracts/staking/contracts/src/immutable/MixinStorage.sol index 394d89278d..fdce971fd3 100644 --- a/contracts/staking/contracts/src/immutable/MixinStorage.sol +++ b/contracts/staking/contracts/src/immutable/MixinStorage.sol @@ -125,4 +125,22 @@ contract MixinStorage is // Rebate Vault (stores rewards for pools before they are moved to the eth vault on a per-user basis) IStakingPoolRewardVault internal rewardVault; + + // Minimum seconds between epochs. + uint256 internal epochDurationInSeconds; + + // How much delegated stake is weighted vs operator stake, in ppm. + uint32 internal rewardDelegatedStakeWeight; + + // Minimum amount of stake required in a pool to collect rewards. + uint256 internal minimumPoolStake; + + // Maximum number of maker addresses allowed to be registered to a pool. + uint256 internal maximumMakersInPool; + + // Numerator for cobb douglas alpha factor. + uint32 internal cobbDouglasAlphaNumerator; + + // Denominator for cobb douglas alpha factor. + uint32 internal cobbDouglasAlphaDenomintor; } diff --git a/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol b/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol index 54e9aeb9b2..5e7f815c5d 100644 --- a/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol +++ b/contracts/staking/contracts/src/libs/LibStakingRichErrors.sol @@ -29,10 +29,11 @@ library LibStakingRichErrors { } enum InitializationErrorCode { - MixinSchedulerAlreadyInitialized + MixinSchedulerAlreadyInitialized, + MixinParamsAlreadyInitialized } - enum InvalidTuningValueErrorCode { + enum InvalidParamValueErrorCode { InvalidCobbDouglasAlpha, InvalidRewardDelegatedStakeWeight, InvalidMaximumMakersInPool @@ -129,9 +130,9 @@ library LibStakingRichErrors { bytes4 internal constant INITIALIZATION_ERROR_SELECTOR = 0x0b02d773; - // bytes4(keccak256("InvalidTuningValue(uint8)")) - bytes4 internal constant INVALID_TUNING_VALUE_ERROR_SELECTOR = - 0xbbfd10bb; + // bytes4(keccak256("InvalidParamValue(uint8)")) + bytes4 internal constant INVALID_PARAM_VALUE_ERROR_SELECTOR = + 0x7b40eece; // bytes4(keccak256("InvalidProtocolFeePaymentError(uint8,uint256,uint256)")) bytes4 internal constant INVALID_PROTOCOL_FEE_PAYMENT_ERROR_SELECTOR = @@ -435,13 +436,13 @@ library LibStakingRichErrors { ); } - function InvalidTuningValue(InvalidTuningValueErrorCode code) + function InvalidParamValue(InvalidParamValueErrorCode code) internal pure returns (bytes memory) { return abi.encodeWithSelector( - INVALID_TUNING_VALUE_ERROR_SELECTOR, + INVALID_PARAM_VALUE_ERROR_SELECTOR, uint8(code) ); } diff --git a/contracts/staking/contracts/src/stake/MixinStake.sol b/contracts/staking/contracts/src/stake/MixinStake.sol index e61e61a5b1..c68c648623 100644 --- a/contracts/staking/contracts/src/stake/MixinStake.sol +++ b/contracts/staking/contracts/src/stake/MixinStake.sol @@ -24,9 +24,11 @@ import "../immutable/MixinConstants.sol"; import "../immutable/MixinStorage.sol"; import "../interfaces/IStakingEvents.sol"; import "./MixinZrxVault.sol"; +import "../staking_pools/MixinStakingPoolRewardVault.sol"; import "../staking_pools/MixinStakingPoolRewards.sol"; import "../sys/MixinScheduler.sol"; import "../libs/LibStakingRichErrors.sol"; +import "./MixinZrxVault.sol"; import "./MixinStakeBalances.sol"; import "./MixinStakeStorage.sol"; @@ -37,7 +39,6 @@ contract MixinStake is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinZrxVault, MixinStakingPoolRewardVault, MixinScheduler, diff --git a/contracts/staking/contracts/src/stake/MixinStakeBalances.sol b/contracts/staking/contracts/src/stake/MixinStakeBalances.sol index 665a240c0b..95ce8a3fdd 100644 --- a/contracts/staking/contracts/src/stake/MixinStakeBalances.sol +++ b/contracts/staking/contracts/src/stake/MixinStakeBalances.sol @@ -35,7 +35,6 @@ contract MixinStakeBalances is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinZrxVault, MixinScheduler, MixinStakeStorage diff --git a/contracts/staking/contracts/src/stake/MixinStakeStorage.sol b/contracts/staking/contracts/src/stake/MixinStakeStorage.sol index 62bd17e19a..b39ffa14aa 100644 --- a/contracts/staking/contracts/src/stake/MixinStakeStorage.sol +++ b/contracts/staking/contracts/src/stake/MixinStakeStorage.sol @@ -33,7 +33,6 @@ contract MixinStakeStorage is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinScheduler { using LibSafeMath for uint256; diff --git a/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol b/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol index 4b3a6545c9..aa191c2968 100644 --- a/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol +++ b/contracts/staking/contracts/src/staking_pools/MixinStakingPool.sol @@ -57,7 +57,6 @@ contract MixinStakingPool is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinZrxVault, MixinStakingPoolRewardVault, MixinScheduler, diff --git a/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol b/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol index f8c7ea342d..d969bfd361 100644 --- a/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol +++ b/contracts/staking/contracts/src/staking_pools/MixinStakingPoolRewards.sol @@ -32,7 +32,6 @@ contract MixinStakingPoolRewards is MixinConstants, Ownable, MixinStorage, - MixinHyperParameters, MixinZrxVault, MixinStakingPoolRewardVault, MixinScheduler, diff --git a/contracts/staking/contracts/src/immutable/MixinHyperParameters.sol b/contracts/staking/contracts/src/sys/MixinParams.sol similarity index 64% rename from contracts/staking/contracts/src/immutable/MixinHyperParameters.sol rename to contracts/staking/contracts/src/sys/MixinParams.sol index 47bfe001fa..9cbbba2f49 100644 --- a/contracts/staking/contracts/src/immutable/MixinHyperParameters.sol +++ b/contracts/staking/contracts/src/sys/MixinParams.sol @@ -20,43 +20,32 @@ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol"; +import "../immutable/MixinConstants.sol"; +import "../immutable/MixinStorage.sol"; import "../interfaces/IStakingEvents.sol"; import "../libs/LibStakingRichErrors.sol"; -import "./MixinConstants.sol"; -contract MixinHyperParameters is +contract MixinParams is IStakingEvents, MixinConstants, - Ownable + Ownable, + MixinStorage { - // Minimum seconds between epochs. - uint256 internal epochDurationInSeconds = 2 weeks; - // How much delegated stake is weighted vs operator stake, in ppm. - uint32 internal rewardDelegatedStakeWeight = (90 * PPM_DENOMINATOR) / 100; // 90% - // Minimum amount of stake required in a pool to collect rewards. - uint256 internal minimumPoolStake = 100 * MIN_TOKEN_VALUE; // 100 ZRX - // Maximum number of maker addresses allowed to be registered to a pool. - uint256 internal maximumMakersInPool = 10; - // Numerator for cobb douglas alpha factor. - uint256 internal cobbDouglasAlphaNumerator = 1; - // Denominator for cobb douglas alpha factor. - uint256 internal cobbDouglasAlphaDenomintor = 2; - - /// @dev Set all hyperparameters at once. + /// @dev Set all configurable parameters at once. /// @param _epochDurationInSeconds Minimum seconds between epochs. /// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. /// @param _minimumPoolStake Minimum amount of stake required in a pool to collect rewards. /// @param _maximumMakersInPool Maximum number of maker addresses allowed to be registered to a pool. /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @param _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor. - function tune( + function setParams( uint256 _epochDurationInSeconds, uint32 _rewardDelegatedStakeWeight, uint256 _minimumPoolStake, uint256 _maximumMakersInPool, - uint256 _cobbDouglasAlphaNumerator, - uint256 _cobbDouglasAlphaDenomintor + uint32 _cobbDouglasAlphaNumerator, + uint32 _cobbDouglasAlphaDenomintor ) external onlyOwner @@ -85,14 +74,14 @@ contract MixinHyperParameters is ); } - /// @dev Retrives all tuned values. + /// @dev Retrives all configurable parameter 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 _maximumMakersInPool Maximum number of maker addresses allowed to be registered to a pool. /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @return _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor. - function getHyperParameters() + function getParams() external view returns ( @@ -100,8 +89,8 @@ contract MixinHyperParameters is uint32 _rewardDelegatedStakeWeight, uint256 _minimumPoolStake, uint256 _maximumMakersInPool, - uint256 _cobbDouglasAlphaNumerator, - uint256 _cobbDouglasAlphaDenomintor + uint32 _cobbDouglasAlphaNumerator, + uint32 _cobbDouglasAlphaDenomintor ) { _epochDurationInSeconds = epochDurationInSeconds; @@ -112,41 +101,68 @@ contract MixinHyperParameters is _cobbDouglasAlphaDenomintor = cobbDouglasAlphaDenomintor; } + /// @dev Initialzize storage belonging to this mixin. + function _initMixinParams() internal { + // Ensure state is uninitialized. + if (epochDurationInSeconds != 0 && + rewardDelegatedStakeWeight != 0 && + minimumPoolStake != 0 && + maximumMakersInPool != 0 && + cobbDouglasAlphaNumerator != 0 && + cobbDouglasAlphaDenomintor != 0 + ) { + LibRichErrors.rrevert( + LibStakingRichErrors.InitializationError( + LibStakingRichErrors.InitializationErrorCode.MixinParamsAlreadyInitialized + ) + ); + } + // Set up defaults. + epochDurationInSeconds = 2 weeks; + rewardDelegatedStakeWeight = (90 * PPM_DENOMINATOR) / 100; // 90% + minimumPoolStake = 100 * MIN_TOKEN_VALUE; // 100 ZRX + maximumMakersInPool = 10; + cobbDouglasAlphaNumerator = 1; + cobbDouglasAlphaDenomintor = 2; + } + /// @dev Asserts that cobb douglas alpha values are valid. + /// @param numerator Numerator for cobb douglas alpha factor. + /// @param denominator Denominator for cobb douglas alpha factor. function _assertValidCobbDouglasAlpha( - uint256 numerator, - uint256 denominator + uint32 numerator, + uint32 denominator ) private pure { - if (int256(numerator) < 0 - || int256(denominator) <= 0 - || numerator > denominator - ) { + // Alpha must be 0 < x < 1 + if (numerator > denominator || denominator == 0) { LibRichErrors.rrevert( - LibStakingRichErrors.InvalidTuningValue( - LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha + LibStakingRichErrors.InvalidParamValue( + LibStakingRichErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha )); } } /// @dev Asserts that a stake weight is valid. + /// @param weight How much delegated stake is weighted vs operator stake, in ppm. function _assertValidRewardDelegatedStakeWeight( - uint256 weight + uint32 weight ) private pure { if (weight > PPM_DENOMINATOR) { LibRichErrors.rrevert( - LibStakingRichErrors.InvalidTuningValue( - LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidRewardDelegatedStakeWeight + LibStakingRichErrors.InvalidParamValue( + LibStakingRichErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight )); } } /// @dev Asserts that a maximum makers value is valid. + /// @param amount Maximum number of maker addresses allowed to be registered to a pool. function _assertValidMaximumMakersInPool( uint256 amount ) @@ -155,8 +171,8 @@ contract MixinHyperParameters is { if (amount == 0) { LibRichErrors.rrevert( - LibStakingRichErrors.InvalidTuningValue( - LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidMaximumMakersInPool + LibStakingRichErrors.InvalidParamValue( + LibStakingRichErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool )); } } diff --git a/contracts/staking/contracts/src/sys/MixinScheduler.sol b/contracts/staking/contracts/src/sys/MixinScheduler.sol index 366afd4c49..a8a9e39623 100644 --- a/contracts/staking/contracts/src/sys/MixinScheduler.sol +++ b/contracts/staking/contracts/src/sys/MixinScheduler.sol @@ -21,7 +21,6 @@ pragma solidity ^0.5.9; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "../libs/LibStakingRichErrors.sol"; -import "../immutable/MixinHyperParameters.sol"; import "../immutable/MixinConstants.sol"; import "../immutable/MixinStorage.sol"; import "../interfaces/IStructs.sol"; @@ -38,8 +37,7 @@ contract MixinScheduler is IStakingEvents, MixinConstants, Ownable, - MixinStorage, - MixinHyperParameters + MixinStorage { using LibSafeMath for uint256; diff --git a/contracts/staking/contracts/test/TestInitTarget.sol b/contracts/staking/contracts/test/TestInitTarget.sol index 95525126d3..3ce473446e 100644 --- a/contracts/staking/contracts/test/TestInitTarget.sol +++ b/contracts/staking/contracts/test/TestInitTarget.sol @@ -20,18 +20,18 @@ pragma experimental ABIEncoderV2; import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "../src/immutable/MixinStorage.sol"; -import "../src/immutable/MixinHyperParameters.sol"; contract TestInitTarget is Ownable, - MixinStorage, - MixinHyperParameters + MixinStorage { // We can't store state in this contract before it is attached, so // we will grant this predefined address a balance to indicate that // `init()` should revert. address public constant SHOULD_REVERT_ADDRESS = 0x5ed6A38c6bEcEd15b0AB58566b6fD7A00463d2F7; + // Counter that is incremented with every call to `init()`. + uint256 private _initCounter = 0; // `msg.sender` of the last `init()` call. address private _initSender = address(0); // `address(this)` of the last `init()` call. @@ -39,8 +39,9 @@ contract TestInitTarget is function init() external { if (SHOULD_REVERT_ADDRESS.balance != 0) { - revert("WHOOPSIE!"); + revert("FORCED_REVERT"); } + _initCounter += 1; _initSender = msg.sender; _initThisAddress = address(this); } @@ -56,4 +57,8 @@ contract TestInitTarget is initSender = _initSender; initThisAddress = _initThisAddress; } + + function getInitCounter() external view returns (uint256) { + return _initCounter; + } } diff --git a/contracts/staking/contracts/test/TestStorageLayout.sol b/contracts/staking/contracts/test/TestStorageLayout.sol index 871316463f..694c21a88f 100644 --- a/contracts/staking/contracts/test/TestStorageLayout.sol +++ b/contracts/staking/contracts/test/TestStorageLayout.sol @@ -107,6 +107,24 @@ contract TestStorageLayout is if sub(rewardVault_slot, slot) { revertIncorrectStorageSlot() } slot := add(slot, 1) + + if sub(epochDurationInSeconds_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) + + if sub(rewardDelegatedStakeWeight_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) + + if sub(minimumPoolStake_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) + + if sub(maximumMakersInPool_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) + + if sub(cobbDouglasAlphaNumerator_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) + + if sub(cobbDouglasAlphaDenomintor_slot, slot) { revertIncorrectStorageSlot() } + slot := add(slot, 1) } } } diff --git a/contracts/staking/src/artifacts.ts b/contracts/staking/src/artifacts.ts index dd538f641c..8f1ea4e8f0 100644 --- a/contracts/staking/src/artifacts.ts +++ b/contracts/staking/src/artifacts.ts @@ -24,7 +24,7 @@ import * as MixinConstants from '../generated-artifacts/MixinConstants.json'; import * as MixinEthVault from '../generated-artifacts/MixinEthVault.json'; import * as MixinExchangeFees from '../generated-artifacts/MixinExchangeFees.json'; import * as MixinExchangeManager from '../generated-artifacts/MixinExchangeManager.json'; -import * as MixinHyperParameters from '../generated-artifacts/MixinHyperParameters.json'; +import * as MixinParams from '../generated-artifacts/MixinParams.json'; import * as MixinScheduler from '../generated-artifacts/MixinScheduler.json'; import * as MixinStake from '../generated-artifacts/MixinStake.json'; import * as MixinStakeBalances from '../generated-artifacts/MixinStakeBalances.json'; @@ -55,7 +55,6 @@ export const artifacts = { MixinExchangeFees: MixinExchangeFees as ContractArtifact, MixinExchangeManager: MixinExchangeManager as ContractArtifact, MixinConstants: MixinConstants as ContractArtifact, - MixinHyperParameters: MixinHyperParameters as ContractArtifact, MixinStorage: MixinStorage as ContractArtifact, IEthVault: IEthVault as ContractArtifact, IStaking: IStaking as ContractArtifact, @@ -79,6 +78,7 @@ export const artifacts = { MixinStakingPool: MixinStakingPool as ContractArtifact, MixinStakingPoolRewardVault: MixinStakingPoolRewardVault as ContractArtifact, MixinStakingPoolRewards: MixinStakingPoolRewards as ContractArtifact, + MixinParams: MixinParams as ContractArtifact, MixinScheduler: MixinScheduler as ContractArtifact, EthVault: EthVault as ContractArtifact, MixinVaultCore: MixinVaultCore as ContractArtifact, diff --git a/contracts/staking/src/wrappers.ts b/contracts/staking/src/wrappers.ts index be7f86922e..6f5f23dea9 100644 --- a/contracts/staking/src/wrappers.ts +++ b/contracts/staking/src/wrappers.ts @@ -22,7 +22,7 @@ export * from '../generated-wrappers/mixin_constants'; export * from '../generated-wrappers/mixin_eth_vault'; export * from '../generated-wrappers/mixin_exchange_fees'; export * from '../generated-wrappers/mixin_exchange_manager'; -export * from '../generated-wrappers/mixin_hyper_parameters'; +export * from '../generated-wrappers/mixin_params'; export * from '../generated-wrappers/mixin_scheduler'; export * from '../generated-wrappers/mixin_stake'; export * from '../generated-wrappers/mixin_stake_balances'; diff --git a/contracts/staking/test/migration.ts b/contracts/staking/test/migration.ts index 0b01bae598..e1467e5a6e 100644 --- a/contracts/staking/test/migration.ts +++ b/contracts/staking/test/migration.ts @@ -1,4 +1,5 @@ import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils'; +import { StakingRevertErrors } from '@0x/order-utils'; import { BigNumber, OwnableRevertErrors, StringRevertError } from '@0x/utils'; import { artifacts, StakingContract, TestInitTargetContract, TestStakingProxyContract } from '../src/'; @@ -12,7 +13,7 @@ blockchainTests('Migration tests', env => { }); describe('StakingProxy', () => { - const REVERT_ERROR = new StringRevertError('WHOOPSIE!'); + const REVERT_ERROR = new StringRevertError('FORCED_REVERT'); let initTargetContract: TestInitTargetContract; async function deployStakingProxyAsync(stakingContractAddress?: string): Promise { @@ -104,6 +105,43 @@ blockchainTests('Migration tests', env => { return expect(tx).to.revertWith(REVERT_ERROR); }); }); + + blockchainTests.resets('upgrades', async () => { + it('modifies prior state', async () => { + const proxyContract = await deployStakingProxyAsync(initTargetContract.address); + await proxyContract.attachStakingContract.awaitTransactionSuccessAsync(initTargetContract.address); + const initCounter = await initTargetContract.getInitCounter.callAsync({ to: proxyContract.address }); + expect(initCounter).to.bignumber.eq(2); + }); + }); + + blockchainTests.resets('upgrade', async () => { + let proxyContract: TestStakingProxyContract; + + before(async () => { + proxyContract = await deployStakingProxyAsync(); + }); + + it('incm', async () => { + const attachedAddress = randomAddress(); + const tx = proxyContract.attachStakingContract.awaitTransactionSuccessAsync(attachedAddress, { + from: notOwnerAddress, + }); + const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress); + return expect(tx).to.revertWith(expectedError); + }); + + it('calls init() and attaches the contract', async () => { + await proxyContract.attachStakingContract.awaitTransactionSuccessAsync(initTargetContract.address); + await assertInitStateAsync(proxyContract); + }); + + it('reverts if init() reverts', async () => { + await enableInitRevertsAsync(); + const tx = proxyContract.attachStakingContract.awaitTransactionSuccessAsync(initTargetContract.address); + return expect(tx).to.revertWith(REVERT_ERROR); + }); + }); }); blockchainTests.resets('Staking.init()', async () => { @@ -123,6 +161,13 @@ blockchainTests('Migration tests', env => { const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress); return expect(tx).to.revertWith(expectedError); }); + + it('throws if already intiialized', async () => { + await stakingContract.init.awaitTransactionSuccessAsync(); + const tx = stakingContract.init.awaitTransactionSuccessAsync(); + const expectedError = new StakingRevertErrors.InitializationError(); + return expect(tx).to.revertWith(expectedError); + }); }); }); // tslint:enable:no-unnecessary-type-assertion diff --git a/contracts/staking/test/hyper_parameters.ts b/contracts/staking/test/params.ts similarity index 66% rename from contracts/staking/test/hyper_parameters.ts rename to contracts/staking/test/params.ts index e16ab393c4..f2797294d9 100644 --- a/contracts/staking/test/hyper_parameters.ts +++ b/contracts/staking/test/params.ts @@ -2,24 +2,24 @@ import { blockchainTests, constants, expect, filterLogsToArguments, Numberish } import { StakingRevertErrors } from '@0x/order-utils'; import { BigNumber, OwnableRevertErrors } from '@0x/utils'; -import { artifacts, IStakingEventsTunedEventArgs, MixinHyperParametersContract } from '../src/'; +import { artifacts, IStakingEventsTunedEventArgs, MixinParamsContract } from '../src/'; -blockchainTests('Hyper-Parameters', env => { - let testContract: MixinHyperParametersContract; +blockchainTests('Configurable Parameters', env => { + let testContract: MixinParamsContract; let ownerAddress: string; let notOwnerAddress: string; before(async () => { [ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync(); - testContract = await MixinHyperParametersContract.deployFrom0xArtifactAsync( - artifacts.MixinHyperParameters, + testContract = await MixinParamsContract.deployFrom0xArtifactAsync( + artifacts.MixinParams, env.provider, env.txDefaults, artifacts, ); }); - blockchainTests.resets('tune()', () => { + blockchainTests.resets('setParams()', () => { interface HyperParameters { epochDurationInSeconds: Numberish; rewardDelegatedStakeWeight: Numberish; @@ -40,12 +40,12 @@ blockchainTests('Hyper-Parameters', env => { cobbDouglasAlphaDenomintor: 2, }; - async function tuneAndAssertAsync(params: Partial, from?: string): Promise { + async function setParamsAndAssertAsync(params: Partial, from?: string): Promise { const _params = { ...DEFAULT_HYPER_PARAMETERS, ...params, }; - const receipt = await testContract.tune.awaitTransactionSuccessAsync( + const receipt = await testContract.setParams.awaitTransactionSuccessAsync( new BigNumber(_params.epochDurationInSeconds), new BigNumber(_params.rewardDelegatedStakeWeight), new BigNumber(_params.minimumPoolStake), @@ -63,8 +63,8 @@ blockchainTests('Hyper-Parameters', env => { expect(event.maximumMakersInPool).to.bignumber.eq(_params.maximumMakersInPool); expect(event.cobbDouglasAlphaNumerator).to.bignumber.eq(_params.cobbDouglasAlphaNumerator); expect(event.cobbDouglasAlphaDenomintor).to.bignumber.eq(_params.cobbDouglasAlphaDenomintor); - // Assert `getHyperParameters()`. - const actual = await testContract.getHyperParameters.callAsync(); + // Assert `getParams()`. + const actual = await testContract.getParams.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); @@ -74,13 +74,13 @@ blockchainTests('Hyper-Parameters', env => { } it('throws if not called by owner', async () => { - const tx = tuneAndAssertAsync({}, notOwnerAddress); + const tx = setParamsAndAssertAsync({}, notOwnerAddress); const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress); return expect(tx).to.revertWith(expectedError); }); it('works if called by owner', async () => { - return tuneAndAssertAsync({}); + return setParamsAndAssertAsync({}); }); describe('rewardDelegatedStakeWeight', () => { @@ -89,9 +89,9 @@ blockchainTests('Hyper-Parameters', env => { // tslint:disable-next-line restrict-plus-operands rewardDelegatedStakeWeight: constants.PPM_100_PERCENT + 1, }; - const tx = tuneAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidTuningValueError( - StakingRevertErrors.InvalidTuningValueErrorCode.InvalidRewardDelegatedStakeWeight, + const tx = setParamsAndAssertAsync(params); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight, ); return expect(tx).to.revertWith(expectedError); }); @@ -102,49 +102,23 @@ blockchainTests('Hyper-Parameters', env => { const params = { maximumMakersInPool: 0, }; - const tx = tuneAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidTuningValueError( - StakingRevertErrors.InvalidTuningValueErrorCode.InvalidMaximumMakersInPool, + const tx = setParamsAndAssertAsync(params); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool, ); return expect(tx).to.revertWith(expectedError); }); }); 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, + const tx = setParamsAndAssertAsync(params); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, ); return expect(tx).to.revertWith(expectedError); }); @@ -154,9 +128,9 @@ blockchainTests('Hyper-Parameters', env => { cobbDouglasAlphaNumerator: 2, cobbDouglasAlphaDenomintor: 1, }; - const tx = tuneAndAssertAsync(params); - const expectedError = new StakingRevertErrors.InvalidTuningValueError( - StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha, + const tx = setParamsAndAssertAsync(params); + const expectedError = new StakingRevertErrors.InvalidParamValueError( + StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha, ); return expect(tx).to.revertWith(expectedError); }); @@ -166,7 +140,7 @@ blockchainTests('Hyper-Parameters', env => { cobbDouglasAlphaNumerator: 1, cobbDouglasAlphaDenomintor: 1, }; - return tuneAndAssertAsync(params); + return setParamsAndAssertAsync(params); }); it('accepts numerator < denominator', async () => { @@ -174,7 +148,7 @@ blockchainTests('Hyper-Parameters', env => { cobbDouglasAlphaNumerator: 1, cobbDouglasAlphaDenomintor: 2, }; - return tuneAndAssertAsync(params); + return setParamsAndAssertAsync(params); }); it('accepts numerator == 0', async () => { @@ -182,7 +156,7 @@ blockchainTests('Hyper-Parameters', env => { cobbDouglasAlphaNumerator: 0, cobbDouglasAlphaDenomintor: 1, }; - return tuneAndAssertAsync(params); + return setParamsAndAssertAsync(params); }); }); }); diff --git a/contracts/staking/test/rewards_test.ts b/contracts/staking/test/rewards_test.ts index 3d6d429c84..f71afd51f2 100644 --- a/contracts/staking/test/rewards_test.ts +++ b/contracts/staking/test/rewards_test.ts @@ -42,7 +42,7 @@ blockchainTests.resets('Testing Rewards', env => { // deploy staking contracts stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper, artifacts.TestStaking); // set up hyper-parameters - await stakingWrapper.stakingContract.tuneAsync({ + await stakingApiWrapper.stakingContract.setParamsAsync({ minimumPoolStake: new BigNumber(0), cobbDouglasAlphaNumerator: new BigNumber(1), cobbDouglasAlphaDenomintor: new BigNumber(6), diff --git a/contracts/staking/test/utils/staking_wrapper.ts b/contracts/staking/test/utils/staking_wrapper.ts index 638239ed9f..05962e0bf7 100644 --- a/contracts/staking/test/utils/staking_wrapper.ts +++ b/contracts/staking/test/utils/staking_wrapper.ts @@ -191,12 +191,12 @@ export class StakingWrapper { const balance = this._web3Wrapper.getBalanceInWeiAsync(owner); return balance; } - public async tuneAsync(params: Partial): Promise { + public async setParamsAsync(params: Partial): Promise { const _params = { ...constants.DEFAULT_HYPER_PARAMETERS, ...params, }; - const calldata = this.getStakingContract().tune.getABIEncodedTransactionData( + const calldata = this.getStakingContract().setParams.getABIEncodedTransactionData( _params.epochDurationInSeconds, _params.rewardDelegatedStakeWeight, _params.minimumPoolStake, @@ -373,9 +373,9 @@ export class StakingWrapper { return txReceipt; } public async getEpochDurationInSecondsAsync(): Promise { - const calldata = this.getStakingContract().getHyperParameters.getABIEncodedTransactionData(); + const calldata = this.getStakingContract().getParams.getABIEncodedTransactionData(); const returnData = await this._callAsync(calldata); - const params = this.getStakingContract().getHyperParameters.getABIDecodedReturnData(returnData); + const params = this.getStakingContract().getParams.getABIDecodedReturnData(returnData); return params[0]; } public async getCurrentEpochStartTimeInSecondsAsync(): Promise { diff --git a/contracts/staking/tsconfig.json b/contracts/staking/tsconfig.json index 8d66f8c1af..c2aacb742c 100644 --- a/contracts/staking/tsconfig.json +++ b/contracts/staking/tsconfig.json @@ -22,7 +22,7 @@ "generated-artifacts/MixinEthVault.json", "generated-artifacts/MixinExchangeFees.json", "generated-artifacts/MixinExchangeManager.json", - "generated-artifacts/MixinHyperParameters.json", + "generated-artifacts/MixinParams.json", "generated-artifacts/MixinScheduler.json", "generated-artifacts/MixinStake.json", "generated-artifacts/MixinStakeBalances.json",