Merge pull request #2248 from 0xProject/fix/staking/cleanup-accounting

Simplify staking state
This commit is contained in:
Amir Bandeali
2019-10-09 18:00:06 +09:00
committed by GitHub
23 changed files with 385 additions and 670 deletions

View File

@@ -52,6 +52,24 @@ contract ZrxVault is
// Asset data for the ERC20 Proxy
bytes internal _zrxAssetData;
/// @dev Only stakingProxy can call this function.
modifier onlyStakingProxy() {
_assertSenderIsStakingProxy();
_;
}
/// @dev Function can only be called in catastrophic failure mode.
modifier onlyInCatastrophicFailure() {
_assertInCatastrophicFailure();
_;
}
/// @dev Function can only be called not in catastropic failure mode
modifier onlyNotInCatastrophicFailure() {
_assertNotInCatastrophicFailure();
_;
}
/// @dev Constructor.
/// @param _zrxProxyAddress Address of the 0x Zrx Proxy.
/// @param _zrxTokenAddress Address of the Zrx Token.
@@ -169,6 +187,15 @@ contract ZrxVault is
return _balances[staker];
}
/// @dev Returns the entire balance of Zrx tokens in the vault.
function balanceOfZrxVault()
external
view
returns (uint256)
{
return _zrxToken.balanceOf(address(this));
}
/// @dev Withdraw an `amount` of Zrx Tokens to `staker` from the vault.
/// @param staker of Zrx Tokens.
/// @param amount of Zrx Tokens to withdraw.
@@ -190,21 +217,7 @@ contract ZrxVault is
);
}
modifier onlyStakingProxy() {
_assertSenderIsStakingProxy();
_;
}
modifier onlyInCatastrophicFailure() {
_assertInCatastrophicFailure();
_;
}
modifier onlyNotInCatastrophicFailure() {
_assertNotInCatastrophicFailure();
_;
}
/// @dev Asserts that sender is stakingProxy contract.
function _assertSenderIsStakingProxy()
private
view
@@ -216,6 +229,7 @@ contract ZrxVault is
}
}
/// @dev Asserts that vault is in catastrophic failure mode.
function _assertInCatastrophicFailure()
private
view
@@ -225,6 +239,7 @@ contract ZrxVault is
}
}
/// @dev Asserts that vault is not in catastrophic failure mode.
function _assertNotInCatastrophicFailure()
private
view

View File

@@ -41,21 +41,15 @@ contract MixinStorage is
// address for read-only proxy to call
address public readOnlyProxyCallee;
// mapping from StakeStatus to the total amount of stake in that status for the entire
// staking system.
mapping (uint8 => IStructs.StoredBalance) public globalStakeByStatus;
// mapping from Owner to Amount of Active Stake
// mapping from StakeStatus to gloabl stored balance
// (access using _loadSyncedBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal _activeStakeByOwner;
// NOTE: only Status.DELEGATED is used to access this mapping, but this format
// is used for extensibility
mapping (uint8 => IStructs.StoredBalance) internal _globalStakeByStatus;
// Mapping from Owner to Amount of Inactive Stake
// mapping from StakeStatus to address of staker to stored balance
// (access using _loadSyncedBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal _inactiveStakeByOwner;
// Mapping from Owner to Amount Delegated
// (access using _loadSyncedBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal _delegatedStakeByOwner;
mapping (uint8 => mapping (address => IStructs.StoredBalance)) internal _ownerStakeByStatus;
// Mapping from Owner to Pool Id to Amount Delegated
// (access using _loadSyncedBalance or _loadUnsyncedBalance)
@@ -65,9 +59,6 @@ contract MixinStorage is
// (access using _loadSyncedBalance or _loadUnsyncedBalance)
mapping (bytes32 => IStructs.StoredBalance) internal _delegatedStakeByPoolId;
// mapping from Owner to Amount of Withdrawable Stake
mapping (address => uint256) internal _withdrawableStakeByOwner;
// tracking Pool Id, a unique identifier for each staking pool.
bytes32 public lastPoolId;

View File

@@ -24,7 +24,8 @@ import "./IStructs.sol";
interface IStaking {
/// @dev Moves stake between statuses: 'active', 'inactive' or 'delegated'.
/// @dev Moves stake between statuses: 'undelegated' or 'delegated'.
/// Delegated stake can also be moved between pools.
/// This change comes into effect next epoch.
/// @param from status to move stake out of.
/// @param to status to move stake into.

View File

@@ -53,29 +53,20 @@ interface IStructs {
/// Note that these balances may be stale if the current epoch
/// is greater than `currentEpoch`.
/// Always load this struct using _loadSyncedBalance or _loadUnsyncedBalance.
/// @param isInitialized
/// @param currentEpoch the current epoch
/// @param currentEpochBalance balance in the current epoch.
/// @param nextEpochBalance balance in `currentEpoch+1`.
struct StoredBalance {
bool isInitialized;
uint32 currentEpoch;
uint64 currentEpoch;
uint96 currentEpochBalance;
uint96 nextEpochBalance;
}
/// @dev Balance struct for stake.
/// @param currentEpochBalance Balance in the current epoch.
/// @param nextEpochBalance Balance in the next epoch.
struct StakeBalance {
uint256 currentEpochBalance;
uint256 nextEpochBalance;
}
/// @dev Statuses that stake can exist in.
/// Any stake can be (re)delegated effective at the next epoch
/// Undelegated stake can be withdrawn if it is available in both the current and next epoch
enum StakeStatus {
ACTIVE,
INACTIVE,
UNDELEGATED,
DELEGATED
}

View File

@@ -95,4 +95,10 @@ interface IZrxVault {
external
view
returns (uint256);
/// @dev Returns the entire balance of Zrx tokens in the vault.
function balanceOfZrxVault()
external
view
returns (uint256);
}

View File

@@ -92,10 +92,6 @@ library LibStakingRichErrors {
bytes4 internal constant POOL_EXISTENCE_ERROR_SELECTOR =
0x9ae94f01;
// bytes4(keccak256("InvalidStakeStatusError(uint8)"))
bytes4 internal constant INVALID_STAKE_STATUS_ERROR_SELECTOR =
0x7cf20260;
// bytes4(keccak256("ProxyDestinationCannotBeNilError()"))
bytes internal constant PROXY_DESTINATION_CANNOT_BE_NIL_ERROR =
hex"6eff8285";
@@ -268,17 +264,6 @@ library LibStakingRichErrors {
);
}
function InvalidStakeStatusError(IStructs.StakeStatus status)
internal
pure
returns (bytes memory)
{
return abi.encodeWithSelector(
INVALID_STAKE_STATUS_ERROR_SELECTOR,
status
);
}
function InitializationError(InitializationErrorCodes code)
internal
pure

View File

@@ -41,10 +41,10 @@ contract MixinStake is
getZrxVault().depositFrom(staker, amount);
// mint stake
_increaseCurrentAndNextBalance(_activeStakeByOwner[staker], amount);
// update global total of active stake
_increaseCurrentAndNextBalance(globalStakeByStatus[uint8(IStructs.StakeStatus.ACTIVE)], amount);
_increaseCurrentAndNextBalance(
_ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker],
amount
);
// notify
emit Stake(
@@ -54,16 +54,23 @@ contract MixinStake is
}
/// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to
/// the staker. Stake must be in the 'inactive' status for at least
/// one full epoch to unstake.
/// the staker. Stake must be in the 'undelegated' status in both the
/// current and next epoch in order to be unstaked.
/// @param amount of ZRX to unstake.
function unstake(uint256 amount)
external
{
address payable staker = msg.sender;
address staker = msg.sender;
IStructs.StoredBalance memory undelegatedBalance =
_loadSyncedBalance(_ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker]);
// stake must be undelegated in current and next epoch to be withdrawn
uint256 currentWithdrawableStake = LibSafeMath.min256(
undelegatedBalance.currentEpochBalance,
undelegatedBalance.nextEpochBalance
);
// sanity check
uint256 currentWithdrawableStake = getWithdrawableStake(staker);
if (amount > currentWithdrawableStake) {
LibRichErrors.rrevert(
LibStakingRichErrors.InsufficientBalanceError(
@@ -73,15 +80,11 @@ contract MixinStake is
);
}
// burn inactive stake
_decreaseCurrentAndNextBalance(_inactiveStakeByOwner[staker], amount);
// update global total of inactive stake
_decreaseCurrentAndNextBalance(globalStakeByStatus[uint8(IStructs.StakeStatus.INACTIVE)], amount);
// update withdrawable field
_withdrawableStakeByOwner[staker] =
currentWithdrawableStake.safeSub(amount);
// burn undelegated stake
_decreaseCurrentAndNextBalance(
_ownerStakeByStatus[uint8(IStructs.StakeStatus.UNDELEGATED)][staker],
amount
);
// withdraw equivalent amount of ZRX from vault
getZrxVault().withdrawFrom(staker, amount);
@@ -93,7 +96,8 @@ contract MixinStake is
);
}
/// @dev Moves stake between statuses: 'active', 'inactive' or 'delegated'.
/// @dev Moves stake between statuses: 'undelegated' or 'delegated'.
/// Delegated stake can also be moved between pools.
/// This change comes into effect next epoch.
/// @param from status to move stake out of.
/// @param to status to move stake into.
@@ -105,17 +109,6 @@ contract MixinStake is
)
external
{
// sanity check - do nothing if moving stake between the same status
if (from.status != IStructs.StakeStatus.DELEGATED
&& from.status == to.status)
{
return;
} else if (from.status == IStructs.StakeStatus.DELEGATED
&& from.poolId == to.poolId)
{
return;
}
address payable staker = msg.sender;
// handle delegation; this must be done before moving stake as the
@@ -136,31 +129,15 @@ contract MixinStake is
);
}
// cache the current withdrawal amount, which may change if we're
// moving out of the inactive status.
uint256 withdrawableStake =
(from.status == IStructs.StakeStatus.INACTIVE)
? getWithdrawableStake(staker)
: 0;
// execute move
IStructs.StoredBalance storage fromPtr = _getBalancePtrFromStatus(staker, from.status);
IStructs.StoredBalance storage toPtr = _getBalancePtrFromStatus(staker, to.status);
_moveStake(fromPtr, toPtr, amount);
// update global total of stake in the statuses being moved between
IStructs.StoredBalance storage fromPtr = _ownerStakeByStatus[uint8(from.status)][staker];
IStructs.StoredBalance storage toPtr = _ownerStakeByStatus[uint8(to.status)][staker];
_moveStake(
globalStakeByStatus[uint8(from.status)],
globalStakeByStatus[uint8(to.status)],
fromPtr,
toPtr,
amount
);
// update withdrawable field, if necessary
if (from.status == IStructs.StakeStatus.INACTIVE) {
_withdrawableStakeByOwner[staker] =
_computeWithdrawableStake(staker, withdrawableStake);
}
// notify
emit MoveStake(
staker,
@@ -198,7 +175,16 @@ contract MixinStake is
);
// Increment how much stake has been delegated to pool.
_increaseNextBalance(_delegatedStakeByPoolId[poolId], amount);
_increaseNextBalance(
_delegatedStakeByPoolId[poolId],
amount
);
// Increase next balance of global delegated stake
_increaseNextBalance(
_globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)],
amount
);
}
/// @dev Un-Delegates a owners stake from a staking pool.
@@ -227,36 +213,15 @@ contract MixinStake is
);
// decrement how much stake has been delegated to pool
_decreaseNextBalance(_delegatedStakeByPoolId[poolId], amount);
}
/// @dev Returns a storage pointer to a user's stake in a given status.
/// @param staker Owner of stake to query.
/// @param status Status of user's stake to lookup.
/// @return storage A storage pointer to the corresponding stake stake
function _getBalancePtrFromStatus(
address staker,
IStructs.StakeStatus status
)
private
view
returns (IStructs.StoredBalance storage)
{
// lookup status
if (status == IStructs.StakeStatus.ACTIVE) {
return _activeStakeByOwner[staker];
} else if (status == IStructs.StakeStatus.INACTIVE) {
return _inactiveStakeByOwner[staker];
} else if (status == IStructs.StakeStatus.DELEGATED) {
return _delegatedStakeByOwner[staker];
}
// invalid status
LibRichErrors.rrevert(
LibStakingRichErrors.InvalidStakeStatusError(status)
_decreaseNextBalance(
_delegatedStakeByPoolId[poolId],
amount
);
// required to compile ~ we should never hit this.
revert("INVALID_STATE");
// decrease next balance of global delegated stake
_decreaseNextBalance(
_globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)],
amount
);
}
}

View File

@@ -29,135 +29,67 @@ contract MixinStakeBalances is
{
using LibSafeMath for uint256;
/// @dev Returns the total active stake across the entire staking system.
/// @return Global active stake.
function getGlobalActiveStake()
/// @dev Gets global stake for a given status.
/// @param stakeStatus UNDELEGATED or DELEGATED
/// @return Global stake for given status.
function getGlobalStakeByStatus(IStructs.StakeStatus stakeStatus)
external
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(
globalStakeByStatus[uint8(IStructs.StakeStatus.ACTIVE)]
balance = _loadSyncedBalance(
_globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)]
);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
if (stakeStatus == IStructs.StakeStatus.UNDELEGATED) {
// Undelegated stake is the difference between total stake and delegated stake
// Note that any ZRX erroneously sent to the vault will be counted as undelegated stake
uint256 totalStake = getZrxVault().balanceOfZrxVault();
balance.currentEpochBalance = totalStake.safeSub(balance.currentEpochBalance).downcastToUint96();
balance.nextEpochBalance = totalStake.safeSub(balance.nextEpochBalance).downcastToUint96();
}
return balance;
}
/// @dev Returns the total inactive stake across the entire staking system.
/// @return Global inactive stake.
function getGlobalInactiveStake()
/// @dev Gets an owner's stake balances by status.
/// @param staker Owner of stake.
/// @param stakeStatus UNDELEGATED or DELEGATED
/// @return Owner's stake balances for given status.
function getOwnerStakeByStatus(
address staker,
IStructs.StakeStatus stakeStatus
)
external
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(
globalStakeByStatus[uint8(IStructs.StakeStatus.INACTIVE)]
balance = _loadSyncedBalance(
_ownerStakeByStatus[uint8(stakeStatus)][staker]
);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
}
/// @dev Returns the total stake delegated across the entire staking system.
/// @return Global delegated stake.
function getGlobalDelegatedStake()
external
view
returns (IStructs.StakeBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(
globalStakeByStatus[uint8(IStructs.StakeStatus.DELEGATED)]
);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
return balance;
}
/// @dev Returns the total stake for a given staker.
/// @param staker of stake.
/// @return Total active stake for staker.
function getTotalStake(address staker)
external
public
view
returns (uint256)
{
return getZrxVault().balanceOf(staker);
}
/// @dev Returns the active stake for a given staker.
/// @param staker of stake.
/// @return Active stake for staker.
function getActiveStake(address staker)
external
view
returns (IStructs.StakeBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(_activeStakeByOwner[staker]);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
}
/// @dev Returns the inactive stake for a given staker.
/// @param staker of stake.
/// @return Inactive stake for staker.
function getInactiveStake(address staker)
external
view
returns (IStructs.StakeBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(_inactiveStakeByOwner[staker]);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
}
/// @dev Returns the stake delegated by a given staker.
/// @param staker of stake.
/// @return Delegated stake for staker.
function getStakeDelegatedByOwner(address staker)
external
view
returns (IStructs.StakeBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(_delegatedStakeByOwner[staker]);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
}
/// @dev Returns the amount stake that can be withdrawn for a given staker.
/// @param staker of stake.
/// @return Withdrawable stake for staker.
function getWithdrawableStake(address staker)
public
view
returns (uint256)
{
return _computeWithdrawableStake(staker, _withdrawableStakeByOwner[staker]);
}
/// @dev Returns the stake delegated to a specific staking pool, by a given staker.
/// @param staker of stake.
/// @param poolId Unique Id of pool.
/// @return Stake delegaated to pool by staker.
/// @return Stake delegated to pool by staker.
function getStakeDelegatedToPoolByOwner(address staker, bytes32 poolId)
public
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(_delegatedStakeToPoolByOwner[staker][poolId]);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
balance = _loadSyncedBalance(_delegatedStakeToPoolByOwner[staker][poolId]);
return balance;
}
/// @dev Returns the total stake delegated to a specific staking pool,
@@ -167,43 +99,9 @@ contract MixinStakeBalances is
function getTotalStakeDelegatedToPool(bytes32 poolId)
public
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
IStructs.StoredBalance memory storedBalance = _loadSyncedBalance(_delegatedStakeByPoolId[poolId]);
return IStructs.StakeBalance({
currentEpochBalance: storedBalance.currentEpochBalance,
nextEpochBalance: storedBalance.nextEpochBalance
});
}
/// @dev Returns the stake that can be withdrawn for a given staker.
/// @param staker to query.
/// @param lastStoredWithdrawableStake The amount of withdrawable stake
/// that was last stored.
/// @return Withdrawable stake for staker.
function _computeWithdrawableStake(
address staker,
uint256 lastStoredWithdrawableStake
)
internal
view
returns (uint256)
{
// stake cannot be withdrawn if it has been reallocated for the `next` epoch;
// so the upper bound of withdrawable stake is always limited by the value of `next`.
IStructs.StoredBalance memory storedBalance = _loadUnsyncedBalance(_inactiveStakeByOwner[staker]);
if (storedBalance.currentEpoch == currentEpoch) {
return LibSafeMath.min256(
storedBalance.nextEpochBalance,
lastStoredWithdrawableStake
);
} else if (uint256(storedBalance.currentEpoch).safeAdd(1) == currentEpoch) {
return LibSafeMath.min256(
storedBalance.nextEpochBalance,
storedBalance.currentEpochBalance
);
} else {
return storedBalance.nextEpochBalance;
}
balance = _loadSyncedBalance(_delegatedStakeByPoolId[poolId]);
return balance;
}
}

View File

@@ -31,7 +31,7 @@ contract MixinStakeStorage is
using LibSafeMath for uint256;
using LibSafeDowncast for uint256;
/// @dev Moves stake between states: 'active', 'inactive' or 'delegated'.
/// @dev Moves stake between states: 'undelegated' or 'delegated'.
/// This change comes into effect next epoch.
/// @param fromPtr pointer to storage location of `from` stake.
/// @param toPtr pointer to storage location of `to` stake.
@@ -87,7 +87,7 @@ contract MixinStakeStorage is
// sync
uint256 currentEpoch_ = currentEpoch;
if (currentEpoch_ > balance.currentEpoch) {
balance.currentEpoch = currentEpoch_.downcastToUint32();
balance.currentEpoch = currentEpoch_.downcastToUint64();
balance.currentEpochBalance = balance.nextEpochBalance;
}
return balance;
@@ -176,8 +176,7 @@ contract MixinStakeStorage is
private
{
// note - this compresses into a single `sstore` when optimizations are enabled,
// since the StakeBalance struct occupies a single word of storage.
balancePtr.isInitialized = true;
// since the StoredBalance struct occupies a single word of storage.
balancePtr.currentEpoch = balance.currentEpoch;
balancePtr.nextEpochBalance = balance.nextEpochBalance;
balancePtr.currentEpochBalance = balance.currentEpochBalance;

View File

@@ -137,7 +137,6 @@ contract MixinStakingPool is
function _assertStakingPoolExists(bytes32 poolId)
internal
view
returns (bool)
{
if (_poolById[poolId].operator == NIL_ADDRESS) {
// we use the pool's operator as a proxy for its existence

View File

@@ -117,7 +117,6 @@ contract TestDelegatorRewards is
delegator
);
IStructs.StoredBalance storage _stake = _delegatedStakeToPoolByOwner[delegator][poolId];
_stake.isInitialized = true;
_stake.currentEpochBalance += uint96(stake);
_stake.nextEpochBalance += uint96(stake);
_stake.currentEpoch = uint32(currentEpoch);
@@ -146,7 +145,6 @@ contract TestDelegatorRewards is
if (_stake.currentEpoch < currentEpoch) {
_stake.currentEpochBalance = _stake.nextEpochBalance;
}
_stake.isInitialized = true;
_stake.nextEpochBalance += uint96(stake);
_stake.currentEpoch = uint32(currentEpoch);
}
@@ -170,7 +168,6 @@ contract TestDelegatorRewards is
if (_stake.currentEpoch < currentEpoch) {
_stake.currentEpochBalance = _stake.nextEpochBalance;
}
_stake.isInitialized = true;
_stake.nextEpochBalance -= uint96(stake);
_stake.currentEpoch = uint32(currentEpoch);
}

View File

@@ -27,8 +27,8 @@ contract TestProtocolFees is
TestStakingNoWETH
{
struct TestPool {
uint256 operatorStake;
uint256 membersStake;
uint96 operatorStake;
uint96 membersStake;
mapping(address => bool) isMaker;
}
@@ -57,8 +57,8 @@ contract TestProtocolFees is
/// @dev Create a test pool.
function createTestPool(
bytes32 poolId,
uint256 operatorStake,
uint256 membersStake,
uint96 operatorStake,
uint96 membersStake,
address[] calldata makerAddresses
)
external
@@ -99,11 +99,12 @@ contract TestProtocolFees is
function getTotalStakeDelegatedToPool(bytes32 poolId)
public
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
TestPool memory pool = _testPools[poolId];
uint256 stake = pool.operatorStake + pool.membersStake;
return IStructs.StakeBalance({
uint96 stake = pool.operatorStake + pool.membersStake;
return IStructs.StoredBalance({
currentEpoch: currentEpoch.downcastToUint64(),
currentEpochBalance: stake,
nextEpochBalance: stake
});
@@ -113,10 +114,11 @@ contract TestProtocolFees is
function getStakeDelegatedToPoolByOwner(address, bytes32 poolId)
public
view
returns (IStructs.StakeBalance memory balance)
returns (IStructs.StoredBalance memory balance)
{
TestPool memory pool = _testPools[poolId];
return IStructs.StakeBalance({
return IStructs.StoredBalance({
currentEpoch: currentEpoch.downcastToUint64(),
currentEpochBalance: pool.operatorStake,
nextEpochBalance: pool.operatorStake
});

View File

@@ -119,32 +119,16 @@ contract TestStorageLayoutAndConstants is
slot := add(slot, 0x1)
assertSlotAndOffset(
globalStakeByStatus_slot,
globalStakeByStatus_offset,
_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,
_ownerStakeByStatus_slot,
_ownerStakeByStatus_offset,
slot,
offset
)
@@ -166,14 +150,6 @@ contract TestStorageLayoutAndConstants is
)
slot := add(slot, 0x1)
assertSlotAndOffset(
_withdrawableStakeByOwner_slot,
_withdrawableStakeByOwner_offset,
slot,
offset
)
slot := add(slot, 0x1)
assertSlotAndOffset(
lastPoolId_slot,
lastPoolId_offset,

View File

@@ -55,7 +55,6 @@
"@0x/dev-utils": "^2.4.0-beta.0",
"@0x/sol-compiler": "^3.2.0-beta.0",
"@0x/tslint-config": "^3.0.1",
"@0x/utils": "^4.5.2",
"@types/lodash": "4.14.104",
"@types/node": "*",
"chai": "^4.0.1",

View File

@@ -3,24 +3,24 @@ import { BigNumber, RevertError } from '@0x/utils';
import * as _ from 'lodash';
import { StakingApiWrapper } from '../utils/api_wrapper';
import { StakeBalance, StakeBalances, StakeInfo, StakeStatus } from '../utils/types';
import { StakeBalances, StakeInfo, StakeStatus, StoredBalance } from '../utils/types';
import { BaseActor } from './base_actor';
export class StakerActor extends BaseActor {
private readonly _poolIds: string[];
private static _incrementNextBalance(balance: StakeBalance, amount: BigNumber): void {
private static _incrementNextBalance(balance: StoredBalance, amount: BigNumber): void {
balance.nextEpochBalance = balance.nextEpochBalance.plus(amount);
}
private static _decrementNextBalance(balance: StakeBalance, amount: BigNumber): void {
private static _decrementNextBalance(balance: StoredBalance, amount: BigNumber): void {
balance.nextEpochBalance = balance.nextEpochBalance.minus(amount);
}
private static _incrementCurrentAndNextBalance(balance: StakeBalance, amount: BigNumber): void {
private static _incrementCurrentAndNextBalance(balance: StoredBalance, amount: BigNumber): void {
balance.currentEpochBalance = balance.currentEpochBalance.plus(amount);
balance.nextEpochBalance = balance.nextEpochBalance.plus(amount);
}
private static _decrementCurrentAndNextBalance(balance: StakeBalance, amount: BigNumber): void {
private static _decrementCurrentAndNextBalance(balance: StoredBalance, amount: BigNumber): void {
balance.currentEpochBalance = balance.currentEpochBalance.minus(amount);
balance.nextEpochBalance = balance.nextEpochBalance.minus(amount);
}
@@ -106,9 +106,8 @@ export class StakerActor extends BaseActor {
const expectedBalances = initBalances;
expectedBalances.zrxBalance = initBalances.zrxBalance.plus(amount);
expectedBalances.stakeBalanceInVault = initBalances.stakeBalanceInVault.minus(amount);
StakerActor._decrementCurrentAndNextBalance(expectedBalances.inactiveStakeBalance, amount);
StakerActor._decrementCurrentAndNextBalance(expectedBalances.globalInactiveStakeBalance, amount);
expectedBalances.withdrawableStakeBalance = initBalances.withdrawableStakeBalance.minus(amount);
StakerActor._decrementCurrentAndNextBalance(expectedBalances.undelegatedStakeBalance, amount);
StakerActor._decrementCurrentAndNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount);
await this._assertBalancesAsync(expectedBalances);
// check zrx balance of vault
const finalZrxBalanceOfVault = await this._stakingApiWrapper.utils.getZrxTokenBalanceOfZrxVaultAsync();
@@ -149,7 +148,7 @@ export class StakerActor extends BaseActor {
public async stakeWithPoolAsync(poolId: string, amount: BigNumber): Promise<void> {
await this.stakeAsync(amount);
await this.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
amount,
);
@@ -182,42 +181,39 @@ export class StakerActor extends BaseActor {
}
private _getNextEpochBalances(balances: StakeBalances): StakeBalances {
const nextBalances = _.cloneDeep(balances);
nextBalances.withdrawableStakeBalance = nextBalances.inactiveStakeBalance.nextEpochBalance.isLessThan(
nextBalances.inactiveStakeBalance.currentEpochBalance,
)
? nextBalances.inactiveStakeBalance.nextEpochBalance
: nextBalances.inactiveStakeBalance.currentEpochBalance;
for (const balance of [
nextBalances.activeStakeBalance,
nextBalances.inactiveStakeBalance,
nextBalances.undelegatedStakeBalance,
nextBalances.delegatedStakeBalance,
nextBalances.globalActiveStakeBalance,
nextBalances.globalInactiveStakeBalance,
nextBalances.globalUndelegatedStakeBalance,
nextBalances.globalDelegatedStakeBalance,
...this._poolIds.map(poolId => nextBalances.delegatedStakeByPool[poolId]),
...this._poolIds.map(poolId => nextBalances.totalDelegatedStakeByPool[poolId]),
]) {
balance.currentEpoch = balances.currentEpoch.plus(1);
balance.currentEpochBalance = balance.nextEpochBalance;
}
return nextBalances;
}
private async _getBalancesAsync(): Promise<StakeBalances> {
const balances: StakeBalances = {
currentEpoch: await this._stakingApiWrapper.stakingContract.currentEpoch.callAsync(),
zrxBalance: await this._stakingApiWrapper.zrxTokenContract.balanceOf.callAsync(this._owner),
stakeBalance: await this._stakingApiWrapper.stakingContract.getTotalStake.callAsync(this._owner),
stakeBalanceInVault: await this._stakingApiWrapper.zrxVaultContract.balanceOf.callAsync(this._owner),
withdrawableStakeBalance: await this._stakingApiWrapper.stakingContract.getWithdrawableStake.callAsync(
undelegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
this._owner,
StakeStatus.Undelegated,
),
activeStakeBalance: await this._stakingApiWrapper.stakingContract.getActiveStake.callAsync(this._owner),
inactiveStakeBalance: await this._stakingApiWrapper.stakingContract.getInactiveStake.callAsync(this._owner),
delegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getStakeDelegatedByOwner.callAsync(
delegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
this._owner,
StakeStatus.Delegated,
),
globalUndelegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getGlobalStakeByStatus.callAsync(
StakeStatus.Undelegated,
),
globalDelegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getGlobalStakeByStatus.callAsync(
StakeStatus.Delegated,
),
globalActiveStakeBalance: await this._stakingApiWrapper.stakingContract.getGlobalActiveStake.callAsync(),
globalInactiveStakeBalance: await this._stakingApiWrapper.stakingContract.getGlobalInactiveStake.callAsync(),
globalDelegatedStakeBalance: await this._stakingApiWrapper.stakingContract.getGlobalDelegatedStake.callAsync(),
delegatedStakeByPool: {},
totalDelegatedStakeByPool: {},
};
@@ -241,22 +237,14 @@ export class StakerActor extends BaseActor {
expect(balances.stakeBalanceInVault, 'stake balance, recorded in vault').to.be.bignumber.equal(
expectedBalances.stakeBalanceInVault,
);
expect(balances.withdrawableStakeBalance, 'withdrawable stake balance').to.be.bignumber.equal(
expectedBalances.withdrawableStakeBalance,
);
expect(balances.activeStakeBalance.currentEpochBalance, 'active stake balance (current)').to.be.bignumber.equal(
expectedBalances.activeStakeBalance.currentEpochBalance,
);
expect(balances.activeStakeBalance.nextEpochBalance, 'active stake balance (next)').to.be.bignumber.equal(
expectedBalances.activeStakeBalance.nextEpochBalance,
);
expect(
balances.inactiveStakeBalance.currentEpochBalance,
'inactive stake balance (current)',
).to.be.bignumber.equal(expectedBalances.inactiveStakeBalance.currentEpochBalance);
expect(balances.inactiveStakeBalance.nextEpochBalance, 'inactive stake balance (next)').to.be.bignumber.equal(
expectedBalances.inactiveStakeBalance.nextEpochBalance,
);
balances.undelegatedStakeBalance.currentEpochBalance,
'undelegated stake balance (current)',
).to.be.bignumber.equal(expectedBalances.undelegatedStakeBalance.currentEpochBalance);
expect(
balances.undelegatedStakeBalance.nextEpochBalance,
'undelegated stake balance (next)',
).to.be.bignumber.equal(expectedBalances.undelegatedStakeBalance.nextEpochBalance);
expect(
balances.delegatedStakeBalance.currentEpochBalance,
'delegated stake balance (current)',
@@ -265,23 +253,17 @@ export class StakerActor extends BaseActor {
expectedBalances.delegatedStakeBalance.nextEpochBalance,
);
expect(
balances.globalActiveStakeBalance.currentEpochBalance,
'global active stake (current)',
).to.bignumber.equal(expectedBalances.globalActiveStakeBalance.currentEpochBalance);
expect(
balances.globalInactiveStakeBalance.currentEpochBalance,
'global inactive stake (current)',
).to.bignumber.equal(expectedBalances.globalInactiveStakeBalance.currentEpochBalance);
balances.globalUndelegatedStakeBalance.currentEpochBalance,
'global undelegated stake (current)',
).to.bignumber.equal(expectedBalances.globalUndelegatedStakeBalance.currentEpochBalance);
expect(
balances.globalDelegatedStakeBalance.currentEpochBalance,
'global delegated stake (current)',
).to.bignumber.equal(expectedBalances.globalDelegatedStakeBalance.currentEpochBalance);
expect(balances.globalActiveStakeBalance.nextEpochBalance, 'global active stake (next)').to.bignumber.equal(
expectedBalances.globalActiveStakeBalance.nextEpochBalance,
);
expect(balances.globalInactiveStakeBalance.nextEpochBalance, 'global inactive stake (next)').to.bignumber.equal(
expectedBalances.globalInactiveStakeBalance.nextEpochBalance,
);
expect(
balances.globalUndelegatedStakeBalance.nextEpochBalance,
'global undelegated stake (next)',
).to.bignumber.equal(expectedBalances.globalUndelegatedStakeBalance.nextEpochBalance);
expect(
balances.globalDelegatedStakeBalance.nextEpochBalance,
'global delegated stake (next)',
@@ -309,19 +291,9 @@ export class StakerActor extends BaseActor {
// @TODO check receipt logs and return value via eth_call
// check balances
// from
if (from.status === StakeStatus.Active) {
StakerActor._decrementNextBalance(expectedBalances.activeStakeBalance, amount);
StakerActor._decrementNextBalance(expectedBalances.globalActiveStakeBalance, amount);
} else if (from.status === StakeStatus.Inactive) {
StakerActor._decrementNextBalance(expectedBalances.inactiveStakeBalance, amount);
StakerActor._decrementNextBalance(expectedBalances.globalInactiveStakeBalance, amount);
if (
expectedBalances.inactiveStakeBalance.nextEpochBalance.isLessThan(
expectedBalances.withdrawableStakeBalance,
)
) {
expectedBalances.withdrawableStakeBalance = expectedBalances.inactiveStakeBalance.nextEpochBalance;
}
if (from.status === StakeStatus.Undelegated) {
StakerActor._decrementNextBalance(expectedBalances.undelegatedStakeBalance, amount);
StakerActor._decrementNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount);
} else if (from.status === StakeStatus.Delegated && from.poolId !== undefined) {
StakerActor._decrementNextBalance(expectedBalances.delegatedStakeBalance, amount);
StakerActor._decrementNextBalance(expectedBalances.globalDelegatedStakeBalance, amount);
@@ -329,12 +301,9 @@ export class StakerActor extends BaseActor {
StakerActor._decrementNextBalance(expectedBalances.totalDelegatedStakeByPool[from.poolId], amount);
}
// to
if (to.status === StakeStatus.Active) {
StakerActor._incrementNextBalance(expectedBalances.activeStakeBalance, amount);
StakerActor._incrementNextBalance(expectedBalances.globalActiveStakeBalance, amount);
} else if (to.status === StakeStatus.Inactive) {
StakerActor._incrementNextBalance(expectedBalances.inactiveStakeBalance, amount);
StakerActor._incrementNextBalance(expectedBalances.globalInactiveStakeBalance, amount);
if (to.status === StakeStatus.Undelegated) {
StakerActor._incrementNextBalance(expectedBalances.undelegatedStakeBalance, amount);
StakerActor._incrementNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount);
} else if (to.status === StakeStatus.Delegated && to.poolId !== undefined) {
StakerActor._incrementNextBalance(expectedBalances.delegatedStakeBalance, amount);
StakerActor._incrementNextBalance(expectedBalances.globalDelegatedStakeBalance, amount);
@@ -352,8 +321,8 @@ export class StakerActor extends BaseActor {
// check balances
expectedBalances.zrxBalance = expectedBalances.zrxBalance.minus(amount);
expectedBalances.stakeBalanceInVault = expectedBalances.stakeBalanceInVault.plus(amount);
StakerActor._incrementCurrentAndNextBalance(expectedBalances.activeStakeBalance, amount);
StakerActor._incrementCurrentAndNextBalance(expectedBalances.globalActiveStakeBalance, amount);
StakerActor._incrementCurrentAndNextBalance(expectedBalances.undelegatedStakeBalance, amount);
StakerActor._incrementCurrentAndNextBalance(expectedBalances.globalUndelegatedStakeBalance, amount);
return expectedBalances;
}
}

View File

@@ -8,6 +8,7 @@ import { StakingProxyReadOnlyModeSetEventArgs } from '../src';
import { deployAndConfigureContractsAsync, StakingApiWrapper } from './utils/api_wrapper';
import { toBaseUnitAmount } from './utils/number_utils';
import { StakeStatus } from './utils/types';
// tslint:disable:no-unnecessary-type-assertion
blockchainTests.resets('Catastrophe Tests', env => {
@@ -39,8 +40,11 @@ blockchainTests.resets('Catastrophe Tests', env => {
await stakingApiWrapper.stakingContract.stake.awaitTransactionSuccessAsync(amountToStake, {
from: actors[0],
});
const activeStakeBalance = await stakingApiWrapper.stakingContract.getActiveStake.callAsync(actors[0]);
expect(activeStakeBalance.currentEpochBalance).to.be.bignumber.equal(amountToStake);
const undelegatedStakeBalance = await stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
actors[0],
StakeStatus.Undelegated,
);
expect(undelegatedStakeBalance.currentEpochBalance).to.be.bignumber.equal(amountToStake);
});
it('should not change state when in read-only mode', async () => {
// set to read-only mode
@@ -50,8 +54,11 @@ blockchainTests.resets('Catastrophe Tests', env => {
await stakingApiWrapper.stakingContract.stake.awaitTransactionSuccessAsync(amountToStake, {
from: actors[0],
});
const activeStakeBalance = await stakingApiWrapper.stakingContract.getActiveStake.callAsync(actors[0]);
expect(activeStakeBalance.currentEpochBalance).to.be.bignumber.equal(ZERO);
const undelegatedStakeBalance = await stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
actors[0],
StakeStatus.Undelegated,
);
expect(undelegatedStakeBalance.currentEpochBalance).to.be.bignumber.equal(ZERO);
});
it('should read values correctly when in read-only mode', async () => {
// stake some zrx
@@ -62,10 +69,11 @@ blockchainTests.resets('Catastrophe Tests', env => {
// set to read-only mode
await stakingApiWrapper.stakingProxyContract.setReadOnlyMode.awaitTransactionSuccessAsync(true);
// read stake balance in read-only mode
const activeStakeBalanceReadOnly = await stakingApiWrapper.stakingContract.getActiveStake.callAsync(
const undelegatedStakeBalanceReadOnly = await stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
actors[0],
StakeStatus.Undelegated,
);
expect(activeStakeBalanceReadOnly.currentEpochBalance).to.be.bignumber.equal(amountToStake);
expect(undelegatedStakeBalanceReadOnly.currentEpochBalance).to.be.bignumber.equal(amountToStake);
});
it('should exit read-only mode', async () => {
// set to read-only mode
@@ -76,8 +84,11 @@ blockchainTests.resets('Catastrophe Tests', env => {
await stakingApiWrapper.stakingContract.stake.awaitTransactionSuccessAsync(amountToStake, {
from: actors[0],
});
const activeStakeBalance = await stakingApiWrapper.stakingContract.getActiveStake.callAsync(actors[0]);
expect(activeStakeBalance.currentEpochBalance).to.be.bignumber.equal(amountToStake);
const undelegatedStakeBalance = await stakingApiWrapper.stakingContract.getOwnerStakeByStatus.callAsync(
actors[0],
StakeStatus.Undelegated,
);
expect(undelegatedStakeBalance.currentEpochBalance).to.be.bignumber.equal(amountToStake);
});
it('should emit event when setting read-only mode', async () => {
// set to read-only mode

View File

@@ -2,7 +2,7 @@ import { constants, expect, getCodesizeFromArtifact } from '@0x/contracts-test-u
import { artifacts } from '../src';
describe.skip('Contract Size Checks', () => {
describe('Contract Size Checks', () => {
describe('Staking', () => {
it('should have a codesize less than the maximum', async () => {
const actualSize = getCodesizeFromArtifact(artifacts.Staking);

View File

@@ -176,7 +176,7 @@ blockchainTests.resets('Testing Rewards', env => {
const amount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(amount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
amount,
);
@@ -248,7 +248,7 @@ blockchainTests.resets('Testing Rewards', env => {
const totalStakeAmount = toBaseUnitAmount(10);
await stakers[0].stakeAsync(stakeAmounts[0]);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[0],
);
@@ -259,7 +259,7 @@ blockchainTests.resets('Testing Rewards', env => {
// second staker delegates (epoch 1)
await stakers[1].stakeAsync(stakeAmounts[1]);
await stakers[1].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmounts[1],
);
@@ -355,7 +355,7 @@ blockchainTests.resets('Testing Rewards', env => {
// undelegate (withdraws delegator's rewards)
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
stakeAmount,
);
// sanity check final balances
@@ -436,7 +436,7 @@ blockchainTests.resets('Testing Rewards', env => {
// undelegate stake and finalize epoch
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
stakeAmount,
);
@@ -472,7 +472,7 @@ blockchainTests.resets('Testing Rewards', env => {
// undelegate stake and finalize epoch
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
stakeAmount,
);
await payProtocolFeeAndFinalize();
@@ -499,7 +499,7 @@ blockchainTests.resets('Testing Rewards', env => {
// undelegate stake and finalize epoch
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
stakeAmount,
);
await payProtocolFeeAndFinalize();
@@ -507,7 +507,7 @@ blockchainTests.resets('Testing Rewards', env => {
await payProtocolFeeAndFinalize(rewardNotForDelegator);
// delegate stake and go to next epoch
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
@@ -530,7 +530,7 @@ blockchainTests.resets('Testing Rewards', env => {
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
@@ -539,7 +539,7 @@ blockchainTests.resets('Testing Rewards', env => {
// undelegate stake and finalize epoch
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
stakeAmount,
);
// this should go to the delegator
@@ -547,7 +547,7 @@ blockchainTests.resets('Testing Rewards', env => {
// delegate stake ~ this will result in a payout where rewards are computed on
// the balance's `currentEpochBalance` field but not the `nextEpochBalance` field.
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
@@ -565,7 +565,7 @@ blockchainTests.resets('Testing Rewards', env => {
const stakeAmount = toBaseUnitAmount(4);
await stakers[0].stakeAsync(stakeAmount);
await stakers[0].moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolId),
stakeAmount,
);
@@ -595,7 +595,7 @@ blockchainTests.resets('Testing Rewards', env => {
const undelegateAmount = toBaseUnitAmount(2.5);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
undelegateAmount,
);
// finalize

View File

@@ -76,11 +76,31 @@ blockchainTests.resets('Stake Statuses', env => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
// still epoch 1 ~ should be able to move stake again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Undelegated),
amount,
);
});
it("should be able to reassign next epoch's stake", async () => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
// still epoch 1 ~ should be able to move stake again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Delegated, poolIds[1]),
amount,
);
});
@@ -88,30 +108,15 @@ blockchainTests.resets('Stake Statuses', env => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
// stake is now inactive, should not be able to move it out of active status again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
amount,
new StakingRevertErrors.InsufficientBalanceError(amount, ZERO),
);
});
it('should fail to reassign stake', async () => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
// still epoch 1 ~ should be able to move stake again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
// stake is now delegated; should fail to re-assign it from inactive back to active
// stake is now undelegated, should not be able to move it out of active status again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[1]),
amount,
new StakingRevertErrors.InsufficientBalanceError(amount, ZERO),
);
@@ -122,14 +127,14 @@ blockchainTests.resets('Stake Statuses', env => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAndMoveAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
// still epoch 1 ~ should be able to move stake again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Undelegated),
amount,
);
});
@@ -137,79 +142,38 @@ blockchainTests.resets('Stake Statuses', env => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAndMoveAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
amount,
);
// stake is now inactive, should not be able to move it out of active status again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
amount,
new StakingRevertErrors.InsufficientBalanceError(amount, ZERO),
);
});
it('should fail to reassign stake', async () => {
// epoch 1
const amount = toBaseUnitAmount(10);
await staker.stakeAndMoveAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
amount,
);
// still epoch 1 ~ should be able to move stake again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
// stake is now delegated; should fail to re-assign it from inactive back to active
// stake is now undelegated, should not be able to move it out of active status again
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[1]),
amount,
new StakingRevertErrors.InsufficientBalanceError(amount, ZERO),
);
});
});
describe('Move Zero Stake', () => {
it('active -> active', async () => {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Active), ZERO);
});
it('active -> inactive', async () => {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), ZERO);
});
it('active -> delegated', async () => {
it('undelegated -> undelegated', async () => {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Undelegated),
ZERO,
);
});
it('undelegated -> delegated', async () => {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
ZERO,
);
});
it('inactive -> active', async () => {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Active), ZERO);
});
it('inactive -> inactive', async () => {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Inactive), ZERO);
});
it('inactive -> delegated', async () => {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
ZERO,
);
});
it('delegated -> active', async () => {
it('delegated -> undelegated', async () => {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Active),
ZERO,
);
});
it('delegated -> inactive', async () => {
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
ZERO,
);
});
@@ -233,51 +197,28 @@ blockchainTests.resets('Stake Statuses', env => {
// setup
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
if (from.status !== StakeStatus.Active) {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), from, amount);
if (from.status !== StakeStatus.Undelegated) {
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Undelegated), from, amount);
}
// run test, checking balances in epochs [n .. n + 2]
// in epoch `n` - `next` is set
// in epoch `n+1` - `current` is set
// in epoch `n+2` - only withdrawable balance should change.
await staker.moveStakeAsync(from, to, amount.div(2));
await staker.goToNextEpochAsync();
await staker.goToNextEpochAsync();
};
it('active -> active', async () => {
await testMovePartialStake(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Active));
it('undelegated -> undelegated', async () => {
await testMovePartialStake(new StakeInfo(StakeStatus.Undelegated), new StakeInfo(StakeStatus.Undelegated));
});
it('active -> inactive', async () => {
await testMovePartialStake(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive));
});
it('active -> delegated', async () => {
it('undelegated -> delegated', async () => {
await testMovePartialStake(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
);
});
it('inactive -> active', async () => {
await testMovePartialStake(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Active));
});
it('inactive -> inactive', async () => {
await testMovePartialStake(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Inactive));
});
it('inactive -> delegated', async () => {
await testMovePartialStake(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
);
});
it('delegated -> active', async () => {
it('delegated -> undelegated', async () => {
await testMovePartialStake(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Active),
);
});
it('delegated -> inactive', async () => {
await testMovePartialStake(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
);
});
it('delegated -> delegated (same pool)', async () => {
@@ -292,22 +233,11 @@ blockchainTests.resets('Stake Statuses', env => {
new StakeInfo(StakeStatus.Delegated, poolIds[1]),
);
});
it('active -> delegated (non-existent pool)', async () => {
it('undelegated -> delegated (non-existent pool)', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, unusedPoolId),
amount,
new StakingRevertErrors.PoolExistenceError(unusedPoolId, false),
);
});
it('inactive -> delegated (non-existent pool)', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, unusedPoolId),
amount,
new StakingRevertErrors.PoolExistenceError(unusedPoolId, false),
@@ -317,7 +247,7 @@ blockchainTests.resets('Stake Statuses', env => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
@@ -328,131 +258,135 @@ blockchainTests.resets('Stake Statuses', env => {
new StakingRevertErrors.PoolExistenceError(unusedPoolId, false),
);
});
it('delegated (non-existent pool) -> active', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, unusedPoolId),
new StakeInfo(StakeStatus.Active),
amount,
new StakingRevertErrors.PoolExistenceError(unusedPoolId, false),
);
});
});
describe('Unstake', () => {
it('should successfully unstake zero ZRX', async () => {
const amount = toBaseUnitAmount(0);
await staker.unstakeAsync(amount);
});
it('should successfully unstake after being inactive for 1 epoch', async () => {
it('should successfully unstake after becoming undelegated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.goToNextEpochAsync(); // stake is now inactive
await staker.goToNextEpochAsync(); // stake is now withdrawable
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Undelegated),
amount,
);
await staker.goToNextEpochAsync(); // stake is now undelegated
await staker.unstakeAsync(amount);
});
it('should fail to unstake with insufficient balance', async () => {
it('should fail to unstake in the same epoch as stake was undelegated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
await staker.goToNextEpochAsync(); // stake is now delegated
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Undelegated),
amount,
);
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
});
it('should fail to unstake in the same epoch as stake was set to inactive', async () => {
it('should fail to unstake in same epoch that undelegated stake has been delegated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
});
it('should fail to unstake after being inactive for <1 epoch', async () => {
it('should fail to unstake one epoch after undelegated stake has been delegated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.goToNextEpochAsync();
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
await staker.goToNextEpochAsync(); // stake is now undelegated
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
});
it('should fail to unstake in same epoch that inactive/withdrawable stake has been reactivated', async () => {
it('should fail to unstake >1 epoch after undelegated stake has been delegated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.goToNextEpochAsync(); // stake is now inactive
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
amount,
);
await staker.goToNextEpochAsync(); // stake is now undelegated
await staker.goToNextEpochAsync(); // stake is now withdrawable
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Active), amount);
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
});
it('should fail to unstake one epoch after inactive/withdrawable stake has been reactivated', async () => {
it('should successfuly unstake freshly deposited stake', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.goToNextEpochAsync(); // stake is now inactive
await staker.goToNextEpochAsync(); // stake is now withdrawable
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Active), amount);
await staker.goToNextEpochAsync(); // stake is active and not withdrawable
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
});
it('should fail to unstake >1 epoch after inactive/withdrawable stake has been reactivated', async () => {
const amount = toBaseUnitAmount(10);
await staker.stakeAsync(amount);
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Active), new StakeInfo(StakeStatus.Inactive), amount);
await staker.goToNextEpochAsync(); // stake is now inactive
await staker.goToNextEpochAsync(); // stake is now withdrawable
await staker.moveStakeAsync(new StakeInfo(StakeStatus.Inactive), new StakeInfo(StakeStatus.Active), amount);
await staker.goToNextEpochAsync(); // stake is active and not withdrawable
await staker.goToNextEpochAsync(); // stake is active and not withdrawable
await staker.unstakeAsync(amount, new StakingRevertErrors.InsufficientBalanceError(amount, ZERO));
await staker.unstakeAsync(amount);
});
});
describe('Simulations', () => {
it('Simulation from Staking Spec', async () => {
// Epoch 1: Stake some ZRX
await staker.stakeAsync(toBaseUnitAmount(4));
// Later in Epoch 1: User delegates and deactivates some stake
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
toBaseUnitAmount(1),
);
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
toBaseUnitAmount(2),
);
// Epoch 2: Status updates (no user intervention required)
await staker.goToNextEpochAsync();
// Epoch 3: Stake that has been inactive for an epoch can be withdrawn (no user intervention required)
await staker.goToNextEpochAsync();
// Later in Epoch 3: User reactivates half of their inactive stake; this becomes Active next epoch
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Active),
toBaseUnitAmount(0.5),
);
// Later in Epoch 3: User re-delegates half of their stake from Pool 1 to Pool 2
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Delegated, poolIds[0]),
new StakeInfo(StakeStatus.Delegated, poolIds[1]),
toBaseUnitAmount(1),
);
// Epoch 4: Status updates (no user intervention required)
await staker.goToNextEpochAsync();
// Later in Epoch 4: User deactivates all active stake
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Inactive),
toBaseUnitAmount(1.5),
);
// Later in Epoch 4: User withdraws all available inactive stake
await staker.unstakeAsync(toBaseUnitAmount(0.5));
// Epoch 5: Status updates (no user intervention required)
await staker.goToNextEpochAsync();
// Later in Epoch 5: User reactivates a portion of their stake
await staker.moveStakeAsync(
new StakeInfo(StakeStatus.Inactive),
new StakeInfo(StakeStatus.Active),
toBaseUnitAmount(1),
);
// Epoch 6: Status updates (no user intervention required)
await staker.goToNextEpochAsync();
});
// it('Simulation from Staking Spec', async () => {
// // Epoch 1: Stake some ZRX
// await staker.stakeAsync(toBaseUnitAmount(4));
// // Later in Epoch 1: User delegates and deactivates some stake
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Active),
// new StakeInfo(StakeStatus.Undelegated),
// toBaseUnitAmount(1),
// );
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Active),
// new StakeInfo(StakeStatus.Delegated, poolIds[0]),
// toBaseUnitAmount(2),
// );
// // Epoch 2: Status updates (no user intervention required)
// await staker.goToNextEpochAsync();
// // Epoch 3: Stake that has been undelegated for an epoch can be withdrawn (no user intervention required)
// await staker.goToNextEpochAsync();
// // Later in Epoch 3: User reactivates half of their undelegated stake; this becomes Active next epoch
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Undelegated),
// new StakeInfo(StakeStatus.Active),
// toBaseUnitAmount(0.5),
// );
// // Later in Epoch 3: User re-delegates half of their stake from Pool 1 to Pool 2
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Delegated, poolIds[0]),
// new StakeInfo(StakeStatus.Delegated, poolIds[1]),
// toBaseUnitAmount(1),
// );
// // Epoch 4: Status updates (no user intervention required)
// await staker.goToNextEpochAsync();
// // Later in Epoch 4: User deactivates all active stake
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Active),
// new StakeInfo(StakeStatus.Undelegated),
// toBaseUnitAmount(1.5),
// );
// // Later in Epoch 4: User withdraws all available undelegated stake
// await staker.unstakeAsync(toBaseUnitAmount(0.5));
// // Epoch 5: Status updates (no user intervention required)
// await staker.goToNextEpochAsync();
// // Later in Epoch 5: User reactivates a portion of their stake
// await staker.moveStakeAsync(
// new StakeInfo(StakeStatus.Undelegated),
// new StakeInfo(StakeStatus.Active),
// toBaseUnitAmount(1),
// );
// // Epoch 6: Status updates (no user intervention required)
// await staker.goToNextEpochAsync();
// });
});
});
// tslint:enable:no-unnecessary-type-assertion

View File

@@ -26,19 +26,16 @@ blockchainTests.resets('MixinStakeStorage unit tests', env => {
);
await testContract.setCurrentEpoch.awaitTransactionSuccessAsync(CURRENT_EPOCH);
defaultUninitializedBalance = {
isInitialized: false,
currentEpoch: constants.INITIAL_EPOCH,
currentEpochBalance: new BigNumber(0),
nextEpochBalance: new BigNumber(0),
};
defaultSyncedBalance = {
isInitialized: true,
currentEpoch: CURRENT_EPOCH,
currentEpochBalance: new BigNumber(16),
nextEpochBalance: new BigNumber(16),
};
defaultUnsyncedBalance = {
isInitialized: true,
currentEpoch: CURRENT_EPOCH.minus(1),
currentEpochBalance: new BigNumber(10),
nextEpochBalance: new BigNumber(16),
@@ -48,7 +45,6 @@ blockchainTests.resets('MixinStakeStorage unit tests', env => {
async function getTestBalancesAsync(index: Numberish): Promise<StoredBalance> {
const storedBalance: Partial<StoredBalance> = {};
[
storedBalance.isInitialized,
storedBalance.currentEpoch,
storedBalance.currentEpochBalance,
storedBalance.nextEpochBalance,
@@ -71,13 +67,11 @@ blockchainTests.resets('MixinStakeStorage unit tests', env => {
getTestBalancesAsync(INDEX_ONE),
]);
expect(actualBalances[0]).to.deep.equal({
isInitialized: true,
currentEpoch: CURRENT_EPOCH,
currentEpochBalance: fromBalance.currentEpochBalance,
nextEpochBalance: fromBalance.nextEpochBalance.minus(amount),
});
expect(actualBalances[1]).to.deep.equal({
isInitialized: true,
currentEpoch: CURRENT_EPOCH,
currentEpochBalance: toBalance.currentEpochBalance,
nextEpochBalance: toBalance.nextEpochBalance.plus(amount),

View File

@@ -120,7 +120,7 @@ export class CumulativeRewardTrackingSimulation {
from: this._staker,
});
receipt = await this._stakingApiWrapper.stakingContract.moveStake.awaitTransactionSuccessAsync(
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
new StakeInfo(StakeStatus.Delegated, this._poolId),
this._amountToStake,
{ from: this._staker },
@@ -130,7 +130,7 @@ export class CumulativeRewardTrackingSimulation {
case TestAction.Undelegate:
receipt = await this._stakingApiWrapper.stakingContract.moveStake.awaitTransactionSuccessAsync(
new StakeInfo(StakeStatus.Delegated, this._poolId),
new StakeInfo(StakeStatus.Active),
new StakeInfo(StakeStatus.Undelegated),
this._amountToStake,
{ from: this._staker },
);

View File

@@ -16,7 +16,6 @@ export interface StakerBalances {
zrxBalance: BigNumber;
stakeBalance: BigNumber;
stakeBalanceInVault: BigNumber;
withdrawableStakeBalance: BigNumber;
activatableStakeBalance: BigNumber;
activatedStakeBalance: BigNumber;
deactivatedStakeBalance: BigNumber;
@@ -59,24 +58,17 @@ export interface EndOfEpochInfo {
}
export interface StoredBalance {
isInitialized: boolean;
currentEpoch: number | BigNumber;
currentEpochBalance: BigNumber;
nextEpochBalance: BigNumber;
}
export interface StakeBalance {
currentEpoch: BigNumber;
currentEpochBalance: BigNumber;
nextEpochBalance: BigNumber;
}
export interface StakeBalanceByPool {
[key: string]: StakeBalance;
[key: string]: StoredBalance;
}
export enum StakeStatus {
Active,
Inactive,
Undelegated,
Delegated,
}
@@ -91,16 +83,14 @@ export class StakeInfo {
}
export interface StakeBalances {
currentEpoch: BigNumber;
zrxBalance: BigNumber;
stakeBalance: BigNumber;
stakeBalanceInVault: BigNumber;
withdrawableStakeBalance: BigNumber;
activeStakeBalance: StakeBalance;
inactiveStakeBalance: StakeBalance;
delegatedStakeBalance: StakeBalance;
globalActiveStakeBalance: StakeBalance;
globalInactiveStakeBalance: StakeBalance;
globalDelegatedStakeBalance: StakeBalance;
undelegatedStakeBalance: StoredBalance;
delegatedStakeBalance: StoredBalance;
globalUndelegatedStakeBalance: StoredBalance;
globalDelegatedStakeBalance: StoredBalance;
delegatedStakeByPool: StakeBalanceByPool;
totalDelegatedStakeByPool: StakeBalanceByPool;
}

View File

@@ -142,12 +142,6 @@ export class InvalidParamValueError extends RevertError {
}
}
export class InvalidStakeStatusError extends RevertError {
constructor(status?: BigNumber | number | string) {
super('InvalidStakeStatusError', 'InvalidStakeStatusError(uint8 status)', { status });
}
}
export class InvalidProtocolFeePaymentError extends RevertError {
constructor(
errorCode?: ProtocolFeePaymentErrorCodes,
@@ -190,7 +184,6 @@ const types = [
InitializationError,
InsufficientBalanceError,
InvalidProtocolFeePaymentError,
InvalidStakeStatusError,
InvalidParamValueError,
MakerPoolAssignmentError,
OnlyCallableByExchangeError,