Note: This is typically the kind of thing I would write up in the research repository, but I think this is a better place for it since we can have a direct conversation around it.
What is the Smoothing Pool?
When we first shared our post-merge plans with the world, they stirred up quite a bit of conversation. In general the feedback was varied - we heard praise for our forward-thinking development mindset, concern over additional Oracle DAO responsibilities, arguments over the dynamics and math behind MEV, and even interest in the gamification potential that could be attached to the protocol. One thing that was almost universally lauded, however, was the Smoothing Pool.
In a nutshell, the Smoothing Pool emulates the behavior that POW mining pools employ today: node operators would assign it as their
fee recipient (the address that priority fees and MEV are sent to), and all of those rewards would be pooled together. There would be some mechanism to determine each node operator’s “share”, and they would be paid their share at some period in time. The intent is to “smooth” the extreme variance of priority fees and MEV by giving all users an equal share of all of those fees. As recent data has shown, these kinds of fees tend to be extreme during things such as NFT launches or major macroeconomic events. Since block proposers have very little time to react to being given an assigment (between 0 and 6 minutes), being a proposer for one of these high-value blocks is akin to winning a small lottery. The Smoothing Pool combats this randomness and essentially promises everyone a reliable, consistent reward structure.
The Smoothing Pool’s popularity among node operators is well established. We have already heard from many users who are currently solo staking today and frustrated by this variance that when Shanghai arrived, they would switch their nodes to Rocket Pool minipools just to gain access to the Smoothing Pool. I submit that a proper and timely implementation of it would be a strong attractant for the protocol in a time where node operators are in extremely high demand.
There are a few challenges in building such a system: determining what each participant’s “fair share” is, delivery of rewards, management of ingress / egress, management of defection, and minimizing the need for trust. Marceau wrote an excellent post that detailed some of these challenges, and stated that they would have to be surmounted for the Smoothing Pool to be viable. In this post, I will offer a candidate design for the Smoothing Pool that provides all of above features while addressing all of those concerns.
There’s a TLDR at the end for people that don’t want to read a book.
Before I begin, I want to give a shout out to Butta and Marceau for helping me come up with some of the ideas in this design and workshop it in advance. Thanks guys!
My design is predicated on the following assumptions:
- Post-merge, Rocket Pool will employ a Trusted Block Builder system where our node operators are given entire blocks to propose from a verifiable third party. That is, node operators cannot assemble their own blocks. This is for two reasons:
- It is too difficult to tell whether or not they extracted their own MEV and thus stole rewards from the staking pool if they build their own block
- It enforces the acquisition and distribution of MEV, increasing the overall returns and competitiveness of the protocol
- The new Merkle Tree-based RPL rewards distributon system (affectionately known as Garlic Bread) is in place and successful
The intended behavior of a functioning Smoothing Pool would work as follows:
- The smoothing pool would be a new smart contract that stores ETH
- Node operators would “opt in” to the Smoothing Pool via a Smart Node command, which would:
- Set their fee recipient address to the Smoothing Pool contract instead of their node’s distributor address so all of their priority fees and MEV would be sent to the pool instead
- Set a flag in the contracts, indicating that they joined it and record the timestamp of when they joined
- There would be a “rewards checkpoint” at regular intervals, analogous to the RPL rewards checkpoint (it could even be the same event if desirable)
- At a rewards checkpoint, the Oracle DAO would distribute each node operator’s “fair share” of the accumulated ETH
- The process repeats ad infinitum
In this design, the Smoothing Pool would be an extension of the Merkle Tree distribution system that Kane has already built for RPL rewards. Instead of managing newly-minted RPL, however, this would manage ETH received from priority fees and MEV. In this way, all of the functional concerns are essentially delegated to a single event: the rewards calculation and distribution. Here is my design for what happens at a reward checkpoint.
The following would be done by the Oracle DAO (the
watchtower) during a checkpoint:
Determine Total Rewards
- Get the initial balance of the Smoothing Pool at the beginning of this interval, which is recorded in
rocketStorage. Call this
- Get the current balance of the Smoothing Pool at the time of the rewards checkpoint. Call this
interval_rewards, the total amount of ETH to be distributed, via
current_pool_balance - initial_pool_balance.
Calculate the Eligibility Interval per Minipool
- Look at the epoch where this interval started, and call the first slot of it
- Look at the latest finalized epoch on the Beacon Chain, and call the last slot of it
- For each node, the Oracle DAO would find the “opt-in” time (call it
node_start) and the “opt-out” time (call it
node_end). Nodes that did not opt in (or opted out prior to the start of the round) would be ignored.
node_starthappened before the start of this interval, set it to
node_enddidn’t happen (because they didn’t exit it), set
- Look at
node_endto determine if the node was eligible at any point during this round. If so, add this node to an
- For each node in
eligible_nodes, go through each minipool and look at each proposal they sent during their eligibility window.
- If the
fee_recipientis not set to the smoothing pool, they cheated. Remove them from
eligible_nodesand penalize their Beacon balance accordingly.
- If the block didn’t come from a Trusted Block Builder, they cheated. Remove them from
eligible_nodesand penalize their Beacon balance accordingly.
Calculate Node Share vs. Pool Staker Share
- Calculate the average fee of all minipools in all remaining nodes in
eligible_nodes. Call it
- Calculate the amount of rewards to send to the staking pool (half of
interval_rewards, minus the
node_shareportion). Call it
- The remaining balance is the
Calculate the Share per Node Operator
- For each minipool attached to each eligible node, look at every attestation on the Beacon Chain from
- For each one that was successfully executed, add 1 to a running total called
- Divide the running total by the total number of epochs. Call this ratio
participation_rate. This makes attestations on the Beacon Chain analogous to “shares” in a PPS-style mining pool for POW.
(node_end - node_start) / (interval_end - interval_start)and call it
reward_share. This is how much ETH from the Smoothing Pool should be given to this minipool.
- For each one that was successfully executed, add 1 to a running total called
- Add up all of the
reward_shares for a node’s minipools. The combined total is the
node_reward_share, which determines how much ETH goes to the node.
- Multiply the
node_rewards_shareof each node by
total_node_rewardsto determine how much ETH that node should receive - the
Distribution of Funds
- Generate a Merkle Tree containing the
node_rewardsfor each node and the
staking_pool_rewards, along with any other important ancillary information about the round.
- Upload the tree to IPFS, the same way the new RPL rewards system does it. Inform the Rocket Pool contracts of the resulting Merkle Root and IPFS link.
- When 51% of the Oracle DAO members come to the same conclusion and upload an identical Merkle Tree, the contracts will canonize the results (as RPL rewards will be done). The
staking_pool_rewardsare sent to the staking pool, and the
total_node_rewardsare sent to a distribution contract (as RPL rewards will be done). Record the balance of the pool after distribution so it can be used as the
initial_pool_balancefor the next interval.
- Node operators are free to claim their Smoothing Pool rewards at their convenience.
Advantages of this Design
This design mitigates all of the potential complications the community has brought forth. I will address them topic-by-topic below.
Node operators are less-accountable for their performance, and could flake out while still earning unfair rewards.
- This is mitigated using the
participation_ratecalculation. By using attestations as a gauge for uptime, we can accurately calculate a node’s fair share; downtime will not be rewarded in this system. Node operators are incentivized to maximize uptime.
Smoothing will increase the profitability of tip/MEV thefts.
- By using the interval-based rewards system, it is easy to detect when a user steals from the system and simply remove any smoothed rewards they would otherwise receive for that entire interval. They would gain no benefit in cheating within the Smoothing Pool as opposed to outside of it.
Smart contract risk, gas costs, technical overhead.
- By piggybacking off of the existing Merkle Tree distribution system for RPL rewards, there is very, very little to be added for Smoothing Pool functionality. The risk is deferred almost entirely to that system which will be employed regardless of the Smoothing Pool’s existence.
- Gas costs for individual claims can be high if the smoothing pool generates fairly low rewards or the node operator has a fairly low total share. However, as it is based on the Merkle Distributor system, users simply have the option of waiting to claim (even multiple intervals at once) until they are comfortable doing so. Furthermore, they could potentially even assign an L2 as their network of choice for smoothed rewards - this functionality is already in place for RPL rewards, so doing it for ETH rewards in this fashion should be trivial.
- The technical overhead comes primarily from the generation of the Merkle Tree, which was already described in detail above. It’s not particularly daunting in my opinion.
Economical viability in terms of MEV.
- As the Smoothing Pool would require the use of a Trusted Block Builder which would provide MEV, the node operator will always do better than simply building their own blocks.
Opportunity cost in terms of developer time.
- Since this system largely derives from an existing system, I expect developer time to be quite reasonable for this approach. Not zero, but quite reasonable. I think it will be short enough to pay for itself in terms of Quality-of-Life improvements for node operators and further attract / incentivize attention from prospective candidates… especially if deployed before Shanghai, so solo stakers have a chance to see it in action.
Indifference to Pool Size
- This design for the Smoothing Pool is effective regardless of how many node operators or minipools opt into it. If more pools come in, node operators have a smaller
reward_sharebut the amount of rewards in the pool will increase and these two factors are expected to even out. Thus, even large node operators would be welcome to join - and even encourage to do so because they would decrease the pool’s susceptibility to variance and provide an even “smoother” experience for everyone.
Disadvantages of this Design
Oracle DAO Dependency
- As with RPL rewards and withdrawability, this depends on the Oracle DAO to act in a trusted capacity. There is contention around adding another layer of responsibility to the Oracle DAO, but I believe that this is mitigated by making the Smoothing Pool opt-in rather than opt-out. Users have the freedom to use it or not based on their confidence and level of trust in the Oracle DAO.
- As this system is a pull rather than a push configuration, the user must pay a transaction fee to claim their rewards. For small node operators, this can be prohibitively expensive relative to the rewards they would earn. However, I offer the following as counterpoints:
- The Merkle distributor is already quite cheap according to Kane’s calculations, taking about 55k gas to claim for one interval and 55k + 15k for each additional interval if claiming for several at once.
- If the gas cost to claim such a thing is prohibitively expensive, I submit that the gas cost to do anything on Ethereum would be prohibitively expensive, so that ETH would be “locked” in your wallet anyway.
- Users can simply let their rewards aggregate and claim multiple at once when gas costs are low, and they could even do this on an L2 where fees are even lower.
Trusted Block Builder Requirement
- Not allowing people to build their own blocks and instead relying on one (or several) trusted block builder(s) goes against decentralization. I submit that this is a larger problem for Rocket Pool beyond just the Smoothing Pool and probably for Ethereum in general, so I will defer discussion of this topic to its own dedicated post. This probably isn’t the correct avenue to argue for or against it, since it may become a protocol-wide requirement anyway.
- The use of intervals means users don’t get their priority fees / MEV as soon as they propose a block; they have to wait for the next claim interval. This is a valid disadvantage, and at the end of the day, a user’s decision to opt in or out of the smoothing pool may come down to this delay in liquidity. I leave it to the community to decide if the opportunity cost outweighs the smoothing effect.
Conclusion & TLDR
- Copy/Paste the Merkle Tree distrbution-based RPL rewards system (Garlic Bread) for the Smoothing Pool
- Determine everyone’s “effective share” by looking at opt-in/opt-out time and attestations during that window
- Cheaters get booted, everybody else wins
- Node ops can let their rewards build up and claim lots whenever they want, put it on an L2, or claim it right away
- Size doesn’t matter, the more the merrier
- Smoothie pool, it’s got what solo stakers crave (consistency)
Alright, now for the fun part. Let’s discuss!