You are building a minimal demo web app for the Wraith Protocol stealth address SDK. This app shows developers how to integrate stealth payments using @wraith-protocol/sdk directly — no agent platform, no API keys, no backend.
A single-page app with two functions: Send and Receive stealth payments. Supports four chains: Horizen (EVM), Stellar, Solana, and CKB (Nervos). A dropdown chain selector in the header switches between them.
This is NOT a full product. It's a reference implementation that developers study to understand how the SDK works in a real app.
reference/horizen-web/— Working Horizen stealth transfer web app (wagmi + RainbowKit)reference/stellar-web/— Working Stellar stealth transfer web app (Freighter)reference/sdk-src/— The SDK source code to understand exact imports and typesreference/docs/— Implementation specs
Read the reference web apps to understand the existing UX patterns. The demo should combine both into one unified app.
- Vite + React 19 + TypeScript
- Tailwind CSS (dark monochrome design system)
- wagmi v2 + RainbowKit (EVM wallet connection)
- @stellar/freighter-api (Stellar wallet connection)
- @solana/web3.js (Solana via Phantom browser wallet)
- @noble/curves + @noble/hashes (ed25519 primitives for Solana/CKB stealth)
- @wraith-protocol/sdk (installed from npm)
- React Router (two routes: /send and /receive)
Same dark palette as all Wraith products:
| Token | Hex |
|---|---|
| surface | #0e0e0e |
| surface-container | #141414 |
| surface-bright | #1a1a1a |
| primary | #c6c6c7 |
| on-surface | #e6e1e5 |
| on-surface-variant | #c4c7c5 |
| outline | #767575 |
| outline-variant | #444444 |
| error | #ee7d77 |
| tertiary | #22c55e |
Fonts: Space Grotesk (headings), Inter (body), JetBrains Mono (code/mono). No border radius anywhere. Sharp corners.
The UI should be minimal and clean — not a dashboard, not flashy. Think: a developer tool demo page. Generous whitespace, clear labels, code-like presentation of addresses and keys.
- Wraith logo + "WRAITH DEMO" text
- Chain switcher: dropdown selector — Horizen, Stellar, Solana, CKB.
- Wallet connect button: RainbowKit when Horizen, Freighter when Stellar, Phantom when Solana, manual key input label when CKB.
- Nav links: Send | Receive
Horizen (EVM) mode:
- Recipient meta-address input (
st:eth:0x...or.wraithname) - Amount input (ETH)
- "Send" button
- On click:
- If .wraith name: use
buildResolveNameto get meta-address (or resolve via publicClient.call) - Use
buildSendStealth()from SDK — returns{ transaction, stealthAddress, ephemeralPubKey, viewTag } - Submit transaction via wagmi's
useSendTransaction
- If .wraith name: use
- Show result: stealth address, tx hash with explorer link
Stellar mode:
- Recipient meta-address input (
st:xlm:...) - Amount input (XLM)
- "Send" button
- On click:
- Use
generateStealthAddress()from SDK - Build Stellar
createAccounttransaction - Sign with Freighter
- Submit to Horizon
- Call Soroban announcer contract
- Use
- Show result: stealth address (G...), tx hash
Solana mode:
- Recipient meta-address input (
st:sol:...) - Amount input (SOL)
- "Send" button
- On click:
- Use
generateStealthAddress()from local stealth lib - Build Solana
SystemProgram.transfertransaction - Sign with Phantom
- Submit to Solana Devnet
- Use
- Show result: stealth address (base58), tx signature
CKB mode:
- Recipient meta-address input (
st:ckb:...) - Amount input (CKB)
- "Generate Stealth Cell" button
- On click:
- Use
generateStealthAddress()from local stealth lib - Show stealth address, lockArgs (ephemeral pubkey + view tag + stealth pubkey)
- User creates the Cell manually (CKB wallet integration pending)
- Use
- Show result: stealth address, lockArgs, ephemeral pubkey, view tag
All chains:
- "Derive Keys" button — signs the STEALTH_SIGNING_MESSAGE with connected wallet
- Shows the user's stealth meta-address (copyable)
- "Scan for Payments" button — calls
fetchAnnouncements()/scanStealthCells() - Shows list of detected stealth payments with balances
- Each payment has a "Withdraw" button
- Withdraw: enter destination address, sends funds out
Horizen withdraw:
- Derive stealth private key from matched announcement
- Use
privateKeyToAccount()+sendTransaction()via viem - Show tx hash with explorer link
Stellar withdraw:
- Derive stealth private scalar from matched announcement
- Build payment transaction, sign with
signStellarTransaction() - Submit to Horizon
- Show tx hash
Solana withdraw:
- Derive stealth private scalar from matched announcement
- Build Solana transfer, sign with
signSolanaTransaction() - Submit to Solana Devnet
- Show tx signature
CKB withdraw:
- Derive stealth private scalar from matched stealth cell
- Show private key for manual withdrawal via ckb-cli
- CKB wallet integration pending
The demo uses the SDK for EVM and Stellar, with local implementations for Solana and CKB:
// EVM
import {
deriveStealthKeys,
generateStealthAddress,
scanAnnouncements,
fetchAnnouncements,
buildSendStealth,
buildRegisterMetaAddress,
getDeployment,
STEALTH_SIGNING_MESSAGE,
SCHEME_ID,
} from '@wraith-protocol/sdk/chains/evm';
// Stellar
import {
deriveStealthKeys,
generateStealthAddress,
scanAnnouncements,
fetchAnnouncements,
getDeployment,
STEALTH_SIGNING_MESSAGE,
SCHEME_ID,
bytesToHex,
} from '@wraith-protocol/sdk/chains/stellar';
// Solana (local primitives — SDK module planned)
import {
deriveStealthKeys,
generateStealthAddress,
scanAnnouncements,
signSolanaTransaction,
STEALTH_SIGNING_MESSAGE,
encodeStealthMetaAddress,
decodeStealthMetaAddress,
} from '@/lib/solana-stealth';
// CKB (local primitives — SDK module planned)
import {
deriveStealthKeys,
generateStealthAddress,
scanStealthCells,
STEALTH_SIGNING_MESSAGE,
encodeStealthMetaAddress,
decodeStealthMetaAddress,
} from '@/lib/ckb-stealth';Commit after each step. Push after each step.
- Vite + React + TypeScript project
- Tailwind with design system colors
- package.json with
@wraith-protocol/sdk,wagmi,@rainbow-me/rainbowkit,@stellar/freighter-api,viem,@tanstack/react-query,react-router-dom - Prettier, commitlint, husky, CI workflow
- Google Fonts (Inter, Space Grotesk, JetBrains Mono)
- index.html with proper title and meta
- README.md
- CLAUDE.md committed
- Header with logo, chain switcher, wallet connect, nav
- Chain context: stores active chain ("horizen" | "stellar" | "solana" | "ckb")
- Wallet providers: RainbowKit for EVM, Freighter for Stellar, Phantom for Solana
- wagmi config with Horizen testnet chain
- Only show the relevant wallet button for the active chain
- Two routes:
/sendand/receive
- Meta-address input
- Amount input
- Build transaction with
buildSendStealth() - Submit via wagmi
useSendTransactionoruseWriteContract - Show stealth address + tx result
- Error handling
- Meta-address input
- Amount input
- Generate stealth address with SDK
- Build Stellar transaction (createAccount)
- Sign with Freighter
- Submit to Horizon
- Announce via Soroban
- Show result
- Derive keys button (sign with wallet via wagmi)
- Show meta-address
- Scan button:
fetchAnnouncements("horizen")+scanAnnouncements() - List payments with balances (fetch via viem publicClient)
- Withdraw: derive stealth private key, send funds to destination
- Derive keys button (sign with Freighter)
- Show meta-address
- Scan button:
fetchAnnouncements("stellar")+scanAnnouncements() - List payments with balances (fetch from Horizon)
- Withdraw: derive scalar, sign tx, submit
demo/
package.json
vite.config.ts
tsconfig.json
tailwind.config.ts
index.html
.prettierrc
.github/workflows/ci.yml
README.md
CLAUDE.md
src/
main.tsx
App.tsx
index.css
config.ts — wagmi config, chain definitions
context/
ChainContext.tsx — active chain state
components/
Header.tsx — logo, chain switcher, wallet, nav
ChainSwitcher.tsx — 4-chain dropdown selector
WalletConnect.tsx — conditional wallet per chain
HorizenSend.tsx — Horizen EVM send
HorizenReceive.tsx — Horizen EVM receive
StellarSend.tsx — Stellar send
StellarReceive.tsx — Stellar receive
SolanaSend.tsx — Solana send (Phantom)
SolanaReceive.tsx — Solana receive (Phantom)
CkbSend.tsx — CKB send (stealth cell generation)
CkbReceive.tsx — CKB receive (manual key input)
lib/
explorer.ts — explorer URL helpers (all 4 chains)
solana-stealth.ts — ed25519 stealth primitives for Solana
ckb-stealth.ts — ed25519 stealth primitives for CKB
pages/
Send.tsx — unified send page, switches by chain
Receive.tsx — unified receive page, switches by chain
reference/ — DO NOT MODIFY
- NEVER add Co-Authored-By lines to commits
- NEVER commit, modify, or delete anything in the reference/ folder — it is gitignored and read-only
- NEVER add numbered step comments in code
- All commit messages MUST follow conventional commits format
- Commit and push after each completed step
- Use
@wraith-protocol/sdkfrom npm — do NOT copy SDK code - Use the exact design system colors
- Keep it minimal — this is a demo, not a product
- No backend, no API keys, no agent client — pure SDK usage
- Show code-like presentation of addresses (font-mono, truncation, copy buttons)