▶ Try it live: egavel.vercel.app
A non-custodial auction platform built on Cashu e-cash.
Bids are locked with a 2-of-3 P2PK lock — the seller, the auction server, and the bidder each hold one key, and no one can move the funds without two signatures. The bid amount is a maximum; the engine bids automatically (second-price / proxy bidding) at the second-highest max plus the minimum increment. The winner pays only the standing price, and outbid bids are refunded instantly. After settlement the seller claims once and the proceeds land directly in their wallet — no waiting, no extra steps for the buyer.
- Proxy bidding (second price) — the entered amount is a maximum. The engine bids just enough to stay in the lead, and the winner pays only the standing price.
- 2-of-3 non-custodial bids — no single party (including the server) can move the funds alone.
- Instant outbid refunds — the moment a higher bid arrives, the losing bid's funds return to the wallet automatically.
- Direct settlement — one click after the auction ends moves the proceeds straight into the seller's wallet. A winner-protected fulfillment escrow (
{seller+winner+server}2-of-3 with a 14-day timeout) is implemented in the codebase behind an opt-in flag for a future mode. - Anti-sniping / Reserve / Buy Now / Watchlist — standard auction features.
- Nostr-linked identity — a Nostr key (NIP-07 extension or nsec) is linked to the trading key via a signed NIP-98 event; linking is required to list and to bid, and the link is permanent. The seller is public (their npub links to nostr.at); the winner stays anonymous publicly and is revealed only to the seller (and themselves) after settlement.
- NIP-99 marketplace mirror — listings are published as kind
30402addressable events (d=egavel-<id>) to Nostr relays for discovery (server-enforced —POST /auctionsrequiresid+ signed30402withd=egavel-<id>; no listing can exist without a valid mirror, even via direct API). Tags carrytitle/summary/price/image/r/expirationplus customreserve/buy_now/auction:start|end. Deletion publishes kind5. View on Nostr vianaddr(nostr.at). - Blossom image hosting (NIP-B7) — images are uploaded via Blossom (
kind 24242auth,PUT /upload) toblossom.primal.net(fallbackcdn.nostrcheck.me). The DB stores only URLs; base64 inline is capped at 4 images / 2 MB. - Public audit log — bids publish hash + standing price as kind
1021; escrow transitions (shipped/confirmed/released/refunded) publish kind1022with[status]tags. Fire-and-forget, never on the critical path. - NUT-13 deterministic wallet — every ecash output derives from your 12-word recovery phrase, so restoring the phrase on another device automatically recovers your balance (no mint URL needed).
- Multi-mint wallet — receive Cashu tokens from any mint, view combined balances, and withdraw per mint (token or Lightning).
- Zero platform fee — the operator takes no cut (
AUCTION_FEE_BPSdefaults to 0).
- Node.js 24+ / pnpm 11+
- For testing: testnut.cashu.space (test Cashu mint; invoices are auto-paid in a few seconds)
pnpm installGenerate a server signing key (the server's key in the 2-of-3 lock):
openssl rand -hex 32Write apps/server/.env (see apps/server/.env.example):
SERVER_PRIVATE_KEY=<64-char hex> # server signing key generated above
PORT=3001
DB_PATH=data/auction.db
AUCTION_FEE_BPS=0 # seller fee (0 = free marketplace; 500 = 5%)pnpm dev # server :3001 / web :3000- Open
http://localhost:3000 - On first visit, save the 12-word recovery phrase shown to you
- Create Listing — the mint is fixed by the app config (dev builds use the testnet mint
testnut.cashu.space) - Use Get Sats on the detail page to get test sats
- Place Bid with a maximum — watch the standing price rise automatically, and see outbid bids refund instantly
The server suite runs fully offline (in-memory SQLite, no mint needed); the web suite covers the pure logic modules.
pnpm --filter @egavel/server test
pnpm --filter @egavel/web exec vitest run- How it works (for the Cashu community):
docs/how-it-works.md - Technical architecture (P2PK lock structure, state machine, API flows):
docs/technical-architecture.md - Security & threat model:
docs/security.md
- NUT-11 — P2PK — the 2-of-3 lock for bids and the fulfillment escrow
- NUT-13 — Deterministic Secrets — 12-word phrase → ecash outputs (balance recovery)
- NIP-07 —
window.nostrCapabilities — browser extension signing - NIP-98 — HTTP Auth — trading ↔ Nostr link (
link:<pubkey>) - NIP-99 — Classified Listings — kind
30402marketplace mirror (d=egavel-<id>) - Blossom — Content-Addressed Storage —
kind 24242auth +PUT /uploadfor images (NIP-B7)
MIT