Merge pull request #2204 from 0xProject/feature/staking/move-storage-layout-assertions

Feature/staking/move storage layout assertions
This commit is contained in:
James Towle
2019-09-24 18:32:12 -07:00
committed by GitHub
12 changed files with 481 additions and 357 deletions

View File

@@ -65,325 +65,4 @@ contract Staking is
_initMixinScheduler();
_initMixinParams();
}
/// @dev This function will fail if the storage layout of this contract deviates from
/// the original staking contract's storage. The use of this function provides assurance
/// that regressions from the original storage layout will not occur.
function _assertStorageLayout()
internal
pure
{
assembly {
let slot := 0x0
let offset := 0x0
/// Ownable
assertSlotAndOffset(
owner_slot,
owner_offset,
slot,
offset
)
slot := add(slot, 0x1)
/// Authorizable
assertSlotAndOffset(
authorized_slot,
authorized_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
authorities_slot,
authorities_offset,
slot,
offset
)
slot := add(slot, 0x1)
/// MixinStorage
assertSlotAndOffset(
stakingContract_slot,
stakingContract_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
readOnlyProxy_slot,
readOnlyProxy_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
readOnlyProxyCallee_slot,
readOnlyProxyCallee_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
globalStakeByStatus_slot,
globalStakeByStatus_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_activeStakeByOwner_slot,
_activeStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_inactiveStakeByOwner_slot,
_inactiveStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeByOwner_slot,
_delegatedStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeToPoolByOwner_slot,
_delegatedStakeToPoolByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeByPoolId_slot,
_delegatedStakeByPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_withdrawableStakeByOwner_slot,
_withdrawableStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
nextPoolId_slot,
nextPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_poolJoinedByMakerAddress_slot,
_poolJoinedByMakerAddress_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_poolById_slot,
_poolById_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
rewardsByPoolId_slot,
rewardsByPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
currentEpoch_slot,
currentEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
currentEpochStartTimeInSeconds_slot,
currentEpochStartTimeInSeconds_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_cumulativeRewardsByPool_slot,
_cumulativeRewardsByPool_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_cumulativeRewardsByPoolLastStored_slot,
_cumulativeRewardsByPoolLastStored_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
validExchanges_slot,
validExchanges_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
epochDurationInSeconds_slot,
epochDurationInSeconds_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
rewardDelegatedStakeWeight_slot,
rewardDelegatedStakeWeight_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
minimumPoolStake_slot,
minimumPoolStake_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
maximumMakersInPool_slot,
maximumMakersInPool_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
cobbDouglasAlphaNumerator_slot,
cobbDouglasAlphaNumerator_offset,
slot,
offset
)
offset := add(offset, 0x4)
// This number will be tightly packed into the previous values storage slot since
// they are both `uint32`. Because of this tight packing, the offset of this value
// must be 4, since the previous value is a 4 byte number.
assertSlotAndOffset(
cobbDouglasAlphaDenominator_slot,
cobbDouglasAlphaDenominator_offset,
slot,
offset
)
slot := add(slot, 0x1)
offset := 0x0
assertSlotAndOffset(
totalFeesCollectedThisEpoch_slot,
totalFeesCollectedThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
totalWeightedStakeThisEpoch_slot,
totalWeightedStakeThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_activePoolsByEpoch_slot,
_activePoolsByEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
numActivePoolsThisEpoch_slot,
numActivePoolsThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
unfinalizedState_slot,
unfinalizedState_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
wethReservedForPoolRewards_slot,
wethReservedForPoolRewards_offset,
slot,
offset
)
// This assembly function will assert that the actual values for `_slot` and `_offset` are
// correct and will revert with a rich error if they are different than the expected values.
function assertSlotAndOffset(
actual_slot,
actual_offset,
expected_slot,
expected_offset
) {
// If expected_slot is not equal to actual_slot, revert with a rich error.
if iszero(eq(expected_slot, actual_slot)) {
mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector
mstore(0x4, 0x0) // Unexpected slot error code
mstore(0x24, expected_slot) // Expected slot
mstore(0x44, actual_slot) // Actual slot
revert(0x0, 0x64)
}
// If expected_offset is not equal to actual_offset, revert with a rich error.
if iszero(eq(expected_offset, actual_offset)) {
mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector
mstore(0x4, 0x1) // Unexpected offset error code
mstore(0x24, expected_offset) // Expected offset
mstore(0x44, actual_offset) // Actual offset
revert(0x0, 0x64)
}
}
}
}
}

View File

@@ -20,18 +20,12 @@ pragma solidity ^0.5.9;
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetProxy.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-utils/contracts/src/LibRichErrors.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../libs/LibStakingRichErrors.sol";
import "../interfaces/IZrxVault.sol";
// solhint-disable separate-by-one-line-in-contract
contract MixinDeploymentConstants {
using LibBytes for bytes;
// @TODO SET THESE VALUES FOR DEPLOYMENT
// Mainnet WETH9 Address
@@ -56,29 +50,6 @@ contract MixinDeploymentConstants {
address constant private WETH_ASSET_PROXY_ADDRESS = address(1);
address constant private ZRX_VAULT_ADDRESS = address(1);
/// @dev Ensures that the WETH_ASSET_DATA is correct.
constructor()
public
{
require(
WETH_ASSET_DATA.equals(abi.encodeWithSelector(
IAssetData(address(0)).ERC20Token.selector,
WETH_ADDRESS
)),
"INVALID_WETH_ASSET_DATA"
);
require(
WETH_ASSET_PROXY_ADDRESS != address(0),
"WETH_ASSET_PROXY_MUST_BE_SET"
);
require(
ZRX_VAULT_ADDRESS != address(0),
"ZRX_VAULT_MUST_BE_SET"
);
}
/// @dev An overridable way to access the deployed WETH contract.
/// Must be view to allow overrides to access state.
/// @return wethContract The WETH contract instance.

View File

@@ -229,7 +229,7 @@ contract MixinStakingPool is
// cache pool and join status for use throughout this function
IStructs.Pool memory pool = _poolById[poolId];
IStructs.MakerPoolJoinStatus memory poolJoinStatus = _poolJoinedByMakerAddress[makerAddress];
// Is the maker already in a pool?
if (poolJoinStatus.confirmed) {
LibRichErrors.rrevert(LibStakingRichErrors.MakerPoolAssignmentError(

View File

@@ -19,8 +19,9 @@
pragma solidity ^0.5.9;
pragma experimental ABIEncoderV2;
import "../src/Staking.sol";
import "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-erc20/contracts/src/interfaces/IEtherToken.sol";
import "../src/Staking.sol";
contract TestStaking is
@@ -64,7 +65,7 @@ contract TestStaking is
return abi.encodeWithSelector(
IAssetData(address(0)).ERC20Token.selector,
wethAddress
);
);
}
function getWethAssetProxy()

View File

@@ -0,0 +1,384 @@
/*
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 "@0x/contracts-asset-proxy/contracts/src/interfaces/IAssetData.sol";
import "@0x/contracts-utils/contracts/src/LibBytes.sol";
import "../src/Staking.sol";
contract TestStorageLayoutAndConstants is
Staking
{
using LibBytes for bytes;
/// @dev Construction will fail if the storage layout or the deployment constants are incompatible
/// with the V1 staking proxy.
constructor() public {
_assertDeploymentConstants();
_assertStorageLayout();
}
/// @dev This function will fail if the deployment constants change to the point where they
/// are considered "invalid".
function _assertDeploymentConstants()
internal
view
{
require(
getWethAssetData().equals(abi.encodeWithSelector(
IAssetData(address(0)).ERC20Token.selector,
getWethContract()
)),
"INVALID_WETH_ASSET_DATA"
);
require(
address(getWethAssetProxy()) != address(0),
"WETH_ASSET_PROXY_MUST_BE_SET"
);
require(
address(getZrxVault()) != address(0),
"ZRX_VAULT_MUST_BE_SET"
);
}
/// @dev This function will fail if the storage layout of this contract deviates from
/// the original staking contract's storage. The use of this function provides assurance
/// that regressions from the original storage layout will not occur.
function _assertStorageLayout()
internal
pure
{
assembly {
let slot := 0x0
let offset := 0x0
/// Ownable
assertSlotAndOffset(
owner_slot,
owner_offset,
slot,
offset
)
slot := add(slot, 0x1)
/// Authorizable
assertSlotAndOffset(
authorized_slot,
authorized_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
authorities_slot,
authorities_offset,
slot,
offset
)
slot := add(slot, 0x1)
/// MixinStorage
assertSlotAndOffset(
stakingContract_slot,
stakingContract_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
readOnlyProxy_slot,
readOnlyProxy_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
readOnlyProxyCallee_slot,
readOnlyProxyCallee_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
globalStakeByStatus_slot,
globalStakeByStatus_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_activeStakeByOwner_slot,
_activeStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_inactiveStakeByOwner_slot,
_inactiveStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeByOwner_slot,
_delegatedStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeToPoolByOwner_slot,
_delegatedStakeToPoolByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_delegatedStakeByPoolId_slot,
_delegatedStakeByPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_withdrawableStakeByOwner_slot,
_withdrawableStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
nextPoolId_slot,
nextPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_poolJoinedByMakerAddress_slot,
_poolJoinedByMakerAddress_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_poolById_slot,
_poolById_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
rewardsByPoolId_slot,
rewardsByPoolId_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
currentEpoch_slot,
currentEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
currentEpochStartTimeInSeconds_slot,
currentEpochStartTimeInSeconds_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_cumulativeRewardsByPool_slot,
_cumulativeRewardsByPool_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_cumulativeRewardsByPoolLastStored_slot,
_cumulativeRewardsByPoolLastStored_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
validExchanges_slot,
validExchanges_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
epochDurationInSeconds_slot,
epochDurationInSeconds_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
rewardDelegatedStakeWeight_slot,
rewardDelegatedStakeWeight_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
minimumPoolStake_slot,
minimumPoolStake_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
maximumMakersInPool_slot,
maximumMakersInPool_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
cobbDouglasAlphaNumerator_slot,
cobbDouglasAlphaNumerator_offset,
slot,
offset
)
offset := add(offset, 0x4)
// This number will be tightly packed into the previous values storage slot since
// they are both `uint32`. Because of this tight packing, the offset of this value
// must be 4, since the previous value is a 4 byte number.
assertSlotAndOffset(
cobbDouglasAlphaDenominator_slot,
cobbDouglasAlphaDenominator_offset,
slot,
offset
)
slot := add(slot, 0x1)
offset := 0x0
assertSlotAndOffset(
totalFeesCollectedThisEpoch_slot,
totalFeesCollectedThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
totalWeightedStakeThisEpoch_slot,
totalWeightedStakeThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_activePoolsByEpoch_slot,
_activePoolsByEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
numActivePoolsThisEpoch_slot,
numActivePoolsThisEpoch_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
unfinalizedState_slot,
unfinalizedState_offset,
slot,
offset
)
slot := add(slot, 0x5)
assertSlotAndOffset(
wethReservedForPoolRewards_slot,
wethReservedForPoolRewards_offset,
slot,
offset
)
// This assembly function will assert that the actual values for `_slot` and `_offset` are
// correct and will revert with a rich error if they are different than the expected values.
function assertSlotAndOffset(
actual_slot,
actual_offset,
expected_slot,
expected_offset
) {
// If expected_slot is not equal to actual_slot, revert with a rich error.
if iszero(eq(expected_slot, actual_slot)) {
mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector
mstore(0x4, 0x0) // Unexpected slot error code
mstore(0x24, expected_slot) // Expected slot
mstore(0x44, actual_slot) // Actual slot
revert(0x0, 0x64)
}
// If expected_offset is not equal to actual_offset, revert with a rich error.
if iszero(eq(expected_offset, actual_offset)) {
mstore(0x0, 0x213eb13400000000000000000000000000000000000000000000000000000000) // Rich error selector
mstore(0x4, 0x1) // Unexpected offset error code
mstore(0x24, expected_offset) // Expected offset
mstore(0x44, actual_offset) // Actual offset
revert(0x0, 0x64)
}
}
}
}
}

View File

@@ -37,7 +37,7 @@
},
"config": {
"abis:comment": "This list is auto-generated by contracts-gen. Don't edit manually.",
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IVaultCore|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|ReadOnlyProxy|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinVaultCore|TestProtocolFees|TestStaking|TestStakingNoWETH|TestStakingProxy|ZrxVault).json"
"abis": "./generated-artifacts/@(IStaking|IStakingEvents|IStakingProxy|IStorage|IStorageInit|IStructs|IVaultCore|IZrxVault|LibCobbDouglas|LibFixedMath|LibFixedMathRichErrors|LibProxy|LibSafeDowncast|LibStakingRichErrors|MixinAbstract|MixinConstants|MixinCumulativeRewards|MixinDeploymentConstants|MixinExchangeFees|MixinExchangeManager|MixinFinalizer|MixinParams|MixinScheduler|MixinStake|MixinStakeBalances|MixinStakeStorage|MixinStakingPool|MixinStakingPoolRewards|MixinStorage|MixinVaultCore|ReadOnlyProxy|Staking|StakingProxy|TestAssertStorageParams|TestCobbDouglas|TestCumulativeRewardTracking|TestDelegatorRewards|TestFinalizer|TestInitTarget|TestLibFixedMath|TestLibProxy|TestLibProxyReceiver|TestLibSafeDowncast|TestMixinVaultCore|TestProtocolFees|TestStaking|TestStakingNoWETH|TestStakingProxy|TestStorageLayoutAndConstants|ZrxVault).json"
},
"repository": {
"type": "git",

View File

@@ -53,6 +53,7 @@ import * as TestProtocolFees from '../generated-artifacts/TestProtocolFees.json'
import * as TestStaking from '../generated-artifacts/TestStaking.json';
import * as TestStakingNoWETH from '../generated-artifacts/TestStakingNoWETH.json';
import * as TestStakingProxy from '../generated-artifacts/TestStakingProxy.json';
import * as TestStorageLayoutAndConstants from '../generated-artifacts/TestStorageLayoutAndConstants.json';
import * as ZrxVault from '../generated-artifacts/ZrxVault.json';
export const artifacts = {
ReadOnlyProxy: ReadOnlyProxy as ContractArtifact,
@@ -104,4 +105,5 @@ export const artifacts = {
TestStaking: TestStaking as ContractArtifact,
TestStakingNoWETH: TestStakingNoWETH as ContractArtifact,
TestStakingProxy: TestStakingProxy as ContractArtifact,
TestStorageLayoutAndConstants: TestStorageLayoutAndConstants as ContractArtifact,
};

View File

@@ -51,4 +51,5 @@ export * from '../generated-wrappers/test_protocol_fees';
export * from '../generated-wrappers/test_staking';
export * from '../generated-wrappers/test_staking_no_w_e_t_h';
export * from '../generated-wrappers/test_staking_proxy';
export * from '../generated-wrappers/test_storage_layout_and_constants';
export * from '../generated-wrappers/zrx_vault';

View File

@@ -0,0 +1,14 @@
import { blockchainTests } from '@0x/contracts-test-utils';
import { artifacts, TestStorageLayoutAndConstantsContract } from '../src';
blockchainTests('Storage Layout and Deployment Constants Regression Tests', env => {
it('Should successfully deploy the staking contract after running the layout and regression test', async () => {
await TestStorageLayoutAndConstantsContract.deployFrom0xArtifactAsync(
artifacts.TestStorageLayoutAndConstants,
env.provider,
env.txDefaults,
artifacts,
);
});
});

View File

@@ -43,6 +43,35 @@ blockchainTests('Staking Pool Management', env => {
const nextPoolId = await stakingApiWrapper.stakingContract.nextPoolId.callAsync();
expect(nextPoolId).to.be.equal(stakingConstants.SECOND_POOL_ID);
});
it('Should successfully create several staking pools, as long as the operator is only a maker in one', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
// create pool
const poolId1 = await poolOperator.createStakingPoolAsync(operatorShare, true);
expect(poolId1).to.be.equal(stakingConstants.INITIAL_POOL_ID);
const poolId2 = await poolOperator.createStakingPoolAsync(operatorShare, false);
expect(poolId2).to.be.equal(stakingConstants.SECOND_POOL_ID);
});
it('Should fail to create several staking pools with the operator as a maker in each', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
// create pool
const poolId1 = await poolOperator.createStakingPoolAsync(operatorShare, true);
expect(poolId1).to.be.equal(stakingConstants.INITIAL_POOL_ID);
await poolOperator.createStakingPoolAsync(
operatorShare,
true,
new StakingRevertErrors.MakerPoolAssignmentError(
StakingRevertErrors.MakerPoolAssignmentErrorCodes.MakerAddressAlreadyRegistered,
poolOperator.getOwner(),
poolId1,
),
);
});
it('Should fail to create a pool with operator share > 100', async () => {
// test parameters
const operatorAddress = users[0];
@@ -57,6 +86,48 @@ blockchainTests('Staking Pool Management', env => {
// create pool
await poolOperator.createStakingPoolAsync(operatorShare, false, revertError);
});
it('should fail to add a maker to a pool if maker has not called `joinStakingPoolAsMaker` yet', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
const makerAddress = users[1];
// create pool
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
await poolOperator.addMakerToStakingPoolAsync(
poolId,
makerAddress,
new StakingRevertErrors.MakerPoolAssignmentError(
StakingRevertErrors.MakerPoolAssignmentErrorCodes.MakerAddressNotPendingAdd,
makerAddress,
constants.NULL_BYTES32,
),
);
});
it('should fail to add a maker to a pool if maker has called `joinStakingPoolAsMaker` on a different pool', async () => {
// test parameters
const operatorAddress = users[0];
const operatorShare = (39 / 100) * PPM_DENOMINATOR;
const poolOperator = new PoolOperatorActor(operatorAddress, stakingApiWrapper);
const otherPoolOperator = new PoolOperatorActor(users[1], stakingApiWrapper);
const makerAddress = users[2];
const maker = new MakerActor(makerAddress, stakingApiWrapper);
const poolId = await poolOperator.createStakingPoolAsync(operatorShare, true);
expect(poolId).to.be.equal(stakingConstants.INITIAL_POOL_ID);
const otherPoolId = await otherPoolOperator.createStakingPoolAsync(operatorShare, true);
// create pool
await maker.joinStakingPoolAsMakerAsync(poolId);
await otherPoolOperator.addMakerToStakingPoolAsync(
otherPoolId,
makerAddress,
new StakingRevertErrors.MakerPoolAssignmentError(
StakingRevertErrors.MakerPoolAssignmentErrorCodes.MakerAddressNotPendingAdd,
makerAddress,
poolId,
),
);
});
it('Should successfully create a pool and add owner as a maker', async () => {
// test parameters
const operatorAddress = users[0];

View File

@@ -51,6 +51,7 @@
"generated-artifacts/TestStaking.json",
"generated-artifacts/TestStakingNoWETH.json",
"generated-artifacts/TestStakingProxy.json",
"generated-artifacts/TestStorageLayoutAndConstants.json",
"generated-artifacts/ZrxVault.json"
],
"exclude": ["./deploy/solc/solc_bin"]