For most of crypto's history, "verified on-chain" has meant less than it sounds. An operator computed the results off-chain, posted the output to a contract, and the chain simply stored it. Gitcoin's grants rounds ran this way for years. The team computed the final match amounts on its own servers, the community reviewed the numbers and voted on Snapshot, and a multisig sent the money. The checking stayed social. You trusted audits, reputation, or a multisig signature, and none of those could tell you whether the published numbers matched the real inputs. Nick Szabo named this problem back in 2001 when he wrote that "trusted third parties are security holes."
A properly ZK-verified process moves the checking into the protocol itself. The operator publishes a zero-knowledge proof that a specific program ran on specific inputs, and a smart contract checks that proof before any result is recorded. If anything in the computation was tampered with, the proof simply fails to verify. And since checking a proof is far cheaper than redoing the work, the chain can afford to verify computations it could never afford to rerun.
In June this stopped being theoretical for public goods funding. Octant ran its Epoch 12 quadratic funding round on exactly this architecture and closed it on June 30, crossing $9 million in cumulative funding to nonprofits and public goods projects in the process. The tally for the round's 25 grantees was accepted by a verifying contract before payouts opened. I do blockchain data analysis for a living, so instead of taking the announcement at face value, I went through the artifacts. Fifteen blobs on Ethereum mainnet, one Groth16 proof on the Succinct explorer, and a set of contracts that either accept the math or revert. This piece walks through how the pipeline works, what the proof covers, and where trust still lives.
Why QF tallies used to be a spreadsheet
Quadratic funding, first formalized by Buterin, Hitzig, and Weyl, allocates a matching pool by weighting the number of contributors more heavily than contribution size. It has also been a textbook case of the gap described above. Someone collects the donations, runs the formula off-chain, and posts the results. Donors take three things on faith. The formula ran as promised, the sybil filtering was honest, and no ballot quietly disappeared.
Running the tally directly on mainnet would fix that, but updating a QF computation with every vote is prohibitively expensive in gas. MACI-style systems attack the adjacent problem of collusion and vote privacy, at the cost of a coordinator role. Octant's design accepts public ballots and goes after a different guarantee: that the tally itself is provably correct.
The pipeline, step by step
Here is the full path a vote takes, reconstructed from Octant's engineering write-up and the on-chain record of Epoch 12.

1. The round is fixed on-chain. The sponsor deploys the round contracts with the project list, the matching pool (200 WETH, funded from the Golem Foundation's ETH staking yield), and the duration. Nothing about the round's parameters lives in a config file someone can edit later.
2. Voters enter with a transaction, then vote for free. Signup is the only gas a voter pays. After that, voting is a signature: participants sign EIP-712 typed ballots and send them to Octant's sequencer. No transaction, no gas. Changing your mind costs nothing, you just sign a new ballot with a higher nonce.
3. Ballots land on Ethereum as blobs. The sequencer periodically flushes everything it has collected into EIP-4844 blobs, the same data type rollups use. In Epoch 12 that meant 15 batches posted roughly once a day from June 17 through the round's close on June 30 (signups had opened about two weeks earlier). The cadence is visible in the block numbers: batches sit about 7,200 blocks apart, almost exactly 24 hours, until the end of the round, when batch 13 carried 82 ballots and a final flush followed about 2.7 hours later with 19 more.
Nearly half of all ballots (101 of 209) arrived in the final day. Whatever else changes in funding mechanisms, deadline behavior apparently does not.
4. A zkVM replays the election. After the round closes, an off-chain service Octant calls the coprocessor reads the blobs and feeds every ballot into a program built on SP1, Succinct Labs' general-purpose zkVM. The program re-runs the entire election under constraint: every signature gets checked against the registered voter set, superseded ballots get dropped by nonce, per-round budgets get enforced, and the quadratic allocation gets computed, including the α scaling factor that handles capital-constrained rounds.
The blobs for Epoch 12 contain 209 signed ballots, and the final tally counts 201 voters. The gap of eight is ballots the program provably filtered out, most plausibly participants who changed their vote and had the earlier ballot superseded by nonce.
The α factor did no cutting this time. Epoch 12 ran at α = 1.000, meaning the community's vote pattern called for 81.86 WETH of the 200 WETH pool, every project received its full ideal match, and the remainder rolls into future rounds.
5. The Succinct Network compresses it into a Groth16 proof. The SP1 execution gets wrapped into a Groth16 proof of a few hundred bytes. Think of it as a receipt binding one specific input set to one specific output. Feed in exactly these ballots and you get exactly this allocation. The asymmetry is the whole point. Producing the proof is expensive, verifying it costs a few pairing checks. Anyone can confirm the computation without rerunning it, and the proof for this round is public on the Succinct explorer.
6. A contract has the final word. The coprocessor submits the proof to a TallyVerifier contract, which checks it against a verifying key encoding what computation should have run. Wrong inputs, modified program logic, or a tampered tally, and the transaction reverts. If the proof holds, the results are written to a VoteRegistry contract, two PaymentSplitter contracts are deployed (one for direct contributions, one for the matching pool), and every project can claim its allocation permissionlessly. Octant cannot delay or gate the payouts after this point.
The design principle running through all six steps is that off-chain work earns no authority until it leaves an on-chain artifact. A ballot has no standing until it sits in a public blob, and a blob has no standing until the verifier contract accepts a proof over it.
What the proof covers, and what it does not
This is the part I care about most, because "verified on-chain" is a phrase that gets stretched. Here is the honest boundary.
The proof attests that every signature was valid, that duplicates were removed by nonce, that no voter exceeded their budget, and that the QF totals and α-scaled allocation were computed exactly as specified. It also commits to the voter set fixed at signup and to the recorded sequence of blobs, so neither voters nor ballots can be swapped between the flush and the proof.
What it does not give you.
Privacy. Voter addresses and ballot choices sit in public blobs. Anyone can read how any address voted. Octant says privacy is on the roadmap, and to their credit they state the limitation plainly rather than hand-waving it.
Censorship resistance at the sequencer. The Octant-run sequencer cannot forge a ballot, the signatures prevent that. It could, however, omit one. A voter whose ballot never made it into a blob would have to notice and complain. This is the same trust profile as most rollup sequencers today, and the same mitigation path applies, either decentralizing the sequencer or adding a forced-inclusion channel.
Permanent data availability. EIP-4844 blobs are pruned from consensus nodes after roughly 18 days. The on-chain commitments stay forever, so a tampered history remains impossible, but anyone wanting to re-derive the tally from raw ballots a year from now will depend on someone having archived the blob data. It is a subtle difference between "verifiable forever" and "verifiable by anyone who kept the receipts."
Failure mode on bad data. The coprocessor reads chain data through an RPC. Octant notes that corrupted input would produce an invalid proof rather than a wrong published result. The system fails closed, which is the right direction to fail.
Why this pattern matters beyond one round
Strip away the QF specifics and the architecture generalizes. Take any allocation formula a community agrees on, compile it into a zkVM program, publish the inputs as blobs, and let a contract accept only a proof that the formula ran faithfully. Grant programs, airdrops, retroactive funding, revenue splits. Every one of them today mostly runs on a spreadsheet and a multisig, and every one of them could run like this.
You have to build and audit the SP1 program, pay for proving, and operate a sequencer. For a 209-vote round, a skeptic could reasonably say a trusted admin would have been fine. But mechanisms earn trust at small scale before they matter at large scale, and the marginal cost of verifying a 209-vote round and a 200,000-vote round is nearly the same few hundred bytes.
My takeaway after walking the artifacts end to end is that the trust surface did not disappear, it moved and shrank. It moved from "the operator computed the results honestly" to "the operator did not censor my ballot," and the second claim is far easier for a participant to check. Andrey Sergeenkov, the researcher who compiled the round's funding data, put the appeal of the design simply, saying it shows that "genuine human coordination is the most effective financial multiplier." In a sector where funding results are usually a PDF and a promise, a tally that a smart contract refuses to accept unless the math checks out is a real step.
You can inspect everything referenced here yourself: the ballots are in the blobs linked from the round page, and the proof is on the Succinct explorer.

