Refactored finalization state.
1. Removes state variables: - totalWeightedStakeThisEpoch - totalFeesCollectedThisEpoch - numActivePoolsThisEpoch 2. No longer indexes by epoch % 2 3. Renamed event StakingPoolActivated → StakingPoolEarnedRewards. 4. Renamed structs: - ActivePool → PoolStats. This holds stats for a pool that earned rewards. - UnfinalizedState → AggregatedStats. This aggregates stats from the former struct.
This commit is contained in:
@@ -81,49 +81,46 @@ contract MixinExchangeFees is
|
||||
return;
|
||||
}
|
||||
|
||||
// Look up the pool for this epoch.
|
||||
// Look up the pool stats and aggregated stats for this epoch.
|
||||
uint256 currentEpoch_ = currentEpoch;
|
||||
mapping (bytes32 => IStructs.ActivePool) storage activePoolsThisEpoch =
|
||||
_getActivePoolsFromEpoch(currentEpoch_);
|
||||
|
||||
IStructs.ActivePool memory pool = activePoolsThisEpoch[poolId];
|
||||
IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][currentEpoch_];
|
||||
IStructs.AggregatedStats memory aggregatedStats = aggregatedStatsByEpoch[currentEpoch_];
|
||||
|
||||
// If the pool was previously inactive in this epoch, initialize it.
|
||||
if (pool.feesCollected == 0) {
|
||||
if (poolStats.feesCollected == 0) {
|
||||
// Compute member and total weighted stake.
|
||||
(pool.membersStake, pool.weightedStake) = _computeMembersAndWeightedStake(poolId, poolStake);
|
||||
(poolStats.membersStake, poolStats.weightedStake) = _computeMembersAndWeightedStake(poolId, poolStake);
|
||||
|
||||
// Increase the total weighted stake.
|
||||
totalWeightedStakeThisEpoch = totalWeightedStakeThisEpoch.safeAdd(pool.weightedStake);
|
||||
aggregatedStats.totalWeightedStake = aggregatedStats.totalWeightedStake.safeAdd(poolStats.weightedStake);
|
||||
|
||||
// Increase the number of active pools.
|
||||
numActivePoolsThisEpoch = numActivePoolsThisEpoch.safeAdd(1);
|
||||
aggregatedStats.poolsToFinalize = aggregatedStats.poolsToFinalize.safeAdd(1);
|
||||
|
||||
// Emit an event so keepers know what pools to pass into
|
||||
// `finalize()`.
|
||||
emit StakingPoolActivated(currentEpoch_, poolId);
|
||||
// Emit an event so keepers know what pools earned rewards this epoch.
|
||||
emit StakingPoolEarnedRewardsInEpoch(currentEpoch_, poolId);
|
||||
}
|
||||
|
||||
// Credit the fees to the pool.
|
||||
pool.feesCollected = pool.feesCollected.safeAdd(protocolFeePaid);
|
||||
poolStats.feesCollected = poolStats.feesCollected.safeAdd(protocolFeePaid);
|
||||
|
||||
// Increase the total fees collected this epoch.
|
||||
totalFeesCollectedThisEpoch = totalFeesCollectedThisEpoch.safeAdd(protocolFeePaid);
|
||||
aggregatedStats.totalFeesCollected = aggregatedStats.totalFeesCollected.safeAdd(protocolFeePaid);
|
||||
|
||||
// Store the pool.
|
||||
activePoolsThisEpoch[poolId] = pool;
|
||||
// Store the updated stats.
|
||||
poolStatsByEpoch[poolId][currentEpoch_] = poolStats;
|
||||
aggregatedStatsByEpoch[currentEpoch_] = aggregatedStats;
|
||||
}
|
||||
|
||||
/// @dev Get information on an active staking pool in this epoch.
|
||||
/// @param poolId Pool Id to query.
|
||||
/// @return pool ActivePool struct.
|
||||
function getActiveStakingPoolThisEpoch(bytes32 poolId)
|
||||
/// @return PoolStats struct for pool id.
|
||||
function getStakingPoolStatsThisEpoch(bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (IStructs.ActivePool memory pool)
|
||||
returns (IStructs.PoolStats memory)
|
||||
{
|
||||
pool = _getActivePoolFromEpoch(currentEpoch, poolId);
|
||||
return pool;
|
||||
return poolStatsByEpoch[poolId][currentEpoch];
|
||||
}
|
||||
|
||||
/// @dev Computes the members and weighted stake for a pool at the current
|
||||
|
||||
@@ -101,25 +101,15 @@ contract MixinStorage is
|
||||
// Denominator for cobb douglas alpha factor.
|
||||
uint32 public cobbDouglasAlphaDenominator;
|
||||
|
||||
/* Finalization states */
|
||||
/* State for finalization */
|
||||
|
||||
/// @dev The total fees collected in the current epoch, built up iteratively
|
||||
/// in `payProtocolFee()`.
|
||||
uint256 public totalFeesCollectedThisEpoch;
|
||||
/// @dev Stats for each pool that generated fees with sufficient stake to earn rewards.
|
||||
/// See `_minimumPoolStake` in MixinParams.
|
||||
mapping (bytes32 => mapping (uint256 => IStructs.PoolStats)) public poolStatsByEpoch;
|
||||
|
||||
/// @dev The total weighted stake in the current epoch, built up iteratively
|
||||
/// in `payProtocolFee()`.
|
||||
uint256 public totalWeightedStakeThisEpoch;
|
||||
|
||||
/// @dev State information for each active pool in an epoch.
|
||||
/// In practice, we only store state for `currentEpoch % 2`.
|
||||
mapping (uint256 => mapping (bytes32 => IStructs.ActivePool)) internal _activePoolsByEpoch;
|
||||
|
||||
/// @dev Number of pools activated in the current epoch.
|
||||
uint256 public numActivePoolsThisEpoch;
|
||||
|
||||
/// @dev State for unfinalized rewards.
|
||||
IStructs.UnfinalizedState public unfinalizedState;
|
||||
/// @dev Aggregated stats across all pools that generated fees with sufficient stake to earn rewards.
|
||||
/// See `_minimumPoolStake` in MixinParams.
|
||||
mapping (uint256 => IStructs.AggregatedStats) public aggregatedStatsByEpoch;
|
||||
|
||||
/// @dev The WETH balance of this contract that is reserved for pool reward payouts.
|
||||
uint256 public wethReservedForPoolRewards;
|
||||
|
||||
@@ -43,24 +43,23 @@ interface IStakingEvents {
|
||||
address exchangeAddress
|
||||
);
|
||||
|
||||
/// @dev Emitted by MixinExchangeFees when a pool pays protocol fees
|
||||
/// for the first time in an epoch.
|
||||
/// @param epoch The epoch in which the pool was activated.
|
||||
/// @dev Emitted by MixinExchangeFees when a pool will earn rewards.
|
||||
/// @param epoch The epoch in which the pool earned rewards.
|
||||
/// @param poolId The ID of the pool.
|
||||
event StakingPoolActivated(
|
||||
event StakingPoolEarnedRewardsInEpoch(
|
||||
uint256 indexed epoch,
|
||||
bytes32 indexed poolId
|
||||
);
|
||||
|
||||
/// @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 poolsToFinalize Number of pools to finalize 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 EpochEnded(
|
||||
uint256 indexed epoch,
|
||||
uint256 numActivePools,
|
||||
uint256 poolsToFinalize,
|
||||
uint256 rewardsAvailable,
|
||||
uint256 totalFeesCollected,
|
||||
uint256 totalWeightedStake
|
||||
|
||||
@@ -65,7 +65,7 @@ interface IStorage {
|
||||
view
|
||||
returns (uint256);
|
||||
|
||||
function activePoolsThisEpoch()
|
||||
function poolsToFinalizeThisEpoch()
|
||||
external
|
||||
view
|
||||
returns (bytes32[] memory);
|
||||
|
||||
@@ -29,29 +29,27 @@ interface IStructs {
|
||||
uint96 lastSetTimestamp;
|
||||
}
|
||||
|
||||
/// @dev Status for a pool that actively traded during the current epoch.
|
||||
/// (see MixinExchangeFees).
|
||||
/// @dev Stats for a pool that actively traded.
|
||||
/// @param feesCollected Fees collected in ETH by this pool.
|
||||
/// @param weightedStake Amount of weighted stake in the pool.
|
||||
/// @param membersStake Amount of non-operator stake in the pool.
|
||||
struct ActivePool {
|
||||
struct PoolStats {
|
||||
uint256 feesCollected;
|
||||
uint256 weightedStake;
|
||||
uint256 membersStake;
|
||||
}
|
||||
|
||||
/// @dev Holds state for unfinalized epoch rewards.
|
||||
/// @dev Holds stats aggregated across a set of pools.
|
||||
/// @param rewardsAvailable Rewards (ETH) available to the epoch
|
||||
/// being finalized (the previous epoch). This is simply the balance
|
||||
/// of the contract at the end of the epoch.
|
||||
/// @param poolsRemaining The number of active pools in the last
|
||||
/// epoch that have yet to be finalized through `finalizePools()`.
|
||||
/// @param poolsToFinalize The number of pools that have yet to be finalized through `finalizePools()`.
|
||||
/// @param totalFeesCollected The total fees collected for the epoch being finalized.
|
||||
/// @param totalWeightedStake The total fees collected for the epoch being finalized.
|
||||
/// @param totalRewardsFinalized Amount of rewards that have been paid during finalization.
|
||||
struct UnfinalizedState {
|
||||
struct AggregatedStats {
|
||||
uint256 rewardsAvailable;
|
||||
uint256 poolsRemaining;
|
||||
uint256 poolsToFinalize;
|
||||
uint256 totalFeesCollected;
|
||||
uint256 totalWeightedStake;
|
||||
uint256 totalRewardsFinalized;
|
||||
|
||||
@@ -38,56 +38,54 @@ contract MixinFinalizer is
|
||||
/// If there were no active pools in the closing epoch, the epoch
|
||||
/// will be instantly finalized here. Otherwise, `finalizePool()`
|
||||
/// should be called on each active pool afterwards.
|
||||
/// @return poolsRemaining The number of unfinalized pools.
|
||||
/// @return poolsToFinalize The number of unfinalized pools.
|
||||
function endEpoch()
|
||||
external
|
||||
returns (uint256 poolsRemaining)
|
||||
returns (uint256)
|
||||
{
|
||||
uint256 closingEpoch = currentEpoch;
|
||||
IStructs.UnfinalizedState memory state = unfinalizedState;
|
||||
uint256 prevEpoch = closingEpoch.safeSub(1);
|
||||
|
||||
// Make sure the previous epoch has been fully finalized.
|
||||
if (state.poolsRemaining != 0) {
|
||||
uint256 poolsToFinalizeFromPrevEpoch = aggregatedStatsByEpoch[prevEpoch].poolsToFinalize;
|
||||
if (poolsToFinalizeFromPrevEpoch != 0) {
|
||||
LibRichErrors.rrevert(
|
||||
LibStakingRichErrors.PreviousEpochNotFinalizedError(
|
||||
closingEpoch.safeSub(1),
|
||||
state.poolsRemaining
|
||||
prevEpoch,
|
||||
poolsToFinalizeFromPrevEpoch
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Convert all ETH to WETH
|
||||
// Since it is finalized, we no longer need stats for the previous epoch.
|
||||
delete aggregatedStatsByEpoch[prevEpoch];
|
||||
|
||||
// Convert all ETH to WETH; the WETH balance of this contract is the total rewards.
|
||||
_wrapEth();
|
||||
|
||||
// Set up unfinalized state.
|
||||
state.rewardsAvailable = _getAvailableWethBalance();
|
||||
state.poolsRemaining = poolsRemaining = numActivePoolsThisEpoch;
|
||||
state.totalFeesCollected = totalFeesCollectedThisEpoch;
|
||||
state.totalWeightedStake = totalWeightedStakeThisEpoch;
|
||||
state.totalRewardsFinalized = 0;
|
||||
unfinalizedState = state;
|
||||
// Load aggregated stats for the epoch we're ending.
|
||||
IStructs.AggregatedStats memory aggregatedStats = aggregatedStatsByEpoch[closingEpoch];
|
||||
aggregatedStatsByEpoch[closingEpoch].rewardsAvailable =
|
||||
aggregatedStats.rewardsAvailable = _getAvailableWethBalance();
|
||||
|
||||
// Emit an event.
|
||||
emit EpochEnded(
|
||||
closingEpoch,
|
||||
state.poolsRemaining,
|
||||
state.rewardsAvailable,
|
||||
state.totalFeesCollected,
|
||||
state.totalWeightedStake
|
||||
aggregatedStats.poolsToFinalize,
|
||||
aggregatedStats.rewardsAvailable,
|
||||
aggregatedStats.totalFeesCollected,
|
||||
aggregatedStats.totalWeightedStake
|
||||
);
|
||||
|
||||
// Reset current epoch state.
|
||||
totalFeesCollectedThisEpoch = 0;
|
||||
totalWeightedStakeThisEpoch = 0;
|
||||
numActivePoolsThisEpoch = 0;
|
||||
|
||||
// Advance the epoch. This will revert if not enough time has passed.
|
||||
_goToNextEpoch();
|
||||
|
||||
// If there were no active pools, the epoch is already finalized.
|
||||
if (poolsRemaining == 0) {
|
||||
emit EpochFinalized(closingEpoch, 0, state.rewardsAvailable);
|
||||
if (aggregatedStats.poolsToFinalize == 0) {
|
||||
emit EpochFinalized(closingEpoch, 0, aggregatedStats.rewardsAvailable);
|
||||
}
|
||||
|
||||
return aggregatedStats.poolsToFinalize;
|
||||
}
|
||||
|
||||
/// @dev Instantly finalizes a single pool that was active in the previous
|
||||
@@ -99,29 +97,28 @@ contract MixinFinalizer is
|
||||
function finalizePool(bytes32 poolId)
|
||||
external
|
||||
{
|
||||
// Load the finalization and pool state into memory.
|
||||
IStructs.UnfinalizedState memory state = unfinalizedState;
|
||||
|
||||
// Noop if all active pools have been finalized.
|
||||
if (state.poolsRemaining == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Compute relevant epochs
|
||||
uint256 currentEpoch_ = currentEpoch;
|
||||
uint256 prevEpoch = currentEpoch_.safeSub(1);
|
||||
IStructs.ActivePool memory pool = _getActivePoolFromEpoch(prevEpoch, poolId);
|
||||
|
||||
// Noop if the pool was not active or already finalized (has no fees).
|
||||
if (pool.feesCollected == 0) {
|
||||
// Load the aggregated stats into memory; noop if no pools to finalize.
|
||||
IStructs.AggregatedStats memory aggregatedStats = aggregatedStatsByEpoch[prevEpoch];
|
||||
if (aggregatedStats.poolsToFinalize == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the pool state so we don't finalize it again, and to recoup
|
||||
// Noop if the pool was not active or already finalized (has no fees).
|
||||
IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch];
|
||||
if (poolStats.feesCollected == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Clear the pool stats so we don't finalize it again, and to recoup
|
||||
// some gas.
|
||||
delete _getActivePoolsFromEpoch(prevEpoch)[poolId];
|
||||
delete poolStatsByEpoch[poolId][prevEpoch];
|
||||
|
||||
// Compute the rewards.
|
||||
uint256 rewards = _getUnfinalizedPoolRewardsFromState(pool, state);
|
||||
uint256 rewards = _getUnfinalizedPoolRewardsFromPoolStats(poolStats, aggregatedStats);
|
||||
|
||||
// Pay the operator and update rewards for the pool.
|
||||
// Note that we credit at the CURRENT epoch even though these rewards
|
||||
@@ -129,7 +126,7 @@ contract MixinFinalizer is
|
||||
(uint256 operatorReward, uint256 membersReward) = _syncPoolRewards(
|
||||
poolId,
|
||||
rewards,
|
||||
pool.membersStake
|
||||
poolStats.membersStake
|
||||
);
|
||||
|
||||
// Emit an event.
|
||||
@@ -143,22 +140,22 @@ contract MixinFinalizer is
|
||||
uint256 totalReward = operatorReward.safeAdd(membersReward);
|
||||
|
||||
// Increase `totalRewardsFinalized`.
|
||||
unfinalizedState.totalRewardsFinalized =
|
||||
state.totalRewardsFinalized =
|
||||
state.totalRewardsFinalized.safeAdd(totalReward);
|
||||
aggregatedStatsByEpoch[prevEpoch].totalRewardsFinalized =
|
||||
aggregatedStats.totalRewardsFinalized =
|
||||
aggregatedStats.totalRewardsFinalized.safeAdd(totalReward);
|
||||
|
||||
// Decrease the number of unfinalized pools left.
|
||||
unfinalizedState.poolsRemaining =
|
||||
state.poolsRemaining =
|
||||
state.poolsRemaining.safeSub(1);
|
||||
aggregatedStatsByEpoch[prevEpoch].poolsToFinalize =
|
||||
aggregatedStats.poolsToFinalize =
|
||||
aggregatedStats.poolsToFinalize.safeSub(1);
|
||||
|
||||
// If there are no more unfinalized pools remaining, the epoch is
|
||||
// finalized.
|
||||
if (state.poolsRemaining == 0) {
|
||||
if (aggregatedStats.poolsToFinalize == 0) {
|
||||
emit EpochFinalized(
|
||||
prevEpoch,
|
||||
state.totalRewardsFinalized,
|
||||
state.rewardsAvailable.safeSub(state.totalRewardsFinalized)
|
||||
aggregatedStats.totalRewardsFinalized,
|
||||
aggregatedStats.rewardsAvailable.safeSub(aggregatedStats.totalRewardsFinalized)
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -177,44 +174,10 @@ contract MixinFinalizer is
|
||||
uint256 membersStake
|
||||
)
|
||||
{
|
||||
IStructs.ActivePool memory pool = _getActivePoolFromEpoch(
|
||||
currentEpoch.safeSub(1),
|
||||
poolId
|
||||
);
|
||||
reward = _getUnfinalizedPoolRewardsFromState(pool, unfinalizedState);
|
||||
membersStake = pool.membersStake;
|
||||
}
|
||||
|
||||
/// @dev Get an active pool from an epoch by its ID.
|
||||
/// @param epoch The epoch the pool was/will be active in.
|
||||
/// @param poolId The ID of the pool.
|
||||
/// @return pool The pool with ID `poolId` that was active in `epoch`.
|
||||
function _getActivePoolFromEpoch(
|
||||
uint256 epoch,
|
||||
bytes32 poolId
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (IStructs.ActivePool memory pool)
|
||||
{
|
||||
pool = _getActivePoolsFromEpoch(epoch)[poolId];
|
||||
return pool;
|
||||
}
|
||||
|
||||
/// @dev Get a mapping of active pools from an epoch.
|
||||
/// This uses the formula `epoch % 2` as the epoch index in order
|
||||
/// to reuse state, because we only need to remember, at most, two
|
||||
/// epochs at once.
|
||||
/// @return activePools The pools that were active in `epoch`.
|
||||
function _getActivePoolsFromEpoch(
|
||||
uint256 epoch
|
||||
)
|
||||
internal
|
||||
view
|
||||
returns (mapping (bytes32 => IStructs.ActivePool) storage activePools)
|
||||
{
|
||||
activePools = _activePoolsByEpoch[epoch % 2];
|
||||
return activePools;
|
||||
uint256 prevEpoch = currentEpoch.safeSub(1);
|
||||
IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch];
|
||||
reward = _getUnfinalizedPoolRewardsFromPoolStats(poolStats, aggregatedStatsByEpoch[prevEpoch]);
|
||||
membersStake = poolStats.membersStake;
|
||||
}
|
||||
|
||||
/// @dev Converts the entire ETH balance of this contract into WETH.
|
||||
@@ -247,10 +210,10 @@ contract MixinFinalizer is
|
||||
view
|
||||
{
|
||||
uint256 prevEpoch = currentEpoch.safeSub(1);
|
||||
IStructs.ActivePool memory pool = _getActivePoolFromEpoch(prevEpoch, poolId);
|
||||
IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][prevEpoch];
|
||||
|
||||
// A pool that has any fees remaining has not been finalized
|
||||
if (pool.feesCollected != 0) {
|
||||
if (poolStats.feesCollected != 0) {
|
||||
LibRichErrors.rrevert(
|
||||
LibStakingRichErrors.PoolNotFinalizedError(
|
||||
poolId,
|
||||
@@ -261,12 +224,12 @@ contract MixinFinalizer is
|
||||
}
|
||||
|
||||
/// @dev Computes the reward owed to a pool during finalization.
|
||||
/// @param pool The active pool.
|
||||
/// @param state The current state of finalization.
|
||||
/// @return rewards Unfinalized rewards for this pool.
|
||||
function _getUnfinalizedPoolRewardsFromState(
|
||||
IStructs.ActivePool memory pool,
|
||||
IStructs.UnfinalizedState memory state
|
||||
/// @param poolStats Stats for a specific pool.
|
||||
/// @param aggregatedStats Stats aggregated across all pools.
|
||||
/// @return rewards Unfinalized rewards for the input pool.
|
||||
function _getUnfinalizedPoolRewardsFromPoolStats(
|
||||
IStructs.PoolStats memory poolStats,
|
||||
IStructs.AggregatedStats memory aggregatedStats
|
||||
)
|
||||
private
|
||||
view
|
||||
@@ -274,17 +237,17 @@ contract MixinFinalizer is
|
||||
{
|
||||
// There can't be any rewards if the pool was active or if it has
|
||||
// no stake.
|
||||
if (pool.feesCollected == 0) {
|
||||
if (poolStats.feesCollected == 0) {
|
||||
return rewards;
|
||||
}
|
||||
|
||||
// Use the cobb-douglas function to compute the total reward.
|
||||
rewards = LibCobbDouglas.cobbDouglas(
|
||||
state.rewardsAvailable,
|
||||
pool.feesCollected,
|
||||
state.totalFeesCollected,
|
||||
pool.weightedStake,
|
||||
state.totalWeightedStake,
|
||||
aggregatedStats.rewardsAvailable,
|
||||
poolStats.feesCollected,
|
||||
aggregatedStats.totalFeesCollected,
|
||||
poolStats.weightedStake,
|
||||
aggregatedStats.totalWeightedStake,
|
||||
cobbDouglasAlphaNumerator,
|
||||
cobbDouglasAlphaDenominator
|
||||
);
|
||||
@@ -292,7 +255,7 @@ contract MixinFinalizer is
|
||||
// Clip the reward to always be under
|
||||
// `rewardsAvailable - totalRewardsPaid`,
|
||||
// in case cobb-douglas overflows, which should be unlikely.
|
||||
uint256 rewardsRemaining = state.rewardsAvailable.safeSub(state.totalRewardsFinalized);
|
||||
uint256 rewardsRemaining = aggregatedStats.rewardsAvailable.safeSub(aggregatedStats.totalRewardsFinalized);
|
||||
if (rewardsRemaining < rewards) {
|
||||
rewards = rewardsRemaining;
|
||||
}
|
||||
|
||||
@@ -74,20 +74,19 @@ contract TestFinalizer is
|
||||
external
|
||||
{
|
||||
require(feesCollected > 0, "FEES_MUST_BE_NONZERO");
|
||||
mapping (bytes32 => IStructs.ActivePool) storage activePools = _getActivePoolsFromEpoch(
|
||||
currentEpoch
|
||||
);
|
||||
IStructs.ActivePool memory pool = activePools[poolId];
|
||||
require(pool.feesCollected == 0, "POOL_ALREADY_ADDED");
|
||||
uint256 currentEpoch_ = currentEpoch;
|
||||
IStructs.PoolStats memory poolStats = poolStatsByEpoch[poolId][currentEpoch_];
|
||||
require(poolStats.feesCollected == 0, "POOL_ALREADY_ADDED");
|
||||
_operatorSharesByPool[poolId] = operatorShare;
|
||||
activePools[poolId] = IStructs.ActivePool({
|
||||
poolStatsByEpoch[poolId][currentEpoch_] = IStructs.PoolStats({
|
||||
feesCollected: feesCollected,
|
||||
membersStake: membersStake,
|
||||
weightedStake: weightedStake
|
||||
});
|
||||
totalFeesCollectedThisEpoch += feesCollected;
|
||||
totalWeightedStakeThisEpoch += weightedStake;
|
||||
numActivePoolsThisEpoch += 1;
|
||||
|
||||
aggregatedStatsByEpoch[currentEpoch_].totalFeesCollected += feesCollected;
|
||||
aggregatedStatsByEpoch[currentEpoch_].totalWeightedStake += weightedStake;
|
||||
aggregatedStatsByEpoch[currentEpoch_].poolsToFinalize += 1;
|
||||
}
|
||||
|
||||
/// @dev Drain the balance of this contract.
|
||||
@@ -131,13 +130,21 @@ contract TestFinalizer is
|
||||
);
|
||||
}
|
||||
|
||||
/// @dev Expose `_getActivePoolFromEpoch`.
|
||||
function getActivePoolFromEpoch(uint256 epoch, bytes32 poolId)
|
||||
/// @dev Expose pool stats for the input epoch.
|
||||
function getPoolStatsFromEpoch(uint256 epoch, bytes32 poolId)
|
||||
external
|
||||
view
|
||||
returns (IStructs.ActivePool memory pool)
|
||||
returns (IStructs.PoolStats memory)
|
||||
{
|
||||
pool = _getActivePoolFromEpoch(epoch, poolId);
|
||||
return poolStatsByEpoch[poolId][epoch];
|
||||
}
|
||||
|
||||
function getAggregatedStatsForPreviousEpoch()
|
||||
external
|
||||
view
|
||||
returns (IStructs.AggregatedStats memory)
|
||||
{
|
||||
return aggregatedStatsByEpoch[currentEpoch - 1];
|
||||
}
|
||||
|
||||
/// @dev Overridden to log and transfer to receivers.
|
||||
|
||||
@@ -86,6 +86,14 @@ contract TestProtocolFees is
|
||||
return true;
|
||||
}
|
||||
|
||||
function getAggregatedStatsForCurrentEpoch()
|
||||
external
|
||||
view
|
||||
returns (IStructs.AggregatedStats memory)
|
||||
{
|
||||
return aggregatedStatsByEpoch[currentEpoch];
|
||||
}
|
||||
|
||||
/// @dev Overridden to use test pools.
|
||||
function getStakingPoolIdOfMaker(address makerAddress)
|
||||
public
|
||||
|
||||
@@ -275,45 +275,21 @@ contract TestStorageLayoutAndConstants is
|
||||
offset := 0x0
|
||||
|
||||
assertSlotAndOffset(
|
||||
totalFeesCollectedThisEpoch_slot,
|
||||
totalFeesCollectedThisEpoch_offset,
|
||||
poolStatsByEpoch_slot,
|
||||
poolStatsByEpoch_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
totalWeightedStakeThisEpoch_slot,
|
||||
totalWeightedStakeThisEpoch_offset,
|
||||
aggregatedStatsByEpoch_slot,
|
||||
aggregatedStatsByEpoch_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
_activePoolsByEpoch_slot,
|
||||
_activePoolsByEpoch_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
numActivePoolsThisEpoch_slot,
|
||||
numActivePoolsThisEpoch_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x1)
|
||||
|
||||
assertSlotAndOffset(
|
||||
unfinalizedState_slot,
|
||||
unfinalizedState_offset,
|
||||
slot,
|
||||
offset
|
||||
)
|
||||
slot := add(slot, 0x5)
|
||||
|
||||
assertSlotAndOffset(
|
||||
wethReservedForPoolRewards_slot,
|
||||
wethReservedForPoolRewards_offset,
|
||||
|
||||
@@ -238,7 +238,7 @@ export class FinalizerActor extends BaseActor {
|
||||
private async _getRewardByPoolIdAsync(poolIds: string[]): Promise<RewardByPoolId> {
|
||||
const activePools = await Promise.all(
|
||||
poolIds.map(async poolId =>
|
||||
this._stakingApiWrapper.stakingContract.getActiveStakingPoolThisEpoch.callAsync(poolId),
|
||||
this._stakingApiWrapper.stakingContract.getStakingPoolStatsThisEpoch.callAsync(poolId),
|
||||
),
|
||||
);
|
||||
const totalRewards = await this._stakingApiWrapper.utils.getAvailableRewardsBalanceAsync();
|
||||
|
||||
@@ -87,21 +87,14 @@ blockchainTests.resets('Finalizer unit tests', env => {
|
||||
|
||||
interface UnfinalizedState {
|
||||
rewardsAvailable: Numberish;
|
||||
poolsRemaining: number;
|
||||
poolsToFinalize: Numberish;
|
||||
totalFeesCollected: Numberish;
|
||||
totalWeightedStake: Numberish;
|
||||
totalRewardsFinalized: Numberish;
|
||||
}
|
||||
|
||||
async function getUnfinalizedStateAsync(): Promise<UnfinalizedState> {
|
||||
const r = await testContract.unfinalizedState.callAsync();
|
||||
return {
|
||||
rewardsAvailable: r[0],
|
||||
poolsRemaining: r[1].toNumber(),
|
||||
totalFeesCollected: r[2],
|
||||
totalWeightedStake: r[3],
|
||||
totalRewardsFinalized: r[4],
|
||||
};
|
||||
return testContract.getAggregatedStatsForPreviousEpoch.callAsync();
|
||||
}
|
||||
|
||||
async function finalizePoolsAsync(poolIds: string[]): Promise<LogEntry[]> {
|
||||
@@ -142,16 +135,16 @@ blockchainTests.resets('Finalizer unit tests', env => {
|
||||
|
||||
async function assertFinalizationLogsAndBalancesAsync(
|
||||
rewardsAvailable: Numberish,
|
||||
activePools: ActivePoolOpts[],
|
||||
poolsToFinalize: ActivePoolOpts[],
|
||||
finalizationLogs: LogEntry[],
|
||||
): Promise<void> {
|
||||
const currentEpoch = await getCurrentEpochAsync();
|
||||
// Compute the expected rewards for each pool.
|
||||
const poolsWithStake = activePools.filter(p => !new BigNumber(p.weightedStake).isZero());
|
||||
const poolsWithStake = poolsToFinalize.filter(p => !new BigNumber(p.weightedStake).isZero());
|
||||
const poolRewards = await calculatePoolRewardsAsync(rewardsAvailable, poolsWithStake);
|
||||
const totalRewards = BigNumber.sum(...poolRewards);
|
||||
const rewardsRemaining = new BigNumber(rewardsAvailable).minus(totalRewards);
|
||||
const [totalOperatorRewards, totalMembersRewards] = getTotalSplitRewards(activePools, poolRewards);
|
||||
const [totalOperatorRewards, totalMembersRewards] = getTotalSplitRewards(poolsToFinalize, poolRewards);
|
||||
|
||||
// Assert the `RewardsPaid` logs.
|
||||
const rewardsPaidEvents = getRewardsPaidEvents(finalizationLogs);
|
||||
@@ -203,13 +196,13 @@ blockchainTests.resets('Finalizer unit tests', env => {
|
||||
|
||||
async function calculatePoolRewardsAsync(
|
||||
rewardsAvailable: Numberish,
|
||||
activePools: ActivePoolOpts[],
|
||||
poolsToFinalize: ActivePoolOpts[],
|
||||
): Promise<BigNumber[]> {
|
||||
const totalFees = BigNumber.sum(...activePools.map(p => p.feesCollected));
|
||||
const totalStake = BigNumber.sum(...activePools.map(p => p.weightedStake));
|
||||
const poolRewards = _.times(activePools.length, () => constants.ZERO_AMOUNT);
|
||||
for (const i of _.times(activePools.length)) {
|
||||
const pool = activePools[i];
|
||||
const totalFees = BigNumber.sum(...poolsToFinalize.map(p => p.feesCollected));
|
||||
const totalStake = BigNumber.sum(...poolsToFinalize.map(p => p.weightedStake));
|
||||
const poolRewards = _.times(poolsToFinalize.length, () => constants.ZERO_AMOUNT);
|
||||
for (const i of _.times(poolsToFinalize.length)) {
|
||||
const pool = poolsToFinalize[i];
|
||||
const feesCollected = new BigNumber(pool.feesCollected);
|
||||
if (feesCollected.isZero()) {
|
||||
continue;
|
||||
@@ -307,32 +300,48 @@ blockchainTests.resets('Finalizer unit tests', env => {
|
||||
expect(events).to.deep.eq([]);
|
||||
});
|
||||
|
||||
it("clears the next epoch's finalization state", async () => {
|
||||
// Add a pool so there is state to clear.
|
||||
await addActivePoolAsync();
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
const epoch = await testContract.currentEpoch.callAsync();
|
||||
expect(epoch).to.bignumber.eq(stakingConstants.INITIAL_EPOCH.plus(1));
|
||||
const numActivePools = await testContract.numActivePoolsThisEpoch.callAsync();
|
||||
const totalFees = await testContract.totalFeesCollectedThisEpoch.callAsync();
|
||||
const totalStake = await testContract.totalWeightedStakeThisEpoch.callAsync();
|
||||
expect(numActivePools).to.bignumber.eq(0);
|
||||
expect(totalFees).to.bignumber.eq(0);
|
||||
expect(totalStake).to.bignumber.eq(0);
|
||||
});
|
||||
|
||||
it('prepares unfinalized state', async () => {
|
||||
// Add a pool so there is state to clear.
|
||||
const pool = await addActivePoolAsync();
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
return assertUnfinalizedStateAsync({
|
||||
poolsRemaining: 1,
|
||||
poolsToFinalize: 1,
|
||||
rewardsAvailable: INITIAL_BALANCE,
|
||||
totalFeesCollected: pool.feesCollected,
|
||||
totalWeightedStake: pool.weightedStake,
|
||||
});
|
||||
});
|
||||
|
||||
it("correctly stores the epoch's aggregated stats after ending the epoch", async () => {
|
||||
const pool = await addActivePoolAsync();
|
||||
const epoch = await testContract.currentEpoch.callAsync();
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
const aggregatedStats = await testContract.aggregatedStatsByEpoch.callAsync(epoch);
|
||||
expect(aggregatedStats).to.be.deep.equal([
|
||||
INITIAL_BALANCE,
|
||||
new BigNumber(1), // pools to finalize
|
||||
pool.feesCollected,
|
||||
pool.weightedStake,
|
||||
new BigNumber(0), // rewards finalized
|
||||
]);
|
||||
});
|
||||
|
||||
it("correctly clear an epoch's aggregated stats after it is finalized", async () => {
|
||||
const pool = await addActivePoolAsync();
|
||||
const epoch = await testContract.currentEpoch.callAsync();
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
await testContract.finalizePool.awaitTransactionSuccessAsync(pool.poolId);
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
const aggregatedStats = await testContract.aggregatedStatsByEpoch.callAsync(epoch);
|
||||
expect(aggregatedStats).to.be.deep.equal([
|
||||
new BigNumber(0),
|
||||
new BigNumber(0),
|
||||
new BigNumber(0),
|
||||
new BigNumber(0),
|
||||
new BigNumber(0),
|
||||
]);
|
||||
});
|
||||
|
||||
it('reverts if the prior epoch is unfinalized', async () => {
|
||||
await addActivePoolAsync();
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
@@ -382,7 +391,7 @@ blockchainTests.resets('Finalizer unit tests', env => {
|
||||
const pool = _.sample(pools) as ActivePoolOpts;
|
||||
await testContract.endEpoch.awaitTransactionSuccessAsync();
|
||||
await finalizePoolsAsync([pool.poolId]);
|
||||
const poolState = await testContract.getActivePoolFromEpoch.callAsync(
|
||||
const poolState = await testContract.getPoolStatsFromEpoch.callAsync(
|
||||
stakingConstants.INITIAL_EPOCH,
|
||||
pool.poolId,
|
||||
);
|
||||
|
||||
@@ -15,7 +15,7 @@ import * as _ from 'lodash';
|
||||
import {
|
||||
artifacts,
|
||||
IStakingEventsEvents,
|
||||
IStakingEventsStakingPoolActivatedEventArgs,
|
||||
IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs,
|
||||
TestProtocolFeesContract,
|
||||
TestProtocolFeesERC20ProxyTransferFromEventArgs,
|
||||
TestProtocolFeesEvents,
|
||||
@@ -152,7 +152,7 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
});
|
||||
|
||||
async function getProtocolFeesAsync(poolId: string): Promise<BigNumber> {
|
||||
return (await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId)).feesCollected;
|
||||
return (await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId)).feesCollected;
|
||||
}
|
||||
|
||||
describe('ETH fees', () => {
|
||||
@@ -369,21 +369,22 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
});
|
||||
|
||||
interface FinalizationState {
|
||||
numActivePools: BigNumber;
|
||||
poolsToFinalize: BigNumber;
|
||||
totalFeesCollected: BigNumber;
|
||||
totalWeightedStake: BigNumber;
|
||||
}
|
||||
|
||||
async function getFinalizationStateAsync(): Promise<FinalizationState> {
|
||||
const aggregatedStats = await testContract.getAggregatedStatsForCurrentEpoch.callAsync();
|
||||
return {
|
||||
numActivePools: await testContract.numActivePoolsThisEpoch.callAsync(),
|
||||
totalFeesCollected: await testContract.totalFeesCollectedThisEpoch.callAsync(),
|
||||
totalWeightedStake: await testContract.totalWeightedStakeThisEpoch.callAsync(),
|
||||
poolsToFinalize: aggregatedStats.poolsToFinalize,
|
||||
totalFeesCollected: aggregatedStats.totalFeesCollected,
|
||||
totalWeightedStake: aggregatedStats.totalWeightedStake,
|
||||
};
|
||||
}
|
||||
|
||||
interface PayToMakerResult {
|
||||
poolActivatedEvents: IStakingEventsStakingPoolActivatedEventArgs[];
|
||||
poolEarnedRewardsEvents: IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs[];
|
||||
fee: BigNumber;
|
||||
}
|
||||
|
||||
@@ -395,13 +396,13 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
new BigNumber(_fee),
|
||||
{ from: exchangeAddress, value: _fee },
|
||||
);
|
||||
const events = filterLogsToArguments<IStakingEventsStakingPoolActivatedEventArgs>(
|
||||
const events = filterLogsToArguments<IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs>(
|
||||
receipt.logs,
|
||||
IStakingEventsEvents.StakingPoolActivated,
|
||||
IStakingEventsEvents.StakingPoolEarnedRewardsInEpoch,
|
||||
);
|
||||
return {
|
||||
fee: new BigNumber(_fee),
|
||||
poolActivatedEvents: events,
|
||||
poolEarnedRewardsEvents: events,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -414,14 +415,14 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
|
||||
it('no active pools to start', async () => {
|
||||
const state = await getFinalizationStateAsync();
|
||||
expect(state.numActivePools).to.bignumber.eq(0);
|
||||
expect(state.poolsToFinalize).to.bignumber.eq(0);
|
||||
expect(state.totalFeesCollected).to.bignumber.eq(0);
|
||||
expect(state.totalWeightedStake).to.bignumber.eq(0);
|
||||
});
|
||||
|
||||
it('pool is not registered to start', async () => {
|
||||
const { poolId } = await createTestPoolAsync();
|
||||
const pool = await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId);
|
||||
const pool = await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId);
|
||||
expect(pool.feesCollected).to.bignumber.eq(0);
|
||||
expect(pool.membersStake).to.bignumber.eq(0);
|
||||
expect(pool.weightedStake).to.bignumber.eq(0);
|
||||
@@ -433,16 +434,16 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
poolId,
|
||||
makers: [poolMaker],
|
||||
} = pool;
|
||||
const { fee, poolActivatedEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolActivatedEvents.length).to.eq(1);
|
||||
expect(poolActivatedEvents[0].poolId).to.eq(poolId);
|
||||
const actualPool = await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId);
|
||||
const { fee, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolEarnedRewardsEvents.length).to.eq(1);
|
||||
expect(poolEarnedRewardsEvents[0].poolId).to.eq(poolId);
|
||||
const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId);
|
||||
const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake);
|
||||
expect(actualPool.feesCollected).to.bignumber.eq(fee);
|
||||
expect(actualPool.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPool.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
expect(actualPoolStats.feesCollected).to.bignumber.eq(fee);
|
||||
expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
const state = await getFinalizationStateAsync();
|
||||
expect(state.numActivePools).to.bignumber.eq(1);
|
||||
expect(state.poolsToFinalize).to.bignumber.eq(1);
|
||||
expect(state.totalFeesCollected).to.bignumber.eq(fee);
|
||||
expect(state.totalWeightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
});
|
||||
@@ -454,16 +455,16 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
makers: [poolMaker],
|
||||
} = pool;
|
||||
const { fee: fee1 } = await payToMakerAsync(poolMaker);
|
||||
const { fee: fee2, poolActivatedEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolActivatedEvents).to.deep.eq([]);
|
||||
const actualPool = await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId);
|
||||
const { fee: fee2, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolEarnedRewardsEvents).to.deep.eq([]);
|
||||
const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId);
|
||||
const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake);
|
||||
const fees = BigNumber.sum(fee1, fee2);
|
||||
expect(actualPool.feesCollected).to.bignumber.eq(fees);
|
||||
expect(actualPool.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPool.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
expect(actualPoolStats.feesCollected).to.bignumber.eq(fees);
|
||||
expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
const state = await getFinalizationStateAsync();
|
||||
expect(state.numActivePools).to.bignumber.eq(1);
|
||||
expect(state.poolsToFinalize).to.bignumber.eq(1);
|
||||
expect(state.totalFeesCollected).to.bignumber.eq(fees);
|
||||
expect(state.totalWeightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
});
|
||||
@@ -477,19 +478,19 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
poolId,
|
||||
makers: [poolMaker],
|
||||
} = pool;
|
||||
const { fee, poolActivatedEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolActivatedEvents.length).to.eq(1);
|
||||
expect(poolActivatedEvents[0].poolId).to.eq(poolId);
|
||||
const actualPool = await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId);
|
||||
const { fee, poolEarnedRewardsEvents } = await payToMakerAsync(poolMaker);
|
||||
expect(poolEarnedRewardsEvents.length).to.eq(1);
|
||||
expect(poolEarnedRewardsEvents[0].poolId).to.eq(poolId);
|
||||
const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId);
|
||||
const expectedWeightedStake = toWeightedStake(pool.operatorStake, pool.membersStake);
|
||||
expect(actualPool.feesCollected).to.bignumber.eq(fee);
|
||||
expect(actualPool.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPool.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
expect(actualPoolStats.feesCollected).to.bignumber.eq(fee);
|
||||
expect(actualPoolStats.membersStake).to.bignumber.eq(pool.membersStake);
|
||||
expect(actualPoolStats.weightedStake).to.bignumber.eq(expectedWeightedStake);
|
||||
totalFees = totalFees.plus(fee);
|
||||
totalWeightedStake = totalWeightedStake.plus(expectedWeightedStake);
|
||||
}
|
||||
const state = await getFinalizationStateAsync();
|
||||
expect(state.numActivePools).to.bignumber.eq(pools.length);
|
||||
expect(state.poolsToFinalize).to.bignumber.eq(pools.length);
|
||||
expect(state.totalFeesCollected).to.bignumber.eq(totalFees);
|
||||
expect(state.totalWeightedStake).to.bignumber.eq(totalWeightedStake);
|
||||
});
|
||||
@@ -502,10 +503,10 @@ blockchainTests('Protocol Fees unit tests', env => {
|
||||
} = pool;
|
||||
await payToMakerAsync(poolMaker);
|
||||
await testContract.advanceEpoch.awaitTransactionSuccessAsync();
|
||||
const actualPool = await testContract.getActiveStakingPoolThisEpoch.callAsync(poolId);
|
||||
expect(actualPool.feesCollected).to.bignumber.eq(0);
|
||||
expect(actualPool.membersStake).to.bignumber.eq(0);
|
||||
expect(actualPool.weightedStake).to.bignumber.eq(0);
|
||||
const actualPoolStats = await testContract.getStakingPoolStatsThisEpoch.callAsync(poolId);
|
||||
expect(actualPoolStats.feesCollected).to.bignumber.eq(0);
|
||||
expect(actualPoolStats.membersStake).to.bignumber.eq(0);
|
||||
expect(actualPoolStats.weightedStake).to.bignumber.eq(0);
|
||||
});
|
||||
|
||||
describe('Multiple makers', () => {
|
||||
|
||||
@@ -9,7 +9,7 @@ import * as _ from 'lodash';
|
||||
import {
|
||||
artifacts,
|
||||
IStakingEventsEpochEndedEventArgs,
|
||||
IStakingEventsStakingPoolActivatedEventArgs,
|
||||
IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs,
|
||||
ReadOnlyProxyContract,
|
||||
StakingProxyContract,
|
||||
TestCobbDouglasContract,
|
||||
@@ -76,13 +76,13 @@ export class StakingApiWrapper {
|
||||
|
||||
findActivePoolIdsAsync: async (epoch?: number): Promise<string[]> => {
|
||||
const _epoch = epoch !== undefined ? epoch : await this.stakingContract.currentEpoch.callAsync();
|
||||
const events = filterLogsToArguments<IStakingEventsStakingPoolActivatedEventArgs>(
|
||||
const events = filterLogsToArguments<IStakingEventsStakingPoolEarnedRewardsInEpochEventArgs>(
|
||||
await this.stakingContract.getLogsAsync(
|
||||
TestStakingEvents.StakingPoolActivated,
|
||||
TestStakingEvents.StakingPoolEarnedRewardsInEpoch,
|
||||
{ fromBlock: BlockParamLiteral.Earliest, toBlock: BlockParamLiteral.Latest },
|
||||
{ epoch: new BigNumber(_epoch) },
|
||||
),
|
||||
TestStakingEvents.StakingPoolActivated,
|
||||
TestStakingEvents.StakingPoolEarnedRewardsInEpoch,
|
||||
);
|
||||
return events.map(e => e.poolId);
|
||||
},
|
||||
|
||||
Reference in New Issue
Block a user