🥉 3rd Place — Uniswap Foundation, Best Uniswap Stack Contribution · ETHGlobal Tokyo 2026
Continuity Track · ENS + Uniswap Foundation
Reckn pays for reproduced work. A program replays a job; when the result matches, settlement gives the buyer one right to write an ENS record. That record is then read inside a Uniswap v4 swap. It is not a reputation badge: it changes whether the swap can execute.
Open the live Sepolia evidence → · Read the 3-minute demo runbook → · Read every receipt →
Submitted 2026-09-27: ethglobal.com/showcase/reckn-47t6m — 3rd place, Uniswap Foundation Best Uniswap Stack Contribution.
| What a judge should see | Where to check it |
|---|---|
| The official ERC-8004 registry blocks an agent from self-feedback, but a second address can submit feedback without proving work. | Live page · receipt |
| A settled replay grants the buyer one ENSv2 setter right, then that right is revoked. | SettlementRecord.sol · ENS evidence |
| The same v4 swap is refused with no record, executes with a record, and is refused again after clearing it. | three live transactions |
| Every live claim and every open limitation is read from Sepolia, not printed as a screenshot. | Live page |
- The hole. ERC-8004 prevents an agent owner from submitting its own feedback. That still does not establish that a different feedback writer did any work.
- The right. A buyer funds an escrow. A proof of reproduced work settles it, and the same settlement opens one ENSv2 write window for that buyer. No owner, resolver, or admin chooses the result.
- The pass. A Uniswap v4
beforeSwaphook reads the settled ENS record synchronously on chain. No record, no swap. Clear it, and the same swap closes again.
Why a pool, and why v4. A record that only says this agent did the work is a badge — nobody has to look at it. In front of a pool it is a key: it decides whether you can trade. That is the difference between reputation and access. And the check runs inside the swap, so it cannot be skipped and cannot be delegated: read the record off-chain and then route the trade, and the party enforcing it is whoever operates the router — a party you have to trust, in the one place this project removed one. v4 is the first version where the pool itself carries that rule.
On Sepolia, with the same sender, pool, and swap:
| Record state | Result |
|---|---|
| No record | refused — NoSettledRecord |
| Settled record | 1.0 in → 0.987158034 out |
| Record cleared | refused again — NoSettledRecord |
The v3 swap is the work being re-executed; the v4 swap is where the earned record is used. The two roles are deliberate: earn on v3, spend on v4.
- The settlement grants the key, not the bytes. A buyer can write
reproducedunder a job whose proof saidfailed. What a settlement creates is the right to write one record, not the record's contents — checkable by anyone against the escrow and the proof, not enforced. - It does not solve identity: an agent can still hire and pay itself.
- It does not make a buyer-chosen verifier trustworthy; the buyer names that program.
- It gates trading, not liquidity provision.
- It is Sepolia, test tokens, and a testnet deployment — not mainnet.
- The hook gates on a settled record, not on the trader's identity:
beforeSwapsees whoever unlocked the PoolManager. We asked Uniswap; the pattern is an allowlist of routers you callmsgSender()on, and we are declining it — an allowlist is a party you have to trust, in the last place we had removed one. - A setter role is scoped to the key and never to a name. We asked ENS; the answer is to partition names across resolver instances, because the resolver instance is the trust boundary. This deployment is already that in its smallest form: one resolver, one name.
The live page reports the one state that must not be taken on faith — whether the deployed agent account still holds a root role capable of overriding the per-record rule. It no longer does, and the page says so because it asked, not because we edited it.
There is also a pool you can trade in: 0x95A466FE…0080,
opened by one settlement, closed to further writes, and
traded by an address that was never granted anything
after the key was destroyed. The demo tokens mint to anyone.
The zk re-execution escrow and proving pipeline are pre-existing work. The Tokyo event work
is the ENSv2 record-right adapter, the Uniswap v4 record gate, the Sepolia deployment and
receipts, live demo, tests, and submission visuals. The full boundary and prior-work disclosure
are in docs/tokyo-2026/DISCLOSURE.md.
AI use is disclosed file by file in docs/tokyo-2026/AI-USE.md.
bash scripts/no-keys.shIt fails if RecknZkEscrow gains an owner, admin, resolver, pause, upgrade path, an unlisted
state-changing entry point, or a caller-identity gate. The live Tokyo evidence is documented in
docs/tokyo-2026/RECEIPTS.md.
Eleven. A check nobody has seen fail is not a check, so each of these has a way of going red that has actually been observed — and one of them is red right now, on purpose.
The three forge test rows were added on 2026-09-27, and adding them is the point. Until
then this table had no row that ran the contracts' own tests, so "every gate is green" was true
and did not mean what it sounded like: renouncing root on 09-26 broke all three event-work
suites at setUp() — they hand the adapter its admin role using the root that no longer exists
— and nothing noticed for fifteen hours. They also ran against whatever the chain happened
to be at the moment of the run, which is a query rather than a test; they are pinned now.
| run it | it goes red when |
|---|---|
bash scripts/no-keys.sh |
the escrow gains a key of any kind |
bash scripts/no-keys-control.sh |
the gate above stops working — it plants eight dissimilar keys and requires a red for each. 10/10 |
bash scripts/no-unpublished-cli.sh |
a command in the docs does not exist |
bash scripts/partner-kit-check.sh |
something an adopter is told to run stops running — the partner package's own 95 tests, the starter's 10 checks, the release gate, and every command the docs name. It does not test the adapter or the hook; an earlier version of this line said it did |
bash tokyo-2026/scripts/take-check.sh |
a line the demo says out loud stops being true on chain — it refuses to record |
bash zk-verdict/scripts/sepolia-receipts.sh |
a receipt is linked that the chain-generated ledger does not hold, or a recorded transaction is linked nowhere. 69/69, both directions |
bash docs/tokyo-2026/check-description.sh |
the submitted description and the repository disagree |
cd tokyo-2026 && forge test |
the event work breaks — the ENS adapter, the v4 hook, and the griefing guard. 18 tests, against the real Sepolia deployment, pinned at block 11784630. Needs an archive RPC in SEPOLIA_RPC (PREFLIGHT §3) |
cd zk-verdict/contracts && forge test |
the central escrow or the Groth16 verifier breaks. 55 tests — binding mismatch reverts, the false-release vector refunds, tampered public values are rejected |
cd contracts && forge test |
the optimistic path breaks. 57 tests |
bash docs/tokyo-2026/check-video.sh |
the submission video would be auto-rejected. Red as of 2026-09-27, and correctly so. Rows 1-5 pass on the uploaded cut …_v21_CAPTIONED.mp4 — 3:02, 1920x1080, 61 speech pauses, 30 scene changes. Row 6 is not measured by anything: no OCR runs, so it holds the hash of a cut a person watched frame by frame, and that was v13, an earlier export. The founder decided not to re-watch. The row stays red rather than being recorded as watched |
The rest of this README preserves the broader research and earlier demos. They are not the Tokyo submission's evidence; use the Tokyo section above and its linked receipts when judging this entry.
In an agent economy the money and the work are rarely on the same chain. That splits one payment into two questions, and today a party with a key answers both:
- Was the work actually done? — an operator inside a TEE, a bonded resolver, a quorum of voters. Each is per-chain: you redeploy the judge and re-earn its reputation on every chain your agent touches.
- How does the asset get to where it is owed? — a bridge.
So the asset's fate is decided by two parties that were never asked the question: a judge who was told the answer, and a bridge whose job is to move value, not to know whether it was earned. Both are doing their own work correctly. The seat that is empty is the one that decides.
Do not move the asset to reach the work. Move a proof of the work to reach the asset.
The buyer escrows the stablecoin on the chain it already lives on. The seller does the work wherever the work belongs. When the delivery is disputed, the execution is replayed against the pre-state the deal pinned. If it reproduces, the escrow releases to the seller. If it does not, the buyer is refunded.
This is for deterministic, high-value work — not a way to grade arbitrary AI output. What
re-execution can settle is a claim that is recomputable from committed inputs: this call, over
this pre-state, moved this number by at least this much. "Was the summary any good" is not that,
and no amount of integration makes it that — see
docs/use-with-your-service.md §1 for the one-minute version and
Scope for the reasoning.
Don't make a bridge decide where money goes. Make proof decide.
Three things follow, and each is checkable rather than asserted:
| where it is checked | ||
|---|---|---|
| Nobody decides. | No owner, admin, resolver, pause or upgrade path — and that is a build condition, not a promise. | scripts/no-keys.sh fails the build if one appears |
| Nothing crosses but a proof. | The USDC is on Arc before the dispute and on Arc after it. Arc never runs a Solana VM. | What crosses, and what does not |
| It is running. | Four settlements on Arc testnet moved real USDC. Two were decided by proofs about work performed on Solana. | the live page reads them from the chain |
And what it does not do, said here rather than in a footnote. It does not remove the need to hold funds on the chain you pay from — what it removes is moving them in order to be judged, not in order to pay. And it does not prove those Solana inputs came from mainnet: the guest recomputes a bank hash over the account set the deal named, which is consistency, not provenance. There is a test that says so, and a panel on the live page that says so to a judge.
Positioning against the adjudicator-based alternatives is in Why; the full boundary
is in What crosses, and what does not; the wording this
project holds itself to, including the claims it refuses to make, is in
docs/messaging.md.
→ psyto.github.io/reckn — the ETHGlobal Tokyo entry. An agent cannot write its own history: the official ERC-8004 registry refuses its self-report, a settlement grants the buyer the right to write one ENS record instead, and a Uniswap v4 hook reads that record inside a swap. Your browser reads all of it off Sepolia as the page loads, including the part that is not finished yet.
→ /arc.html — the earlier Arc work, still live: your browser compares the deployed bytecode against this source and reads four settlements off Arc testnet. A different submission; the Tokyo entry does not claim it.
→ /money-shot.html — one dispute, judged two ways: an opinion model approves a false claim, a replay overrules it, and the money goes back to the buyer.
And it lets you try to break the claim yourself. Type anything you like into it —
argue, insist, paste an instruction telling the system to approve — and watch the hash of
your words change on every keystroke while the dealBinding, the proof's traceHash and
the verdict, all read live from Arc, do not move. Prose is real and it is recorded. It is
simply not something the verdict is a function of.
One page, no server, no wallet, no clone. It calls Arc's public RPC from your browser
and checks three things in front of you: that the bytecode holding the money is
byte-identical to the source in this repository (RecknZkEscrow has no constructor, so
the same source always produces the same deployment); that four settlements really
happened, with the verdict and the recipient decoded out of the receipts rather than
printed from the page; and that one deal is still funded and frozen — with the refund
path that will return it. The page is generated from
zk-verdict/contracts/arc.json and forge's build
output, so no hash on it is typed by hand.
bash scripts/arc-demo.sh # then open http://127.0.0.1:8787And it is live on Arc testnet. Not "deployment-ready" — deployed, and it has moved money: a real Groth16 proof released 1.000000 USDC to a seller, and a proof that the balance decreased refunded the buyer, both on chain 5042002.
RecknZkEscrow |
0x580f2c32…5669 — no owner, no constructor |
RecknVerdictVerifier |
0xc5f45b9d…97b7 |
SP1Verifier (Groth16, fixed) |
0xc84a89a5…5fbb |
| released to the seller | 0x2836ddb8…055e0 — block 60,720,091, 345,874 gas |
| refunded to the buyer | 0xeb971aa4…9456f |
| released by a Solana proof | 0x5c09cc07…2c4be — block 60,721,364. USDC on Arc, moved by a proof about work performed on Solana |
| refunded by a Solana proof | 0x3fca1b9a…65d1f — the Solana transfer credited below the floor, so the buyer got the USDC back |
The USDC is Circle's own predeploy at 0x3600…0000, so the escrow holds the chain's
native money — no wrapper, and no change to the contract to make that work.
Five buttons, five real transactions against a local chain at Arc's chain id:
| press | what happens |
|---|---|
| fund 250.00 USDC, then settle with the proof | a conditional stablecoin payment, released by a Groth16 proof and by nothing else |
| submit another execution's proof | it verifies — it is a real proof — and BindingMismatch() stops it. The money does not move |
| settle with the failing proof | a proof that the balance decreased refunds the buyer |
| settle with the Solana proof | USDC on Arc, released by a proof about work performed on Solana. No bridge, no light client, no resolver |
| refund now → wait 30 days → refund | TooEarly(), then anyone may return the money to the buyer — and the caller gets nothing for it |
Everything else in this README is the argument for why those five buttons behave that way, and what is still not true (the gaps are listed, not buried).
Reckn is an escrow layer for agent-to-agent (x402-style) payments where the dispute adjudicator is deterministic re-execution — not a TEE'd LLM judge, not self-reported feedback, not an unaudited internal loop.
When a buyer challenges a delivery, Reckn pins the pre-state, replays the disputed work against it, and evaluates the predicate the deal was bound to at funding time. The verdict commits the re-execution trace hash and pre-state root on-chain, so anyone can independently re-run and reach the same verdict. The signature that releases (or refunds) escrow binds to a re-execution, not to prose.
That re-execution now also runs inside a zkVM: a real Groth16 proof that the
committed work reproduces the verdict — EVM (revm) or Solana (System transfer),
each against a cryptographically authenticated prestate (MPT vs state_root /
bank_hash lattice) — is verified on-chain by one generic verifier, and that
proof settles escrow directly (RecknZkEscrow):
Reproduced releases to the seller, Failed refunds the buyer, with no resolver
at all — the proof carries its own authority. The EVM guest runs real revm
over the seller's committed CALL against an MPT-proven prestate (406,715 cycles);
the Solana guest is the narrower slice — a bank_hash-authenticated System
transfer (986,097 cycles).
One escrow settles both. The adjudicating program is named by the funder per deal
and pinned by its codehash, so a single RecknZkEscrow — with no constructor and no
immutable, meaning every deployment of that source is the same contract — settles
an EVM proof and a Solana proof side by side. No resolver, no bridge, and no light
client on the adjudication path. The funder chooses the program; the proof, checked by
that program, chooses the payout. Scope and limits are stated honestly in
zk-verdict/, including what is not closed
(in docs/status.md).
▶ Why it matters, in twenty seconds: the same dispute, judged by an opinion LLM
and by deterministic re-execution, watching them disagree — the animation below is
driven by real reexec-evm output. Open dashboard/index.html
locally to toggle Honest delivery / False claim yourself (the data is inline, so
file:// works), or run it live on a throwaway chain:
bash scripts/anvil-e2e.sh. That page is the hook; the
buttons above are the check.
▶ ZK money-shot: dashboard/variants/ — watch a disputed
payment get re-executed inside a zkVM → proven → verified on-chain
→ settled on the proof alone, on EVM or Solana (real fixture data). Flip tamper
prestate and the pipeline is rejected: no proof, no settlement. One command:
bash zk-verdict/scripts/zk-e2e.sh.
▶ USDC on Arc, released by a proof about work on Solana — the same page, further down. The deal names the Solana guest's verifier; the escrow never learns which virtual machine the work happened on.
▶ Demo video — the ETHOnline submission (3:52, 1920×1080, narrated):
dashboard/media/Reckn_ETHOnline_20260909.mp4
— the deck's four checks, each one answered by the live page driving a real chain, ending on
this run's own no-keys.sh output, with a human English voice-over. No synthetic voice was
used anywhere. docs/ethonline-2026/PREFLIGHT.md measures it against the event's requirements
and it now clears all six.
The silent master it was cut from is
dashboard/media/reckn-demo-v3.mp4 (3:57). It is not
the same picture: the narrated file runs 5.8 s shorter and, from roughly 3:10 onward, ahead
of the master. Re-recording the master will not reproduce the submission, and it is not meant
to — the script it is timed against is dashboard/video/VO.md.
The earlier v2 film (reckn-arc-demo-v2.mp4, 3:04, and a no-cards cut at 3:03) and the v1
files are kept for comparison and are not the submission.
Regenerate it with cd dashboard/video && npm install && node record.js; the recorder
asserts each step's result and refuses to record one that did not happen.
The same escrow source, unmodified, now settles on a second payment chain — and that
is a statement about the source, checked by a gate (zk-verdict/scripts/tempo-arc-parity.sh),
not a claim that the two chains adjudicate alike. They do not: the adjudicator is named per
deal by the funder, and a TIP-20 can be paused or policy-gated where Arc's USDC cannot. On Tempo
testnet (2026-09-08) the escrow held PathUSD — a real TIP-20, not a mock — and a proof
about work performed on Solana released it to the seller, while a proof that the work did not
reproduce refunded the buyer. Tempo has no gas token, so the fee that settled each of those
was paid in the same stablecoin the escrow was holding, read off the receipts' own
feeToken. Explorer-linked hashes:
docs/specs/011-tempo-tip20-slice.md §10.
→ psyto.github.io/reckn/tempo.html — the
same idea as the Arc page, for the second chain: your browser calls Tempo's public RPC and
checks it in front of you. Nothing on it is passed in but addresses and transaction hashes —
the page calls deals() on the escrow, reads the settlement receipts, and works out the
verdict, the recipient and the fee token itself. It also shows the deal that a real proof of
a different execution failed to settle: still funded, money still in the escrow, no
transaction to link because it never reached a block.
Four of the checks behind that page read the live chain rather than this repository:
tempo-verify.sh re-derives every outcome from receipts instead of trusting the run that
produced them (the deal ids come out of the Funded events, not from a terminal),
tempo-receipts.sh requires every recorded hash to exist on chain with the status the
record claims — including the one that failed, which is recorded rather than hidden —
tempo-arc-parity.sh is the gate behind the sentence above, and tempo-page-check.sh runs
that page's own JavaScript against Tempo and fails if what it renders is not true. The page
said "Nothing is deployed to Tempo" for several hours after the escrow was deployed and had
settled twice; that check exists so it cannot happen twice.
Everything else on this page is Arc. This is not claimed as ETHOnline event work — see
docs/ethonline-2026/PREFLIGHT.md §2.
▶ Demo video, pre-event cut (35s):
dashboard/media/reckn-demo-full.mp4
— a self-explanatory 35s cut with title cards (no audio needed): the hook (agent
payments settle on a trusted judge you can't check) → the money-shot judged two ways
(false → refund, honest → release) → live anvil-e2e.sh on a real chain (pin the
anchor, publish the witness, re-execute, refund, reproduce the verdict keyless) → the
close (one engine, any chain, any rail). Component clips:
reckn-demo.mp4 (dashboard),
reckn-e2e.mp4 (terminal).
No key can judge.
Every competing design in this lane has someone holding a key — a TEE operator,
a bonded resolver, a voting set. Reckn's zk path has none: RecknZkEscrow has no
owner, admin, resolver, pause or upgrade, and settleWithProof is permissionless.
Authority to move money comes from a proof verifying, and nothing else.
Because a claim like that decays the moment someone adds "just one" privileged field, it is enforced mechanically rather than promised:
bash scripts/no-keys.sh # exit 0 = the claim still holdsIt fails the build if a privileged role appears, if the state-changing surface
grows beyond the enumerated fund / settleWithProof / refundAfterDeadline, if
any msg.sender gate is introduced, or if the constructor stores its caller. The
check is itself tested against three negative controls (add an admin field, add
an unlisted function, add a msg.sender gate — each must fail it). Widening the
surface is allowed, but only by changing the claim in the same commit: this
README, AGENTS.md, and the script move together, or not at all.
A second condition, added 2026-09-09, covers the other end — not is the claim still true but does the thing a stranger is told to run still run:
bash scripts/partner-kit-check.sh # 0 = it runs · 1 = broken · 3 = COULD NOT VERIFYIt runs the package's tests, the starter end to end, and the release gate — which packs
the package, installs it into an empty project and drives the CLI as a consumer would,
because reading a file list is not the same thing as installing one. It exists because
nothing was doing this: on 2026-09-09 a commit made a profile field mandatory, updated the
source and the tests, missed the example, and the starter stayed broken at HEAD while
passing in every working tree. It was found by hand, hours later.
Three exit codes, not two. A missing anvil or forge returns 3, never 0: a check that
goes green because it could not look is the defect it exists to prevent.
This is the "correct version" of a pattern that keeps winning agent-economy hackathons (e.g. ETHGlobal NY 2026 Clawback — "chargebacks for the machine economy"). Every entry in that lane gates payment on a trusted adjudicator:
| Project | Adjudicator | Trust root |
|---|---|---|
| Clawback | Confidential LLM Attester (TEE) | an LLM's opinion (TEE proves it ran, not that it's right) |
| AgentRankr | feedback events | self-reported, sybil-gameable |
| Sidekick | per-block loop | unaudited venue internals |
| Reckn | re-execution | deterministic replay anyone can reproduce |
The practical version of this section — a table you can check your own agent against in a
minute — is docs/use-with-your-service.md §1. This one is the
reasoning behind it.
Re-execution cannot judge subjective quality ("was the essay good?"). Reckn's lane is the class of agent payments whose deliverable is machine-verifiable:
- on-chain action delegation ("executed this swap at ≤X slippage") — the claim
is causal, so it funds as a
POSTSTATE_DELTApredicate ("the fill credited ≥ minOut" =post − pre ≥ minOuton the output-balance slot). Unlike a plain bound ("balance ≥ minOut", which a no-op plan satisfies straight off the prestate), the delta adjudicates the increase the plan itself caused, so a seller cannot be paid without moving the balance. Demonstrated end-to-end in Act II ofanvil-e2e.sh: a real crediting fill clears the floor, reproduces, and is released to the seller - computation with a spec (re-run, check output matches)
- provenance-bearing data / oracle claims (reproduce the claimed source state)
The crux: at escrow-funding time the deal is bound to a re-executable predicate
(spec), which makes the dispute decidable. Subjective deliverables fall
back to a conventional judge — out of scope here, but the adjudicator boundary is
cut so such a judge is just another pluggable backend.
Replay is deterministic because it runs against a committed prestate
(prestateAnchor), not the live mempool — so ordering, front-running, and MEV of
the original execution are irrelevant to the re-run. The flip side is the scope
line: a deliverable whose correctness depends on live-chain ordering not captured
by the committed anchor is not in the decidable lane, and block-context that a
single committed prestate can't reproduce (e.g. BLOCKHASH of a connected header)
is trapped as an operational error rather than silently guessed. The predicate
must be checkable against prestate + plan alone.
EIP-3009 deposit, deal ⟵ specHash
┌──────────────────────────────────────────┐
▼ │
Held ──(seller submits deliverable+result)──▶ Delivered
▲ │
│ (buyer challenges)
│ ▼
│ Disputed ── emits Disputed event
│ │
│ Re-exec Attester
│ (pin pre-state → replay → eval predicate)
│ │
└──── refund ◀── Resolved ◀── verdict ──────┘
release ▲ (Reproduced → release, Failed → refund)
By default the verdict settles optimistically: a bonded resolver commits it
into a Settling state that opens a challenge window, and finalize settles once
the window elapses — unless a second registered resolver posts a conflicting
verdict first, which fail-safes to a buyer refund. This is the default on both VMs
(the diagram shows the direct verdict → settlement it collapses to).
The adjudicator lives behind a VM-neutral boundary:
ReexecBackend.verdict(specHash, prestateAnchor)
-> { verdict: Reproduced | Failed, traceHash, prestateRoot }
- EVM backend — revm replay (implemented)
- Solana backend — LiteSVM / SBF replay (implemented)
- cross-VM binder — one router dispatches a dispute to the right VM backend
(implemented: a single
BackendRouterre-executes both VMs, proven by test)
verdict(specHash, prestateAnchor) is shorthand; the runnable interface also
takes the committed spec/delivery/anchor bytes, so consensus never depends on a
hidden mutable store. The verdict envelope is VM-agnostic; only the engine
underneath differs. See
docs/protocol-architecture.md for the
versioned interface, predicate profile, trust boundary, and EVM-first plan; see
docs/roadmap-crossvm.md for the extension roadmap.
Reckn's trust root is re-execution, which depends on neither a specific chain nor a specific payment rail. The adjudicator is VM-neutral (proven on both EVM and Solana behind one router) and rail-agnostic: how the escrow was funded — x402 / EIP-3009 on EVM, Token-2022 on Solana, or any future rail — never touches how a dispute is decided. One re-execution engine, any chain, any rail.
So the emerging agent-payment stack is a set of supported targets, not a dependency. The reference implementation funds via x402 / EIP-3009, settles on EVM (Circle Arc is one target — Best Agentic Economy) and on Solana, and slots behind Chainlink CRE / MCP as thin, swappable adapters. Reckn does not bet on any one of them: if a rail wins, it is already positioned; if a rail stalls, the verdict still reproduces anywhere. The dual-VM implementation is the proof — Solana is not scope creep, it is the demonstration that the adjudicator outlives any single stack.
Adopted, judge-legible pieces: ERC-8004 reputation (implemented) · x402 /
EIP-3009 payments (EVM escrow — a buyer agent's x402 authorization is the escrow
funding; see docs/x402-payments.md) · Circle Arc as one
settlement target · Chainlink CRE / MCP as swappable orchestration.
Where the execution engineering came from. Re-execution is unforgiving in a specific way —
the same inputs must produce the same bytes, on another machine, inside a zkVM, a month later.
That discipline grew out of our work on RDK: deterministic state transitions, replayable
scenarios, pinned execution environments, and treating a revert as a result rather than a crash.
It was developed here into a mechanism for deciding payments, which is a different problem.
To be exact about what that is not: Reckn does not reuse RDK's re-execution code, and Reckn is
not built on Reth — its EVM stack is revm 38 + alloy, and reth-trie was declined on purpose
so an offline verifier would not acquire a node's database layer. The habits that did carry over,
and the file that checks each one, are in
docs/positioning.md § Where the execution engineering came from.
The 150-word version of all of this, with every clause traced to the file that carries it and
an audit of what the words may not mean: docs/cwf-2026/PITCH.md.
2026-09-25 → 09-27, Continuity track. Submitted 2026-09-27 — ethglobal.com/showcase/reckn-47t6m — for the ENS and Uniswap Foundation partner prizes and for Top 10 Finalist judging. Result: 3rd place, Uniswap Foundation — Best Uniswap Stack Contribution.
| The lane | docs/specs/013-settlement-granted-record-rights.md, at r4 — it supersedes 012 and absorbs its Uniswap half |
| Event work | commits after 2026-09-25 21:00 JST, when hacking began. A commit merely dated 09-25 is not event work — five landed that day before the boundary. Check it yourself: git log --oneline eddac8d..HEAD |
| Boundary commit | eddac8d (2026-09-25 19:31 +0900), recorded in STATUS.md before the window opened |
| Pre-existing work | docs/tokyo-2026/DISCLOSURE.md. The broader Reckn research below is pre-existing; the Tokyo section at the top names the event work separately |
| What was measured before building | spikes/tokyo-2026/FINDINGS.md — including two places the design was wrong |
Live, and your browser checks it for you: psyto.github.io/reckn.
Every transaction: docs/tokyo-2026/RECEIPTS.md, checked in both
directions against a record generated from the chain.
| what | the line | on Sepolia |
|---|---|---|
| a settlement grants the buyer one record — the ENS role is granted against the setter's calldata, so it authorises one key and is revoked after | SettlementRecord.sol:225 · :264 |
0xA6966f9f… |
| the outcome is re-derived from the proof, never taken from the caller | SettlementRecord.sol:240 |
|
| the record key names the name it belongs to, because an ENSv2 role is scoped to the key alone | SettlementRecord.sol:152 |
|
a beforeSwap hook gates a v4 pool on that record, read on chain inside the swap, no CCIP-Read |
RecordGatedHook.sol:71 |
0x68116b80…0080 |
| the error the PoolManager wraps in ERC-7751 | RecordGatedHook.sol:45 |
|
| settlement is permissionless — a proof, not a key | RecknZkEscrow.sol:133 |
0x6d6a9deb… |
| the buyer commits to the terms first | RecknZkEscrow.sol:101 · binding.rs |
|
| the only way out that is not a proof, and it pays the caller nothing | RecknZkEscrow.sol:176 |
Beat 5, as five transactions. Same sender, same pool, same swap; the only thing that changes is whether the record exists: refused · the buyer writes · executed, 1.0 in and 0.987158034 out · the buyer clears it · refused again.
And one proof that did not exist when the event started: generated 2026-09-26, 416.56 s, settling a deal on chain forty minutes later.
What is still open is in 013 §1.1 and
on the page itself, which reads it off the chain rather than asserting it: the record's contents
are not proof-derived, the hook cannot identify the swapper (beforeSwap's sender is the
unlocker). Root was renounced on 2026-09-26 and the agent can no longer write its own record —
re-read from chain in the same run that destroyed the key, and the live page checks it on every
load rather than asserting it.
Developer feedback for the sponsors: FEEDBACK.md.
Reckn was entered in ETHOnline 2026 (9/4–16, async) under Continuity — Ship a Feature. It did not pass the Round 1 asynchronous judging; partner-prize judging ran to 9/17. The boundary is left stated here rather than reconstructed later, and is pre-existing work for Tokyo.
| Pre-event product work ends at | a122b44 (2026-08-02) |
| Commits dated 2026-09-03 | harness, planning and documentation only — no product feature |
| Event work | commits dated 2026-09-04 or later — the date is primary, not the hash |
EVENT_START |
121194ca3e25bab4ec92aaa4da1277f3a60b8421, recorded in STATUS.md |
| Accepted | 2026-09-04, Continuity Track |
| Retreat checkpoint | 9/9 — tasks 008 and 009 both green, or the founder decides. Met early, 2026-09-07: ac009.sh --all → 13/13 rows passed, and its AC-12 ran ac005.sh --all and ac008.sh --all to completion inside the same run, 2/2 exit 0. Confirming each gate in turn, on different trees, does not satisfy the word simultaneously; that is the only thing AC-12 exists for. Re-measured 2026-09-09, with the sibling set now four rather than two: twelve of thirteen rows green in one run, and AC-12 red in that run because the working tree moved while it ran — README.md was edited at 13:59, inside the 13:02–14:01 window. Its content assertions all matched and only the witness digest differed. Re-run on a still tree: both-green discovered 4 siblings, 4/4 exit 0, ac008 18/18. Every row has a green measurement and they are not all from one run, which is the true statement |
| Freeze | 9/12 |
Every feature described in this README is pre-event work, disclosed to ETHGlobal in advance. Nothing here is claimed as event-day work, and nothing below is described as finished before it is.
What the event is for, in execution order (AGENTS.md §3):
- 008 — verdict domain soundness. Close the false release described
in
docs/status.md: the guest judges the balance delta on the low 64 bits while the off-chain engine uses the fullU256, so a decrease proves as a maximal credit. Also make "the same engine runs in-guest" checkable rather than assumed. - 009 — cross-VM settlement. Settle an EVM escrow on a Solana proof. Today an
SVM verdict is verified on-chain by the same generic verifier, but only EVM proofs
reach
settleWithProof. This is the event's headline: a payment escrowed on one chain, disputed over work performed on another, settled by a proof — no resolver on either side, and no bridge or light client in the adjudication path. - 003 — key gauntlet (stopped, not abandoned). Publish every party's private key and demonstrate with a test matrix that every theft path reverts, folding in the keyless timeout — the timeout half landed 2026-09-06, so a funded deal with no proof no longer locks forever; the key gauntlet itself is still stopped. Its spec hit the harness's six-round review limit still holding one open hole — a constant-keyed branch that no check rejects — and the rules say to stop and hand it back rather than write a seventh round. It is out of the 9/9 checkpoint and may return before the freeze.
- 004 — live adversarial input. Open the seller's delivery claim to free-form text, so anyone watching can write whatever they like about what was delivered — and watch it change nothing. The claim is that prose does not move re-execution, and it is stated without reference to any judge: a judge we wrote ourselves being "persuaded" would be evidence of nothing.
- 005 — Arc / USDC. Settle in Circle's USDC on Arc. The contract needed no change
— a deal names its payment token at funding — so the deliverable is evidence, in
USDC's own units and semantics: six decimals, revert-not-
false, and a blacklisted recipient. Landed 2026-09-06, including a live testnet deployment.
Where this stands (2026-09-07): 008, 009, 005 and the keyless timeout have
landed, and the three gates were green together in one run (above). 004 is next,
its spec at round 2 with a CHANGES verdict; 003 stays stopped — that is a founder
call, not a scheduling one. 002 (real ERC-20 workload) is not started. Nothing here
is described as finished before it is, and the two tasks that are not done are named
rather than omitted.
Each task goes through a written spec with mechanically checkable acceptance
criteria and an adversarial review by a second model before any implementation. The
specs and every review verdict are committed under docs/specs/ and
docs/reviews/ — including the ones that failed.
The submission form's contents live in the repository, paste-ready and current:
docs/ethonline-2026/SUBMISSION-FORM.md. Its
reproduction of the disclosure is rendered from
DISCLOSURE.md by a script rather than retyped,
so the two cannot silently disagree; the working drafts that used to live outside the
repository are listed there as superseded, each with the specific thing it now gets wrong.
The repository is developed by an autonomous harness — reckn-spec (frame-thin:
closes the frame) → reckn-codex-review (adversarial, second model) →
reckn-codex-impl (frame-thick: fills the frame) → review → commit, with
reckn-demo owning what a judge sees first. Rules, stop conditions and the
Continuity discipline are in AGENTS.md; the plan and the advance
disclosure are in docs/ethonline-2026/.
In a machine economy the binding constraint is human attention, not cost. An escrow a person approves is a serialisation point: agents run continuously and in parallel, and every release queues behind someone reading something.
x402 has processed 165 million payments across 69,000 agents. At the dispute rate card payments actually run at (~0.5%) that is 825,000 decisions — 14 to 34 person-years of reading, depending on whether you allow two minutes or five. (Derived: the counts and the rate are cited, the minutes are an assumption. Halve it and the shape is unchanged — transaction count grows, human attention does not.)
Reckn's release condition is fixed before the work begins and evaluated by a computation both parties can run. Nobody reads anything, nobody approves anything, and there is no queue behind anybody.
The fee is the symptom of that person existing. A decided payment dispute costs a merchant $110–128 all-in today, against a $20–50 processor fee — the rest is people reading conflicting stories. Global chargeback volume is $33.79B in 2025, heading to $41.69B by 2028, and every $1 lost to one costs $5.13 once you count the disputes never contested. That cost exists because somebody has to decide.
Settling a dispute here costs 0.0070–0.0077 USDC — measured on Arc against the four live settlements, at the real gas price. Verifying a Groth16 proof and moving the money is under a cent, and it does not grow with the size of the dispute.
The number that constrains us is the other one. The average x402 payment is $0.52, and you cannot re-execute a fifty-cent API call under a zkVM and come out ahead.
So the comparison set is not every agent payment — it is the payments that would otherwise need an escrow at all, and those pay a percentage today: Upwork takes 10–20% from the seller plus 3–5% from the client, Fiverr a flat 20% plus 5.5%. Reckn charges a fixed cost instead. They cross at roughly a $10 delivery if a proof costs $1, or $50 if it costs $5 — and above that a $1,000 job pays $100–200 to a platform, or a proof plus two thirds of a cent here.
Note there is no dispute process in any of this. RecknZkEscrow has three states —
None, Funded, Settled — and no Disputed one, because re-execution is not a remedy a
dispute triggers: it is how settlement works, every time. The full arithmetic, the cost we
have not measured, and what would falsify the whole case are in
docs/why.md — the two constraints (a human in the release path, and a
bridge in the asset path), why they are the same defect, and every number labelled
measured, cited or unknown.
Same principle, different property used each time — docs/chain-fit.md.
The Arc architecture diagram — what calls what, and the two edges that carry the design — is in
docs/arc-usdc.md § The architecture.
Arc is a stablecoin-native rail where a conditional payment settles without bridging the asset.
On Tempo the escrow and the fee that releases it are the same stablecoin, because Tempo has
no native gas token. Receipts for both, and the limits neither of them fixes, are on that page.
Where Tempo's own verification stops, and Reckn starts. Tempo publishes Tempo Evals — "Evaluation harnesses for agents building on Tempo and related protocols" — which grades an agent's integration with a verifier that "deterministically checks the submission" rather than with a judge. That is the layer before any commerce exists. Reckn is the layer after the work.
Tempo Evals verifies that an agent can correctly integrate and operate on Tempo. Reckn verifies whether that agent's committed delivery earned the payment.
Tempo makes agent payments operable and evaluable; Reckn makes high-stakes agent payments accountable.
Complementary layers — not an integration, and not an endorsement. Reckn is an ordinary EVM
contract on Tempo: it reads no Evals, Harbor or RewardKit score, is not a suite in that
repository, and has not been evaluated by it. Tempo runs no Solana VM, and the absence of a bridge
is a statement about who may authorise the payment — not about Solana provenance, which
remains unproven either way. Side by side, with the receipts:
docs/chain-fit.md.
What "settled by a Solana proof" means, precisely. The escrow's adjudication path carries no bridge, no light client and no resolver. It is not a statement that the committed
bank_hashwas ever a real Solana cluster's — the guest recomputes it from the committed account set. Settled by a Solana proof means settled by a proof about a Solana-shaped state the deal named.
The most common misreading of this project is that Arc verifies Solana, or that something is bridged. Neither is true, and the distinction is the whole design:
flowchart LR
subgraph solana["Solana — where the WORK happened"]
TX["a committed transaction<br/>+ the account set it touched"]
end
subgraph guest["SP1 zkVM — where the JUDGING happens"]
RX["re-execute: verify signatures,<br/>recompute bank_hash,<br/>apply transfer semantics"]
PV["public values:<br/>outcome · traceHash · dealBinding"]
RX --> PV
end
subgraph arc["Arc — where the MONEY always was"]
V["RecknVerdictVerifier<br/>checks a Groth16 proof"]
E["RecknZkEscrow<br/>no owner · no resolver"]
U["USDC 0x3600…0000"]
V --> E --> U
end
TX --> RX
PV -->|"a proof. nothing else crosses."| V
style PV fill:#123,stroke:#6cf,color:#fff
style E fill:#0b3d2e,stroke:#0f7,color:#fff
No bridge is needed because no asset moves. The USDC is on Arc at the start and on Arc at the end; only a proof travels, and Arc never runs a Solana VM — it checks that one program executed correctly over public inputs. No light client is needed because Arc is not being asked what Solana's state is; it is being asked whether a computation over a committed state is valid.
That buys a precise thing, and it is worth stating both halves out loud:
| What this does today | Settle USDC on Arc conditionally on the re-executed result of work performed on Solana, with no bridge, no light client and no adjudicator anywhere on the path that decides the payout. |
| What this does not do today | Prove that the committed inputs came from Solana mainnet. The guest recomputes a bank_hash over the account set the deal named — internal consistency, not provenance. A fabricated account set hashes just as well, and a test asserts exactly that. Closing it needs a light client, or an oracle/attestation with its trust model written down. |
Without both rows, a reader cannot tell this apart from a bridge, from a light client, or from an oracle. With them, the boundary is the interesting part rather than the hidden one.
→ docs/use-with-your-service.md — the whole integration in
one page. What Reckn decides and how to tell in a minute whether it fits your agent; the two
calls; the buyer path and the seller path; and what you have to bring. If you read one page
after this README, read that one.
The short version: two calls. fund opens a deal, settleWithProof closes it, and the
second is permissionless — the key that pays the gas has no bearing on where the money goes, so
there is no step where you hand anyone authority. refundAfterDeadline returns the money after
thirty days and is the only exit that needs no proof.
docs/integrate.md— the contract surface in about a page, including computing adealBindingyourself before any work happensdocs/partner-kit.md— the TypeScript package and starter in detail: the five refusals, the profiles, the endpoint requirements, the known limitsbash scripts/partner-kit-check.sh— run before believing any of the above. It is the only thing that verifies the commands this section gives you actually work.docs/positioning.md— which layer this is and which layers it composes with. AI chooses, negotiates, and explains. Re-execution decides the payout. It also says what Reckn does not suit, which is most agent spending.
Nobody outside this project has used it yet, and that is not claimed anywhere.
docs/status.md — what is built, what was closed during ETHOnline
(2026-09-04 onward), and Known gaps (not closed), which is the section worth reading
first if you are deciding whether to believe any of this.
It lives outside the README because it is the part that goes stale fastest, and a README that is quietly out of date costs more than a long one. Nothing was softened on the way out.
docs/layout.md — where everything lives, crate by crate.
Run the whole live dispute on a throwaway local chain:
bash scripts/anvil-e2e.shPrerequisites: Foundry (anvil, forge, cast), Rust
(cargo), and jq. The script needs no arguments and cleans up after itself.
It spins up anvil, deploys the escrow / registry / a mock USDC, then has the
seller publish a proof-verified prestate witness to a content store
(reckn-keeper witness … --write, bound to the block's state_root) and commit
its SHA-256 into the delivery. The run has two acts over the same frozen state:
- Act I (refund, exact-match): a deal is funded on a
RESULT_EQUALSpredicate; the seller'sbalanceOfSLOAD plan can't satisfy it, so re-execution returnsFailedand refunds the buyer. - Act II (release, causal delta): a second deal is funded on a
POSTSTATE_DELTApredicate — "the fill must credit ≥ minOut" (post − preon the output-balance slot), the flagship swap slippage floor done causally. A real crediting plan (its own proof-carrying witness) raises the balance, so the adjudicated increase clears the floor, re-execution returnsReproduced, and the escrow releases to the seller. A no-op plan would yield delta 0 and could not be paid — which is the whole point.
In each act the keeper picks up the Disputed event, fetches the committed
spec / delivery / anchor / witness from the content store (each hash-checked
before parsing), MPT-verifies the witness against the anchor, re-executes the
seller's plan, signs the verdict, and submits resolveOptimistic — which
commits the verdict and opens a bonded challenge window rather than paying
instantly. With no conflicting verdict, the window elapses and anyone calls
finalizeSettlement to pay per the verdict. Finally, a keyless independent
re-verifier reads each on-chain verdict back and reproduces it from public
inputs alone — proving the resolver couldn't have lied, for both the refund and
the release.
The run narrates each phase in plain language (with the real addresses, hashes, and deal id shown underneath), so it reads as a story even if you don't know the internals:
▶ Setting up: an escrow and a test USDC on a fresh local chain
▶ Freezing the exact chain state the work will be judged against
▶ Seller attaches tamper-proof evidence of the state it ran against
▶ Buyer pays 1,000 USDC into escrow for the promised result
▶ Seller delivers a wrong result but claims success; buyer disputes it
▶ Reckn replays the actual work and checks it against the promise
PASS: re-execution returned Failed and refunded buyer; deal=0x…
▶ Anyone can reproduce this verdict themselves — no trust in the keeper
VERIFIED — resolver verdict reproduced from public inputs with no resolver key. …
PASS: independent re-verification reproduced the on-chain verdict.
▶ Act II: buyer funds a *causal* slippage floor — the fill must CREDIT ≥ minOut
▶ Reckn replays the work: the plan CREDITED ≥ minOut, so the seller is paid
PASS: delta predicate reproduced (credited ≥ minOut); seller released; deal=0x…
▶ Anyone can reproduce the released verdict too — same public inputs, no key
PASS: independent re-verification reproduced the RELEASE verdict.
That is the entire trust chain end-to-end on a real node:
deal.prestateAnchorHash → checked anchor → block_hash → RLP-verified header → state_root → MPT-proven witness → closed-world replay → verdict → settlement.
The block_hash → header → state_root link binds the committed state root to the
real block: the keeper commits the anvil block header, and the keyless verdict path
proves keccak256(rlp(header)) == block_hash before trusting state_root.
bash zk-verdict/scripts/zk-e2e.shSame dispute, taken all the way to zero trusted parties: the disputed work is
re-executed inside a zkVM — real revm (EVM) / the real Solana transfer (SVM),
each against a cryptographically authenticated prestate (MPT vs state_root /
bank_hash lattice; a tampered prestate is rejected) — a real Groth16 proof of
that execution is verified on-chain by one generic verifier, and
RecknZkEscrow settles the escrow on
the proof alone (Reproduced → seller, Failed → buyer). No resolver, no signer
allow-list. The on-chain half runs on committed real proofs with just forge; the
live in-guest half runs if the SP1 toolchain is present.
Each component is self-contained; there is no top-level build.
# settlement contracts (Foundry) — 57 tests (verified EIP-3009 funding + opt-in seller DA bond + end-to-end on real engine output)
cd contracts && forge install foundry-rs/forge-std --no-git && forge test
# re-execution engine (revm 38, MPT-verified prestate + header binding) — 16 tests
cd reexec-evm && cargo test
# keeper signature + content-store guard — 3 tests
cd keeper && cargo test
# cross-VM binder: one router re-executes EVM + SVM, fails closed — 6 tests
cd binder && cargo test
# ZK re-execution, one command: re-execute both VMs in the zkVM (tampered prestate
# rejected), verify the REAL Groth16 proofs on-chain, and SETTLE the escrow to the
# seller on the proof alone — no resolver (RecknZkEscrow) — 34 tests
bash zk-verdict/scripts/zk-e2e.sh
# or piecemeal:
cd zk-verdict/contracts && forge test # verify + settle
cd zk-verdict/script && cargo run --release --bin reexec -- --execute # EVM in-guest
cd zk-verdict/script && cargo run --release --bin svm -- --execute # SVM in-guest
# the 008 vectors: value domain (14), engine identity (13), binding (18),
# domain closure (13), outcome map (6) — every one decided twice, in-guest and
# off-chain, and required to agree — 64 tests
cd zk-verdict/script && cargo test
# one escrow, two virtual machines: an EVM proof and a Solana proof settled through
# a single RecknZkEscrow, plus the sixteen cross-VM criteria — 16 tests
cd zk-verdict/contracts && forge test --match-contract RecknCrossVmSettlement
# the acceptance gates: manifest rows parsed out of the specs themselves
bash zk-verdict/scripts/ac008.sh --check # manifest arithmetic, no runs
bash zk-verdict/scripts/ac008.sh AC-02 # one row, count asserted before success
bash zk-verdict/scripts/ac009.sh --check # 13 rows + the naming gate
bash zk-verdict/scripts/ac009.sh AC-1 # one escrow, two VMs, both settled
bash zk-verdict/scripts/ac005.sh --all # 4 rows: USDC units, and the two
# transcription gates over the live receipts
bash zk-verdict/scripts/ac011.sh --all # 8 rows: the Tempo slice. Four of them read
# the live chain — a settlement, a refund, and
# the deal a mismatched proof could not move
bash zk-verdict/scripts/tempo-arc-parity.sh # one escrow source, two payment chains,
# byte-identical, fetched from both
bash zk-verdict/scripts/ac009.sh --all # everything, plus every sibling gate,
# in one run — an overnight job, not a minute
bash scripts/no-keys.sh # the build condition, five checks
bash zk-verdict/scripts/surfaces.sh # the two files 008 may not touch
# Reckn on Arc: a conditional USDC payment released by a proof. Local chain at Arc's
# chain id (5042002) — deploy → fund 250.00 USDC → settle → refund. No key, no funds.
bash scripts/arc-usdc-e2e.sh
cd zk-verdict/contracts && forge test --match-contract RecknArcUsdc # 6 tests
open dashboard/arc.html # the run above, rendered (data inlined)
# one-command local chain demo: Act I false claim → Failed → refund;
# Act II causal delta predicate (credited ≥ minOut) → Reproduced → seller release
cd .. && bash scripts/anvil-e2e.sh
# regenerate the dashboard's data from the real engine
cd reexec-evm && cargo run --example moneyshot > ../dashboard/moneyshot.json
# view the money-shot (data is inline, so file:// works)
open dashboard/index.htmlThe contract↔keeper EIP-712 digest is pinned by a shared golden
(packages/protocol/golden/verdict-eip712-v1.json):
forge test --match-contract VerdictDigestTest and the keeper's
eip712_digest_matches_golden must agree, or a keeper signature would be rejected
by resolve().
Two models, split by how thick the frame is rather than by seniority: Claude
Code closes the frame (spec, invariants, acceptance criteria, non-goals) and Codex
fills it and attacks it. The relay is no longer human — Claude Code drives Codex
directly through the agents in .claude/agents/, and the one
rule that keeps the review honest is author independence: the model that wrote
a change never reviews it, and when Codex is asked for a second opinion the payload
says who wrote the artifact.
The original frame-thick convergence is complete — its result is
docs/protocol-architecture.md.
docs/architecture-brief.md is the original task
brief, kept for history.




