Readability Improvements

This commit is contained in:
Greg Hysen 2019-09-05 03:35:03 -07:00
parent b5be162fa2
commit da83f75a13
18 changed files with 220 additions and 197 deletions

View File

@ -207,8 +207,8 @@ contract MixinExchangeFees is
bytes32 poolId = activePoolsThisEpoch[i]; bytes32 poolId = activePoolsThisEpoch[i];
// compute weighted stake // compute weighted stake
uint256 totalStakeDelegatedToPool = getTotalStakeDelegatedToPool(poolId).current; uint256 totalStakeDelegatedToPool = getTotalStakeDelegatedToPool(poolId).currentEpochBalance;
uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(getStakingPoolOperator(poolId), poolId).current; // @TODO Update uint256 stakeHeldByPoolOperator = getStakeDelegatedToPoolByOwner(getStakingPoolOperator(poolId), poolId).currentEpochBalance;
uint256 weightedStake = stakeHeldByPoolOperator.safeAdd( uint256 weightedStake = stakeHeldByPoolOperator.safeAdd(
totalStakeDelegatedToPool totalStakeDelegatedToPool
.safeSub(stakeHeldByPoolOperator) .safeSub(stakeHeldByPoolOperator)

View File

@ -42,19 +42,24 @@ contract MixinStorage is
address internal stakingContract; address internal stakingContract;
// mapping from Owner to Amount of Active Stake // mapping from Owner to Amount of Active Stake
mapping (address => IStructs.DelayedBalance) internal activeStakeByOwner; // (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal activeStakeByOwner;
// mapping from Owner to Amount of Inactive Stake // mapping from Owner to Amount of Inactive Stake
mapping (address => IStructs.DelayedBalance) internal inactiveStakeByOwner; // (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal inactiveStakeByOwner;
// mapping from Owner to Amount Delegated // mapping from Owner to Amount Delegated
mapping (address => IStructs.DelayedBalance) internal delegatedStakeByOwner; // (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => IStructs.StoredBalance) internal delegatedStakeByOwner;
// mapping from Owner to Pool Id to Amount Delegated // mapping from Owner to Pool Id to Amount Delegated
mapping (address => mapping (bytes32 => IStructs.DelayedBalance)) internal delegatedStakeToPoolByOwner; // (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (address => mapping (bytes32 => IStructs.StoredBalance)) internal delegatedStakeToPoolByOwner;
// mapping from Pool Id to Amount Delegated // mapping from Pool Id to Amount Delegated
mapping (bytes32 => IStructs.DelayedBalance) internal delegatedStakeByPoolId; // (access using _loadAndSyncBalance or _loadUnsyncedBalance)
mapping (bytes32 => IStructs.StoredBalance) internal delegatedStakeByPoolId;
// mapping from Owner to Amount of Withdrawable Stake // mapping from Owner to Amount of Withdrawable Stake
mapping (address => uint256) internal withdrawableStakeByOwner; mapping (address => uint256) internal withdrawableStakeByOwner;

View File

@ -25,9 +25,9 @@ interface IStakingEvents {
event MoveStake( event MoveStake(
address indexed owner, address indexed owner,
uint256 amount, uint256 amount,
uint8 fromState, uint8 fromStatus,
bytes32 indexed fromPool, bytes32 indexed fromPool,
uint8 toState, uint8 toStatus,
bytes32 indexed toProol bytes32 indexed toProol
); );

View File

@ -39,7 +39,7 @@ interface IStructs {
address makerAddress; address makerAddress;
} }
/// @dev State for Staking Pools (see MixinStakingPool). /// @dev Status for Staking Pools (see MixinStakingPool).
/// @param operatorAddress Address of pool operator. /// @param operatorAddress Address of pool operator.
/// @param operatorShare Portion of pool rewards owned by operator, in ppm. /// @param operatorShare Portion of pool rewards owned by operator, in ppm.
struct Pool { struct Pool {
@ -47,7 +47,7 @@ interface IStructs {
uint32 operatorShare; uint32 operatorShare;
} }
/// @dev State for a pool that actively traded during the current epoch. /// @dev Status for a pool that actively traded during the current epoch.
/// (see MixinExchangeFees). /// (see MixinExchangeFees).
/// @param poolId Unique Id of staking pool. /// @param poolId Unique Id of staking pool.
/// @param feesCollected Fees collected in ETH by this pool in the current epoch. /// @param feesCollected Fees collected in ETH by this pool in the current epoch.
@ -59,33 +59,39 @@ interface IStructs {
uint256 delegatedStake; uint256 delegatedStake;
} }
/// @dev A delayed balance allows values to be computed /// @dev Encapsulates a balance for the current and next epochs.
struct DelayedBalance { /// Note that these balances may be stale if the current epoch
uint96 current; /// is greater than `currentEpoch`.
uint96 next; /// Always load this struct using _loadAndSyncBalance or _loadUnsyncedBalance.
uint64 lastStored; /// @param currentEpoch the current epoch
/// @param currentEpochBalance balance in the current epoch.
/// @param nextEpochBalance balance in the next epoch.
struct StoredBalance {
uint64 currentEpoch;
uint96 currentEpochBalance;
uint96 nextEpochBalance;
} }
/// @dev Balance struct for stake. /// @dev Balance struct for stake.
/// @param current Balance in the current epoch. /// @param currentEpochBalance Balance in the current epoch.
/// @param next Balance in the next epoch. /// @param nextEpochBalance Balance in the next epoch.
struct StakeBalance { struct StakeBalance {
uint256 current; uint256 currentEpochBalance;
uint256 next; uint256 nextEpochBalance;
} }
/// @dev States that stake can exist in. /// @dev Statuses that stake can exist in.
enum StakeState { enum StakeStatus {
ACTIVE, ACTIVE,
INACTIVE, INACTIVE,
DELEGATED DELEGATED
} }
/// @dev Info used to describe a state. /// @dev Info used to describe a status.
/// @param state of the stake. /// @param status of the stake.
/// @param poolId Unique Id of pool. This is set when state=DELEGATED. /// @param poolId Unique Id of pool. This is set when status=DELEGATED.
struct StakeStateInfo { struct StakeInfo {
StakeState state; StakeStatus status;
bytes32 poolId; bytes32 poolId;
} }

View File

@ -122,17 +122,17 @@ library LibStakingRichErrors {
bytes4 internal constant INVALID_COBB_DOUGLAS_ALPHA_ERROR_SELECTOR = bytes4 internal constant INVALID_COBB_DOUGLAS_ALPHA_ERROR_SELECTOR =
0x8f8e73de; 0x8f8e73de;
// bytes4(keccak256("EthVaultNotSet()")) // bytes4(keccak256("EthVaultNotSetError()"))
bytes4 internal constant ETH_VAULT_NOT_SET = bytes4 internal constant ETH_VAULT_NOT_SET_ERROR_SELECTOR =
0xdb3f0be8; 0xa067f596;
// bytes4(keccak256("RewardVaultNotSet()")) // bytes4(keccak256("RewardVaultNotSetError()"))
bytes4 internal constant REWARD_VAULT_NOT_SET = bytes4 internal constant REWARD_VAULT_NOT_SET_ERROR_SELECTOR =
0xfcb260f7; 0xe6976d70;
// bytes4(keccak256("InvalidStakeState(uint256)")) // bytes4(keccak256("InvalidStakeStatusError(uint256)"))
bytes4 internal constant INVALID_STAKE_STATE = bytes4 internal constant INVALID_STAKE_STATUS_ERROR_SELECTOR =
0xe6586728; 0xb7161acd;
// solhint-disable func-name-mixedcase // solhint-disable func-name-mixedcase
function MiscalculatedRewardsError( function MiscalculatedRewardsError(
@ -475,34 +475,34 @@ library LibStakingRichErrors {
); );
} }
function EthVaultNotSet() function EthVaultNotSetError()
internal internal
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return abi.encodeWithSelector( return abi.encodeWithSelector(
ETH_VAULT_NOT_SET ETH_VAULT_NOT_SET_ERROR_SELECTOR
); );
} }
function RewardVaultNotSet() function RewardVaultNotSetError()
internal internal
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return abi.encodeWithSelector( return abi.encodeWithSelector(
REWARD_VAULT_NOT_SET REWARD_VAULT_NOT_SET_ERROR_SELECTOR
); );
} }
function InvalidStakeState(uint256 state) function InvalidStakeStatusError(uint256 status)
internal internal
pure pure
returns (bytes memory) returns (bytes memory)
{ {
return abi.encodeWithSelector( return abi.encodeWithSelector(
INVALID_STAKE_STATE, INVALID_STAKE_STATUS_ERROR_SELECTOR,
state status
); );
} }
} }

View File

@ -44,7 +44,7 @@ contract MixinStake is
using LibSafeMath for uint256; using LibSafeMath for uint256;
/// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault. Unstake to retrieve the ZRX. /// @dev Stake ZRX tokens. Tokens are deposited into the ZRX Vault. Unstake to retrieve the ZRX.
/// Stake is in the 'Active' state. /// Stake is in the 'Active' status.
/// @param amount of ZRX to stake. /// @param amount of ZRX to stake.
function stake(uint256 amount) function stake(uint256 amount)
external external
@ -55,7 +55,7 @@ contract MixinStake is
_depositFromOwnerIntoZrxVault(owner, amount); _depositFromOwnerIntoZrxVault(owner, amount);
// mint stake // mint stake
_mintBalance(activeStakeByOwner[owner], amount); _incrementCurrentAndNextBalance(activeStakeByOwner[owner], amount);
// notify // notify
emit Stake( emit Stake(
@ -65,7 +65,7 @@ contract MixinStake is
} }
/// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to the owner. /// @dev Unstake. Tokens are withdrawn from the ZRX Vault and returned to the owner.
/// Stake must be in the 'inactive' state for at least one full epoch to unstake. /// Stake must be in the 'inactive' status for at least one full epoch to unstake.
/// @param amount of ZRX to unstake. /// @param amount of ZRX to unstake.
function unstake(uint256 amount) function unstake(uint256 amount)
external external
@ -84,7 +84,7 @@ contract MixinStake is
} }
// burn inactive stake // burn inactive stake
_burnBalance(inactiveStakeByOwner[owner], amount); _decrementCurrentAndNextBalance(inactiveStakeByOwner[owner], amount);
// update withdrawable field // update withdrawable field
withdrawableStakeByOwner[owner] = currentWithdrawableStake.safeSub(amount); withdrawableStakeByOwner[owner] = currentWithdrawableStake.safeSub(amount);
@ -99,30 +99,30 @@ contract MixinStake is
); );
} }
/// @dev Moves stake between states: 'active', 'inactive' or 'delegated'. /// @dev Moves stake between statuses: 'active', 'inactive' or 'delegated'.
/// This change comes into effect next epoch. /// This change comes into effect next epoch.
/// @param from state to move stake out of. /// @param from status to move stake out of.
/// @param to state to move stake into. /// @param to status to move stake into.
/// @param amount of stake to move. /// @param amount of stake to move.
function moveStake( function moveStake(
IStructs.StakeStateInfo calldata from, IStructs.StakeInfo calldata from,
IStructs.StakeStateInfo calldata to, IStructs.StakeInfo calldata to,
uint256 amount uint256 amount
) )
external external
{ {
// sanity check - do nothing if moving stake between the same state // sanity check - do nothing if moving stake between the same status
if (from.state != IStructs.StakeState.DELEGATED && from.state == to.state) { if (from.status != IStructs.StakeStatus.DELEGATED && from.status == to.status) {
return; return;
} else if (from.state == IStructs.StakeState.DELEGATED && from.poolId == to.poolId) { } else if (from.status == IStructs.StakeStatus.DELEGATED && from.poolId == to.poolId) {
return; return;
} }
address payable owner = msg.sender; address payable owner = msg.sender;
// handle delegation; this must be done before moving stake as the current // handle delegation; this must be done before moving stake as the current
// (out-of-sync) state is used during delegation. // (out-of-sync) status is used during delegation.
if (from.state == IStructs.StakeState.DELEGATED) { if (from.status == IStructs.StakeStatus.DELEGATED) {
_undelegateStake( _undelegateStake(
from.poolId, from.poolId,
owner, owner,
@ -130,7 +130,7 @@ contract MixinStake is
); );
} }
if (to.state == IStructs.StakeState.DELEGATED) { if (to.status == IStructs.StakeStatus.DELEGATED) {
_delegateStake( _delegateStake(
to.poolId, to.poolId,
owner, owner,
@ -138,28 +138,28 @@ contract MixinStake is
); );
} }
// cache the current withdrawal state if we're moving out of the inactive state. // cache the current withdrawal amoiunt, which may change if we're moving out of the inactive status.
uint256 cachedWithdrawableStakeByOwner = (from.state == IStructs.StakeState.INACTIVE) uint256 withdrawableStake = (from.status == IStructs.StakeStatus.INACTIVE)
? getWithdrawableStake(owner) ? getWithdrawableStake(owner)
: 0; : 0;
// execute move // execute move
IStructs.DelayedBalance storage fromPtr = _getBalancePtrFromState(from.state); IStructs.StoredBalance storage fromPtr = _getBalancePtrFromStatus(owner, from.status);
IStructs.DelayedBalance storage toPtr = _getBalancePtrFromState(to.state); IStructs.StoredBalance storage toPtr = _getBalancePtrFromStatus(owner, to.status);
_moveStake(fromPtr, toPtr, amount); _moveStake(fromPtr, toPtr, amount);
// update withdrawable field, if necessary // update withdrawable field, if necessary
if (from.state == IStructs.StakeState.INACTIVE) { if (from.status == IStructs.StakeStatus.INACTIVE) {
withdrawableStakeByOwner[owner] = _computeWithdrawableStake(owner, cachedWithdrawableStakeByOwner); withdrawableStakeByOwner[owner] = _computeWithdrawableStake(owner, withdrawableStake);
} }
// notify // notify
emit MoveStake( emit MoveStake(
owner, owner,
amount, amount,
uint8(from.state), uint8(from.status),
from.poolId, from.poolId,
uint8(to.state), uint8(to.status),
to.poolId to.poolId
); );
} }
@ -183,10 +183,10 @@ contract MixinStake is
_syncCumulativeRewardsNeededByDelegator(poolId, currentEpoch); _syncCumulativeRewardsNeededByDelegator(poolId, currentEpoch);
// increment how much stake the owner has delegated to the input pool // increment how much stake the owner has delegated to the input pool
_incrementBalance(delegatedStakeToPoolByOwner[owner][poolId], amount); _incrementNextBalance(delegatedStakeToPoolByOwner[owner][poolId], amount);
// increment how much stake has been delegated to pool // increment how much stake has been delegated to pool
_incrementBalance(delegatedStakeByPoolId[poolId], amount); _incrementNextBalance(delegatedStakeByPoolId[poolId], amount);
} }
/// @dev Un-Delegates a owners stake from a staking pool. /// @dev Un-Delegates a owners stake from a staking pool.
@ -208,33 +208,33 @@ contract MixinStake is
_syncCumulativeRewardsNeededByDelegator(poolId, currentEpoch); _syncCumulativeRewardsNeededByDelegator(poolId, currentEpoch);
// decrement how much stake the owner has delegated to the input pool // decrement how much stake the owner has delegated to the input pool
_decrementBalance(delegatedStakeToPoolByOwner[owner][poolId], amount); _decrementNextBalance(delegatedStakeToPoolByOwner[owner][poolId], amount);
// decrement how much stake has been delegated to pool // decrement how much stake has been delegated to pool
_decrementBalance(delegatedStakeByPoolId[poolId], amount); _decrementNextBalance(delegatedStakeByPoolId[poolId], amount);
} }
/// @dev Returns a storage pointer to a user's stake in a given state. /// @dev Returns a storage pointer to a user's stake in a given status.
/// @param state of user's stake to lookup. /// @param owner of stake to query.
/// @param status of user's stake to lookup.
/// @return a storage pointer to the corresponding stake stake /// @return a storage pointer to the corresponding stake stake
function _getBalancePtrFromState(IStructs.StakeState state) function _getBalancePtrFromStatus(address owner, IStructs.StakeStatus status)
private private
view view
returns (IStructs.DelayedBalance storage) returns (IStructs.StoredBalance storage)
{ {
// lookup state // lookup status
address owner = msg.sender; if (status == IStructs.StakeStatus.ACTIVE) {
if (state == IStructs.StakeState.ACTIVE) {
return activeStakeByOwner[owner]; return activeStakeByOwner[owner];
} else if (state == IStructs.StakeState.INACTIVE) { } else if (status == IStructs.StakeStatus.INACTIVE) {
return inactiveStakeByOwner[owner]; return inactiveStakeByOwner[owner];
} else if (state == IStructs.StakeState.DELEGATED) { } else if (status == IStructs.StakeStatus.DELEGATED) {
return delegatedStakeByOwner[owner]; return delegatedStakeByOwner[owner];
} }
// invalid state // invalid status
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.InvalidStakeState(uint256(state)) LibStakingRichErrors.InvalidStakeStatusError(uint256(status))
); );
// required to compile ~ we should never hit this. // required to compile ~ we should never hit this.

View File

@ -59,10 +59,10 @@ contract MixinStakeBalances is
view view
returns (IStructs.StakeBalance memory balance) returns (IStructs.StakeBalance memory balance)
{ {
IStructs.DelayedBalance memory storedBalance = _syncBalanceDestructive(activeStakeByOwner[owner]); IStructs.StoredBalance memory storedBalance = _loadAndSyncBalance(activeStakeByOwner[owner]);
return IStructs.StakeBalance({ return IStructs.StakeBalance({
current: storedBalance.current, currentEpochBalance: storedBalance.currentEpochBalance,
next: storedBalance.next nextEpochBalance: storedBalance.nextEpochBalance
}); });
} }
@ -74,10 +74,10 @@ contract MixinStakeBalances is
view view
returns (IStructs.StakeBalance memory balance) returns (IStructs.StakeBalance memory balance)
{ {
IStructs.DelayedBalance memory storedBalance = _syncBalanceDestructive(inactiveStakeByOwner[owner]); IStructs.StoredBalance memory storedBalance = _loadAndSyncBalance(inactiveStakeByOwner[owner]);
return IStructs.StakeBalance({ return IStructs.StakeBalance({
current: storedBalance.current, currentEpochBalance: storedBalance.currentEpochBalance,
next: storedBalance.next nextEpochBalance: storedBalance.nextEpochBalance
}); });
} }
@ -89,8 +89,7 @@ contract MixinStakeBalances is
view view
returns (uint256) returns (uint256)
{ {
uint256 cachedWithdrawableStakeByOwner = withdrawableStakeByOwner[owner]; return _computeWithdrawableStake(owner, withdrawableStakeByOwner[owner]);
return _computeWithdrawableStake(owner, cachedWithdrawableStakeByOwner);
} }
/// @dev Returns the stake delegated by a given owner. /// @dev Returns the stake delegated by a given owner.
@ -101,10 +100,10 @@ contract MixinStakeBalances is
view view
returns (IStructs.StakeBalance memory balance) returns (IStructs.StakeBalance memory balance)
{ {
IStructs.DelayedBalance memory storedBalance = _syncBalanceDestructive(delegatedStakeByOwner[owner]); IStructs.StoredBalance memory storedBalance = _loadAndSyncBalance(delegatedStakeByOwner[owner]);
return IStructs.StakeBalance({ return IStructs.StakeBalance({
current: storedBalance.current, currentEpochBalance: storedBalance.currentEpochBalance,
next: storedBalance.next nextEpochBalance: storedBalance.nextEpochBalance
}); });
} }
@ -117,10 +116,10 @@ contract MixinStakeBalances is
view view
returns (IStructs.StakeBalance memory balance) returns (IStructs.StakeBalance memory balance)
{ {
IStructs.DelayedBalance memory storedBalance = _syncBalanceDestructive(delegatedStakeToPoolByOwner[owner][poolId]); IStructs.StoredBalance memory storedBalance = _loadAndSyncBalance(delegatedStakeToPoolByOwner[owner][poolId]);
return IStructs.StakeBalance({ return IStructs.StakeBalance({
current: storedBalance.current, currentEpochBalance: storedBalance.currentEpochBalance,
next: storedBalance.next nextEpochBalance: storedBalance.nextEpochBalance
}); });
} }
@ -132,31 +131,31 @@ contract MixinStakeBalances is
view view
returns (IStructs.StakeBalance memory balance) returns (IStructs.StakeBalance memory balance)
{ {
IStructs.DelayedBalance memory storedBalance = _syncBalanceDestructive(delegatedStakeByPoolId[poolId]); IStructs.StoredBalance memory storedBalance = _loadAndSyncBalance(delegatedStakeByPoolId[poolId]);
return IStructs.StakeBalance({ return IStructs.StakeBalance({
current: storedBalance.current, currentEpochBalance: storedBalance.currentEpochBalance,
next: storedBalance.next nextEpochBalance: storedBalance.nextEpochBalance
}); });
} }
/// @dev Returns the stake that can be withdrawn for a given owner. /// @dev Returns the stake that can be withdrawn for a given owner.
/// This stake is in the "Deactive & Withdrawable" state.
/// @param owner to query. /// @param owner to query.
/// @param lastStoredWithdrawableStake The amount of withdrawable stake that was last stored.
/// @return Withdrawable stake for owner. /// @return Withdrawable stake for owner.
function _computeWithdrawableStake(address owner, uint256 cachedWithdrawableStakeByOwner) function _computeWithdrawableStake(address owner, uint256 lastStoredWithdrawableStake)
internal internal
view view
returns (uint256) returns (uint256)
{ {
// stake cannot be withdrawn if it has been reallocated for the `next` epoch; // 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`. // so the upper bound of withdrawable stake is always limited by the value of `next`.
IStructs.DelayedBalance memory storedBalance = inactiveStakeByOwner[owner]; IStructs.StoredBalance memory storedBalance = _loadUnsyncedBalance(inactiveStakeByOwner[owner]);
if (storedBalance.lastStored == currentEpoch) { if (storedBalance.currentEpoch == currentEpoch) {
return storedBalance.next < cachedWithdrawableStakeByOwner ? storedBalance.next : cachedWithdrawableStakeByOwner; return LibSafeMath.min256(storedBalance.nextEpochBalance, lastStoredWithdrawableStake);
} else if (uint256(storedBalance.lastStored).safeAdd(1) == currentEpoch) { } else if (uint256(storedBalance.currentEpoch).safeAdd(1) == currentEpoch) {
return storedBalance.next < storedBalance.current ? storedBalance.next : storedBalance.current; return LibSafeMath.min256(storedBalance.nextEpochBalance, storedBalance.currentEpochBalance);
} else { } else {
return storedBalance.next; return storedBalance.nextEpochBalance;
} }
} }
} }

View File

@ -36,6 +36,7 @@ contract MixinStakeStorage is
{ {
using LibSafeMath for uint256; using LibSafeMath for uint256;
using LibSafeDowncast for uint256;
/// @dev Moves stake between states: 'active', 'inactive' or 'delegated'. /// @dev Moves stake between states: 'active', 'inactive' or 'delegated'.
/// This change comes into effect next epoch. /// This change comes into effect next epoch.
@ -43,8 +44,8 @@ contract MixinStakeStorage is
/// @param toPtr pointer to storage location of `to` stake. /// @param toPtr pointer to storage location of `to` stake.
/// @param amount of stake to move. /// @param amount of stake to move.
function _moveStake( function _moveStake(
IStructs.DelayedBalance storage fromPtr, IStructs.StoredBalance storage fromPtr,
IStructs.DelayedBalance storage toPtr, IStructs.StoredBalance storage toPtr,
uint256 amount uint256 amount
) )
internal internal
@ -55,104 +56,118 @@ contract MixinStakeStorage is
} }
// load balance from storage and synchronize it // load balance from storage and synchronize it
IStructs.DelayedBalance memory from = _syncBalanceDestructive(fromPtr); IStructs.StoredBalance memory from = _loadAndSyncBalance(fromPtr);
IStructs.DelayedBalance memory to = _syncBalanceDestructive(toPtr); IStructs.StoredBalance memory to = _loadAndSyncBalance(toPtr);
// sanity check on balance // sanity check on balance
if (amount > from.next) { if (amount > from.nextEpochBalance) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.InsufficientBalanceError( LibStakingRichErrors.InsufficientBalanceError(
amount, amount,
from.next from.nextEpochBalance
) )
); );
} }
// move stake for next epoch // move stake for next epoch
from.next = LibSafeDowncast.downcastToUint96(uint256(from.next).safeSub(amount)); from.nextEpochBalance = uint256(from.nextEpochBalance).safeSub(amount).downcastToUint96();
to.next = LibSafeDowncast.downcastToUint96(uint256(to.next).safeAdd(amount)); to.nextEpochBalance = uint256(to.nextEpochBalance).safeAdd(amount).downcastToUint96();
// update state in storage // update state in storage
_storeBalance(fromPtr, from); _storeBalance(fromPtr, from);
_storeBalance(toPtr, to); _storeBalance(toPtr, to);
} }
/// @dev Synchronizes the fields of a stored balance. /// @dev Loads a balance from storage and synchronizes its current/next fields.
/// The structs `current` field is set to `next` if the /// The structs `current` field is set to `next` if the
/// current epoch is greater than the epoch in which the struct /// current epoch is greater than the epoch in which the struct
/// was stored. /// was stored.
/// @param balance to update. This will be equal to the return value after calling. /// @param balancePtr to load and sync.
/// @return synchronized balance. /// @return synchronized balance.
function _syncBalanceDestructive(IStructs.DelayedBalance memory balance) function _loadAndSyncBalance(IStructs.StoredBalance storage balancePtr)
internal internal
view view
returns (IStructs.DelayedBalance memory) returns (IStructs.StoredBalance memory balance)
{ {
// load from storage
balance = balancePtr;
// sync
uint256 currentEpoch = getCurrentEpoch(); uint256 currentEpoch = getCurrentEpoch();
if (currentEpoch > balance.lastStored) { if (currentEpoch > balance.currentEpoch) {
balance.lastStored = LibSafeDowncast.downcastToUint64(currentEpoch); balance.currentEpoch = currentEpoch.downcastToUint64();
balance.current = balance.next; balance.currentEpochBalance = balance.nextEpochBalance;
} }
return balance; return balance;
} }
/// @dev Mints new value in a balance. /// @dev Loads a balance from storage without synchronizing its fields.
/// This causes both the `current` and `next` fields to increase immediately. /// This function exists so that developers will have to explicitly
/// communicate that they're loading a synchronized or unsynchronized balance.
/// These balances should never be accessed directly.
/// @param balancePtr to load.
/// @return unsynchronized balance.
function _loadUnsyncedBalance(IStructs.StoredBalance storage balancePtr)
internal
view
returns (IStructs.StoredBalance memory balance)
{
balance = balancePtr;
return balance;
}
/// @dev Increments both the `current` and `next` fields.
/// @param balancePtr storage pointer to balance. /// @param balancePtr storage pointer to balance.
/// @param amount to mint. /// @param amount to mint.
function _mintBalance(IStructs.DelayedBalance storage balancePtr, uint256 amount) function _incrementCurrentAndNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount)
internal internal
{ {
// Remove stake from balance // Remove stake from balance
IStructs.DelayedBalance memory balance = _syncBalanceDestructive(balancePtr); IStructs.StoredBalance memory balance = _loadAndSyncBalance(balancePtr);
balance.next = LibSafeDowncast.downcastToUint96(uint256(balance.next).safeAdd(amount)); balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeAdd(amount).downcastToUint96();
balance.current = LibSafeDowncast.downcastToUint96(uint256(balance.current).safeAdd(amount)); balance.currentEpochBalance = uint256(balance.currentEpochBalance).safeAdd(amount).downcastToUint96();
// update state // update state
_storeBalance(balancePtr, balance); _storeBalance(balancePtr, balance);
} }
/// @dev Burns existing value in a balance. /// @dev Decrements both the `current` and `next` fields.
/// This causes both the `current` and `next` fields to decrease immediately.
/// @param balancePtr storage pointer to balance. /// @param balancePtr storage pointer to balance.
/// @param amount to mint. /// @param amount to mint.
function _burnBalance(IStructs.DelayedBalance storage balancePtr, uint256 amount) function _decrementCurrentAndNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount)
internal internal
{ {
// Remove stake from balance // Remove stake from balance
IStructs.DelayedBalance memory balance = _syncBalanceDestructive(balancePtr); IStructs.StoredBalance memory balance = _loadAndSyncBalance(balancePtr);
balance.next = LibSafeDowncast.downcastToUint96(uint256(balance.next).safeSub(amount)); balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeSub(amount).downcastToUint96();
balance.current = LibSafeDowncast.downcastToUint96(uint256(balance.current).safeSub(amount)); balance.currentEpochBalance = uint256(balance.currentEpochBalance).safeSub(amount).downcastToUint96();
// update state // update state
_storeBalance(balancePtr, balance); _storeBalance(balancePtr, balance);
} }
/// @dev Increments a balance. /// @dev Increments the `next` field (but not the `current` field).
/// Ths updates the `next` field but not the `current` field.
/// @param balancePtr storage pointer to balance. /// @param balancePtr storage pointer to balance.
/// @param amount to increment by. /// @param amount to increment by.
function _incrementBalance(IStructs.DelayedBalance storage balancePtr, uint256 amount) function _incrementNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount)
internal internal
{ {
// Add stake to balance // Add stake to balance
IStructs.DelayedBalance memory balance = _syncBalanceDestructive(balancePtr); IStructs.StoredBalance memory balance = _loadAndSyncBalance(balancePtr);
balance.next = LibSafeDowncast.downcastToUint96(uint256(balance.next).safeAdd(amount)); balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeAdd(amount).downcastToUint96();
// update state // update state
_storeBalance(balancePtr, balance); _storeBalance(balancePtr, balance);
} }
/// @dev Decrements a balance. /// @dev Decrements the `next` field (but not the `current` field).
/// Ths updates the `next` field but not the `current` field.
/// @param balancePtr storage pointer to balance. /// @param balancePtr storage pointer to balance.
/// @param amount to decrement by. /// @param amount to decrement by.
function _decrementBalance(IStructs.DelayedBalance storage balancePtr, uint256 amount) function _decrementNextBalance(IStructs.StoredBalance storage balancePtr, uint256 amount)
internal internal
{ {
// Remove stake from balance // Remove stake from balance
IStructs.DelayedBalance memory balance = _syncBalanceDestructive(balancePtr); IStructs.StoredBalance memory balance = _loadAndSyncBalance(balancePtr);
balance.next = LibSafeDowncast.downcastToUint96(uint256(balance.next).safeSub(amount)); balance.nextEpochBalance = uint256(balance.nextEpochBalance).safeSub(amount).downcastToUint96();
// update state // update state
_storeBalance(balancePtr, balance); _storeBalance(balancePtr, balance);
@ -162,16 +177,16 @@ contract MixinStakeStorage is
/// @param balancePtr points to where `balance` will be stored. /// @param balancePtr points to where `balance` will be stored.
/// @param balance to save to storage. /// @param balance to save to storage.
function _storeBalance( function _storeBalance(
IStructs.DelayedBalance storage balancePtr, IStructs.StoredBalance storage balancePtr,
IStructs.DelayedBalance memory balance IStructs.StoredBalance memory balance
) )
private private
{ {
// note - this compresses into a single `sstore` when optimizations are enabled, // note - this compresses into a single `sstore` when optimizations are enabled,
// since the StakeBalance struct occupies a single word of storage. // since the StakeBalance struct occupies a single word of storage.
balancePtr.lastStored = balance.lastStored; balancePtr.currentEpoch = balance.currentEpoch;
balancePtr.next = balance.next; balancePtr.nextEpochBalance = balance.nextEpochBalance;
balancePtr.current = balance.current; balancePtr.currentEpochBalance = balance.currentEpochBalance;
} }
/// @dev Returns true iff storage pointers resolve to same storage location. /// @dev Returns true iff storage pointers resolve to same storage location.
@ -180,9 +195,9 @@ contract MixinStakeStorage is
/// @return true iff pointers are equal. /// @return true iff pointers are equal.
function _arePointersEqual( function _arePointersEqual(
// solhint-disable-next-line no-unused-vars // solhint-disable-next-line no-unused-vars
IStructs.DelayedBalance storage balancePtrA, IStructs.StoredBalance storage balancePtrA,
// solhint-disable-next-line no-unused-vars // solhint-disable-next-line no-unused-vars
IStructs.DelayedBalance storage balancePtrB IStructs.StoredBalance storage balancePtrB
) )
private private
pure pure

View File

@ -73,7 +73,7 @@ contract MixinStakingPoolRewardVault is
address payable rewardVaultAddress = address(uint160(address(rewardVault))); address payable rewardVaultAddress = address(uint160(address(rewardVault)));
if (rewardVaultAddress == NIL_ADDRESS) { if (rewardVaultAddress == NIL_ADDRESS) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.RewardVaultNotSet() LibStakingRichErrors.RewardVaultNotSetError()
); );
} }
@ -96,7 +96,7 @@ contract MixinStakingPoolRewardVault is
IStakingPoolRewardVault _rewardVault = rewardVault; IStakingPoolRewardVault _rewardVault = rewardVault;
if (address(_rewardVault) == NIL_ADDRESS) { if (address(_rewardVault) == NIL_ADDRESS) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.RewardVaultNotSet() LibStakingRichErrors.RewardVaultNotSetError()
); );
} }

View File

@ -48,33 +48,32 @@ contract MixinStakingPoolRewards is
returns (uint256 totalReward) returns (uint256 totalReward)
{ {
// cache some values to reduce sloads // cache some values to reduce sloads
IStructs.DelayedBalance memory delegatedStake = delegatedStakeToPoolByOwner[member][poolId]; IStructs.StoredBalance memory delegatedStake = _loadUnsyncedBalance(delegatedStakeToPoolByOwner[member][poolId]);
uint256 currentEpoch = getCurrentEpoch(); uint256 currentEpoch = getCurrentEpoch();
// value is always zero in these two scenarios: // value is always zero in these two scenarios:
// 1. The current epoch is zero: delegation begins at epoch 1 // 1. The owner's delegated is current as of this epoch: their rewards have been moved to the ETH vault.
// 2. The owner's delegated is current as of this epoch: their rewards have been moved to the ETH vault. // 2. The current epoch is zero: delegation begins at epoch 1
if (currentEpoch == 0 || delegatedStake.lastStored == currentEpoch) return 0; if (delegatedStake.currentEpoch == currentEpoch || currentEpoch == 0) return 0;
// compute reward accumulated during `lastStored` epoch; // compute reward accumulated during `delegatedStake.currentEpoch`;
// the `current` balance describes how much stake was collecting rewards when `lastStored` was set. uint256 rewardsAccumulatedDuringLastStoredEpoch = (delegatedStake.currentEpochBalance != 0)
uint256 rewardsAccumulatedDuringLastStoredEpoch = (delegatedStake.current != 0)
? _computeMemberRewardOverInterval( ? _computeMemberRewardOverInterval(
poolId, poolId,
delegatedStake.current, delegatedStake.currentEpochBalance,
delegatedStake.lastStored - 1, delegatedStake.currentEpoch - 1,
delegatedStake.lastStored delegatedStake.currentEpoch
) )
: 0; : 0;
// compute the rewards accumulated by the `next` balance; // compute the reward accumulated by the `next` balance;
// this starts at `lastStored + 1` and goes up until the last epoch, during which // this starts at `delegatedStake.currentEpoch + 1` and goes up until the last epoch, during which
// rewards were accumulated. This is at most the most recently finalized epoch (current epoch - 1). // rewards were accumulated. This is at most the most recently finalized epoch (current epoch - 1).
uint256 rewardsAccumulatedAfterLastStoredEpoch = (cumulativeRewardsByPoolLastStored[poolId] > delegatedStake.lastStored) uint256 rewardsAccumulatedAfterLastStoredEpoch = (cumulativeRewardsByPoolLastStored[poolId] > delegatedStake.currentEpoch)
? _computeMemberRewardOverInterval( ? _computeMemberRewardOverInterval(
poolId, poolId,
delegatedStake.next, delegatedStake.nextEpochBalance,
delegatedStake.lastStored, delegatedStake.currentEpoch,
cumulativeRewardsByPoolLastStored[poolId] cumulativeRewardsByPoolLastStored[poolId]
) )
: 0; : 0;

View File

@ -34,7 +34,7 @@ import "../interfaces/IVaultCore.sol";
/// recoverable flaw/bug/vulnerability, simply detach the staking contract /// recoverable flaw/bug/vulnerability, simply detach the staking contract
/// by setting its address to `address(0)`. Once in Catastrophic Failure Mode, /// by setting its address to `address(0)`. Once in Catastrophic Failure Mode,
/// a vault cannot be reset to normal mode; this prevents corruption of related /// a vault cannot be reset to normal mode; this prevents corruption of related
/// state in the staking contract. /// status in the staking contract.
contract MixinVaultCore is contract MixinVaultCore is
Authorizable, Authorizable,
IVaultCore IVaultCore

View File

@ -280,7 +280,7 @@ contract StakingPoolRewardVault is
IEthVault _ethVault = ethVault; IEthVault _ethVault = ethVault;
if (address(_ethVault) == address(0)) { if (address(_ethVault) == address(0)) {
LibRichErrors.rrevert( LibRichErrors.rrevert(
LibStakingRichErrors.EthVaultNotSet() LibStakingRichErrors.EthVaultNotSetError()
); );
} }

View File

@ -64,7 +64,7 @@ export class Simulation {
await this._withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync(this._p); await this._withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync(this._p);
} }
// @TODO cleanup state and verify the staking contract is empty // @TODO cleanup status and verify the staking contract is empty
} }
private async _withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync( private async _withdrawRewardForStakingPoolMemberForDelegatorsByUndelegatingAsync(

View File

@ -203,27 +203,27 @@ export class StakingWrapper {
} }
public async moveStakeAsync( public async moveStakeAsync(
owner: string, owner: string,
_fromState: { _fromStatus: {
state: number, status: number,
poolId?: string poolId?: string
}, },
_toState: { _toStatus: {
state: number, status: number,
poolId?: string poolId?: string
}, },
amount: BigNumber, amount: BigNumber,
): Promise<TransactionReceiptWithDecodedLogs> { ): Promise<TransactionReceiptWithDecodedLogs> {
const fromState = { const fromStatus = {
state: _fromState.state, status: _fromStatus.status,
poolId: _fromState.poolId !== undefined ? _fromState.poolId : constants.NIL_POOL_ID poolId: _fromStatus.poolId !== undefined ? _fromStatus.poolId : constants.NIL_POOL_ID
}; };
const toState = { const toStatus = {
state: _toState.state, status: _toStatus.status,
poolId: _toState.poolId !== undefined ? _toState.poolId : constants.NIL_POOL_ID poolId: _toStatus.poolId !== undefined ? _toStatus.poolId : constants.NIL_POOL_ID
}; };
const calldata = this.getStakingContract().moveStake.getABIEncodedTransactionData( const calldata = this.getStakingContract().moveStake.getABIEncodedTransactionData(
fromState, fromStatus,
toState, toStatus,
amount, amount,
); );
const txReceipt = await this._executeTransactionAsync(calldata, owner); const txReceipt = await this._executeTransactionAsync(calldata, owner);

View File

@ -50,11 +50,11 @@ export interface SimulationParams {
} }
export interface StakeBalance { export interface StakeBalance {
current: BigNumber, currentEpochBalance: BigNumber,
next: BigNumber, nextEpochBalance: BigNumber,
} }
export enum StakeStateId { export enum StakeStatus {
ACTIVE, ACTIVE,
INACTIVE, INACTIVE,
DELEGATED DELEGATED

View File

@ -6,8 +6,6 @@ import "./LibSafeMathRichErrors.sol";
library LibSafeMath { library LibSafeMath {
using LibSafeMath for uint256;
function safeMul(uint256 a, uint256 b) function safeMul(uint256 a, uint256 b)
internal internal
pure pure

View File

@ -293,6 +293,7 @@ const types = [
TransactionGasPriceError, TransactionGasPriceError,
TransactionInvalidContextError, TransactionInvalidContextError,
TransactionSignatureError, TransactionSignatureError,
IncompleteFillError,
]; ];
// Register the types we've defined. // Register the types we've defined.

View File

@ -204,21 +204,21 @@ export class InvalidCobbDouglasAlphaError extends RevertError {
} }
} }
export class EthVaultNotSet extends RevertError { export class EthVaultNotSetError extends RevertError {
constructor() { constructor() {
super('EthVaultNotSet', 'EthVaultNotSet()'); super('EthVaultNotSetError', 'EthVaultNotSetError()');
} }
} }
export class RewardVaultNotSet extends RevertError { export class RewardVaultNotSetError extends RevertError {
constructor() { constructor() {
super('RewardVaultNotSet', 'RewardVaultNotSet()'); super('RewardVaultNotSetError', 'RewardVaultNotSetError()');
} }
} }
export class InvalidStakeState extends RevertError { export class InvalidStakeStatusError extends RevertError {
constructor(state?: BigNumber) { constructor(status?: BigNumber) {
super('InvalidStakeState', 'InvalidStakeState(uint256 state)', { state }); super('InvalidStakeStatusError', 'InvalidStakeStatusError(uint256 status)', { status });
} }
} }
@ -248,9 +248,9 @@ const types = [
InvalidPoolOperatorShareError, InvalidPoolOperatorShareError,
PoolAlreadyExistsError, PoolAlreadyExistsError,
InvalidCobbDouglasAlphaError, InvalidCobbDouglasAlphaError,
EthVaultNotSet, EthVaultNotSetError,
RewardVaultNotSet, RewardVaultNotSetError,
InvalidStakeState InvalidStakeStatusError
]; ];
// Register the types we've defined. // Register the types we've defined.