An SDK for private commerce. Two payment modes. Zero-knowledge loyalty. No hosted infrastructure.
Agora is an npm package (agora-protocol) that gives AI agents private payments and anonymous loyalty proofs. Agents install it, plan a payment, and execute it in one of two modes: stealth (recipient privacy) or Railgun (full sender + recipient privacy). Merchants never see the buyer. The buyer never touches raw cryptography.
Merchants reward repeat customers via ZK loyalty proofs — no customer database, no tracking, no data liability. Receipts are EdDSA-signed by the merchant and verified in-circuit.
Built for The Synthesis hackathon. Visual explainer →
Buyer Agent Merchant Agent
| |
|-- import { AgoraExecutor, planAgoraRecipe } from "agora-protocol"
| |
|-- 1. Discover merchant via ERC-8004 registry --------------->|
|<-- deal catalog (with stealthMetaAddress) -------------------|
| |
|-- 2. planAgoraRecipe({ token, amount, merchantMeta }) |
| (pure calldata — no side effects, no network) |
| |
|-- 3a. executeStealth(plan, walletClient) |
| OR |
|-- 3b. executeRailgun(plan, railgunConfig, walletClient) |
| |
| Stealth mode: |
| ERC20 transfer -> stealth address (recipient privacy) |
| |
| Railgun mode: |
| Railgun shielded pool -> Relay Adapt -> stealth address |
| (full sender + recipient privacy) |
| |
| Merchant scans announcements ---|
| with viewing key, detects pay |
| |
|-- 4. Pull encrypted receipt via GET /receipts/{ephPubKey} ---|
| (XChaCha20-Poly1305, same ECDH as stealth derivation) |
| |
|-- 5. ZK loyalty proof -----------------------------(on-chain verify)
| "I spent >= $500 at your |
| shop" — EdDSA-signed, |
| no identity revealed |
Two modes, one planner. Both stealth and Railgun paths use the same planAgoraRecipe() to generate calldata, the same stealth address derivation, and the same on-chain contracts.
| Component | Location |
|---|---|
| LoyaltyVerifier | Arbitrum 0x2153...4eBd |
| MerchantRegistry | Arbitrum 0xc908...1DF2 |
| LoyaltyManager | Arbitrum 0x7E68...800e |
| Agent Identity | Base ERC-8004 #35295 (Synthesis participant fc01b9da) |
| On-chain proof | tx 0x7c525dc1... (EdDSA-signed Groth16 verified, 326k gas) |
| Stealth payment | tx 0x86709... (USDC to stealth address, merchant scan confirmed) |
| Railgun shield | tx 0xf1921... (USDC shielded into Railgun pool for full privacy) |
| Source | github.com/vu1n/agora-protocol |
Stealth mode (default): Agent derives a one-time stealth address from the merchant's meta-address (ERC-5564) and sends ERC20 directly. Merchant scans with viewing key. Recipient privacy guaranteed. Sender visible on-chain.
Railgun mode (full privacy): Agent has Railgun engine initialized. SDK calls generateCrossContractCallsProof + populateProvedCrossContractCalls to route through shielded pool via Relay Adapt to stealth address. Full sender + recipient privacy.
Merchant serves receipts encrypted with XChaCha20-Poly1305 (AEAD) at GET /receipts/{ephemeralPubKey}. Key derived via ECDH with domain separation (keccak256(shared || "agora-receipt")). Only the buyer can decrypt. Tampered ciphertext throws. The SDK exports encryptReceipt and decryptReceipt helpers.
Buyers post "looking to buy X" from throwaway stealth-address-backed ERC-8004 identities. Fund one transaction, use once, discard.
| Use case | scopeCommitment | minTimestamp | Example |
|---|---|---|---|
| Per-merchant loyalty | hash(sellerId) |
0 (all time) |
"I spent >= $500 at your shop" |
| Time-bounded loyalty | hash(sellerId) |
now - 90 days |
"I spent >= $300 in the last quarter" |
| Intra-merchant category LTV | hash(categoryId) |
0 or bounded |
"I spent >= $400 on coffee at your shop" |
The scopeCommitment field determines the scope of the proof. For per-merchant proofs, it hashes the merchant's ID. For category proofs, it hashes a category identifier — each proof is against a single merchant's Merkle tree.
Merchants define what LTV means to them by requesting multiple proofs in parallel across the categories that matter to their business:
"Show me this buyer's spend on [coffee, brunch, breakfast] in the past 180 days"
→ Verify 3 proofs in parallel:
scopeCommitment=hash("coffee"), minTimestamp=now-180d, threshold=$200
scopeCommitment=hash("brunch"), minTimestamp=now-180d, threshold=$100
scopeCommitment=hash("breakfast"), minTimestamp=now-180d, threshold=$50
→ All 3 pass? → Premium tier. Offer 15% off.
This is more powerful than a single aggregate number because each merchant customizes their LTV formula. A coffee shop weights coffee spend. A restaurant weights dining categories. The buyer proves each scope independently — the merchant composes the results. No single proof needs to span multiple merchants' trees.
- EdDSA-signed receipts — each receipt is signed by the merchant (Baby Jubjub / Poseidon), verified in-circuit
- Merchant pubkey validated on-chain —
LoyaltyManagercross-checks proof's pubkey againstMerchantRegistry, preventing self-signing - Leaf uniqueness — pairwise index comparison prevents counting the same receipt twice
- Merkle root from registry — callers cannot supply their own root
- Nullifier replay prevention —
Poseidon(buyerSecret, merkleRoot), one proof per buyer per root version
Merchants advertise through their ERC-8004 agent registration:
{
"services": [
{ "type": "agora-deals", "endpoint": "https://shop.example/deals.json" },
{ "type": "agora-receipts", "endpoint": "https://shop.example/receipts" },
{ "type": "agora-skill", "endpoint": "https://github.com/vu1n/agora-protocol/blob/main/skill-buyer.md" }
]
}| Metric | Value |
|---|---|
| Circuit constraints | 82,510 non-linear (EdDSA-signed) |
| Proof generation (cold) | ~4-5s |
| Proof generation (cached) | 0ms |
| On-chain verification gas | ~326k |
| On-chain verification cost (Arbitrum) | ~$0.05-0.10 |
| Per-purchase on-chain cost | $0 (receipts stored locally) |
| Layer | Tool | Tests | Result |
|---|---|---|---|
| TypeScript unit + integration | bun test | 63 tests (stealth, recipe, proof-cache, executor, encryption, intents, receipt-server, railgun-helper, private-intent) | 63/63 pass |
| Solidity unit tests | Foundry | 9 tests with real EdDSA-signed Groth16 proofs | 9/9 pass |
| Stateful invariant fuzz | Foundry | 128k random call sequences, 3 invariants | 3/3 hold |
| Symbolic verification | Halmos | Nullifier reuse, root binding, access control, deactivation, count, scope | 6 proofs verified |
| Circuit adversarial | Circom/snarkjs | 10 negative inputs including EdDSA forgery | 10/10 rejected |
| Circuit static analysis | Circomspect | Full circuit | Clean |
| End-to-end | TypeScript | 20 assertions (stealth + EdDSA signing + on-chain) | 20/20 pass |
| Demo | TypeScript | 3 EdDSA-signed proof types verified on-chain | 3/3 pass |
| On-chain (Arbitrum mainnet) | cast/Foundry | Merchant registered + EdDSA proof verified | verificationCount: 1 |
agora/
circuits/
loyalty_verify.circom <- ZK circuit: EdDSA sigs + leaf uniqueness + time bounds
generate_test_witness.mjs <- EdDSA smoke test
negative_tests.mjs <- 10 adversarial tests (including signature forgery)
contracts/
src/
LoyaltyVerifier.sol <- auto-generated Groth16 verifier (82k constraints)
MerchantRegistry.sol <- agent ID -> EdDSA pubkey + Merkle root
LoyaltyManager.sol <- proof verification + nullifier + EdDSA key check
test/
LoyaltyManager.t.sol <- 9 unit tests with real EdDSA proofs
LoyaltyManager.invariant.t.sol <- stateful fuzz testing (128k calls)
LoyaltyManager.symbolic.t.sol <- Halmos symbolic verification
src/
prover.ts <- Poseidon Merkle tree + Groth16 proof gen (EdDSA witness)
proof-cache.ts <- pre-generates proofs for instant checkout
types.ts <- SpendReceipt with EdDSA sig, MerchantEdDSAKey
demo.ts <- 3 EdDSA-signed proof types verified on-chain
e2e.ts <- full stealth + EdDSA + on-chain integration test
receipt-server.ts <- reference merchant receipt server (Hono)
sdk/
index.ts <- SDK public surface
stealth.ts <- ERC-5564 stealth addresses + receipt encrypt/decrypt
recipe.ts <- payment + loyalty proof orchestration
executor.ts <- stealth + Railgun execution modes
bazaar.ts <- deal discovery via ERC-8004 agent cards
intents.ts <- stealth intents: throwaway identities for anonymous buyer discovery
private-intent.ts <- Railgun + stealth intents: fully anonymous buyer discovery
railgun-helper.ts <- convenience wrapper for Railgun engine init + wallet + provider
steps/
payment.ts <- stealth payment calldata
loyalty.ts <- ZK proof submission calldata
skill-buyer.md <- agent skill doc for buyers
skill-merchant.md <- agent skill doc for merchants
bun install
bun test # 63 TypeScript tests
cd contracts && forge test -vvv # 12 Foundry tests (9 unit + 3 invariant)
cd circuits && node negative_tests.mjs # 10 circuit tests (7 adversarial + 3 baselines)
anvil & npx tsx src/e2e.ts # 20-assertion E2E
anvil & npx tsx src/demo.ts # 3 EdDSA proof types- Buyer Skill — install SDK, pay privately, pull encrypted receipts, prove loyalty
- Merchant Skill — register with EdDSA key, publish deals, serve encrypted receipts, verify proofs
- Threat Model — adversary classes, attack vectors, privacy boundaries, trust assumptions
- npm publish — release
agora-protocolas a public package - Receipt revocation — ZK-compatible mechanism for handling refunds (sparse Merkle exclusion proofs or accumulator-based revocation)
- Agent: Agora (ERC-8004 identity on Base, agent #35295)
- Hackathon: The Synthesis
- Tracks: Private Agents Trusted Actions (Venice), Synthesis Open Track, Agents With Receipts (Protocol Labs)
- Built with: Circom, snarkjs, Foundry, Halmos, viem, @railgun-community/wallet, @noble/ciphers, TypeScript
- Model: Claude Opus 4.6 | Harness: Claude Code
MIT