Release history

Changelog

Every release of BTX PQ Wallet, newest first — what changed, and why. The post-quantum send core and key derivation are byte-pinned to the BTX node across all of them.

v0.20.2

Latest 2026-07-07

qID Sign-In polish. No change to the crypto core or the proof format (still v1).

  • The Sign-In screen now shows the request's canonical site origin, so a challenge cannot dress up its "Site" line with a misleading path or embedded credentials.
  • The pasted request and the generated proof are cleared when you close Settings or lock the wallet, so nothing lingers on screen.

v0.20.1

2026-07-07

Connectivity fix for networks that inspect HTTPS. No change to the send path or the crypto core.

  • Explorer connection now uses the operating system's certificate store. The wallet trusts the same certificates the system browser does, so it connects on networks behind a VPN, a corporate proxy, or antivirus that inspects HTTPS. Before this, the app trusted only a bundled root set, so on those networks the balance could not load (it showed "Explorer offline") even though the browser reached the same explorer fine. Under the hood: reqwest now uses rustls with native OS roots. This does not weaken anything: the wallet never sends keys over the network, and the transaction sighash commits to the amounts, so a proxied or lying explorer still cannot forge a wrong-amount spend.
  • Clearer connection error. When the explorer cannot be reached, the wallet now shows the real reason (for example a rejected certificate or a timeout) instead of a generic "offline", so a proxy or antivirus problem is identifiable at a glance.

v0.20.0

2026-07-07

The in-wallet qID Sign-In, plus release chores. No changes to the vendored PQ crypto core (qid.bundle.js) or the transaction signing path.

  • qID Sign-In (new). Prove you control a wallet to an app or service without exposing any key. An app gives you a one-time challenge, you paste it into Settings → qID Sign-In, check which site it is for, and sign. The wallet produces a standard ownership proof (a v1 ML-DSA-44 login signature) that you paste back. This is the wallet side of the Sign-In With BTX standard (qID), the BTX equivalent of Sign-In With Ethereum. A sign-in signature is domain-separated from spending (BTX-qID/login-v1 vs TapSighash), so it can never move funds. The screen shows the site and challenge before you sign, and read-only wallets cannot sign.
  • Under the hood: the challenge parsing and proof assembly are a new pure, unit-tested module (ui/signin.js), and the whole-frontend sha256 integrity gate pins it too, so everything ships byte-for-byte as reviewed. Signing reuses the existing signLogin primitive in the crypto core, unchanged. GitHub Actions Node bumped from 20 to 24.

v0.19.0

2026-07-05

Security hardening plus readability and multi-wallet UX. No changes to the vendored PQ crypto core (qid.bundle.js) or the signing path.

  • Auto-lock (new). The wallet now locks itself after a period of inactivity and returns to the wallet list, so an unlocked wallet — whose seed and spend keys live in memory while it is open — is not left exposed if you step away. You re-open it the same way as always (passphrase, Touch ID, or Windows Hello). Configurable in Settings → Security → Auto-lock after inactivity: Off / 1 min / 5 min / 15 min (default 5 min). It never locks a watch-only wallet (no key to protect) and never interrupts a send that is broadcasting. Following a full re-audit of the v0.18 hardening, this closes the last ranked open item: the previous lock was manual-only, leaving the in-memory keys exposed for the whole session.
  • Network proxy tightened. The chain proxy is now constrained to the exact Esplora routes the wallet uses (address lookups, UTXOs, history, broadcast) — query strings, arbitrary paths and methods, and non-hex broadcast bodies are refused. Defense-in-depth on top of the existing egress pin.
  • Readable settings. Each Settings section header (General, Appearance, Security, …) now reads at full size and in full-strength text instead of the same faint grey as its fields, and every field label is white — so the panel is legible at a glance.
  • Never miss a deposit — even from the wallet list. When a wallet receives while you're on the wallets overview, it now chimes and marks that wallet with a small gold hexagon next to its balance (and a brief gold flash on the amount). The marker lingers ~30 minutes, so you can tell exactly which wallet changed even if you missed the sound.
  • Copy. Dropped the "test build" framing across the app while keeping the honest facts (not yet code-signed, on mainnet, verify the SHA-256); the at-rest KDF is correctly described as Argon2id.
  • Under the hood: the auto-lock timing decision is a new pure, unit-tested module (ui/autolock.js), and the whole-frontend sha256 integrity gate pins it too, so everything ships byte-for-byte as reviewed.

v0.18.0

2026-07-04

Security hardening + send/receive UX polish. No changes to the vendored PQ crypto core (qid.bundle.js) or the signing path.

  • Security: mainnet-only send guard — rejects tbtx/btxrt (testnet/regtest) addresses that decode to the same mainnet scriptPubKey; a CI "no DOM-sink" guardrail that fails the build if any HTML/JS-injection sink is introduced (locks in the "safe DOM only" property); the vendored-bundle integrity gate is now a fail-closed whole-frontend sha256 gate (every shipped ui/ file pinned) and CI runs it — plus the anti-XSS gate — by name.
  • Send: fixed the "send twice in a row" failure (bad-txns-inputs-missingorspent) by excluding a pending send's already-spent inputs from the next send, with a clear "previous send is still confirming" message instead of the raw node error; removed the confusing change and size rows from the send preview.
  • Receive: a continuous slow "coins arriving" animation now runs on the amount while a deposit confirms, plus a new double confirm chime when it becomes final; the incoming/confirming line is now white.
  • Receipt: bigger animated Sent badge + the sent amount shown big and white, with the saved contact name.
  • Wallets list: a force-refresh button.
  • Copy: removed the shielded (SMILE) line from the wallet screen. Version metadata reconciled to 0.18.0 (Cargo.toml was lagging at 0.16.0).

v0.17.0

2026-06-27

A polish release. The post-quantum send core and qid.bundle.js are byte-unchanged; all new logic is unit-tested (full suite now 117 green). Transparent-only.

Fixed

  • Sending no longer shows a phantom "+X BTX incoming." While a send was confirming, the balance card briefly showed your own change coming back as if it were an incoming deposit. The explorer under-reports the spent side of a mempool spend, so the old funded-minus-spent math only "saw" the change returning. The pending line now classifies the actual mempool transaction — it recognises the credit as your own change — and reads "Sending X BTX, confirming…" instead of a confusing +<change> BTX incoming.
  • The "Your wallets" list keeps its balances up to date. It used to freeze on the figures from when you first opened it and only refreshed after an app restart. It now re-checks every listed wallet on the same timer as the open wallet (default 30s), updates each row in place without disturbing an in-progress rename, and refreshes the sending wallet immediately after a send. The refresh is overlap-guarded and sequential, so a long list of large wallets can't stack explorer requests.

Added

  • A little 16-bit celebration when money moves. A short, quiet (~35%) blip plays when a transaction is sent — a rising two-note tone, with gold coins bursting outward from your balance — and a different, brighter chirp when a deposit arrives, with coins pulled inward onto the number. Toggle it in Settings → General → Sound effects (on by default). The sounds are synthesised in-app (no audio files are bundled), watch-only wallets stay silent, and all motion respects "reduce motion".

Changed

  • The Send "to" field now shows the whole address. It wraps onto two rows (in a slightly larger font) instead of truncating, and the first and last six characters are highlighted in white so a pasted address can be verified at a glance. The send preview shows the full destination address too.
  • A clearer address book. Picking a saved address now uses a custom dropdown that shows each name above its full address (no more cramped native list), and the Settings → Address book rows put Edit and a compact Delete on the right. Settings category labels are larger and white for readability.
  • The bonuz link in Settings → Links now points to the new BTX-in-bonuz page (bonuz.xyz/btx-wallet), which explains it and links the mobile downloads.

Under the hood

  • New unit-tested pure helper pendingFromTxs (change-aware mempool classification, reusing the existing classifyTx), and a balance-fetch overlap guard mirroring the history one. Sounds are generated with the WebAudio API (square-wave oscillators), so nothing new is bundled and the CSP is unchanged.

v0.16.0

2026-06-18

A recovery-and-usability release. The post-quantum send core and qid.bundle.js are byte-unchanged (same key derivation and P2MR sighash); all new logic is unit-tested (full suite now 109 green). Transparent-only.

Fixed

  • The node-recovery sweep no longer reports a completed transfer as "Nothing moved." A P2MR sweep is txid-deterministic (the post-quantum signature lives in the witness, so it doesn't change the txid), so re-broadcasting an already-confirmed sweep returns the node's RPC -27 ("transaction outputs already in utxo set"). The wallet now reads that as "already in your wallet — confirmed on-chain" with a link to verify, instead of a scary failure with a raw RPC dump; the contradictory "your funds are on the way" line no longer shows when nothing was sent. A real user hit this, and their funds had in fact moved and confirmed on-chain the whole time.
  • Recovering node funds before you have a wallet here no longer dead-ends. A first-time user who recovered a node wallet.dat used to be told to "create a wallet, then run Recover again" — which forced a re-upload and a full re-scan. The wallet now guides you to set up (or restore) your wallet first and continues straight into the scan and sweep, with no second upload and no re-scan.
  • History no longer chokes on a wallet with thousands of transactions (e.g. a watched miner address). Auto-refresh now guards against overlapping fetches and keeps a small per-address cache of confirmed txs (display-only, never the spendable balance), fetching just the newest page each refresh instead of re-walking ~500.

Added

  • Read-only (watch-only) wallets. Add any btx1z address to follow its balance and history. It is clearly badged READ-ONLY (with a small "view only" chip in the wallet list); sending, the master-key backup, and the receive QR are hidden, and it can never be a recovery-sweep destination.
  • Copy a full explorer link wherever a transaction ID appears. The sweep result and the send receipt now show the txid with Copy link (a complete minebtx URL), Copy ID, and Open ↗, so a paste is a clickable link rather than a bare hash. History already behaved this way; it's now consistent across the app.
  • An easyBTX Telegram link (t.me/easybtx) in Settings.

Changed

  • Shielded (SMILE) is no longer on this wallet's roadmap. BTX is moving applications and shielding to an upcoming EVX layer-2 (EVM-style); this wallet stays transparent-only.

Under the hood

  • New unit-tested pure helpers: explorer-URL builders, a broadcast-error classifier, and the history cache merge (mergeTxs) in ui/txview.js; canReceiveSweep (ui/wallets.js); isValidBtxAddress (ui/recover.js). 13 new tests; full suite 109 green. qid.bundle.js unchanged (sha256 pin intact).

v0.15.0

2026-06-15

A usability and correctness release focused on transaction history, pending funds, and the send screen. The post-quantum send core and qid.bundle.js are unchanged (byte-identical key derivation and P2MR sighash). Transparent-only, and unaffected by the BTX block-125,000 shielded sunset; verified against the BTX 0.32.x series through 0.32.11.

Fixed

  • History now shows your full transaction list, not just the most recent 25. The wallet used to fetch only the newest page from the explorer and stop at 25, so an active wallet looked like it was missing older transactions (the most common confusion users reported). It now follows the explorer's pagination, shows an honest count footer, and always offers an "Open full history in explorer" link. (Note: the minebtx explorer's own index may still omit a few transactions; that is server-side, not the wallet.)
  • Incoming and outgoing pending (mempool) funds are now visible. A deposit that is still confirming shows a "+X incoming, confirming…" line under the balance and a PENDING chip in History, so a payment you just received no longer looks like nothing arrived. The spendable/headline balance stays confirmed-only.
  • A just-sent transaction no longer briefly looks missing. After a broadcast, History and balance now re-check on a short escalating schedule instead of a single delayed refresh.
  • Send-screen errors are now plain language. An empty or mistyped address, an out-of-range fee rate, and the fee safety cap now show clear guidance instead of raw decoder or builder text.

Changed

  • More accurate transaction labels. Self-transfers and consolidations show the fee paid instead of a misleading "-0 BTX", and a transaction whose direction can't be confirmed (the explorer dropped an input) is flagged rather than silently mislabeled.
  • Correct live fee estimate. The one-input fee hint now uses the builder's real ~3916 vB instead of a hardcoded 4950 vB, which had overstated the network fee by about 26%.
  • Settings/header copy notes that shielded (SMILE) balances must be recovered with a shielded-capable BTX node, so holders of shielded funds aren't left wondering why this wallet doesn't show them.

Under the hood

  • New, fully unit-tested ui/txview.js module (explorer pagination, transaction classification, confirmed vs. pending balance split, and friendly send-error mapping), 26 new tests; full suite 96 tests green.

v0.14.3

2026-06-13

A security-hardening release from an independent round-3 super-audit plus an exhaustive follow-up sweep of the wallet and the qID library (every finding independently re-verified). No new features. The post-quantum send core and qid.bundle.js are unchanged — byte-identical key derivation and P2MR sighash, pinned by the offline vectors — and verified compatible with BTX v0.32.8.

Security

  • The node-recovery sweep destination is now authenticated. It derives the destination address from authenticated key material (the unlocked wallet's seal-reconciled address, a no-passphrase wallet's seed, or a protected wallet unlocked inline) instead of an unauthenticated stored address — a local-write attacker can no longer redirect recovered funds.
  • Removed an unauthenticated egress-allowlist persistence channel. A custom explorer is re-confirmed per session through the native dialog; the previously-persisted explorer-allow.txt — which a local attacker could forge to widen the network allow-list and exfiltrate the seed through a compromised webview — is gone.
  • CI now runs the vendored-bundle integrity gate (sha256 pins on qid.bundle.js / argon2.bundle.js) before building the signed installer, so a tampered seed-handling bundle can never ship.
  • Recovery files are written owner-only (0600); recovery / wallet.dat reads are capped at 64 MiB and the wallet.dat seed match is linear (no longer a quadratic freeze on a hostile file); a poisoned address-book entry can no longer block the wallet screen from rendering; the recovery scan now warns on an unverifiable balance instead of treating it as empty.

qID library (the future "Login with qID" SDK — not used by the released wallet)

  • Attestation capabilities are now enforced, not just signed; key supersession pins the winning login key per serial; the single-input transaction builders range-check inputs uniformly; buildRecoverySpend requires an external round-3 SPHINCS+ signature instead of a node-rejected fallback; relying-party nonce issuance is memory-bounded.

Note

  • The vendored qid.bundle.js (cf2d33…) is intentionally unchanged: its send/derivation crypto is byte-identical to qID main, and the qID changes above are to code the wallet does not run. A bundle re-vendor stays a deliberate, regtest-gated step.

v0.14.2

2026-06-12

Shows the app version in the header on the wallet-selector and create/unlock screens, and records a compatibility check against the current BTX node. No new crypto; qid.bundle.js and the send core are unchanged. (v0.14.1 was a local-only build; its header-version change ships here.)

Added

  • Version in the header on the selector + create/unlock screens (hidden on the wallet screen, where the action icons sit).

Verified

  • Compatible with BTX v0.32.6 / v0.32.7. The transparent P2MR consensus rules the wallet reproduces — key derivation, opcodes, the 0xc2 P2MR leaf + Merkle tags, the TapSighash path, the witness-v2 bech32m address, and the min-relay/dust policy — are byte-identical upstream. The 0.32.x changes are the shielded-pool sunset, mining, and P2P transport only, none of which the transparent-only wallet touches. No send-core or key-derivation change required.

v0.14.0

2026-06-11

Rebrand to BTX PQ wallet, a full theming system, and a batch of send/privacy UX fixes. The post-quantum send core and qid.bundle.js are unchanged — no new crypto — and the money-critical identifiers (the macOS Keychain service, the BTX-WALLET-RECOVERY file magic) are untouched, so existing wallets and recovery files keep working. (Supersedes the internal-only v0.13.0.)

Added

  • Theming (Settings → Appearance). Three independent controls: a logo (BTX PQ wallet pixel mark · pq hex mark — which also sets the app & Dock icon), a colour (Green · Ocean · Violet · Amber), and a mode (System · Dark · Light). System follows the OS appearance live; Dark/Light pin it. Every colour works in both light and dark.
  • Live macOS Dock icon matching the chosen logo+colour (new set_dock_icon command via AppKit; a no-op on other platforms, and it never touches the on-disk .app bundle icon).
  • Post-send receipt. After a broadcast the send form is replaced by a clear "Sent ✓" card with the full transaction hash, a Copy button, and a View-in-explorer link. Returning to Send shows a fresh form.
  • bonuz wallet promo (Settings → Links): "BTX is live in the bonuz wallet", in the bonuz brand (animated orange→pink gradient).

Changed

  • Name → BTX PQ wallet across the app, window title, About, and icons.
  • The privacy-eye now also masks transaction amounts in History, not just the balance.

Removed

  • The "You are on mainnet" warning, and the misleading Send all button (it errored and read as "send my whole balance"). The underlying sweep still powers node-fund recovery.

Fixed

  • Received is always green, Sent always red — in every theme. Direction colours had tracked the theme accent (so "received" turned cyan in the Ocean theme); they are now their own --pos/--neg tokens that a reskin can't change.

v0.12.1

2026-06-03

Recover node-era funds from an EasyBTX/btxd pqhd (post-quantum HD) descriptor wallet — from either the recovery .txt or the binary wallet.dat. The post-quantum send core and qid.bundle.js are unchanged; no new crypto.

Added

  • Recover node funds (EasyBTX/btxd file). A new wizard on the create/add screen parses a node EasyBTX Wallet Recovery File, derives every node address through the frozen qID bundle (byte-for-byte identical to btxd — guarded in CI by a node-verified address oracle), scans each address's real balance from the explorer, shows the total, and on explicit confirmation sweeps each funded address (one transaction each, signed with that address's own derived identity) into one single-address wallet you control. The same file also works via "Restore from a file" (auto-detected). Scanning is sequential with a live progress bar + Stop, since each address costs a ~6s SLH-DSA keygen (inherent — it must match the node); a "Scan deeper" option covers funds past the used range.
  • Import a binary wallet.dat directly. Users who only have the node's wallet.dat (no .txt) can recover too: a dependency-free SQLite reader extracts the pqhd seed(s) and feeds the same scan/move pipeline. Each extracted seed is trusted only if SHA256(seed)[:4] equals the descriptor's public stub, so a parse bug fails closed. Encrypted wallets are detected and refused with guidance.
  • Move-into-your-existing-wallet UX. Recovered funds move into the wallet you already use (shown by name, same master key — not a new wallet/key), explained in a plain-language banner, with an optional build → review → broadcast preview that shows the exact amount / fee / destination before anything sends.

Security / safety

  • Rejects any descriptor whose path isn't */0h/0h/{0,1}/* (the frozen bundle pins coin=account=0h, so any other path would derive wrong addresses), plus public-form seeds, foreign files, and malformed input.
  • Shows the scanned on-chain balance before any sweep; never persists the node seeds (the recovery file is the durable backup — an interrupted sweep is replayable); keeps the per-tx 0.02 BTX max-fee + dust clamps.

v0.12.0

2026-06-02

Pre-release security-hardening update. Driven by an internal adversarial security audit (.gstack/security-reports/) and its fixes. The post-quantum send core and qid.bundle.js are unchanged. 40 node:test + 18 Rust tests green.

Security

  • F1 (HIGH): external-link opener. open_url no longer opens links through a Windows shell; it validates the URL (https-only, well-formed, no shell-unsafe characters) and opens with a shell-less opener. Closes a command-execution path that was reachable through a crafted explorer URL.
  • F5 (MEDIUM): explorer proxy. chain_request now validates the explorer base URL (a valid http/https URL with a host; cleartext http allowed only to a loopback host), closing an SSRF / cleartext-downgrade gap.
  • F2 (HIGH): recovery-file restore. Restoring from a recovery file now derives and shows the wallet's btx1z address, requires explicit confirmation, and hard-fails if the file's address line does not match its key (anti address-poisoning).
  • F4 (MEDIUM): passphrase policy. Minimum passphrase length raised from 6 to 12, enforced on create / set / change / recovery-file / restore. Never enforced on unlock, so existing wallets still open.
  • F6 (MEDIUM): build supply chain. All GitHub Actions pinned to full commit SHAs, the Rust toolchain pinned, and Dependabot added for review-gated bumps.
  • F10: local security reports (.gstack/) are now gitignored.
  • F7 (LOW): defense-in-depth. Transient seed buffers in the macOS keychain commands (mac_seal/mac_unseal) are wiped via zeroize on every exit path.
  • F9 (LOW): supply chain. The vendored crypto bundles (qid.bundle.js, argon2.bundle.js) are integrity-pinned by sha256 in a test, with provenance recorded. (F8, legacy PBKDF2 iterations, is intentionally left unchanged: the count must match existing v1 blobs to decrypt them, and those auto-upgrade to Argon2id on unlock.)

Changed

  • F3: create screen. Passphrase and Touch ID are presented as the recommended, most-secure tier. The no-passphrase option stays available (one click) but now carries a clear "stored unencrypted on this device" warning plus an info button that explains the tradeoff and reassures that the wallet is self-custodial either way. Both options are kept by design.

Security model (unchanged, for reference)

  • Keys are generated on-device and never leave it. At rest: a passphrase seal uses Argon2id (64 MiB, t=3) then AES-256-GCM; a biometric seal stores the seed in the OS keychain behind Touch ID (macOS) or Windows Hello.
  • Sends have a hard 0.02 BTX max-fee clamp, a dust guard, and a confirm step.
  • A full independent third-party audit is planned but not yet complete; keep your 64-character master key backed up offline.

v0.11.0

internal only, never publicly released
  • Re-vendored hardened qID crypto bundle. Native macOS Touch ID unlock (dormant until the app is signed). Opt-in code-signing wiring (macOS entitlements + gated Windows CI signing). Address book for public addresses. Argon2id replaced PBKDF2 for new seals; legacy PBKDF2 seals lazy-upgrade to Argon2id on unlock.

v0.10.0

2026-06-02
  • Multiple wallets (start-screen list, add / forget / rename, lossless migration of the legacy single wallet). Settings security: set / change / remove passphrase. Save / Restore checksummed recovery files via native dialogs. Argon2id KDF for new seals.

v0.9.1

2026-06-01

The first public release — the build you can actually download, on macOS and Windows, with passkey unlock and a full transaction history.

Highlights

  • Public macOS (.dmg) and Windows (.exe) downloads. The Windows installer (NSIS) is built reproducibly in GitHub Actions on windows-latest.
  • Passkey unlock via the WebAuthn PRF extension: the 32-byte seed is sealed with AES-256-GCM under a key minted inside the authenticator (Touch ID / Windows Hello / security key), and the design fails closed if PRF is unavailable rather than storing the seed unprotected.
  • Transaction history — per-transaction RECEIVED / SENT with a signed amount, date, counterparty address, and explorer link, computed locally from the transaction vin/vout deltas.

Trust

  • An "Is it safe?" section publishes the SHA-256 and VirusTotal lookup for every build, and explains plainly why a brand-new unsigned installer draws a SmartScreen reputation warning and a few machine-learning antivirus flags.

Notes

  • Test build: unsigned and on mainnet (sends move real BTX). Passkeys work on Windows (WebView2); on the unsigned macOS build they fall back to a passphrase until the app is code-signed.

v0.5.0

2026-05-31

The first build where the whole loop works: receive, hold, and send real BTX on mainnet.

Highlights

  • Real post-quantum sends confirmed on BTX mainnet (P2MR with ML-DSA signatures), including Send all (full sweep).
  • A Receive tab with an address QR code and a one-line, copyable btx1z address.
  • A Settings panel: configurable Esplora explorer URL, an auto-refresh interval, and the master-key backup.
  • Auto-refresh of balance and history on a timer, and explorer deep-links on every history row.

Safety

  • A dust guard and a hard 0.02 BTX maximum-fee clamp are enforced before any broadcast, with a preview of the fee, change, and input count and an explicit confirm step.

Notes

  • All network requests run in the Rust layer — the webview never reaches the internet directly — while the seed stays in the webview. Single address (v1).

v0.1.0

2026-05-31

The first build: a native desktop wallet on the node-verified post-quantum send core.

Highlights

  • Post-quantum keys derived on-device from a single 32-byte master seed: ML-DSA (the spending/login key) and SLH-DSA (the recovery key), combined into a btx1z P2MR address.
  • Receive, balance, and send on the node-verified qID core — multi-input P2MR construction (selectAndBuild, buildSweepAll) with every sighash commitment rebuilt per input.
  • Self-custodial: keys are generated on the device and never leave it; a one-time 64-character master-key backup is the only recovery.

Architecture

  • A Tauri 2 desktop shell with a Rust chain_request command proxying all chain traffic, a passphrase seal using PBKDF2 (210k iterations) + AES-256-GCM in local storage, and strict safe-DOM rendering (no innerHTML of any external string).

Notes

  • Test build on BTX mainnet — sends move real BTX. Transparent funds only.