grenadeandClaude Fable 5.1 102f659900
ci / gate (push) Canceled after 3m6s
feat(ui): a dashboard of the whole wallet, first after unlock
The default route is now a dashboard (#85): one figure for everything
the wallet holds, priced in USD at 1Click's index prices, and a bar
splitting it by chain. The accounts page moves to /accounts.

Rust reads and prices; the webview draws:
- Each mainnet chain's accounts (the balances read as the accounts page
  does) and its shielded balance (the wormhole cache's unspent leaves,
  no scan), and the intents account's tokens, one view call.
- Prices come from GET /v0/tokens, cached a minute. A price arrives as a
  JSON number, is rendered to 8 places and parsed as a decimal; every
  product is integer arithmetic on base units, brought to 8 decimals
  first so a 24-decimal token cannot overflow u128. Three tests pin it,
  including a million wNEAR.
- What cannot be valued is named, not guessed; a chain not reached yet
  is started, marked, and the UI asks again every five seconds.

The form follows the house data-viz method: a hero figure (48px, the
body sans, proportional figures), and part-to-whole as a single bar
with a 2px surface gap between segments rather than a ring, which
hides close values and has no room for labels. Chains keep a fixed
colour slot for good (Quantus bronze, NEAR Intents blue, three more
validated for later); the legend table beneath carries every value and
holding, so colour never carries a fact alone. Both palettes passed the
validator against the wallet's own surfaces; the light mode's contrast
warning on two slots is what the table answers.

Checked in a dev run: unlock lands on the dashboard, the index priced
QTC at $140.23, both chains read live, and an empty wallet drew the
recessed track. A bar with segments wants a wallet that holds
something, which the operator's will show.

Closes #85

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01NUx7SPonBnB3ofU4mH41WT
2026-10-12 12:14:24 +03:00
2026-10-12 11:24:22 +03:00
2026-10-12 11:24:22 +03:00

blackbeard wallet

A desktop wallet for post-quantum chains, Quantus first. Linux, Windows and macOS; installable on Fedora with dnf.

Shape

The wallet is a Rust cargo workspace with a Tauri shell and a React webview. That split is the security model, not a convenience: every key, signature, decoded transaction and amount lives on the Rust side, and the webview only renders what a Tauri command hands it. Nothing that could serialise a secret is reachable from JavaScript.

crates/
  wallet-entities/   domain types and the IPC wire protocol; exported to TypeScript
  wallet-core/       wallet logic and the ports it is written against
  wallet-data/       adapters behind those ports: keystore, cache, RPC, provider APIs
  wallet-app/        the Tauri binary; commands are one-line shims into core
ui/                  Vite + React + TypeScript webview

The ports in wallet-core are what make "any post-quantum chain" a profile rather than a rewrite:

  • KeyScheme turns a seed and a path into a signer. ML-DSA-65 and ML-DSA-87 now; whatever the next chain uses later.
  • ChainAdapter knows one chain: balances, building and submitting a transaction, watching it. The Substrate adapter is driven by runtime metadata plus a small per-chain profile (ss58 prefix, decimals, signature enum, transaction extensions, signing-context rule, coin type).
  • SwapProvider is a swap venue. NEAR Intents first.
  • NearRpc is NEAR, the chain under the wallet's intents account, routed to a node that tracks the shard of the account each call is about.
  • FiatRamp builds a provider session through a relay on our infrastructure, which holds the provider secrets, and opens it in the system browser.

The wallet is post-quantum only. Classical chains appear only as transit legs of a swap or ramp; the wallet never derives a secp256k1 or ed25519 key. That includes NEAR: the intents account is a NEAR account whose only key is ML-DSA-65 (NEP-645), derived from the wallet's phrase as NEP-649 specifies. NEAR verifies it under the empty FIPS 204 context, where Quantus requires QUANTUS_EXTRINSIC.

Why these choices

Quantus signs extrinsics with ML-DSA, hashes public keys with Poseidon2 for the account id, and shields mining rewards behind a Plonky2 wormhole whose prover is minutes of native CPU. All of that exists as Rust crates and nothing else, so the core is Rust. Tauri is the house desktop convention (~/git/architecture/generic.md §4) and the only shell that packages rpm, deb, msi and dmg with a Rust-owned IPC boundary out of the box.

QTC reaches NEAR as qtc.omft.near through a bridge with a deposit address per account, and its liquidity is in Ref pools rather than with 1Click's solvers. So swaps run through an intents account the wallet holds (#71), using only calls intents.near authorises by the calling account. Its signed intents (execute_intents) accept classical signatures only, and the wallet never makes one. #72 ran the whole route that way on mainnet.

Building

pnpm --dir ui install
cargo tauri dev --config crates/wallet-app/tauri.conf.json   # from crates/wallet-app: cargo tauri dev
cargo test --workspace                                        # also regenerates ui/src/api/generated

The CI gate is cargo fmt --check, cargo clippy -D warnings, cargo test, and the webview's typecheck, lint and build. Run them before claiming done.

Work

Work is filed before it is done. Epics carry the epic label and an external definition of done; their steps carry child, in dependency order, at https://git.lair.cafe/blackbeard/wallet/issues. A commit that finishes a child closes it (Closes #N); when an investigation contradicts an issue, the correction is a comment on the issue, dated, not a surprise in a diff.

S
Description
Desktop wallet for post-quantum chains, Quantus first: ML-DSA signing in Rust, Tauri shell, NEAR Intents swaps and fiat ramps via transit chains. Linux (rpm/deb), Windows and macOS.
Readme
3.7 MiB
v0.4.1
Latest
2026-10-12 08:37:06 +00:00
Languages
Rust 73.4%
TypeScript 23.3%
CSS 1.6%
Python 1.2%
Shell 0.3%
Other 0.1%