@0x/contracts-staking: Rename MixinHyperParameters -> MixinParams.

`@0x/contracts-staking`: Move params storage variables into `MixinStorage`.
`@0x/contracts-staking`: Add storage layout tests for new state vars.
`@0x/contracts-staking`: Add more migration tests.
`@0x/contracts-staking`: Add `_initMixinParams()` function that sets up `MixinParams` state.
This commit is contained in:
Lawrence Forman 2019-09-07 22:29:30 -04:00
parent 2a21d87193
commit 25787ea806
21 changed files with 197 additions and 125 deletions

View File

@ -24,6 +24,7 @@ import "./fees/MixinExchangeManager.sol";
import "./stake/MixinZrxVault.sol"; import "./stake/MixinZrxVault.sol";
import "./staking_pools/MixinStakingPoolRewardVault.sol"; import "./staking_pools/MixinStakingPoolRewardVault.sol";
import "./sys/MixinScheduler.sol"; import "./sys/MixinScheduler.sol";
import "./sys/MixinParams.sol";
import "./stake/MixinStakeBalances.sol"; import "./stake/MixinStakeBalances.sol";
import "./stake/MixinStake.sol"; import "./stake/MixinStake.sol";
import "./staking_pools/MixinStakingPool.sol"; import "./staking_pools/MixinStakingPool.sol";
@ -37,7 +38,7 @@ contract Staking is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters, MixinParams,
MixinZrxVault, MixinZrxVault,
MixinExchangeManager, MixinExchangeManager,
MixinStakingPoolRewardVault, MixinStakingPoolRewardVault,
@ -64,7 +65,8 @@ contract Staking is
onlyOwner onlyOwner
{ {
// DANGER! When performing upgrades, take care to modify this logic // DANGER! When performing upgrades, take care to modify this logic
// not to accidentally overwrite existing state. // to prevent accidentally clearing prior state.
_initMixinScheduler(); _initMixinScheduler();
_initMixinParams();
} }
} }

View File

@ -21,8 +21,8 @@ pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "./libs/LibProxy.sol"; import "./libs/LibProxy.sol";
import "./immutable/MixinStorage.sol"; import "./immutable/MixinStorage.sol";
import "./immutable/MixinHyperParameters.sol";
import "./interfaces/IStorageInit.sol"; import "./interfaces/IStorageInit.sol";
import "./interfaces/IStakingEvents.sol";
import "./interfaces/IStakingProxy.sol"; import "./interfaces/IStakingProxy.sol";
@ -31,8 +31,7 @@ contract StakingProxy is
IStakingProxy, IStakingProxy,
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage
MixinHyperParameters
{ {
using LibProxy for address; using LibProxy for address;

View File

@ -49,7 +49,6 @@ contract MixinExchangeFees is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinZrxVault, MixinZrxVault,
MixinExchangeManager, MixinExchangeManager,
MixinStakingPoolRewardVault, MixinStakingPoolRewardVault,

View File

@ -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) // Rebate Vault (stores rewards for pools before they are moved to the eth vault on a per-user basis)
IStakingPoolRewardVault internal rewardVault; 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;
} }

View File

@ -29,10 +29,11 @@ library LibStakingRichErrors {
} }
enum InitializationErrorCode { enum InitializationErrorCode {
MixinSchedulerAlreadyInitialized MixinSchedulerAlreadyInitialized,
MixinParamsAlreadyInitialized
} }
enum InvalidTuningValueErrorCode { enum InvalidParamValueErrorCode {
InvalidCobbDouglasAlpha, InvalidCobbDouglasAlpha,
InvalidRewardDelegatedStakeWeight, InvalidRewardDelegatedStakeWeight,
InvalidMaximumMakersInPool InvalidMaximumMakersInPool
@ -129,9 +130,9 @@ library LibStakingRichErrors {
bytes4 internal constant INITIALIZATION_ERROR_SELECTOR = bytes4 internal constant INITIALIZATION_ERROR_SELECTOR =
0x0b02d773; 0x0b02d773;
// bytes4(keccak256("InvalidTuningValue(uint8)")) // bytes4(keccak256("InvalidParamValue(uint8)"))
bytes4 internal constant INVALID_TUNING_VALUE_ERROR_SELECTOR = bytes4 internal constant INVALID_PARAM_VALUE_ERROR_SELECTOR =
0xbbfd10bb; 0x7b40eece;
// bytes4(keccak256("InvalidProtocolFeePaymentError(uint8,uint256,uint256)")) // bytes4(keccak256("InvalidProtocolFeePaymentError(uint8,uint256,uint256)"))
bytes4 internal constant INVALID_PROTOCOL_FEE_PAYMENT_ERROR_SELECTOR = bytes4 internal constant INVALID_PROTOCOL_FEE_PAYMENT_ERROR_SELECTOR =
@ -435,13 +436,13 @@ library LibStakingRichErrors {
); );
} }
function InvalidTuningValue(InvalidTuningValueErrorCode code) function InvalidParamValue(InvalidParamValueErrorCode code)
internal internal
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return abi.encodeWithSelector( return abi.encodeWithSelector(
INVALID_TUNING_VALUE_ERROR_SELECTOR, INVALID_PARAM_VALUE_ERROR_SELECTOR,
uint8(code) uint8(code)
); );
} }

View File

@ -24,9 +24,11 @@ import "../immutable/MixinConstants.sol";
import "../immutable/MixinStorage.sol"; import "../immutable/MixinStorage.sol";
import "../interfaces/IStakingEvents.sol"; import "../interfaces/IStakingEvents.sol";
import "./MixinZrxVault.sol"; import "./MixinZrxVault.sol";
import "../staking_pools/MixinStakingPoolRewardVault.sol";
import "../staking_pools/MixinStakingPoolRewards.sol"; import "../staking_pools/MixinStakingPoolRewards.sol";
import "../sys/MixinScheduler.sol"; import "../sys/MixinScheduler.sol";
import "../libs/LibStakingRichErrors.sol"; import "../libs/LibStakingRichErrors.sol";
import "./MixinZrxVault.sol";
import "./MixinStakeBalances.sol"; import "./MixinStakeBalances.sol";
import "./MixinStakeStorage.sol"; import "./MixinStakeStorage.sol";
@ -37,7 +39,6 @@ contract MixinStake is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinZrxVault, MixinZrxVault,
MixinStakingPoolRewardVault, MixinStakingPoolRewardVault,
MixinScheduler, MixinScheduler,

View File

@ -35,7 +35,6 @@ contract MixinStakeBalances is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinZrxVault, MixinZrxVault,
MixinScheduler, MixinScheduler,
MixinStakeStorage MixinStakeStorage

View File

@ -33,7 +33,6 @@ contract MixinStakeStorage is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinScheduler MixinScheduler
{ {
using LibSafeMath for uint256; using LibSafeMath for uint256;

View File

@ -57,7 +57,6 @@ contract MixinStakingPool is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinZrxVault, MixinZrxVault,
MixinStakingPoolRewardVault, MixinStakingPoolRewardVault,
MixinScheduler, MixinScheduler,

View File

@ -32,7 +32,6 @@ contract MixinStakingPoolRewards is
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage,
MixinHyperParameters,
MixinZrxVault, MixinZrxVault,
MixinStakingPoolRewardVault, MixinStakingPoolRewardVault,
MixinScheduler, MixinScheduler,

View File

@ -20,43 +20,32 @@ pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "../immutable/MixinConstants.sol";
import "../immutable/MixinStorage.sol";
import "../interfaces/IStakingEvents.sol"; import "../interfaces/IStakingEvents.sol";
import "../libs/LibStakingRichErrors.sol"; import "../libs/LibStakingRichErrors.sol";
import "./MixinConstants.sol";
contract MixinHyperParameters is contract MixinParams is
IStakingEvents, IStakingEvents,
MixinConstants, MixinConstants,
Ownable Ownable,
MixinStorage
{ {
// Minimum seconds between epochs. /// @dev Set all configurable parameters at once.
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.
/// @param _epochDurationInSeconds Minimum seconds between epochs. /// @param _epochDurationInSeconds Minimum seconds between epochs.
/// @param _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. /// @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 _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 _maximumMakersInPool Maximum number of maker addresses allowed to be registered to a pool.
/// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @param _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
/// @param _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor. /// @param _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor.
function tune( function setParams(
uint256 _epochDurationInSeconds, uint256 _epochDurationInSeconds,
uint32 _rewardDelegatedStakeWeight, uint32 _rewardDelegatedStakeWeight,
uint256 _minimumPoolStake, uint256 _minimumPoolStake,
uint256 _maximumMakersInPool, uint256 _maximumMakersInPool,
uint256 _cobbDouglasAlphaNumerator, uint32 _cobbDouglasAlphaNumerator,
uint256 _cobbDouglasAlphaDenomintor uint32 _cobbDouglasAlphaDenomintor
) )
external external
onlyOwner 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 _epochDurationInSeconds Minimum seconds between epochs.
/// @return _rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm. /// @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 _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 _maximumMakersInPool Maximum number of maker addresses allowed to be registered to a pool.
/// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor. /// @return _cobbDouglasAlphaNumerator Numerator for cobb douglas alpha factor.
/// @return _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor. /// @return _cobbDouglasAlphaDenomintor Denominator for cobb douglas alpha factor.
function getHyperParameters() function getParams()
external external
view view
returns ( returns (
@ -100,8 +89,8 @@ contract MixinHyperParameters is
uint32 _rewardDelegatedStakeWeight, uint32 _rewardDelegatedStakeWeight,
uint256 _minimumPoolStake, uint256 _minimumPoolStake,
uint256 _maximumMakersInPool, uint256 _maximumMakersInPool,
uint256 _cobbDouglasAlphaNumerator, uint32 _cobbDouglasAlphaNumerator,
uint256 _cobbDouglasAlphaDenomintor uint32 _cobbDouglasAlphaDenomintor
) )
{ {
_epochDurationInSeconds = epochDurationInSeconds; _epochDurationInSeconds = epochDurationInSeconds;
@ -112,41 +101,68 @@ contract MixinHyperParameters is
_cobbDouglasAlphaDenomintor = cobbDouglasAlphaDenomintor; _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. /// @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( function _assertValidCobbDouglasAlpha(
uint256 numerator, uint32 numerator,
uint256 denominator uint32 denominator
) )
private private
pure pure
{ {
if (int256(numerator) < 0 // Alpha must be 0 < x < 1
|| int256(denominator) <= 0 if (numerator > denominator || denominator == 0) {
|| numerator > denominator
) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.InvalidTuningValue( LibStakingRichErrors.InvalidParamValue(
LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha LibStakingRichErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha
)); ));
} }
} }
/// @dev Asserts that a stake weight is valid. /// @dev Asserts that a stake weight is valid.
/// @param weight How much delegated stake is weighted vs operator stake, in ppm.
function _assertValidRewardDelegatedStakeWeight( function _assertValidRewardDelegatedStakeWeight(
uint256 weight uint32 weight
) )
private private
pure pure
{ {
if (weight > PPM_DENOMINATOR) { if (weight > PPM_DENOMINATOR) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.InvalidTuningValue( LibStakingRichErrors.InvalidParamValue(
LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidRewardDelegatedStakeWeight LibStakingRichErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight
)); ));
} }
} }
/// @dev Asserts that a maximum makers value is valid. /// @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( function _assertValidMaximumMakersInPool(
uint256 amount uint256 amount
) )
@ -155,8 +171,8 @@ contract MixinHyperParameters is
{ {
if (amount == 0) { if (amount == 0) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.InvalidTuningValue( LibStakingRichErrors.InvalidParamValue(
LibStakingRichErrors.InvalidTuningValueErrorCode.InvalidMaximumMakersInPool LibStakingRichErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool
)); ));
} }
} }

View File

@ -21,7 +21,6 @@ pragma solidity ^0.5.9;
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol"; import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibSafeMath.sol"; import "@0x/contracts-utils/contracts/src/LibSafeMath.sol";
import "../libs/LibStakingRichErrors.sol"; import "../libs/LibStakingRichErrors.sol";
import "../immutable/MixinHyperParameters.sol";
import "../immutable/MixinConstants.sol"; import "../immutable/MixinConstants.sol";
import "../immutable/MixinStorage.sol"; import "../immutable/MixinStorage.sol";
import "../interfaces/IStructs.sol"; import "../interfaces/IStructs.sol";
@ -38,8 +37,7 @@ contract MixinScheduler is
IStakingEvents, IStakingEvents,
MixinConstants, MixinConstants,
Ownable, Ownable,
MixinStorage, MixinStorage
MixinHyperParameters
{ {
using LibSafeMath for uint256; using LibSafeMath for uint256;

View File

@ -20,18 +20,18 @@ pragma experimental ABIEncoderV2;
import "@0x/contracts-utils/contracts/src/Ownable.sol"; import "@0x/contracts-utils/contracts/src/Ownable.sol";
import "../src/immutable/MixinStorage.sol"; import "../src/immutable/MixinStorage.sol";
import "../src/immutable/MixinHyperParameters.sol";
contract TestInitTarget is contract TestInitTarget is
Ownable, Ownable,
MixinStorage, MixinStorage
MixinHyperParameters
{ {
// We can't store state in this contract before it is attached, so // We can't store state in this contract before it is attached, so
// we will grant this predefined address a balance to indicate that // we will grant this predefined address a balance to indicate that
// `init()` should revert. // `init()` should revert.
address public constant SHOULD_REVERT_ADDRESS = 0x5ed6A38c6bEcEd15b0AB58566b6fD7A00463d2F7; 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. // `msg.sender` of the last `init()` call.
address private _initSender = address(0); address private _initSender = address(0);
// `address(this)` of the last `init()` call. // `address(this)` of the last `init()` call.
@ -39,8 +39,9 @@ contract TestInitTarget is
function init() external { function init() external {
if (SHOULD_REVERT_ADDRESS.balance != 0) { if (SHOULD_REVERT_ADDRESS.balance != 0) {
revert("WHOOPSIE!"); revert("FORCED_REVERT");
} }
_initCounter += 1;
_initSender = msg.sender; _initSender = msg.sender;
_initThisAddress = address(this); _initThisAddress = address(this);
} }
@ -56,4 +57,8 @@ contract TestInitTarget is
initSender = _initSender; initSender = _initSender;
initThisAddress = _initThisAddress; initThisAddress = _initThisAddress;
} }
function getInitCounter() external view returns (uint256) {
return _initCounter;
}
} }

View File

@ -107,6 +107,24 @@ contract TestStorageLayout is
if sub(rewardVault_slot, slot) { revertIncorrectStorageSlot() } if sub(rewardVault_slot, slot) { revertIncorrectStorageSlot() }
slot := add(slot, 1) 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)
} }
} }
} }

View File

@ -24,7 +24,7 @@ import * as MixinConstants from '../generated-artifacts/MixinConstants.json';
import * as MixinEthVault from '../generated-artifacts/MixinEthVault.json'; import * as MixinEthVault from '../generated-artifacts/MixinEthVault.json';
import * as MixinExchangeFees from '../generated-artifacts/MixinExchangeFees.json'; import * as MixinExchangeFees from '../generated-artifacts/MixinExchangeFees.json';
import * as MixinExchangeManager from '../generated-artifacts/MixinExchangeManager.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 MixinScheduler from '../generated-artifacts/MixinScheduler.json';
import * as MixinStake from '../generated-artifacts/MixinStake.json'; import * as MixinStake from '../generated-artifacts/MixinStake.json';
import * as MixinStakeBalances from '../generated-artifacts/MixinStakeBalances.json'; import * as MixinStakeBalances from '../generated-artifacts/MixinStakeBalances.json';
@ -55,7 +55,6 @@ export const artifacts = {
MixinExchangeFees: MixinExchangeFees as ContractArtifact, MixinExchangeFees: MixinExchangeFees as ContractArtifact,
MixinExchangeManager: MixinExchangeManager as ContractArtifact, MixinExchangeManager: MixinExchangeManager as ContractArtifact,
MixinConstants: MixinConstants as ContractArtifact, MixinConstants: MixinConstants as ContractArtifact,
MixinHyperParameters: MixinHyperParameters as ContractArtifact,
MixinStorage: MixinStorage as ContractArtifact, MixinStorage: MixinStorage as ContractArtifact,
IEthVault: IEthVault as ContractArtifact, IEthVault: IEthVault as ContractArtifact,
IStaking: IStaking as ContractArtifact, IStaking: IStaking as ContractArtifact,
@ -79,6 +78,7 @@ export const artifacts = {
MixinStakingPool: MixinStakingPool as ContractArtifact, MixinStakingPool: MixinStakingPool as ContractArtifact,
MixinStakingPoolRewardVault: MixinStakingPoolRewardVault as ContractArtifact, MixinStakingPoolRewardVault: MixinStakingPoolRewardVault as ContractArtifact,
MixinStakingPoolRewards: MixinStakingPoolRewards as ContractArtifact, MixinStakingPoolRewards: MixinStakingPoolRewards as ContractArtifact,
MixinParams: MixinParams as ContractArtifact,
MixinScheduler: MixinScheduler as ContractArtifact, MixinScheduler: MixinScheduler as ContractArtifact,
EthVault: EthVault as ContractArtifact, EthVault: EthVault as ContractArtifact,
MixinVaultCore: MixinVaultCore as ContractArtifact, MixinVaultCore: MixinVaultCore as ContractArtifact,

View File

@ -22,7 +22,7 @@ export * from '../generated-wrappers/mixin_constants';
export * from '../generated-wrappers/mixin_eth_vault'; export * from '../generated-wrappers/mixin_eth_vault';
export * from '../generated-wrappers/mixin_exchange_fees'; export * from '../generated-wrappers/mixin_exchange_fees';
export * from '../generated-wrappers/mixin_exchange_manager'; 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_scheduler';
export * from '../generated-wrappers/mixin_stake'; export * from '../generated-wrappers/mixin_stake';
export * from '../generated-wrappers/mixin_stake_balances'; export * from '../generated-wrappers/mixin_stake_balances';

View File

@ -1,4 +1,5 @@
import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils'; import { blockchainTests, constants, expect, hexRandom } from '@0x/contracts-test-utils';
import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber, OwnableRevertErrors, StringRevertError } from '@0x/utils'; import { BigNumber, OwnableRevertErrors, StringRevertError } from '@0x/utils';
import { artifacts, StakingContract, TestInitTargetContract, TestStakingProxyContract } from '../src/'; import { artifacts, StakingContract, TestInitTargetContract, TestStakingProxyContract } from '../src/';
@ -12,7 +13,7 @@ blockchainTests('Migration tests', env => {
}); });
describe('StakingProxy', () => { describe('StakingProxy', () => {
const REVERT_ERROR = new StringRevertError('WHOOPSIE!'); const REVERT_ERROR = new StringRevertError('FORCED_REVERT');
let initTargetContract: TestInitTargetContract; let initTargetContract: TestInitTargetContract;
async function deployStakingProxyAsync(stakingContractAddress?: string): Promise<TestStakingProxyContract> { async function deployStakingProxyAsync(stakingContractAddress?: string): Promise<TestStakingProxyContract> {
@ -104,6 +105,43 @@ blockchainTests('Migration tests', env => {
return expect(tx).to.revertWith(REVERT_ERROR); 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 () => { blockchainTests.resets('Staking.init()', async () => {
@ -123,6 +161,13 @@ blockchainTests('Migration tests', env => {
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress); const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress);
return expect(tx).to.revertWith(expectedError); 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 // tslint:enable:no-unnecessary-type-assertion

View File

@ -2,24 +2,24 @@ import { blockchainTests, constants, expect, filterLogsToArguments, Numberish }
import { StakingRevertErrors } from '@0x/order-utils'; import { StakingRevertErrors } from '@0x/order-utils';
import { BigNumber, OwnableRevertErrors } from '@0x/utils'; import { BigNumber, OwnableRevertErrors } from '@0x/utils';
import { artifacts, IStakingEventsTunedEventArgs, MixinHyperParametersContract } from '../src/'; import { artifacts, IStakingEventsTunedEventArgs, MixinParamsContract } from '../src/';
blockchainTests('Hyper-Parameters', env => { blockchainTests('Configurable Parameters', env => {
let testContract: MixinHyperParametersContract; let testContract: MixinParamsContract;
let ownerAddress: string; let ownerAddress: string;
let notOwnerAddress: string; let notOwnerAddress: string;
before(async () => { before(async () => {
[ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync(); [ownerAddress, notOwnerAddress] = await env.getAccountAddressesAsync();
testContract = await MixinHyperParametersContract.deployFrom0xArtifactAsync( testContract = await MixinParamsContract.deployFrom0xArtifactAsync(
artifacts.MixinHyperParameters, artifacts.MixinParams,
env.provider, env.provider,
env.txDefaults, env.txDefaults,
artifacts, artifacts,
); );
}); });
blockchainTests.resets('tune()', () => { blockchainTests.resets('setParams()', () => {
interface HyperParameters { interface HyperParameters {
epochDurationInSeconds: Numberish; epochDurationInSeconds: Numberish;
rewardDelegatedStakeWeight: Numberish; rewardDelegatedStakeWeight: Numberish;
@ -40,12 +40,12 @@ blockchainTests('Hyper-Parameters', env => {
cobbDouglasAlphaDenomintor: 2, cobbDouglasAlphaDenomintor: 2,
}; };
async function tuneAndAssertAsync(params: Partial<HyperParameters>, from?: string): Promise<void> { async function setParamsAndAssertAsync(params: Partial<HyperParameters>, from?: string): Promise<void> {
const _params = { const _params = {
...DEFAULT_HYPER_PARAMETERS, ...DEFAULT_HYPER_PARAMETERS,
...params, ...params,
}; };
const receipt = await testContract.tune.awaitTransactionSuccessAsync( const receipt = await testContract.setParams.awaitTransactionSuccessAsync(
new BigNumber(_params.epochDurationInSeconds), new BigNumber(_params.epochDurationInSeconds),
new BigNumber(_params.rewardDelegatedStakeWeight), new BigNumber(_params.rewardDelegatedStakeWeight),
new BigNumber(_params.minimumPoolStake), new BigNumber(_params.minimumPoolStake),
@ -63,8 +63,8 @@ blockchainTests('Hyper-Parameters', env => {
expect(event.maximumMakersInPool).to.bignumber.eq(_params.maximumMakersInPool); expect(event.maximumMakersInPool).to.bignumber.eq(_params.maximumMakersInPool);
expect(event.cobbDouglasAlphaNumerator).to.bignumber.eq(_params.cobbDouglasAlphaNumerator); expect(event.cobbDouglasAlphaNumerator).to.bignumber.eq(_params.cobbDouglasAlphaNumerator);
expect(event.cobbDouglasAlphaDenomintor).to.bignumber.eq(_params.cobbDouglasAlphaDenomintor); expect(event.cobbDouglasAlphaDenomintor).to.bignumber.eq(_params.cobbDouglasAlphaDenomintor);
// Assert `getHyperParameters()`. // Assert `getParams()`.
const actual = await testContract.getHyperParameters.callAsync(); const actual = await testContract.getParams.callAsync();
expect(actual[0]).to.bignumber.eq(_params.epochDurationInSeconds); expect(actual[0]).to.bignumber.eq(_params.epochDurationInSeconds);
expect(actual[1]).to.bignumber.eq(_params.rewardDelegatedStakeWeight); expect(actual[1]).to.bignumber.eq(_params.rewardDelegatedStakeWeight);
expect(actual[2]).to.bignumber.eq(_params.minimumPoolStake); expect(actual[2]).to.bignumber.eq(_params.minimumPoolStake);
@ -74,13 +74,13 @@ blockchainTests('Hyper-Parameters', env => {
} }
it('throws if not called by owner', async () => { it('throws if not called by owner', async () => {
const tx = tuneAndAssertAsync({}, notOwnerAddress); const tx = setParamsAndAssertAsync({}, notOwnerAddress);
const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress); const expectedError = new OwnableRevertErrors.OnlyOwnerError(notOwnerAddress, ownerAddress);
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
it('works if called by owner', async () => { it('works if called by owner', async () => {
return tuneAndAssertAsync({}); return setParamsAndAssertAsync({});
}); });
describe('rewardDelegatedStakeWeight', () => { describe('rewardDelegatedStakeWeight', () => {
@ -89,9 +89,9 @@ blockchainTests('Hyper-Parameters', env => {
// tslint:disable-next-line restrict-plus-operands // tslint:disable-next-line restrict-plus-operands
rewardDelegatedStakeWeight: constants.PPM_100_PERCENT + 1, rewardDelegatedStakeWeight: constants.PPM_100_PERCENT + 1,
}; };
const tx = tuneAndAssertAsync(params); const tx = setParamsAndAssertAsync(params);
const expectedError = new StakingRevertErrors.InvalidTuningValueError( const expectedError = new StakingRevertErrors.InvalidParamValueError(
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidRewardDelegatedStakeWeight, StakingRevertErrors.InvalidParamValueErrorCode.InvalidRewardDelegatedStakeWeight,
); );
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -102,49 +102,23 @@ blockchainTests('Hyper-Parameters', env => {
const params = { const params = {
maximumMakersInPool: 0, maximumMakersInPool: 0,
}; };
const tx = tuneAndAssertAsync(params); const tx = setParamsAndAssertAsync(params);
const expectedError = new StakingRevertErrors.InvalidTuningValueError( const expectedError = new StakingRevertErrors.InvalidParamValueError(
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidMaximumMakersInPool, StakingRevertErrors.InvalidParamValueErrorCode.InvalidMaximumMakersInPool,
); );
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
}); });
describe('cobb-douglas alpha', () => { 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 () => { it('throws with denominator == 0', async () => {
const params = { const params = {
cobbDouglasAlphaNumerator: 0, cobbDouglasAlphaNumerator: 0,
cobbDouglasAlphaDenomintor: 0, cobbDouglasAlphaDenomintor: 0,
}; };
const tx = tuneAndAssertAsync(params); const tx = setParamsAndAssertAsync(params);
const expectedError = new StakingRevertErrors.InvalidTuningValueError( const expectedError = new StakingRevertErrors.InvalidParamValueError(
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha, StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha,
); );
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -154,9 +128,9 @@ blockchainTests('Hyper-Parameters', env => {
cobbDouglasAlphaNumerator: 2, cobbDouglasAlphaNumerator: 2,
cobbDouglasAlphaDenomintor: 1, cobbDouglasAlphaDenomintor: 1,
}; };
const tx = tuneAndAssertAsync(params); const tx = setParamsAndAssertAsync(params);
const expectedError = new StakingRevertErrors.InvalidTuningValueError( const expectedError = new StakingRevertErrors.InvalidParamValueError(
StakingRevertErrors.InvalidTuningValueErrorCode.InvalidCobbDouglasAlpha, StakingRevertErrors.InvalidParamValueErrorCode.InvalidCobbDouglasAlpha,
); );
return expect(tx).to.revertWith(expectedError); return expect(tx).to.revertWith(expectedError);
}); });
@ -166,7 +140,7 @@ blockchainTests('Hyper-Parameters', env => {
cobbDouglasAlphaNumerator: 1, cobbDouglasAlphaNumerator: 1,
cobbDouglasAlphaDenomintor: 1, cobbDouglasAlphaDenomintor: 1,
}; };
return tuneAndAssertAsync(params); return setParamsAndAssertAsync(params);
}); });
it('accepts numerator < denominator', async () => { it('accepts numerator < denominator', async () => {
@ -174,7 +148,7 @@ blockchainTests('Hyper-Parameters', env => {
cobbDouglasAlphaNumerator: 1, cobbDouglasAlphaNumerator: 1,
cobbDouglasAlphaDenomintor: 2, cobbDouglasAlphaDenomintor: 2,
}; };
return tuneAndAssertAsync(params); return setParamsAndAssertAsync(params);
}); });
it('accepts numerator == 0', async () => { it('accepts numerator == 0', async () => {
@ -182,7 +156,7 @@ blockchainTests('Hyper-Parameters', env => {
cobbDouglasAlphaNumerator: 0, cobbDouglasAlphaNumerator: 0,
cobbDouglasAlphaDenomintor: 1, cobbDouglasAlphaDenomintor: 1,
}; };
return tuneAndAssertAsync(params); return setParamsAndAssertAsync(params);
}); });
}); });
}); });

View File

@ -42,7 +42,7 @@ blockchainTests.resets('Testing Rewards', env => {
// deploy staking contracts // deploy staking contracts
stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper, artifacts.TestStaking); stakingApiWrapper = await deployAndConfigureContractsAsync(env, owner, erc20Wrapper, artifacts.TestStaking);
// set up hyper-parameters // set up hyper-parameters
await stakingWrapper.stakingContract.tuneAsync({ await stakingApiWrapper.stakingContract.setParamsAsync({
minimumPoolStake: new BigNumber(0), minimumPoolStake: new BigNumber(0),
cobbDouglasAlphaNumerator: new BigNumber(1), cobbDouglasAlphaNumerator: new BigNumber(1),
cobbDouglasAlphaDenomintor: new BigNumber(6), cobbDouglasAlphaDenomintor: new BigNumber(6),

View File

@ -191,12 +191,12 @@ export class StakingWrapper {
const balance = this._web3Wrapper.getBalanceInWeiAsync(owner); const balance = this._web3Wrapper.getBalanceInWeiAsync(owner);
return balance; return balance;
} }
public async tuneAsync(params: Partial<HyperParameters>): Promise<TransactionReceiptWithDecodedLogs> { public async setParamsAsync(params: Partial<HyperParameters>): Promise<TransactionReceiptWithDecodedLogs> {
const _params = { const _params = {
...constants.DEFAULT_HYPER_PARAMETERS, ...constants.DEFAULT_HYPER_PARAMETERS,
...params, ...params,
}; };
const calldata = this.getStakingContract().tune.getABIEncodedTransactionData( const calldata = this.getStakingContract().setParams.getABIEncodedTransactionData(
_params.epochDurationInSeconds, _params.epochDurationInSeconds,
_params.rewardDelegatedStakeWeight, _params.rewardDelegatedStakeWeight,
_params.minimumPoolStake, _params.minimumPoolStake,
@ -373,9 +373,9 @@ export class StakingWrapper {
return txReceipt; return txReceipt;
} }
public async getEpochDurationInSecondsAsync(): Promise<BigNumber> { public async getEpochDurationInSecondsAsync(): Promise<BigNumber> {
const calldata = this.getStakingContract().getHyperParameters.getABIEncodedTransactionData(); const calldata = this.getStakingContract().getParams.getABIEncodedTransactionData();
const returnData = await this._callAsync(calldata); const returnData = await this._callAsync(calldata);
const params = this.getStakingContract().getHyperParameters.getABIDecodedReturnData(returnData); const params = this.getStakingContract().getParams.getABIDecodedReturnData(returnData);
return params[0]; return params[0];
} }
public async getCurrentEpochStartTimeInSecondsAsync(): Promise<BigNumber> { public async getCurrentEpochStartTimeInSecondsAsync(): Promise<BigNumber> {

View File

@ -22,7 +22,7 @@
"generated-artifacts/MixinEthVault.json", "generated-artifacts/MixinEthVault.json",
"generated-artifacts/MixinExchangeFees.json", "generated-artifacts/MixinExchangeFees.json",
"generated-artifacts/MixinExchangeManager.json", "generated-artifacts/MixinExchangeManager.json",
"generated-artifacts/MixinHyperParameters.json", "generated-artifacts/MixinParams.json",
"generated-artifacts/MixinScheduler.json", "generated-artifacts/MixinScheduler.json",
"generated-artifacts/MixinStake.json", "generated-artifacts/MixinStake.json",
"generated-artifacts/MixinStakeBalances.json", "generated-artifacts/MixinStakeBalances.json",