All posts

The Data Behind a Live Merkl Campaign, Proven on Ethereum

Merkl runs reward campaigns for DeFi protocols. A project puts up tokens to reward, say, liquidity in a pool, and Merkl works out who earned what and pays them. Right now it's running a campaign on the Uniswap v4 ETH/AUTO pool that pays out TOKE rewards.

Campaigns like that are settled from indexed data. Somebody reads the pool's swaps and liquidity changes over the period, works out who provided what, and distributes accordingly. If a single event goes missing from that read, the payouts are wrong, and nothing in the pipeline notices.

On August 16 we proved that read. We took eight consecutive mainnet blocks, 25764866 through 25764873, and proved the whole set of Uniswap v4 PoolManager events in them: 79 events, every Swap and every ModifyLiquidity the contract emitted, including the campaign pool's own liquidity change in block 25764867. The proof says that set is complete and correct for those blocks, and it's anchored to Ethereum's own record of recent block hashes (EIP-2935), so the chain checks the anchor itself rather than taking our word for which blocks we meant.

A contract on mainnet verified it for 300,340 gas, about 0.0000146 ETH. A few cents.

It's the third proof we've had verified on Ethereum, after an EigenLayer event window in July and Lido's full validator set earlier this month, and the first on data a live campaign is paying out from.

What it proves is the inputs a reward calculation should be computed from. It doesn't recompute Merkl's allocation on top of them. Proving the inputs is the half that's been missing, and recomputing a distribution over a proven input set is the natural piece to build on it.

Where the proof sits in a reward campaign: the pool's events are read by an indexer, Merkl works out who earned what, and rewards are paid; the proof covers the read, all 79 PoolManager events across the eight blocks, and not yet the allocation computed on top

The filter covers all v4 pool events rather than just the campaign's pool, because the circuit binds an event's contract address and its signature, not its indexed topics. That makes the proven set a superset of what the campaign needs, and the campaign's events are provably inside it.

What the filter binds and what the proof covers: the filter commits to the PoolManager contract and the Swap and ModifyLiquidity signatures but not the pool id, so the proven set is all 79 events in the window, with the campaign pool's own liquidity change provably among them

Everything else is the same machinery as the EigenLayer run. Same circuits, same verification key, same window shape. The only pin that moved was the filter commitment, which is what you'd expect when the only thing you changed is which events you're watching. The verifier contract is open source.

Pointing it at another protocol's events is a filter change. If there's a campaign, a distribution, or a payout you'd like to see under a proof like this, we're at info@willow.tech.

Work with Willow.

We partner with protocols and teams that need data they can prove.

Partners

Request a call