MEV Smoothing Pool for Dappnode

Hey y’all.

I’d like to introduce for public scrutiny our idea for an MEV Smoothing Pool for Solo Stakers.

1. What is an MEV Smoothing Pool?

A Smart Contract that receives MEV rewards from a group of stakers that decide to share MEV rewards.

The idea behind it is that one will get a high value MEV block only very seldomly or never. By joining forces with other stakers, the overall rewards for everyone increase.

Does it make sense to aggregate rewards?

TL;DR: Yes. As of today, a joiner in a pool can expect to earn double the amount than a solo staker.

Please continue reading if you’d like to see the explanation:

Ken Smith details in this talk at Devcon his research about it. Feel free to watch the video to get more info, or read his report - find it in References below. In short, the answer is yes, it makes sense.

Because there is a long term distribution of very few blocks with very high rewards, we have a very low median payout per block in rewards, but a higher average. This means that a single validator is likely to stay around the median, but a pool is likely to capture something closer to the average for its members.

For the data that I offered in the TL;DR, in this dashboard we can see that a solo staker would be expected to earn around the median, and a participant in the pool around the average. That’s currently more than double the amount.

Initial Design for the Solo Stakers Smoothing Pool

A MEV Smoothing Pool that allows users to set their fee recipient to it and receive overall higher fees. Since this service effectively generates extra revenue for the validators, a fee can be introduced to align interests and have a win-win scenario. It’s also a way for Dappnode to achieve sources of revenue that are not extractive from the user, like donations, and rely on the collaboration of the team and the users to generate surplus value.

User Flow:

1) Subscription

1a) Active subscription:

Users can subscribe to the pool via UI by signing a message with the deposit address of the Validator an setting a poolRecipient. The registration will be completed as soon as there’s a successful block proposed from the validator that effectively sends the MEV rewards to the pool.

1b) Default subscription

Users will also be registered automatically when they send a MEV block reward to the pool. Their deposit address will be set as the poolRecipient.

2) Accruing Rewards

Rewards are accrued automatically from the moment of the first deposit into the pool.
Users can check the UI to see their pendingBalance.

3) Claiming Rewards

Each period, those validators who have proposed a block and sent the rewards to the MEV Smoothing pool will see their pendingBalance turned into availableBalance. Users can claim their availableBalance at any time.

4) Unsubscribing from the pool

Users can unsubscribe from the pool at any time by calling unsubscribe. Their availableBalance will still be available, but their pendingBalance will be split among the rest of the pool. Hence it is recommended that they exit during the same period when they successfully send MEV rewards to the pool and they get their pendingBalance turned to availableBalance.

4) Dealing with cheaters

Those who are subscribed to the Pool and are caught sending MEV rewards to a different address other than the Smoothing Pool, will be banned. Their pendingRewards will be split among the rest of the participants of the pool and they won’t be able to join the pool again.

Other considerations

There should be 4 smoothing pools:

  1. OFAC Compliant
  2. Non-compliant
  3. Ethical
  4. Max-profit

to respect people’s desire to comply with OFAC sanctions or not. The OFAC compliant might have a higher fee to dedicate to anti-censorship activities.


Needs 3 pieces:

  1. Smart Contract - to register, unregister, receive the rewards and distribute them.
  2. Oracle - to update the balances of the accounts, detect default registrations, cheaters and bans.
  3. UI - to facilitate subscription and unsubscription, consult balances and to claim.

Smart contract design:



SC Subscription

To subscribe you will need to provide a Proof that you control the deposit address of a validator. Upon provision of the proof, you will be able to set the poolRecipient - the address where you will be able to claim the rewards.

Merkle Tree subscriptions:
- Index Validator
- Leaf: Deposit address

  • User calls SC to suscribe:
    • ValidatorID, MTproof[], poolRecipient
    • Check agains the merkle tree msg.sender is deposit address

Mapping SC: ValidatorToSuscription (Validator → Suscription);
Suscriptions: address depositAddress, uint64 timestampStart, uint64 timestampEnd, address poolRecipient

offChain Suscription
  • Oracle Detects a fee is recieved in the smoothing pool contract
    • Suscribe the deposit address of that validator and set it as poolRecipient
    • Oracles suscriptions:
      • Oracle can suscribe another address (Array)
        • (ValidatorID, timestampStart, depositAddress)[]

The centralized service (“Offchain” above) registers deposit address per validator in the SC.


  • CAll to the unsuscribe method, only depositAddress
    - ValidatorID
    - Update the timestampEnd.
  • The user will be able to claim the available balance of that validator at when the oracle does the next update.
  • Call, only depositAddress
    • ValidatorID, newPoolRecipeint

Users will submit a proof that they can claim availableBalance.

  • Merkle tree containg all the corresponding balances to each withdrawal address (or deposit address)
    • Leaf:
      • Address (deposit)
      • ValidatorIDs[] → can be deleted
      • Available balance
      • Pending balance (Will be unlocked once a block is proposed and the fee recipeint is correct)
      • Unbann balance
      • Pool recipient → Authorized account to claim funds (default deposit addr)

0xAAA (deposit addr)
0xBBB ( Pool recipient)
Update Claimed(0xAAA)

Mapping SC: Claimed (address → ClaimedBalance);
Mapping SC: ValidatorToSuscription (Validator → Suscription);

Suscriptions: uint32 ValidatorID, uint64 timestampStart, uint64 timestampEnd, bool banned, feeRecipient

unbanUser (banned user can call it to be “unbanned”)
  • CAll to the unBanUser method
    • User should pay the Unban balance of the leaf of the MT

banUser (Oracle can call it when detects foul play)

  1. A block comes and you don’t send the reward to the pool
  2. Oracle detects that and splits your pending balance among the rest and rest of participants, putting your Pending balance to 0
  3. Puts your pending balance in negative, so it’s recorded in the MT leaf - this is done so we can generate a proof that this is the amount and call the unban.


Validator poposes a block from validator list:
- Check if is the correct fee recipient
- If not, ban validators, and redistribute pending balance to the rest of validators.
- Distribute fee between suscribed validators
- Consolidate state
Pending Blanace → Available Balance


  • Subscriptions → ValidatorID, DepositAddress


  1. Deposit Addres vs. Withdrawal Address

Who can set the the poolRecipient address?


  • What needs to show?
  • Subscribe: signing with withdrawal address
    Merkle tree optimistic
  • Store in SC in every slot of time how many validatores suscribed
  • Prove:
    • Easy to prove is if someone cheated with zero knowledge, bc fee recipeint is different
    • Checking the difference balance of the SC can be calcualted the balance of every validator suscribed

Current Questions

  • What are the consequences of marking the deposit address controller of the validator and poolRecipient?

    • What are the cases when giving the control of the poolRecipient address to the deposit address would actually disserve the real owner of the ETH of the validator?
  • Are there extra considerations for making the pool mainly targeted to Solo Stakers than a generic pool?

  • Would overcompliooors consider rewards tainted if they received profits from a pool that accepts any relayer? Even if they only propose blocks from compliant relayers.

  • What happens if someone sends ETH to the pool? Unlikely, but how can we cover it? Split it regularly among the users? What happens if it’s Tornado ETH?

  • When banning, should we ban all related validators? Those would be the validators that are related to the same deposit address.

Next steps:

In the next few days we will publish for public scrutiny:

  • Smart contract design* Done 25/10/22
  • Oracle design
  • UI design

Would be also happy to do a community call to explain to the community and hear more feedback about it! Planning one for this week if possible.


Rocket Pool Smoothing Pool

MEV info


This seems the logic iteration for dappnode’s solo stakers community. Great job!

1 Like

Sounds great! I suppose you have looked at all the arguments in the Rocket Pool’s Design Rational? There seem to be a few objections/suggestions which I only looked at briefly. Will try to read up on it and watch that Devcon talk. Sounds like a great idea! I’m in!
FYI, at the beginning you are referencing a PDF and Google doc but seem to have forgotten the actual link.

1 Like

Updated with Smart Contract design!

1 Like

Fixed! I had put them below in the references and now I’m guiding the user to the right place - Thanks for the catch!

Yes! Certainly. We share a lot of the thoughts on the design.


What are the incentives for the oracle to be honest?

Cool, it sounds great!

Sounds fine, what’s the fee estimated to be compared to other smoothing approaches.

Really love this! Great thinking.

I wonder, does Dappnode take a portion of the pool above a “normal” share based on participation? I would actually be okay with 5-15% always going to the dappnode project.