Pay in USDT when the buyer has no signal.
The payer signs on their phone offline. The merchant settles on Ethereum when they are back online. Funds stay in self-custodial USDT on Ethereum mainnet — keys never leave the device.
Live demo · Wallet · Env · Cloud backup · Roadmap
A Spanish-language PWA for self-custodial USDT on Ethereum. Payments do not wait on the buyer’s data connection: they authorize a spend with an EIP-712 signature, hand it over in person (QR, NFC, Bluetooth, sound, light, file, or copy), and the merchant broadcasts it later.
Settlement is always Tether USD (USDT) on Ethereum mainnet. There is no ARS token on-chain. Local currency in the UI is a live FX reference.
The lulox.eth shop is the live demo catalog (1–2 USDT items).
Buyer (maybe airplane mode) Merchant (needs the network)
───────────────────────────── ────────────────────────────
1. Sign Permit2 EIP-712
2. Hand over the envelope ─────────► 3. permitTransferFrom()
USDT moves on-chain
Signing is not a transfer. Mainnet USDT is a classic ERC-20. It does not implement ERC-2612 permit(), so Walinox uses Uniswap Permit2 instead:
- Once per wallet:
approvePermit2 (0x000000000022D473030F116dDEE9F6B43aC78BA3). - Each offline spend: sign
PermitTransferFrom(signature transfer). - The merchant (or any online party) calls
permitTransferFrom— that is when USDT actually moves.
Online sends can skip the envelope and call ERC-20 transfer directly.
| Channel | Role |
|---|---|
| QR | Default in-person path |
| Copy / file | Always available |
| NFC / sound / light / Bluetooth | Same signed envelope, different air |
After the first PWA load, a buyer can pay in airplane mode.
Walinox is built on Tether’s current client-side kits — not a custodial Tether account.
| Piece | What Walinox uses | Docs |
|---|---|---|
| USDT | Ethereum mainnet ERC-20 settlement | tether.io · token |
| WDK | Local non-custodial wallet (@tetherto/wdk, @tetherto/wdk-wallet-evm) |
About WDK · Get started |
| EIP-7702 gasless | Pay gas in USDT via @tetherto/wdk-wallet-evm-7702-gasless (Candide bundler). If that fails, the EOA needs ETH. |
EIP-7702 · WDK module · package |
| QVAC | “En una frase” form fill. Tries on-device Qwen3 0.6B Instruct Q4 (Ajustes download) when @qvac/sdk can load, else /api/agent, else heuristic. Official SDK runtimes are Node / Bare / Expo — not a Chrome PWA. |
qvac.tether.io |
| MoonPay | Fiat → USDT on-ramp (Tether WDK’s documented fiat rail) | MoonPay |
The seed stays on the device (PIN-encrypted). Tether does not custody keys. Walinox never stores the seed on the server.
| Primitive | Why it is here |
|---|---|
| ERC-20 | USDT transfers |
| EIP-712 | Typed signatures for Permit2, terms of use, and vales |
| ERC-2612 | Not used — mainnet USDT has no permit() |
| Uniswap Permit2 | Signed spends that work for any ERC-20 |
| EIP-7702 / ERC-4337 | Optional gasless path (paymaster takes USDT) |
| ENS | Names like lulox.eth as pay-to addresses |
Injected wallets (MetaMask, Rabby, Rainbow, …) connect through RainbowKit + wagmi on Ethereum mainnet.
- P2P / B2B — send, receive, request, pay (scan a signed envelope).
- B2C / Shop — seller catalog, POS checkout, collect over every offline channel.
- Wallet — on-chain USDT balance, on-ramp, receive, send, pay.
- Contacts, inbox, activity, settings — PIN / biometrics, theme, seed backup (local wallet).
Deferred (public storefront URL, vouchers as a marketplace, monthly reports, USDT → ARS off-ramp): roadmap.
Node 22.17+.
npm install
npm test
npm run build
npm startEnvironment variables: docs/env.md. How users get a wallet: docs/wallet.md. Multi-device app data (never the seed): database.md.
- Local seed is PIN-encrypted on the device. There is no cloud recovery of the 12 words.
- Durable web push on Vercel needs a durable store in production.
- The public Candide bundler is rate-limited; gasless can fall back to an ETH-paying EOA.
- MoonPay on-ramp needs
NEXT_PUBLIC_MOONPAY_API_KEY. ARS off-ramp is still roadmap.