jwinterm 4fae5cfad0 fix(popup): client-side returning-user PoW bypass + remove premature doge
Two popup-side fixes for the SW jobs landing in 690bdfe. Originally
shipped as separate fix commits; squashed for a coherent history
before v0.3.0 release.

1. Skip client-side PoW solve for returning wallets
   ---------------------------------------------------
   `checkRestore` already tells us whether the wallet is known. The
   backend's `is_returning_user` check uses the same predicate to
   bypass PoW verification even when POW_REQUIRED=true (see
   smirk-backend's src/api/auth.rs). Without this fix the client was
   burning ~3-5s of PBKDF2 on every lock+unlock and every existing-
   wallet import for a solution the server immediately discarded.

   Mirror the bypass in two places — `@smirk/core::bootstrapAuth`
   (benefits desktop) and the extension's bootstrap-auth SW handler.
   Same isKnownWallet flag drives both.

   New wallets still solve — the Sybil gate keeps doing its job.

2. Stop showing the doge placeholder on every unlock
   ---------------------------------------------------
   The BootstrappingPlaceholder gate was `!session?.bootstrap?.userId`,
   which fired for the snapshot-restore path that sets
   `bootstrap: { userId: '', ... }` + last-known balances. That
   correctly-rendered home was being hidden behind the doge on every
   unlock until the live bootstrap completed.

   Change: gate on `!session?.balances`. Placeholder now fires only
   when there's genuinely nothing to show (cold start, no snapshot).
   Subsequent unlocks render the home from the snapshot within a
   paint.

Tests

Three new contract tests in packages/core/src/__tests__/wallet-flow-pow.test.ts
pin the bypass behavior:

  - new wallet → powSolver IS called, altcha_solution rides in body
  - returning wallet → powSolver NOT called, altcha_solution omitted
  - returning wallet still propagates xmr/wow_start_height from
    checkRestore (regression guard for the resume-heights
    optimization)

All 66 @smirk/core tests pass. Chrome build clean.

User-observable wins, paired with the backend bypass landing
(smirk-backend 29cffd3):
  - Lock + unlock: instant home from snapshot. No doge, no solve.
  - Import of existing wallet: ~300-800ms (checkRestore + register).
    No solve.
  - Onboarding a fresh new wallet: ~3-5s solve, unchanged.
2026-06-12 20:48:51 -04:00
2026-05-07 20:39:47 -04:00

Smirk Monorepo

Open-source client code for the Smirk multi-currency wallet — Rust crates for chain-specific cryptography, a wasm-bindgen wrapper, and (eventually) the TypeScript packages that power the browser extension and mobile app.

Status

Component Status
crates/monero-oxide/ Working — Monero + Wownero transaction construction, in production via the smirk-extension v0.2.x stack
crates/secp256k1zkp/ Vendored — Grin's grin_secp256k1zkp v0.7.15 + Smirk patches for wasm32. Provides Bulletproofs, Pedersen commitments, aggsig
crates/smirk-wasm/ Working — single WASM bundle exposing Monero/Wownero/Grin crypto to JS
crates/grin-ext/ Working — seed derivation, slatepack address (Grim-verified), Schnorr (single + multi-party + adaptor), slate v4 (JSON + compact binary), Pedersen + Bulletproofs, slatepack codec (armor + bin + age encryption), kernels (incl. NRD), full slate construction (standard + invoice flow), transaction wire-format assembly, payment proofs, 6 high-level wallet orchestrators, cross-validated against grin_wallet_libwallet 5.4.0
crates/btc-ext/ Working — BIP32/BIP39 derivation, P2WPKH (BIP84) + P2TR (BIP86) addresses for BTC + LTC, PSBT construction + signing + extraction. Built on rust-bitcoin
crates/swap-core/ Stub — atomic swap state machine, implementation pending (v0.4 work)
packages/wasm/ Working — @smirk/wasm TS bindings around the WASM crypto bundle (BTC PSBT, XMR/WOW signing, full Grin surface incl. wallet orchestrators)
packages/core/ Working — shared TS lib (API client, crypto, BIP-137 signing, address codecs, HD derivation, session-state + wizard scaffold, pendingOutgoing reconciliation, wallet-flow composition)
packages/assets/ Working — @smirk/assets registry: pure-data definitions (decimals, family, capabilities, networks) for every chain Smirk supports. 44 unit tests.
packages/ui/ Working — @smirk/ui shared Preact components: Home (UnifiedBalance, BalanceCard, ActionRow), SendWizard (5 assets incl. Grin interactive Exchange step), GrinRequestWizard, ReceiveScreen, OnboardingWizard, LockScreen, AppShell + BottomNav, ApprovalScreen (dapp prompt UI), theme registry (7 themes incl. retro themes)
packages/dapp-api/ Working — @such-software/smirk-dapp-api transport-agnostic dapp injection: wire protocol, WalletHandler dispatcher, page-context window.smirk factory, WalletProvider / OriginPermissionStore / ApprovalHandler interfaces. Platform adapters live in packages/extension/ (and eventually mobile / desktop).
packages/extension/ Working — Chrome MV3 + Firefox MV3. Keystore + wallet-flow + lockscreen, send (BTC/LTC/XMR/WOW/Grin), receive, social tipping (two-phase create), per-asset detail screen, tri-state balance (confirmed/pending/locked), pendingOutgoing reconciliation. window.smirk dapp injection (connect, signMessage for BTC+LTC, isConnected, disconnect, getPublicKeys, getAddresses) with per-origin permissions + standalone approval-window flow + global privacy toggle in Settings.
packages/dapp-browser/ Working — @smirk/dapp-browser embedded-browser shell abstraction. Platform-agnostic DappBrowserController + MockController; UI consumers (BrowserShell, BrowserUrlBar, BrowserTabStrip) live in @smirk/ui.
packages/keymap/ Working — @smirk/keymap cross-platform keyboard-shortcut registry (per-platform bindings, action enum, runtime dispatcher).
packages/swap/ Working — @smirk/swap swap orchestration. ThorchainSwap + TrocadorSwap aggregator implementations; native adaptor-signature implementations planned v0.4+.
packages/desktop/ Working — @smirk/desktop Tauri 2.x wallet shell + embedded dapp browser. Wraps the extension popup via a chrome.* shim (storage backed by tauri-plugin-store). Each browser tab is a borderless WebviewWindow positioned over the wallet UI's frame slot.
packages/mobile/ Not yet populated — Capacitor planned v0.4

The legacy browser extension at Such-Software/smirk-extension is frozen at v0.2.x; packages/extension/ here is the canonical v0.3+ client.

Layout

smirk-monorepo/
├── crates/                   # Rust workspace
│   ├── monero-oxide/         # vendored — Monero + Wownero transaction library
│   ├── secp256k1zkp/         # vendored — Grin's secp256k1-zkp Rust bindings
│   │                         #   (Bulletproofs, Pedersen, aggsig); patched for wasm32
│   ├── smirk-wasm/           # wasm-bindgen wrapper, single WASM bundle for JS consumers
│   ├── grin-ext/             # Grin / Mimblewimble protocol implementation
│   ├── btc-ext/              # BTC + LTC: BIP32, P2WPKH/P2TR addresses, PSBT signing
│   └── swap-core/            # atomic swap state machine (stub — v0.4)
├── packages/                 # npm workspace (TypeScript)
│   ├── wasm/                 # @smirk/wasm — TS bindings around crates/smirk-wasm/pkg/
│   ├── core/                 # @smirk/core — API client, crypto, HD derivation, codecs
│   ├── assets/               # @smirk/assets — pure-data registry of every supported chain
│   ├── ui/                   # @smirk/ui — shared Preact components (BalanceCard, SendWizard, OnboardingWizard, BrowserShell, ...)
│   ├── dapp-api/             # @such-software/smirk-dapp-api — transport-agnostic window.smirk wire protocol + WalletHandler
│   ├── dapp-browser/         # @smirk/dapp-browser — embedded-browser shell abstraction (Tauri + Capacitor)
│   ├── keymap/               # @smirk/keymap — cross-platform keyboard-shortcut registry
│   ├── swap/                 # @smirk/swap — swap orchestration (THORChain, Trocador, future native adaptor sigs)
│   ├── extension/            # @smirk/extension — Chrome MV3 + Firefox (the v0.3.0 canonical client)
│   └── desktop/              # @smirk/desktop — Tauri 2.x wallet shell + embedded dapp browser (v0.3.0)
├── docs/                     # design notes per crate
├── Cargo.toml                # flat Rust workspace, all crates listed at root
├── package.json              # npm workspace root
├── tsconfig.base.json        # shared TS compiler config
├── Makefile                  # cross-language build orchestration
└── MONOREPO.md               # developer guide

Build

Requires:

  • A recent stable Rust toolchain with the wasm32-unknown-unknown target
  • A wasm-bindgen-cli version matching Cargo.lock
  • Node.js 20+
# Cargo workspace
make rust-build      # cargo build --release --workspace
make rust-test       # cargo test --workspace

# WASM bundle (output: crates/smirk-wasm/pkg/)
make wasm

# TypeScript workspace (depends on WASM)
make ts-install      # npm install across packages/*
make ts-typecheck    # tsc --noEmit across packages/*
make ts-build        # tsc -p across packages/*

# Everything (Rust + WASM + TS)
make build
make test

CI runs the same make targets — see .github/workflows/ci.yml.

Reproducible from source

For reviewers (Mozilla AMO, App Store, security audits) the goal is git clone → make build → byte-equivalent output. Every byte of crypto code lives in crates/. The standalone Rust crate wownero-oxide is published to crates.io for external consumers, but the monorepo build does not depend on the published version — crates/monero-oxide/ is the source of truth.

Companion repos

Repo Role
Such-Software/smirk-extension Legacy v0.2.x browser extension. Frozen — packages/extension/ here is the canonical v0.3+ client.
Such-Software/monero-oxide Standalone fork retained for wownero-* crates.io publishing; kept in sync with this monorepo via git subtree
monero-oxide/monero-oxide Upstream — Monero only

License

MIT — see LICENSE.

Description
A repository for Smirk Wallet browser extension, mobile apps, and core
Readme MIT 20 MiB
Languages
TypeScript 34.6%
Rust 33%
C 28.3%
M4 0.8%
Sage 0.7%
Other 2.5%