giteablackbeard/wallet

Rust 73.4%TypeScript 23.3%CSS 1.6%Python 1.2%Shell 0.4%HTML 0.1%JavaScript 0.1%

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. A green gate on main also uploads a debug build of the app as a run artifact (blackbeard-wallet-<sha>-x86_64-linux-gnu-debug, kept seven days), so a change can be tried on a machine before a release is cut. It is the dev profile, so slower than a release, and it needs the GTK/WebKitGTK libraries the rpm depends on.

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.

257 activities