Autonomous, verification-gated servicing for tokenized real-world cashflows on Casper.
An autonomous agent and on-chain vault that release a tokenized cashflow to its holders
only after independently verifying the money actually arrived — verification, not attestation.
The contract verifies the quorum on-chain; verifiers carry on-chain reputation; the AI explains — the chain decides.
Built for the Casper Agentic Buildathon 2026 · Casper Innovation Track.
- The problem
- The insight
- How it works
- The demonstrable moment
- The depth ladder
- The moat stack
- x402 — native, not bolted on
- Casper example-direction-#2
- Proven on-chain
- See it live
- Architecture
- Repository layout
- Run it locally
- Honesty & disclosure
- License
Tokenized real-world assets — invoices, rent, royalties, private credit — are a fast-growing on-chain market. But servicing them is still manual and trust-based: someone has to confirm the off-chain cashflow genuinely arrived, then distribute it to token holders. On-chain today, projects push data in via oracles; nobody autonomously pushes verified cashflow out. Holders are left trusting an issuer's word that they got paid.
Recording that a payout happened is not proof it was owed.
Quittance shifts servicing from attestation (one source's say-so) to verification (an independent 2-of-3 quorum) before any funds move. The agent doesn't take anyone's word — it pays independent verifiers to check, and gates the on-chain distribution on their quorum.
Each cycle, the autonomous servicer agent:
- Detects a cycle is due for a tokenized asset.
- Pays three independent verifiers over x402 to answer: "did the cashflow arrive?" — real, per-call economic commitment, settled on Casper.
- Requires a 2-of-3 quorum of signed yes/no verdicts.
- If met → calls the vault's
distribute(), which verifies each Ed25519 verdict signature on-chain (SPEC-4), pays holders pro-rata, writes a verifiable receipt (SPEC-1), scores each verifier's on-chain reputation (SPEC-6), and the agent records an AI verification brief (SPEC-5) explaining the cycle. - If not → halts, pays out nothing, flags a dispute — and writes no receipt, scores no reputation, records no brief.
detect cycle → pay 3 verifiers (x402) → 2-of-3 quorum?
├─ yes → distribute on-chain + receipt
└─ no → HALT · funds withheld
Feed a fake "paid" claim through one compromised verifier and watch the agent refuse to release the funds. That refusal — paid-for, independent, and enforced on-chain — is the whole product. Try it interactively →
| Level | Quorum enforced… | Who's here |
|---|---|---|
| L0 (qualifier) | off-chain (agent counts 2-of-3) | Quittance (shipped) |
| L1 | off-chain; chain logs proof | AgentPay Guard (code-verified) |
| L2.5 | on-chain address-collation (counts callers) | Concordia (code-verified) |
| 🔥 L3 (final-round) | ON-CHAIN signature verification of data-bound verdicts (atomic) | Quittance (SPEC-4) |
| L4 | L3 + verdicts bound to (asset, cycle) + replay protection |
Quittance (SPEC-4) |
The qualifier shipped at L0. The final-round campaign moves the quorum on-chain (SPEC-4): distribute() verifies each Ed25519 signature via env().verify_signature, counts valid distinct-verifier yes-votes, and reverts QuorumNotMet below threshold. The servicer key alone can no longer release funds — it must present ≥quorum valid signed yes-verdicts. This is the strongest on-chain verification in the finalist field (code-verified vs demo-simple competitors; Caspergard's repo 404 — unverifiable).
| SPEC | What it adds | Honest limit |
|---|---|---|
| SPEC-4 | On-chain Ed25519 signature verification (L3) — forged/replayed/unregistered sigs rejected by the chain | single-operator verifiers (demo) |
| SPEC-6 | On-chain per-verifier reputation (cycles_seen/voted/agreed) — the unique moat; maps to Casper example-#2 |
tracks settled cycles only — halted cycles don't score (no ground truth without settlement) |
| SPEC-1 | Queryable on-chain Receipt per (asset, cycle) via get_receipt |
new cycles only (no backfill) |
| SPEC-5 | Per-cycle AI verification brief — the agent explains the verified record on-chain | narration, not proof — the verifiable truth is the on-chain sigs + reputation |
| SPEC-2 | Real payment-rail adapter — one verifier reads Stripe test mode instead of a fixture | one of three verifiers; live e2e pending a test-mode key |
The property that makes the moat honest: the only way to accumulate cycles_agreed is to vote yes on a cycle that actually settles. A compromised verifier cannot inflate its reputation via a fraud cycle — the cycle halts, no update, no reward.
67% of the Casper Agentic Buildathon prize pool is x402 Ecosystem Credits. Quittance uses x402 natively for every verifier payment — real, per-call economic commitment, settled on Casper via the CSPR.cloud facilitator. Each of the three verifiers is paid per verdict over x402 (header PAYMENT-SIGNATURE); the settle txs are in the table below. This isn't a side feature — it's the payment rail the whole verification thesis runs on.
Casper's example-direction-#2: "RWA Oracle Agents with Verifiable On-Chain Identity and a reputation score based on historical accuracy." Quittance is that, built:
- ✅ Verifiable on-chain identity — verifiers are registered pubkeys in the vault's
verifier_registryfromregister_asset(SPEC-6). - ✅ Reputation score based on historical accuracy —
cycles_agreed/cycles_votedper verifier, queryable viaget_verifier_registry(SPEC-6). - ✅ RWA oracle agents — the autonomous servicer + three x402-paid verifiers for tokenized cashflow servicing (the RWA lane, uncontested in the field).
Both paths are real, executed, and verifiable on testnet.cspr.live. The agent uses the same vault and the same three verifiers for both cycles — only the consensus differs.
| Event | Path | Result | Transaction |
|---|---|---|---|
ServicerVault deployed |
— | entity 6a6747d2…b27e132 |
4313f749…1c4c9e |
| Qualifying x402 settle | — | first verifier payment | 6b03ad75…bf3cd4 |
| Distribute | ✅ Happy — 3/3 → quorum met | Holder A +7 / Holder B +3 CSPR (pro-rata) | 6821e0f3…c37829 |
| Verifier settle · v1 | 🛑 Fraud — 1/3 → quorum NOT met | agent paid, then halted | a02b1c7d…d6a7d |
| Verifier settle · v2 | 🛑 Fraud | agent paid, then halted | 40a85e53…75df93 |
| Verifier settle · v3 | 🛑 Fraud | agent paid, then halted | 8a962e50…4115ff |
The result that matters: in the fraud cycle one verifier lies "yes" while the two honest ones say "no." The agent still pays all three for verification (real money, on-chain) — and still refuses to release the cashflow on a single dishonest "yes." Holder balances stay unchanged; the agent's own funds never move into a distribution. You cannot bribe one verifier to unlock the money.
The final-round contract carries the full moat stack: on-chain Ed25519 signature verification (SPEC-4, L3), queryable receipts (SPEC-1), on-chain verifier reputation (SPEC-6), and the agentic verification brief (SPEC-5). Deployed as a fresh vault (servicer_vault_package_hash_v2) + proven on casper-test:
| Event | SPEC | Result | Transaction |
|---|---|---|---|
ServicerVault v2 deployed |
1/4/5/6 | entity 753a16ea…4d61d7 (337.69 CSPR install) |
66d3afb3…067c9 |
| register_asset(inv-001) | — | 3 verifiers, 2 holders, quorum 2 | 19adc747…96764 |
| fund pool (10 CSPR) | — | pool funded (re-funded for the full-x402 proof: 22db74f2…4fae4) |
4c8f877b…8383f |
| distribute (direct, L3 proof) | 4 | contract verified 3 TS-signed Ed25519 sigs ON-CHAIN → holders +7/+3 CSPR (8.51 CSPR gas) | e6fbfb83…66e68 |
| record_brief(happy) | 5 | AI verification brief stored on-chain | 1ff73ae2…4f618 |
Full agent→x402→distribute loop (proven on a fresh happy2 cycle, since happy was already distributed above): the agent pays 3 verifiers over x402 (real WCSPR settles), collects 3 signed yes-verdicts, and the contract verifies each signature on-chain + pays holders pro-rata — the complete rail, not a direct call.
| Event | SPEC | Result | Transaction |
|---|---|---|---|
| x402 settle · v1 (happy2) | — | real verifier payment | 939dba12…99c4 |
| x402 settle · v2 (happy2) | — | real verifier payment | e92a84ad…9ba66 |
| x402 settle · v3 (happy2) | — | real verifier payment | bab83f8e…a351a |
| distribute(happy2) | 4 | 3 x402-paid yes-verdicts → on-chain sig verify → holders +7/+3 CSPR | b94e0d4f…3d31c |
Fraud halt on v2 (1/3 → no quorum → funds withheld, holders unchanged):
| Event | Result | Transaction |
|---|---|---|
| x402 settle · v1 (fraud) | agent paid, v1 lied "yes" | 974544fa…ed6a |
| x402 settle · v2 (fraud) | agent paid, v2 honest "no" | f6726bd7…8c19 |
| x402 settle · v3 (fraud) | agent paid, v3 honest "no" | fac7e71e…2f3b2c |
| halt | 1/3 → QuorumNotMet → no distribute, holders unchanged |
(no distribute tx — that's the point) |
The cross-side proof that matters: the distribute txs prove the TS-side canonicalBytes signing (in the verifier, @noble/ed25519) is verified byte-for-byte by the Rust-side canonical_bytes reconstruction + env().verify_signature on the real Casper host — the one open e2e risk, closed. e6fbfb83 is the direct-distribute L3 proof; b94e0d4f is the full agent→x402→distribute proof. The qualifier table above is the L0 build (agent attests); the v2 tables are the L3 build (chain verifies).
| 🟢 Live dashboard | quittance.rectorspace.com — issuer view (asset + both cycle histories) |
| 👛 Holder view | quittance.rectorspace.com/holder — balances read live from chain (Holder A 21 CSPR · Holder B 9 CSPR — reflecting the v2 happy cycle's +7/+3 payout on top of prior demo cycles) |
| 🎬 Demo video | quittance.rectorspace.com/demo (~2 min) |
| Component | Responsibility | Stack |
|---|---|---|
ServicerVault |
Holds the native-CSPR distribution pool + holder registry; verifies each Ed25519 verdict signature on-chain (SPEC-4); records per-cycle receipts (SPEC-1) + per-verifier reputation (SPEC-6) + AI briefs (SPEC-5); exposes quorum-gated distribute(). |
Odra (Rust), Casper |
| Servicer agent | Runs the cycle: pays verifiers over x402, enforces the quorum, calls the contract through stable adapter seams, verifies finality. | TypeScript, casper-js-sdk v5 |
| Verifier services ×3 | Independent, x402-gated HTTP endpoints returning signed yes/no verdicts over evidence. | TypeScript / Express |
| Dashboard | Issuer config + holder view: cycle history, quorum stamps, live on-chain balances, every tx deep-linked to cspr.live. | Next.js 15, Vercel |
Casper-native by design: an Odra contract on casper-test, a native-CSPR pool with pro-rata transfers, x402 verifier payments settled via the CSPR.cloud facilitator, real Ed25519 Casper identities, and holder balances read live from chain.
quittance/
├── agent/ # autonomous servicer agent — runCycle state machine
├── packages/
│ ├── core/ # domain logic: verdict verification, quorum rules (framework-free)
│ └── adapters/ # chain + verifier client adapters (casper-js-sdk, x402)
├── contracts/ # ServicerVault — Odra (Rust) smart contract + wasm
├── verifiers/ # x402-gated verifier services (independent yes/no signers)
├── dashboard/ # Next.js dashboard (issuer + holder views), deployed on Vercel
├── e2e/ # end-to-end harness: deploy, fund, run-cycle, settle, check-balances
├── SPEC.md # design
├── PLAN.md # implementation plan
└── DAY1-DERISK.md # critical-path de-risk runbook
Prerequisites: Node ≥ 18, pnpm, and (for the contract) the Rust toolchain + cargo-odra.
pnpm install # install the workspace
pnpm --filter @quittance/core test # domain logic (verdict + quorum)
pnpm --filter @quittance/dashboard dev # dashboard at http://localhost:3000
pnpm --filter @quittance/dashboard test # dashboard unit testsContract build & tests:
cd contracts && cargo odra test # OdraVM unit testsEnd-to-end on casper-test (needs a funded testnet key — see .env.example):
node e2e/deploy-servicer.mjs submit # deploy the vault
node e2e/harness/run-cycle.mjs happy # quorum met → distribute
node e2e/harness/run-cycle.mjs fraud # quorum fails → haltFor the buildathon demo, the off-chain "cashflow arrived" evidence is mocked/sandboxed by default — the three verifiers stand in for real payment-rail adapters (bank APIs, Stripe, etc.). The innovation is the verification-gated autonomous release, not the data source. SPEC-2 (real-rail adapter) upgrades one verifier to read Stripe test mode (a real external API, sk_test_... — no real money) instead of a fixture: the verifier calls Stripe's payment_intents endpoint, confirms status: succeeded, and binds the verdict to the PI's metadata.reference. Conservative failure — any non-confirming path (API error, non-succeeded status, missing reference) → the verifier votes no (funds withheld). The codebase ships this adapter with full unit-test coverage (injectable fetch); the default demo config keeps all three verifiers on mocked fixtures for reproducibility, and the live e2e against Stripe test mode runs with a test-mode key. Testnet only: verifier payments use WCSPR via x402, holder distribution is native test CSPR; the payout token is a test asset, not a real stablecoin.
Three honest limits of the final-round campaign, disclosed plainly:
- Reputation tracks settled cycles only. A halted cycle (the fraud showcase) reverts before any state write, so it scores nothing — the contract cannot authoritatively establish ground truth without settlement. The clean side: a compromised verifier cannot inflate its reputation via a fraud cycle (the cycle halts, no update).
- The AI brief is narration, not proof. The LLM explains the cryptographically verified record; it never decides fund release (the quorum stays signature-based). A compromised agent could mislead a dashboard reader, but cannot move funds — the on-chain signatures + reputation remain the verifiable truth.
- Single-operator verifiers. All three run by one operator (RECTOR) for the demo. SPEC-4 (distinct keys) + SPEC-6 (transparent reputation) make collusion harder and visible, not operationally impossible. Genuine verifier independence + a staking/slashing marketplace are post-hackathon (see
ROADMAP.md).
MIT — © RECTOR-LABS.
Quittance · casper-test · verify, not attest
