Skip to content

clatsonhacks/ShadePay

Repository files navigation

ShadePay — Private Nanopayments for Agents on Arc

Pay by the fraction. Settle the net. Reveal nothing.

An AI agent consumes a paid service and pays per request — value as small as a fraction of a cent — by signing tiny vouchers off-chain. Only the private net settles on-chain, in USDC on Arc, funded cross-chain via Circle CCTP. Built on a zero-knowledge shielded pool, so the individual payments are invisible and only an auditable receipt is revealed.

Nanopayments  •  Per-call streaming  •  ZK-private  •  Agent-native (x402)  •  Cross-chain USDC (CCTP)

Arc (Circle L1) · USDC-native gas · Groth16 / BN254 · EdDSA vouchers · Circle CCTP v2 · x402 · TypeScript + Solidity + Circom

Built for the Lepton Agents Hackathon · Canteen × Circle × Arc


The 60-second version

For as long as a payment couldn't be smaller than ~30¢ after fees, you couldn't sell a one-cent play or charge an agent per API call — you had to bundle a month and charge $10. Nanopayments remove the floor. But a transparent per-call loop leaks every payment. ShadePay gives you both: sub-cent, per-call payments that are also private, settled on Arc in USDC.

Two rails, one story:

BASE RAIL — StreamPay.sol      real native USDC per second, on-chain meter
                               open (fund cap) · pause/resume · withdraw · stop-with-refund
                               continuous authorization of a RATE, not a signature per tick

PRIVACY LAYER — shielded stream  vouchers off-chain, one ZK proof to settle the private NET
                                 (composes on top of the base rail — hides per-tick detail)
OPEN     agent locks a spending cap into a channel (real USDC — or private via the ZK layer)
STREAM   the on-chain meter accrues per second in real USDC; vouchers off-chain add privacy
SETTLE   service withdraws / stops (base) or submits the highest voucher (privacy)
RECLAIM  the agent is refunded the unspent tail — no funds can be stranded

The USDC backing the channel is bridged in from another chain (Base / Arbitrum) via Circle CCTP — so an agent pays for an Arc service with funds from anywhere.


It runs live on Arc testnet

Not a mock — deployed and settled on real Arc testnet (chainId 5042002).

Base rail — real per-second USDC (StreamPay)

Contract 0x469305823f9796f973363F48a508a47309B2D92c. Payer 0x20D3…1796, payee (distinct address) 0xdAE1…9970. Cap 0.005 USDC at $0.0001/sec, value-conservation invariant asserted on-chain from Withdrawn + Stopped events (payee_paid + payer_refund == deposit).

Step Real tx (on arcscan)
Open — fund 0.005 USDC as msg.value 0x8ec9165f…
Withdraw — mid-stream 0.0011 USDC → service 0xf1eb8d0f…
Pause · Resume · Stop 0x8070… · 0x9003… · 0x8ebc…
Stop paid: 0.0013 USDC → service, 0.0026 USDC refunded to agent (from Stopped event)

Total streamed to the service address: 0.0024 USDC over the run, verifiable on arcscan. Full run log: see docs/E2E_REAL_WORKFLOW.md.

Privacy layer — shielded net (agent-service)

Both ZK proofs verified on-chain by Arc's BN254 pairing precompiles:

What Transaction (on arcscan)
Open a payment channel (ZK proof) 0x6e87f408… — block 50,297,330
Settle 100 requests' net (ZK proof) 0xec66753c… — block 50,297,357

Cross-chain funding — real USDC via Circle CCTP

What Chain Transaction
Burn 5 USDC Base Sepolia 0x1d8cb919…
Mint ~4.995 USDC Arc testnet 0x8b7af5e6…

See it yourself

npm install
cd contracts/arc && forge build && cd ../..
npm run circuits:build:arc && npx tsx scripts/sync-arc-verifiers.ts

# the base real-USDC rail: agent streams real native USDC at ~$0.0001/sec on Arc,
# pauses, resumes, withdraws mid-stream, then stops with refund — every step
# settled on-chain in real value, with real tx hashes on arcscan:
npm run streampay-demo             # local anvil (real EVM)
npm run streampay-demo:arc         # REAL Arc testnet (real USDC, real hashes)

# the privacy layer on top: agent buys a service across 100 metered requests
# via ZK-shielded vouchers, then settles the private net with one proof:
npm run agent-service-demo         # local anvil (no funds needed)
npm run agent-service-demo:arc     # live on real Arc testnet
REQUESTS=1000 npm run agent-service-demo:arc     # scale to 1000 requests

# the literal cross-chain leg: burn USDC on Base Sepolia, mint on Arc via CCTP:
BASE_SEPOLIA_PRIVATE_KEY=0x…  npm run cctp-bridge:arc

streampay-demo is the honest base rail: real native USDC moves on-chain by the second at a sub-cent rate, with pause / resume / mid-stream withdraw / stop-and- refund, and a value-conservation invariant checked at the end (payee-paid + payer-refund == deposit). agent-service-demo sits on top: it prints, per request, the prompt the agent sent, the payment it authorized, and the service's response — then one shielded settlement for the whole session.


How it works

A unidirectional payment channel anchored to a shielded note:

  • Vouchers are just signatures. Each per-call payment is an EdDSA-Poseidon signature over {channelId, cumulative, seq}. The agent signs, the service verifies — no chain, no gas. Millions of ticks cost nothing.
  • The settle proof verifies the voucher in-circuit. stream_settle runs circomlib's EdDSAPoseidonVerifier on the payer's signature and bounds cumulative ≤ cap, so the service can never settle more than the agent signed, and value is conserved (payee + refund == cap).
  • Notes live in a shared shielded pool. Open/settle/reclaim mint ordinary shielded notes into ShieldedPool's O(log n) Merkle tree; recipients spend them later through the normal withdraw/transfer paths.
  • The channel is consumed exactly once — either settle or reclaim, never both — and the agent's input note nullifier is burned so it can't be reused.

The 8 named safety invariants (cap bound, forged-voucher rejection, value conservation, spend-once, timeout-reclaim, ASP-eligibility, receipt integrity) are each covered by a specific test — see docs/SHADE_STREAMS_STATUS.md.


Architecture

Layer Where Role
BN254 circuits circuits/*_bn254/, circuits/lib_bn254/ commitment + Merkle membership, in-circuit EdDSA voucher, value conservation
Proving library packages/proving/src/bn254/ TS-native witness + Groth16 proof → native uint256[] calldata (no Rust, no byte-packer)
Contracts contracts/arc/src/ ShieldedPool, StreamEscrow, NullifierRegistry, IncrementalMerkleTree, 7 verifiers
Voucher SDK + agents packages/sdk/src/{streams,agents,receipts}.ts sign/verify vouchers, PayerAgent/PayeeAgent, receipts
Chain client + CCTP packages/arc-actions/ ethers calls, CCTP config + real bridge
x402 + relayer apps/api/src/x402.ts, apps/relayer/src/stream-relayer.ts service gating + batched settlement

Everything security-critical is on-chain: proof verification (BN254 precompiles), nullifier spend-once, value conservation, Merkle append. The backend never sees a note secret or a private key.


Circle & Arc stack used

Need Primitive Status
Settlement chain, USDC gas Arc (chainId 5042002) ✅ deployed + settled live
Per-request payment trigger x402 apps/api/src/x402.ts
Cross-chain USDC funding Circle CCTP v2 ✅ real burn→attest→mint executed
Batched settlement on-Arc settleBatch ✅ (Circle Gateway gasless variant: documented seam)
Agent wallets / identity EdDSA voucher keys + EVM wallets

Repository layout

circuits/              Circom circuits — *_bn254 (Arc) + originals (Stellar)
contracts/arc/         Solidity: ShieldedPool, StreamEscrow, verifiers + Foundry tests
packages/
  proving/src/bn254/   TS-native BN254 proving (Poseidon, Merkle, coins, proofs)
  sdk/src/             voucher SDK, agents, receipts (browser-safe)
  arc-actions/         ethers chain client + CCTP config/bridge + demos
apps/
  api/src/x402.ts      x402 voucher-gated service middleware
  relayer/src/         streaming relayer (batched channel closes)
docs/                  SHADE_STREAMS.md (full overview), status + design docs

Documentation


Honest status

Real & verified on-chain: the BN254 ZK layer, every settlement path (deposit/withdraw/transfer/MPC/RFQ/CCTP-exit), the streaming payment channel (open/stream/settle/reclaim/batch), x402 gating, the agent layer, receipts, deployment on real Arc testnet, and a real cross-chain CCTP transfer. 210+ automated checks pass.

Documented seams (external infra, not code gaps): Circle Gateway gasless batching (needs Gateway endpoints), using the actual CCTP-minted Arc USDC in the pool (a config change vs. the demo's mock token), and deny-set compliance (needs the exclusion circuit). Each is called out where it lives.

Testnet only. Not audited. Do not use with real funds. This is a hackathon build demonstrating a working private-nanopayments stack on Arc.

About

No description, website, or topics provided.

Resources

Stars

Watchers

Forks

Releases

Packages

Contributors

Languages