@0x/contracts-staking
: More work on MixinFinalizer
.
This commit is contained in:
parent
bbae6b3de2
commit
73f1aca4a1
@ -65,10 +65,11 @@ contract MixinFinalizer is
|
||||
external
|
||||
returns (uint256 _unfinalizedPoolsRemaining)
|
||||
{
|
||||
uint256 closingEpoch = currentEpoch;
|
||||
// Make sure the previous epoch has been fully finalized.
|
||||
if (unfinalizedPoolsRemaining != 0) {
|
||||
LibRichErrors.rrevert(LibStakingRichErrors.PreviousEpochNotFinalized(
|
||||
currentEpoch - 1,
|
||||
closingEpoch.sub(1),
|
||||
unfinalizedPoolsRemaining
|
||||
));
|
||||
}
|
||||
@ -78,15 +79,23 @@ contract MixinFinalizer is
|
||||
unfinalizedTotalFeesCollected = totalFeesCollected;
|
||||
unfinalizedTotalWeightedStake = totalWeightedStake;
|
||||
totalRewardsPaid = 0;
|
||||
// Emit an event.
|
||||
emit EpochEnded(
|
||||
closingEpoch,
|
||||
numActivePoolsThisEpoch,
|
||||
rewardsAvailable,
|
||||
totalWeightedStake,
|
||||
totalFeesCollected
|
||||
);
|
||||
// Reset current epoch state.
|
||||
totalFeesCollected = 0;
|
||||
totalWeightedStake = 0;
|
||||
numActivePoolsThisEpoch = 0;
|
||||
// Advance the epoch. This will revert if not enough time has passed.
|
||||
_goToNextEpoch();
|
||||
// If there were no active pools, finalize the epoch now.
|
||||
// If there were no active pools, the epoch is already finalized.
|
||||
if (unfinalizedPoolsRemaining == 0) {
|
||||
emit EpochFinalized();
|
||||
emit EpochFinalized(closingEpoch, 0, unfinalizedRewardsAvailable);
|
||||
}
|
||||
return _unfinalizedPoolsRemaining = unfinalizedPoolsRemaining;
|
||||
}
|
||||
@ -96,10 +105,96 @@ contract MixinFinalizer is
|
||||
/// repeatedly until all active pools that were emitted in in a
|
||||
/// `StakingPoolActivated` in the prior epoch have been finalized.
|
||||
/// Pools that have already been finalized will be silently ignored.
|
||||
/// We deliberately try not to revert here in case multiple parties
|
||||
/// are finalizing pools.
|
||||
/// @param poolIds List of active pool IDs to finalize.
|
||||
/// @return rewardsPaid Total rewards paid to the pools passed in.
|
||||
/// @return _unfinalizedPoolsRemaining The number of unfinalized pools left.
|
||||
function finalizePools(bytes32[] memory poolIds) external {
|
||||
function finalizePools(bytes32[] memory poolIds)
|
||||
external
|
||||
returns (uint256 rewardsPaid, uint256 _unfinalizedPoolsRemaining)
|
||||
{
|
||||
uint256 epoch = currentEpoch.sub(1);
|
||||
uint256 poolsRemaining = unfinalizedPoolsRemaining;
|
||||
uint256 numPoolIds = poolIds.length;
|
||||
uint256 rewardsPaid = 0;
|
||||
// Pointer to the active pools in the last epoch.
|
||||
// We use `(currentEpoch - 1) % 2` as the index to reuse state.
|
||||
mapping(bytes32 => IStructs.ActivePool) storage activePools =
|
||||
activePoolsByEpoch[epoch % 2];
|
||||
for (uint256 i = 0; i < numPoolIds && poolsRemaining != 0; i++) {
|
||||
bytes32 poolId = poolIds[i];
|
||||
IStructs.ActivePool memory pool = activePools[poolId];
|
||||
// Ignore pools that aren't active.
|
||||
if (pool.feesCollected != 0) {
|
||||
// Credit the pool with rewards.
|
||||
// We will transfer the total rewards to the vault at the end.
|
||||
rewardsPaid = rewardsPaid.add(_creditRewardsToPool(poolId, pool));
|
||||
// Clear the pool state so we don't finalize it again,
|
||||
// and to recoup some gas.
|
||||
activePools[poolId] = IStructs.ActivePool(0, 0);
|
||||
// Decrease the number of unfinalized pools left.
|
||||
poolsRemaining = poolsRemaining.sub(1);
|
||||
// Emit an event.
|
||||
emit RewardsPaid(epoch, poolId, reward);
|
||||
}
|
||||
}
|
||||
// Deposit all the rewards at once into the RewardVault.
|
||||
_depositIntoStakingPoolRewardVault(rewardsPaid);
|
||||
// Update finalization state.
|
||||
totalRewardsPaidLastEpoch = totalRewardsPaidLastEpoch.add(rewardsPaid);
|
||||
_unfinalizedPoolsRemaining = unfinalizedPoolsRemaining = poolsRemaining;
|
||||
// If there are no more unfinalized pools remaining, the epoch is
|
||||
// finalized.
|
||||
if (poolsRemaining == 0) {
|
||||
emit EpochFinalized(
|
||||
epoch,
|
||||
totalRewardsPaidLastEpoch,
|
||||
unfinalizedRewardsAvailable.sub(totalRewardsPaidLastEpoch)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev Computes the rewards owned for a pool during finalization and
|
||||
/// credits it in the RewardVault.
|
||||
/// @param The epoch being finalized.
|
||||
/// @param poolId The pool's ID.
|
||||
/// @param pool The pool.
|
||||
/// @return rewards Amount of rewards for this pool.
|
||||
function _creditRewardsToPool(
|
||||
uint256 epoch,
|
||||
bytes32 poolId,
|
||||
IStructs.ActivePool memory pool
|
||||
)
|
||||
internal
|
||||
returns (uint256 rewards)
|
||||
{
|
||||
// Use the cobb-douglas function to compute the reward.
|
||||
reward = _cobbDouglas(
|
||||
unfinalizedRewardsAvailable,
|
||||
pool.feesCollected,
|
||||
unfinalizedTotalFeesCollected,
|
||||
pool.weightedStake,
|
||||
unfinalizedTotalWeightedStake,
|
||||
cobbDouglasAlphaNumerator,
|
||||
cobbDouglasAlphaDenomintor
|
||||
);
|
||||
// Credit the pool the reward in the RewardVault.
|
||||
(, uint256 membersPortionOfReward) = rewardVault.recordDepositFor(
|
||||
poolId,
|
||||
reward,
|
||||
// If no delegated stake, all rewards go to the operator.
|
||||
pool.delegatedStake == 0
|
||||
);
|
||||
// Sync delegator rewards.
|
||||
if (membersPortionOfReward != 0) {
|
||||
_recordRewardForDelegators(
|
||||
poolId,
|
||||
membersPortionOfReward,
|
||||
pool.delegatedStake,
|
||||
epoch
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/// @dev The cobb-douglas function used to compute fee-based rewards for staking pools in a given epoch.
|
||||
|
@ -145,7 +145,7 @@ contract MixinStorage is
|
||||
uint256 totalWeightedStakeThisEpoch;
|
||||
/// @dev State information for each active pool in an epoch.
|
||||
/// In practice, we only store state for `currentEpoch % 2`.
|
||||
mapping(uint256 => mapping(bytes32 => ActivePool)) activePoolsByEpoch;
|
||||
mapping(uint256 => mapping(bytes32 => IStructs.ActivePool)) activePoolsByEpoch;
|
||||
/// @dev Number of pools activated in the current epoch.
|
||||
uint256 numActivePoolsThisEpoch;
|
||||
/// @dev Rewards (ETH) available to the epoch being finalized (the previous
|
||||
|
@ -43,23 +43,13 @@ interface IStakingEvents {
|
||||
address exchangeAddress
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinScheduler when the epoch is changed.
|
||||
/// @param epoch The epoch we changed to.
|
||||
/// @param startTimeInSeconds The start time of the epoch.
|
||||
/// @param earliestEndTimeInSeconds The earliest this epoch can end.
|
||||
event EpochChanged(
|
||||
uint256 epoch,
|
||||
uint256 startTimeInSeconds,
|
||||
uint256 earliestEndTimeInSeconds
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinFinalizer when an epoch has ended.
|
||||
/// @param epoch The closing epoch.
|
||||
/// @param numActivePools Number of active pools in the closing epoch.
|
||||
/// @param rewardsAvailable Rewards available to all active pools.
|
||||
/// @param totalWeightedStake Total weighted stake across all active pools.
|
||||
/// @param totalFeesCollected Total fees collected across all active pools.
|
||||
event EpochFinalized(
|
||||
event EpochEnded(
|
||||
uint256 epoch,
|
||||
uint256 numActivePools,
|
||||
uint256 rewardsAvailable,
|
||||
@ -77,6 +67,16 @@ interface IStakingEvents {
|
||||
uint256 rewardsRemaining
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinFinalizer when rewards are paid out to a pool.
|
||||
/// @param epoch The epoch when the rewards were earned.
|
||||
/// @param poolId The pool's ID.
|
||||
/// @param reward Amount of reward paid.
|
||||
event RewardsPaid(
|
||||
uint255 epoch,
|
||||
bytes32 poolId,
|
||||
uint255 reward
|
||||
);
|
||||
|
||||
/// @dev Emitted whenever staking parameters are changed via the `setParams()` function.
|
||||
/// @param epochDurationInSeconds Minimum seconds between epochs.
|
||||
/// @param rewardDelegatedStakeWeight How much delegated stake is weighted vs operator stake, in ppm.
|
||||
@ -111,22 +111,6 @@ interface IStakingEvents {
|
||||
uint256 endEpoch
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinExchangeFees when rewards are paid out.
|
||||
/// @param totalActivePools Total active pools this epoch.
|
||||
/// @param totalFeesCollected Total fees collected this epoch, across all active pools.
|
||||
/// @param totalWeightedStake Total weighted stake attributed to each pool. Delegated stake is weighted less.
|
||||
/// @param totalRewardsPaid Total rewards paid out across all active pools.
|
||||
/// @param initialContractBalance Balance of this contract before paying rewards.
|
||||
/// @param finalContractBalance Balance of this contract after paying rewards.
|
||||
event RewardsPaid(
|
||||
uint256 totalActivePools,
|
||||
uint256 totalFeesCollected,
|
||||
uint256 totalWeightedStake,
|
||||
uint256 totalRewardsPaid,
|
||||
uint256 initialContractBalance,
|
||||
uint256 finalContractBalance
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinStakingPool when a new pool is created.
|
||||
/// @param poolId Unique id generated for pool.
|
||||
/// @param operator The operator (creator) of pool.
|
||||
|
@ -23,11 +23,13 @@ interface IStructs {
|
||||
|
||||
/// @dev Status for a pool that actively traded during the current epoch.
|
||||
/// (see MixinExchangeFees).
|
||||
/// @param feesCollected Fees collected in ETH by this pool in the current epoch.
|
||||
/// @param weightedStake Amount of weighted stake currently held by the pool.
|
||||
/// @param feesCollected Fees collected in ETH by this pool.
|
||||
/// @param weightedStake Amount of weighted stake in the pool.
|
||||
/// @param delegatedStake Amount of delegated, non-operator stake in the pool.
|
||||
struct ActivePool {
|
||||
uint256 feesCollected;
|
||||
uint256 weightedStake;
|
||||
uint256 delegatedStake;
|
||||
}
|
||||
|
||||
/// @dev Encapsulates a balance for the current and next epochs.
|
||||
|
@ -87,13 +87,6 @@ contract MixinScheduler is
|
||||
uint256 earliestEndTimeInSeconds = currentEpochStartTimeInSeconds.safeAdd(
|
||||
epochDurationInSeconds
|
||||
);
|
||||
|
||||
// notify of epoch change
|
||||
emit EpochChanged(
|
||||
currentEpoch,
|
||||
currentEpochStartTimeInSeconds,
|
||||
earliestEndTimeInSeconds
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Assert scheduler state before initializing it.
|
||||
|
Loading…
x
Reference in New Issue
Block a user