Merge pull request #2204 from 0xProject/feature/staking/move-storage-layout-assertions
Feature/staking/move storage layout assertions
This commit is contained in:
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@@ -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.
|
||||
|
@@ -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(
|
||||
|
@@ -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()
|
||||
|
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -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",
|
||||
|
@@ -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,
|
||||
};
|
||||
|
@@ -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';
|
||||
|
@@ -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,
|
||||
);
|
||||
});
|
||||
});
|
@@ -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];
|
||||
|
@@ -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"]
|
||||
|
Reference in New Issue
Block a user