Skip to content

RECTOR-LABS/quittance

Repository files navigation

Quittance — verify, not attest

Live demo Demo video Casper testnet Odra MIT

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 arrivedverification, 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.


Contents


The problem

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.

The insight: verify, not attest

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.

How it works

Each cycle, the autonomous servicer agent:

  1. Detects a cycle is due for a tokenized asset.
  2. Pays three independent verifiers over x402 to answer: "did the cashflow arrive?" — real, per-call economic commitment, settled on Casper.
  3. Requires a 2-of-3 quorum of signed yes/no verdicts.
  4. 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.
  5. If nothalts, 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

The demonstrable moment

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 →

The depth ladder — where the quorum is enforced

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).

The moat stack

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.

x402 — native, not bolted on

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 example-direction-#2

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_registry from register_asset (SPEC-6).
  • Reputation score based on historical accuracycycles_agreed / cycles_voted per verifier, queryable via get_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).

Proven on-chain (casper-test)

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.

Final-round v2 (SPEC-1/4/5/6 — the campaign contract)

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).

See it live

🟢 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)

Architecture

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.

Repository layout

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

Run it locally

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 tests

Contract build & tests:

cd contracts && cargo odra test                # OdraVM unit tests

End-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 → halt

Honesty & disclosure

For 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).

License

MIT — © RECTOR-LABS.

Quittance · casper-test · verify, not attest

Releases

No releases published

Packages

 
 
 

Contributors