Shade is a POC for a privacy-preserving settlement rail for autonomous AI-agent B2B commerce, built on Monad. It hides supplier relationships, order volumes, and pricing from public view using stealth addresses, a pseudonymous vault-and-relayer model, and hash-only invoice binding which keeps suppliers' identities and keys completely outside the LLM's reach. AI agents negotiate within hard-coded policy limits and see only opaque handles, quantities, and prices. Business relationships therefore remain hidden to privy eyes.
| Live Demo | https://ah-monad-space.vercel.app/ |
| Repository | https://github.com/kronzter/ah-monad |
| Network | Monad Testnet — Chain ID 10143 |
| Contracts | Verified on MonadVision and Monadscan |
| Contract | Address | Explorers |
|---|---|---|
Settlement |
0xe68c651f7d8e5a3c7cbafac6cc9e02d9ca454e7d |
MonadVision · Monadscan |
StealthAnnouncer (ERC-5564) |
0x41130b9916228b21e928bb582dd23cd20f630113 |
MonadVision · Monadscan |
MockPermitToken (sUSD, open mint, EIP-2612) |
0xed8ced876c7ecbf600d5b802b64af5682fdb9962 |
MonadVision · Monadscan |
Addresses are also in deployments/monad-testnet.json.
- Stealth addresses. Every payment goes to a fresh ERC-5564-style one-time address derived from the supplier's stealth meta-address. Two payments to the same supplier never look connected on-chain.
- Vault + relayer hide the sender. A vendor deposits once under a pseudonymous vault key. Each payment is an
EIP-712 signed intent that a single relayer submits and pays gas for, so
tx.fromis always the relayer and the tokenTransferisSettlement → one-time address(never the payer). The relayer cannot forge intents. - The LLM never holds the sensitive data. The vendor and supplier agents (LLMs) only see opaque handles,
quantities and prices (
{handle: "S1", qty: 200}). Supplier identities, meta-addresses, keys and payment history live in plain wallet code the model cannot reach, so a prompt injection has nothing to exfiltrate. Policy (known handles, price band, quantity cap, "pay only what the supplier accepted") is enforced in code. - Negotiation runs on explicit criteria, enforced in code. The supplier's pricing engine (volume tiers, a confidential margin floor, a scheduled concession curve, a 2% instant-on-chain-settlement lever, a round limit) decides accept / counter / reject and the numbers; the LLM only voices it. The buyer agent has a target, a hard ceiling, a max concession per round and a never-bid-above-their-ask rule, blocked by the tool, not by hope. The UI's deal room charts bids and asks converging and scores the deal against every criterion.
- Payments bind to invoices. The agreed invoice (qty, unit price, total, terms, nonce — no identities) is
hashed; both parties sign it off-chain; only the hash goes on-chain (
invoices[hash]), so an auditor can later reveal the JSON to prove a payment matches an agreement. - Monad throughput makes decoys real. Decoys are full fake payments through the same code path (random recipient, random invoice, in-range amount) fired concurrently with real ones. Real and decoy logs are identical, so a scraper sees one relayer paying strangers.
user ─NL─► Vendor agent (LLM: handles/qty/price only) ◄──► Supplier agent (LLM: own price sheet only)
│ tool call: settle(handle, qty, price) │ accepts terms
▼ ▼
VendorWallet (plain code) SupplierWallet (plain code)
registry · keys · policy · history view/spend keys · scan · countersign
│ signed EIP-712 intent ▲ finds its payments by view tag
▼ │
Relayer ── one tx.from, pays gas ──► Settlement ─► StealthAnnouncer (ERC-5564 events)
vault → one-time address
Requirements: Node 20+, pnpm, Foundry (only for contract tests), a Monad testnet key with some MON (faucets: see the Monad docs), and an LLM key (DeepSeek by default).
git clone https://github.com/kronzter/ah-monad && cd ah-monad
pnpm install
cp .env.example .env # set RELAYER_PKS (funded testnet key, >10 MON) and DEEPSEEK_API_KEY
pnpm dev # http://localhost:3000In the UI: I. Start the conversation (two LLM agents haggle live in a chat, then settle on-chain) → II. Fire burst (3 real payments among decoys) → III. Run injection (competitor tries to extract the supplier graph) → Declassify with supplier key in the ledger to see which rows only the supplier's view key can prove.
No UI? pnpm demo:agents runs negotiation + payment + supplier scan + injection in the terminal;
pnpm demo runs the decoy burst; pnpm latency measures single-payment latency.
Checks: pnpm test:contracts (8 Foundry tests), pnpm test (stealth crypto), pnpm typecheck, pnpm build.
Deploy your own copy: pnpm build:contracts && NETWORK=monad-testnet pnpm deploy:contracts, then
pnpm verify:contracts (publishes source to MonadVision and Monadscan through Monad's verification API).
npm i -g vercel@latest && vercel login
pnpm vercel:setup # link the folder to a Vercel project
pnpm vercel:env # copies NETWORK, RELAYER_PKS, DEEPSEEK_*, DEMO_SEED (and optional RPC_URL) from .env to production
pnpm deploy:vercel # production deploy, prints the URLDEMO_SEED must be set on Vercel: it makes the supplier and vault identities identical on every serverless
instance. The relayer key you set there pays testnet gas for anyone using the public demo, so use a
dedicated testnet-only key. Expensive routes are rate-limited and refuse bursts if the relayer drops below
MIN_RELAYER_MON.
| What | Result |
|---|---|
| One payment sent alone (send → receipt, 8 runs) | 364–978 ms, median 873 ms |
| Burst: 3 real + 50 decoys, one sender | 53/53 confirmed, all landed in 4–7 s across ~10 blocks |
| Burst per-tx latency | median 2.7–3.8 s: bounded by the shared public RPC (50 calls/s), not the chain |
| Ledger after a burst | 1 distinct tx.from, one-time recipients only; supplier view key proves only its own payments |
| Prompt injection (4 payloads, full context scanned) | 0 secret markers leaked |
Single payments are sub-second. Burst latency through a shared public RPC is not; a private RPC (RPC_URL)
improves it. We report both because the anonymity-set argument depends on volume, and we would rather show the
real numbers.
- Amounts are public. Decoys draw amounts from the same range as real payments, which blurs price×quantity fingerprints but does not remove them. Fixed-denomination payouts are on the roadmap.
- The vault key is a pseudonym, not anonymity. The intent signature is in calldata, so the vault key is recoverable and the initial deposit links a treasury to it once. The real fix is the shielded pool (roadmap).
- The relayer is trusted for liveness and censorship, not custody: it cannot forge intents or move vault funds.
- Supplier sweeps go into a pseudonymous supplier vault key, not a known wallet, because sweeping to a known wallet would link the payment to the supplier and undo the stealth address.
- This is a testnet demo with a mock token. Not audited.
KYC-gated fixed-denomination shielded pool for large transfers · viewing-key audit export for regulators · multi-relayer / private-RPC deployment · tool-abuse hardening tests for agents that hold payment authority.
contracts/ Foundry: Settlement, StealthAnnouncer, MockPermitToken + tests
lib/ ERC-5564 stealth crypto, EIP-712 intents, invoices, permits, chunked log reads
wallet/ VendorWallet / SupplierWallet: registry, keys, policy, history (no LLM imports)
relayer/ nonce manager, paced broadcast, shared receipt poller, decoy bursts
agents/ vendor / supplier / competitor agents (Vercel AI SDK, tool calling)
app/ Next.js UI + API routes (negotiate, burst, attack, ledger)
script/ deploy, verify, demos
deployments/ committed Monad testnet addresses
docs/ pitch script and launch kit
Built for Monad Blitz Mumbai V4. Scaffolded with monskills (see .monskills).