[Discussion] Verifying SRv3 module balances

Hi,

While reviewing SRv3, I noticed that a malicious Accounting Oracle quorum gains slightly more control over module-fee distribution.

This does not appear to be a big issue, but it seems worth discussing whether this additional trust assumption could be reduced.

Previously, module fees were weighted by the number of active validators in each module. A dishonest quorum could influence this by over-reporting exits for a module, but the removed weight was distributed proportionally among every remaining module. The attack was therefore indirect and diluted.

With SRv3, the Accounting Oracle directly reports the validator balance attributed to each module. A dishonest quorum could therefore:

  • subtract 100,000 ETH from module A;
  • add the same 100,000 ETH to a module it controls;
  • keep Lido’s total reported CL balance unchanged.

The stETH rebase would remain correct and no validator principal would move, but part of the module fees would be redirected from A to B.

The sanity checker limits the sum of positive module-balance changes to roughly 100,000 to 150,000 ETH per daily report, depending on activations and consolidations. This limits the speed of the attack, but the reallocation could be accumulated or maintained across reports.

EIP-4788 may provide a way to authenticate these balances, similarly to the CL proofs already used by TopUpGateway. The difficulty is that a module may contain thousands of validators, making it impractical to verify every balance naively onchain.

I see two possible approaches.

1. Optimistic verification

Alongside each module balance, the oracle could commit to a Merkle-sum tree containing the validators attributed to that module and their balances.

Anyone could challenge an entry by posting a bond and providing:

  • its proof in the Merkle-sum tree;
  • an SSZ proof of the validator’s actual balance against the EIP-4788 beacon root;
  • proof that the validator belongs to the claimed module.

A successful challenge could freeze the affected module-fee distribution until a corrected report is submitted.

Only module fees would need to be escrowed during the challenge period. The stETH rebase and withdrawal processing could continue normally.

The main difficulty would be proving not only that individual balances are correct, but also that validators were not omitted, duplicated, or assigned to the wrong module.

2. ZK verification

The Accounting Oracle could instead provide a proof that:

  • every relevant Lido validator was included exactly once
  • every validator was assigned to the correct module
  • every balance matches the Consensus Layer state
  • the reported module balances are the corresponding sums

Lido already has an SP1-based ZK oracle for aggregate accounting:

https://github.com/lidofinance/sp1-lido-accounting-zk

Extending it to expose authenticated per-module totals may be a natural starting point, although proving validator-to-module membership would require additional work.

Interested in feedback on whether this additional verification would justify its complexity, and whether there are simpler mitigations I may have missed.

2 Likes

Hey @th0rgal , great writeup. The properties you asked for in the zk verified approach (each validator included once, assigned to the correct module, matched to consensus-layer state) are the statement we’ve been building. We just posted a working proof of it, verified on mainnet: Proposal: Exact validator-set accounting for the Lido second-opinion oracle . The module-reallocation concern you raise is why per-module totals are on the roadmap of the grant proposal as Milestone 3: the attribution is already proven, and exposing the sums is the easy part. Would value your read on the construction, the counter-closure and the four-bucket join especially.