Skip to content

Architecture

GhostDeal is a private dapp: the wallet holds the keys, the app asks it to act, a small Cairo helper is the deal logic.

That is the STRK20 Wallet API route: no proving backend, no custody of notes, no viewing keys in the app.

Stack

flowchart TB
  subgraph ui ["GhostDeal PWA"]
    A["Listings, QR, Pay, Claim"]
  end
  subgraph wallet ["Privacy wallet"]
    B["Wallet API 0.10.3+"]
    C["Viewing keys stay here"]
  end
  subgraph chain ["Starknet"]
    D["STRK20 privacy pool"]
    E["GhostDeal privacy_invoke helper"]
  end
  A --> B
  B --> D
  D --> E
Layer What it is in this repo
UI Next.js 16 PWA (src/app/)
Wallet starknet.js 10, get-starknet discovery 6. Connect on desktop via the injected picker. Connect on phone inside the wallet's in-app browser. Wallet API >= 0.10.3
Actions strk20InvokeTransaction in src/lib/escrow.ts
Helper Cairo privacy_invoke escrow in cairo/
Private swaps AVNU's deployed executor for shielded STRK ↔ USDC, quoted from AVNU's public API and batched in src/lib/avnu.ts
Pool Official STRK20 pool on Mainnet and Sepolia. Addresses live in src/utils/constants.ts

What the helper does

The pool calls privacy_invoke on our contract in the same private transaction as the token movement.

Op Job
Deposit Lock token + amount against the seller claimHash, store the buyer refundHash, closed = false
Claim Seller proves the claim secret. Close the commitment. Return an OpenNoteDeposit so the pool credits the seller
Cancel Buyer proves the refund secret. Same shape as claim, funds return as a private note

The helper has no admin key, no upgrade, and no owner functions. Only the pool pinned at construction can call privacy_invoke.

Token roles

Listings can be priced in USDC or STRK. Pool fees are always STRK.

Token Primary Role Rationale
USDC Listing price (native Circle USDC, 6 decimals) Price stability between listing and meetup. Pay on-chain supports it.
STRK Listing price or gas / pool fees Native Starknet fuel. STRK listings pay in shielded STRK. USDC listings still need shielded STRK for the pool fee.

Token-agnostic escrow

The Cairo helper (cairo/src/lib.cairo) stores token: ContractAddress and amount: u256. Pay in this dapp supports STRK and native Circle USDC only (src/lib/escrow.ts).

Account

/account is where the connected user preps their own shielded funds. It never shows a counterparty balance.

  • Show balance asks the wallet once for STRK and USDC (strk20Balances). A token with no notes shows 0. Switching chips reuses that read (src/app/account/page.tsx, readShieldedBalances in src/lib/escrow.ts).
  • Shield / Unshield deposit or withdraw the selected token through the wallet.
  • Convert quotes and submits a private STRK ↔ USDC swap through AVNU. The pool fee is charged in shielded STRK.

Shared listings

Listings are off-chain. With UPSTASH_REDIS_REST_URL and UPSTASH_REDIS_REST_TOKEN, the catalog is shared across phones (src/lib/marketplaceRedis.ts); Pay, cash out, and cancel patch the status (open, locked, or released).

Networks and addresses

Addresses live in src/utils/constants.ts.

  • STRK20 pool Mainnet: 0x040337b1af3c663e86e333bab5a4b28da8d4652a15a69beee2b677776ffe812a
  • STRK20 pool Sepolia: 0x0254a6b2997ef52e9f830ce1f543f6b29768295e8d17e2267d672c552cfe0d91
  • GhostDeal helper Mainnet: 0x1ad47d7b59f736383221af3847aeb737d358e0c2cce947482ca48dad6c4ca72
  • GhostDeal helper Sepolia: 0x2fe8c2bc2194ccdf899c0566057217a34e139c0c5e6f7931f2b24cb436a22cf