[ODAO] Proposal for Rewards Tree Spec v6

Hi all,

In this post I’d like to formally raise a proposal for v6 of the Rewards Tree spec.
v5 has been quite successful; so much so that it’s been used for several intervals so far.
That being said, there are some opportunities for improvement.

This v6 proposal is a small update to v5 that clarify some ambiguous points, make Oracle DAO rewards more fair for members that just joined, and update the rules around how solo staker migrations interact with the Smoothing Pool.
It is an extension of the discussion Patches raised earlier and incorporates most of the popular changes.
Admittedly, the one left out is complicated to do from a technical perspective and needs more time for exploration before it is added to the spec - see the note at the end of this post for more info.

A draft of the v6 spec corresponding to this proposal is available for review.
This hasn’t been formally implemented or tested yet so this is not ready for release as of this posting, but the changes are extremely small from a technical standpoint and we don’t anticipate any difficulty implementing and testing it.

Due to this, we estimate that v6 will be used for either Interval 11 or 12 (July 6th or August 3rd) depending on the discussion here and our testing time.

Read below for the full details on what’s changed.

Proposed Changes

This proposal includes 2 changes to the spec, and 2 clarifications:

Calculating Attestation Performance for the Smoothing Pool

In the Calculating Attestation Performance and Minipool Scores section, the method for determining if a duty is eligible for assessment has been amended. Minipools must now be in the staking status, and their statusTime (the time they entered the staking status) must be before an attestation duty in order for it to be considered; otherwise, it is ignored.
This is done to properly support consistent rewards calculation for solo staker migrations using the new “rolling records” system that does periodic checkpoints of successful and missing attestations at arbitrary states during the interval.

Realistically this change only impacts solo staker migrations.
Currently, in v5, the system will begin assessing minipool attestations the moment the minipool goes live (enters initialized status).
This doesn’t actually make a difference for conventionally-created minipools because they enter staking far before they will ever start attesting, but solo staker migrations will be attesting well before they get to staking status (which is done after a promotion when the 3-day scrub check ends).

While this behavior is accurate from a rewards perspective, we want to make this change for a few reasons:

  1. It enforces that dissolved minipools that are still attesting (either from scrubbed solo migration or from rescuing dissolved minipools) are not eligible for Smoothing Pool rewards.
  2. It bypasses the situation where a solo staker never calls promote and the minipool gets dissolved after the timeout, but it received Smoothing Pool earnings for the period between prelaunch and dissolved. This is awkward to handle, and philosophically it doesn’t make much sense for a minipool to earn Smoothing Pool rewards when it isn’t actually contributing to the protocol because it ends up getting dissolved.
  3. It makes it easier to do consistent “checkpoints” where attestation records are recorded and saved in real-time instead of back-calculating all attestations for the entire interval after it’s over. This is because once a minipool enters staking, that is the only state it will ever be in (finalized is not a state, it’s a separate flag) and the time a minipool entered staking is recorded on-chain so we can use it as a definitive point of comparison regardless of when we do the performance check.

The third point is particularly important because moving forward, we are updating the Watchtower to use this new “rolling record” system so tree generation (and thus rewards submission) can be done in a matter of minutes rather than hours.

Oracle DAO RPL Reward Prorating

In Oracle DAO Rewards, Oracle DAO rewards are no longer pro-rated by the node’s registration time. Instead, they are pro-rated based on the time the node joined the Oracle DAO

This was one of the requests in Patches’ original post, and it makes sense to do. We have the time a node joined the Oracle DAO on-chain, so we will use that as the basis when calculating each member’s rewards instead of the node registration time.
This was unanimously voted on by the community already.


The Minipool Eligibility section is now marked as optional, as the new scoring system will process attestations the same way with or without it.

There is a new section called (Optional) Removing Idle Minipools which clarifies that prior to rewards calculation, minipools with no score (no successful or missing attestations) can be removed from subsequent calculations. The Rocket Pool rewards interval files include a “minipool performance” file for the interval, and this simply clarifies that it is not an error if such minipools do not appear in that file.

These two points simply clarify some of the details involved in potential spec implementations. By themselves they don’t change rewards at all; they’re simply there to highlight things that are not necessary, thus avoiding ambiguity in things like the minipool performance file the watchtower generates.

A Note About Pro-Rated Exits

One of the requests made in Patches’ original post was that RPL rewards be pro-rated for an interval if a minipool exits during the interval.
While this was a popular request, it adds a lot of technical complexity that will require supplemental evaluation before we can commit to it in the spec.

The problem is that RPL is not calculated at the minipool level, it’s calculated at the node level.
As of ruleset v5, this is done as follows:

  1. At the end of the interval, take a snapshot of everyone’s RPL stake and the RPL price reported by the Oracle DAO.
  2. Calculate each node’s “true effective” RPL stake (also called “rewardable” in the new Grafana dashboard) by determining how many minipools are active on the Beacon Chain and using that to assess the minimum and maximum RPL stake for the node.
    1. If the node’s RPL stake is below the minimum, set it to 0.
    2. If the node’s RPL stake is above the maximum, clamp it to the maximum.
  3. Calculate the total true effective RPL stake for the entire network by summing the true effective RPL stake of each node.
  4. Use this to determine each node’s share of the RPL inflation (node's true effective stake / total true effective stake).

Whenever a minipool exits, it potentially changes the node’s true effective RPL stake and thus the entire network’s true effective RPL stake.
Thus, in order to support “partial credit” of exited minipools, the spec would require us to track every single exit and recalculate both the node’s effective RPL stake and the network’s total true effective RPL stake, then use those for each slot moving forward until the next exit (at which point it’s all recalculated again).

In other words, it turns RPL calculation from a simple one-and-done problem into a situation where each node must be given an “RPL earned” amount at every slot in the interval which can vary based on exits, analogous to how the Smoothing Pool performance calculation is done.
If we’re going to do that, it opens the door to other things such as pro-rating RPL rewards per-minipool by their staking time (instead of the node’s registration time) and potentially even pro-rating RPL based on attestation performance (which has had a highly contentious discussion in the past, but has seen some resurgence in the community).
We think it makes sense to better explore the ramifications of such a system first before committing to it in the spec.

Regardless, it is certainly technically feasible to do this but it’s a lot of work because it’s a drastic deviation from how things are done today under the hood.
It looks like the demand for it is there so it’s something we will investigate for a future spec update (v7 or beyond), we just want to apply the changes in this v6 proposal first because they’re much smaller and easier to do but still important.


That should be it for this proposal - let me know your thoughts below.
If it looks like this is approved without any contention from the community we can likely get it in for Interval 11.
Thanks everyone!


As a newbie to this spec, I think it could be clearer how to use startTime (i.e. RocketRewardsPool.getClaimIntervalTimeStart()). You say you call this to get the “currently active interval” start time. Presumably you need to call this in the state of a block that is inside the interval you want to calculate rewards for for it to make sense? (Or if that didn’t make sense, can you be clearer about which startTime should be used as the basis for say, interval 17, and how to determine that?)

Yes, you need to call it on a block that occurred during the interval. For the current interval you can just use the call with nil as the block number (AKA whatever the chain head is). For previous intervals you need to get the event emitted in the rocketRewardsPool contract in order to get the start and end block so you know which state can be used to call it. The event name is RewardSnapshot so you can key off of that in its ABI. To get the number of the block that emitted the event for the interval you want, call rocketRewardsPool.getClaimIntervalExecutionBlock(interval_index).

Ramana has just finished his implementation of v6 which matches mine. Based on this and no complaints against these changes, we plan to use v6 for rewards interval 12 on Mainnet (August 6th).

1 Like

massive props to @ramana for this, treegen is no easy thing to implement



Three cheers for @ramana !
And one cheer for the bounty system delivering something important to RP!