Pre-funded USDT vouchers, accepted offline over a local P2P mesh, settled on-chain when connectivity returns.
Live on Sepolia · Quick start · Security model · Architecture deep-dive →
Signet lets people transact in stablecoins without internet, without a bank, and without a server — then anchors every payment to Ethereum the moment a connection reappears. Cryptography secures the money; an on-device AI makes it usable in any language.
📐 Want the full picture? The complete system design — flows, sequence diagrams, threat model and the double-spend proof — lives in
ARCHITECTURE.md.
Self-custodial stablecoin payments assume you are online. Billions of moments of commerce are not: a market stall when the tower is down, a bus with no signal, a village with intermittent data. Cash still wins there — and cash cannot be programmable money.
A buyer pre-funds a vault on-chain while they have connectivity. Offline, they hand a merchant a cryptographically signed voucher bound to that merchant and that exact bill. The merchant verifies it locally and accepts immediately — no network needed. A local Pears/Hyperswarm mesh replicates "seen" vouchers so a duplicate is caught early. When connectivity returns, the merchant redeems on-chain, where the vault's spent mapping is the final double-spend arbiter.
Signet does not claim offline blockchain finality. It provides bounded-risk offline acceptance backed by locked USDT and deferred on-chain settlement.
🎙️ QVAC 🖋️ Voucher core 📡 Pears mesh ⛓️ VoucherVault
speech/text ─────▶ create · sign · verify ─▶ transport + "seen" ─▶ deposit · redeem
→ invoice (EIP-191, offline) replication (offline) spent[] = finality
(on-device AI) early double-spend (Ethereum)
warning
| Layer | File | Role |
|---|---|---|
| Accessibility | qvac/invoice.js, qvac/qvac-adapter.js |
Turns natural, local-language speech ("one coffee, one USDT") into a structured invoice, fully on-device. Pluggable engine — the real QVAC SDK drops in with one call. |
| Voucher core | shared/voucher.js |
Create, sign (EIP-191) and verify single-use vouchers bound to (merchant, invoiceHash). Fully offline. |
| Mesh | peer/mesh.js |
Serverless device-to-device transport over Pears/Hyperswarm + replication of the local seen set for offline double-spend warning. |
| Settlement | contracts/VoucherVault.sol |
Buyers lock USDT; merchants redeem signed vouchers. spent[voucherId] is the final arbiter — first redeem wins, every later one reverts. |
| Bridge + UI | bridge/server.js, web/ |
A Node bridge runs the real mesh peers, crypto and settlement, then streams live events over WebSocket to a Vite/React interface. The UI is a window onto the real system — nothing is faked. |
This is the overview. For the full flow, sequence diagrams, message protocol, threat model and the double-spend proof, read
ARCHITECTURE.md.
Both contracts are deployed and source-verified on Sepolia. A real voucher was redeemed on-chain, and a second redeem of the same voucher reverted — the double-spend guarantee, proven publicly.
| Address | ||
|---|---|---|
| VoucherVault | 0xa194A96F6812C153F71B2448C937BB9454ad1614 |
verified source ↗ |
| MockUSDT | 0x509e7C1758ba12C6907f93D4ee6458b6DEB8353C |
verified source ↗ |
| Redeem proof | tx 0x6776cd7d…f5f21 |
view on Etherscan ↗ |
Full deployment record: deployments.json.
Requirements: Node ≥ 20.6, Foundry (anvil, forge).
npm install
npm run build:contracts # forge build -> out/
npm test # 15/15: voucher core + QVACnpm run signet # local anvil: online lock -> offline mesh -> on-chain settleExpected arc:
🌐 ONLINE buyer locks 3 USDT in the VoucherVault
✈️ OFFLINE QVAC invoice -> signed voucher -> Merchant A ACCEPTS on the mesh
the SAME voucher at Merchant B -> REJECTED (mesh early-warning)
🌐 RECONNECT Merchant A redeems on-chain (real tx)
a second on-chain redeem -> REVERTED "already spent"
Create .env (never commit it — it's git-ignored):
RPC_URL=https://ethereum-sepolia-rpc.publicnode.com
PRIVATE_KEY=0x... # a funded Sepolia test wallet
ETHERSCAN_API_KEY=... # optional, for contract verificationnpm run signet:sepolia # unified demo on live Sepolia
npm run settle:sepolia # settlement-only, prints an Etherscan tx linknpm run demo # offline mesh only (accept + local double-spend reject)
npm run settle # on-chain settlement only (local anvil)
npm run test:voucher # voucher core (5)
npm run test:qvac # QVAC accessibility (10)- Money is secured by cryptography, not by the AI. QVAC only improves accessibility; it never holds keys or authorizes spend.
- Vouchers are single-use and bound to a specific merchant + invoice hash via an EIP-191 signature. A stolen or copied voucher cannot be redeemed elsewhere or against another bill.
- Offline acceptance is bounded-risk, backed by USDT locked on-chain. The mesh gives early warning of a double-spend.
- The chain is the final arbiter.
spent[voucherId]guarantees exactly one successful redeem; concurrent attempts resolve deterministically on-chain.
The accessibility layer runs on-device, zero cloud, so it works in airplane mode and keeps the "no server" guarantee. toInvoice() is engine-agnostic: today a deterministic multilingual parser (EN/TR/ES) backs it; register the real QVAC SDK with setEngine() / useQvac() and nothing else changes.
contracts/ VoucherVault.sol · MockUSDT.sol
shared/ voucher.js (+ tests)
qvac/ invoice.js · qvac-adapter.js (+ tests)
peer/ mesh.js (Pears/Hyperswarm)
app/ signet.js (unified demo) · demo.js (offline only)
scripts/ settle.js (on-chain settlement, any RPC)
bridge/ server.js (live WebSocket bridge to the real system)
web/ Vite/React UI (a live window onto the bridge)
deploy/ nginx.conf · systemd unit for hosting the bridge
A full breakdown of every module, the wire protocol and the settlement math is in
ARCHITECTURE.md.
No bank. No server. No cloud AI. Connectivity can vanish; commerce need not.
