| Commit message (Collapse) | Author | Age | Files | Lines |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The EC crypto (candidate derivation + full scan) now runs in a worker, off the
main thread, so even a large mainnet scan can't jank the UI at all. The worker is
bundled separately and embedded as base64 (single-file app), spawned from a Blob
URL; it holds the keys + per-tweak cache. If workers are unavailable or the bundle
is missing, scanning falls back to the main thread (still cached + yielding).
scanSilentPayments / _scanSpItems / _scanSpMempool now go through _spHitBlocks and
_spScanItems, which dispatch to the worker (or the fallback). +27KB to index.html
for the worker's crypto bundle.
Verified via CDP: worker runs keys/candidates/scan correctly in-browser; a real
reload + mainnet scan threw 0 exceptions and the SP address renders.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
A freshly-generated wallet can't have received SP before it existed, so set its
scan watermark to the current tip on first connect (skipping the whole historical
catch-up) instead of scanning from 0. Threaded a 'generated' flag through the
create flow (openWallet → enterWallet → activateAccount → load spFresh); imported
wallets still scan from the indexer start since they may have prior receipts.
Verified on regtest: a fresh wallet skips the block-5780 receipt (watermark=tip,
balance 0); the same seed imported finds it.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Profiling (CDP) showed the toggle lag/high CPU was _scanSpMempool re-scanning the
ENTIRE mempool item set on every WS push (the mempool churns constantly), redoing
an EC point-multiplication per tweak on the main thread — ~1s blocks.
- Memoize silentPaymentScan/silentPaymentCandidate by tweak (outcome is fixed),
cleared when the SP keys change, capped to bound memory. Steady-state CPU from
re-scanning dropped from ~1s/push to ~0 (measured 18ms over 9s idle).
- Yield to the event loop during the catch-up block loop and the mempool scan, so
a large first/cold scan (mainnet) doesn't freeze the UI.
- Coalesce mempool scans (latest-wins, never two at once) with a race guard so a
block confirming mid-scan can't duplicate an outpoint.
Measured after: receive toggle 8/8 switches, avg 5ms / max 9ms (was 1-2s).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The screen-changing back buttons (tx detail, gift sub-view, all-gifts, bump,
account settings, accounts) now call goBack(), which does history.back() when
there's an entry to pop — so they no longer push a duplicate entry. Falls back to
an explicit parent-screen navigation when there's no in-app history (e.g. reloaded
straight into a sub-screen). Modal-dismiss buttons (revoke, rename, password,
draft) are unchanged — they don't touch nav state.
Verified via CDP: detail (i=2) → in-app back → i=1 (popped) → Forward restores
the detail.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
Mirror the app's screen position (screen, tab, txDetail, bump, giftsAll, giftMode,
claimStep) into the browser history, so Back/Forward (and Android system back)
move between screens actually viewed. render() snapshots just these nav fields and
pushState()s on change — incidental re-renders (typing, polling) don't add
entries. popstate restores the snapshot and re-renders. History-API calls are
guarded so they can never break a render.
Verified via CDP: tab nav and tx-detail push entries; Back/Forward (incl. A→B→A)
restore the right screen and the DOM follows.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
| |
Mainnet wallets now use https://halwallet.app/sp (our indexer on cs, behind
nginx /sp), enabling silent-payment receiving on mainnet.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
- One Receive card with an Address ⇄ Silent payment toggle (no separate card, no
BIP-352 badge, no scan-status line or Rescan button — discovery is automatic).
- SP receipts appear in History like normal payments: wallet.history merges BIP84
txs with per-tx SP receive rows (spTxRows), newest first; the detail view and
pagination use it. SP outputs carry a firstSeen timestamp.
- Receive description simplified to 'A reusable address that can't be tracked.'
- Removed the '· Silent payment' tag from the Send recipient line.
Verified on regtest: a received SP shows in history and balance with no manual
scan.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
silentpay.js: silentPaymentCandidate() (our P_0 for a tweak) + buildBloom/bloomHas
(double-hashed sha256, ~0.8% FP). Validated: candidate == P_0 on all no-label
vectors.
Indexer /scan now returns, per block, the tweaks + a Bloom over that block's
taproot output keys (no outputs), with an optional dustLimit. The wallet derives
a candidate per tweak, tests the filter, and only fetches /block on a hit — so a
big historical scan costs candidate math + a handful of fetches instead of
downloading and scanning every block. Live WS pushes still carry full items.
SP_DUST_LIMIT defaults to 0 (receive everything; the indexer honors any value).
Verified end-to-end on regtest: the filter flow finds the output.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Indexer: scan the mempool (getrawmempool + getrawtransaction; prevouts fetched
explicitly since verbosity-2 omits them for mempool txs), track SP-eligible
unconfirmed txs, serve /mempool, and push {type:'mempool'} on change. Switched
Core RPC to node:http (no keep-alive) + serialized calls — Bun's fetch was
dropping sockets under the added mempool load.
Wallet: handle the mempool push and /mempool catch-up (_scanSpMempool) — pending
SP receipts rebuild on each update (also drops RBF'd/vanished ones); block pushes
promote a pending entry to confirmed. So a silent payment shows the instant it's
broadcast, like a normal receive, with no mining.
Verified on regtest: an unconfirmed SP is detected and served; clean logs.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
The header reads wallet.spendable (and pendingIncoming), which reduce over
this.utxos only; SP outputs live in this.spUtxos, so received SP value showed in
the Receive card but not the balance. Add confirmed SP to spendable and pending
SP to pendingIncoming.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
The visible spScanning state is now set only for manual scans; auto-scans use a
separate concurrency guard (_spScanBusy). Previously an auto-scan set spScanning
and the final emit fired before it was cleared (and silent scans skipped the
clearing emit), leaving the Receive card stuck on 'Scanning…'.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The indexer now serves a /ws endpoint and publishes each newly-indexed block's
SP items to subscribers. The wallet subscribes (_spConnect) and scans pushed
items on arrival (_scanSpItems) — folding receipts into the balance instantly —
catching up via /scan on connect/reconnect. Polling for SP is now only a fallback
for when the socket isn't live.
Verified on regtest: connect, mine a block, wallet receives the push.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
scanSilentPayments() now recomputes the balance so received SP value shows in the
wallet total (not just the Receive card), and gains a silent mode. It's triggered
automatically after each full scan and on the poll loop (incremental, cheap), so
payments appear without tapping anything. The Receive card now shows a status
line ('Watching for payments' / found amount) with a small manual Rescan instead
of a primary Scan button.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
buildTx now includes received SP outputs in the coin pool, and sign() spends them
as taproot key-path inputs signed manually with d = spend_priv + t_k (the output
key is used raw — no BIP-341 tweak — so btc-signer's auto key-path signing
doesn't apply; we set tapKeySig from preimageWitnessV1 + schnorr.sign). The fee
estimator is fed a tapInternalKey (sizing only) with disableScriptCheck. SP value
folds into the displayed balance. Paying an sp1… recipient still uses BIP84 coins
(SP-input-funded SP sends need even-Y handling, deferred).
Validated on regtest via testmempoolaccept: a wallet-built, wallet-signed spend
of a received SP output is accepted by Core.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
wallet.js: scanSilentPayments() pulls the indexer's /scan range, matches outputs
on-device, and verifies each is unspent via the chain backend; spUtxos + balance
are tracked in their own bucket (one-time taproot keys), persisted in the cache.
silentPaymentsAvailable()/spBalance() expose state.
app.js: the Receive tab shows the reusable sp address (QR + copy), a 'Scan for
silent payments' button, and the found amount; Settings gains a per-network SP
indexer picker (under Data source) with custom/self-host support.
sp-indexer.js: added /scan/{from} so a client fetches a whole range in one
request instead of one fetch per block.
Receiving verified end-to-end on regtest (scan finds the output, 49,999,800 sat
confirmed). Spending SP outputs is the remaining piece.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
api.js: per-network SP indexer config (presets + custom, stored per network) with
getSpIndexerConfig/spIndexerUrl/spReceiveEnabled — regtest defaults to the local
indexer, others to custom; a hosted mainnet default slots in once we run one.
wallet.js: silentPaymentKeys() derives BIP-352 scan/spend keys from the master
seed (needs the mnemonic / depth-0 xprv), and silentPaymentAddress() returns the
sp1…/tsp1… address. Verified it matches the vector-validated e2e address.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
tools/sp-indexer.js: a minimal BIP-352 oracle (Bun) that walks Core and serves,
per block, one entry per eligible tx — the tweak (input_hash*A) plus that tx's
taproot outputs — for the wallet to scan on-device. Shares src/silentpay.js so
the tweak math is the vector-validated code. Added to the regtest compose as the
'sp' service (oven/bun, pointed at bc:18443).
inputPubKey now accepts a witness as either serialized hex (vectors) or an array
of stack items (Core getblock RPC). Verified end-to-end on regtest: a real SP
payment is indexed and the scan recovers the output, value, and spend tweak.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
silentpay.js gains the receiving half of silent payments, validated against all
official BIP-352 vectors (29/29 receiving sub-cases):
- inputPubKey(): recover the eligible input pubkey from P2PKH/P2WPKH/P2SH-P2WPKH/
P2TR inputs (skips uncompressed keys, excludes NUMS script-path, hash160-matches
malleated P2PKH scriptSigs)
- silentPaymentTweak(): the oracle tweak input_hash*A (sum over eligible inputs,
input hash over all outpoints, point-at-infinity guarded) — used by the indexer
- silentPaymentScan(): ecdh = scan_priv*tweak, derive P_k = B_spend + t_k*G, match
the tx's taproot outputs, return per-output spend tweaks
- silentPaymentOutputPrivKey(), deriveSilentPaymentKeys() (m/352' paths),
encodeSilentPaymentAddress()
Labels not yet implemented (wallet uses a single no-label address).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
On a fresh open, receiveSeenIndex was baselined to the pre-scan frontier (line
691), so the moment the socket's reconcile credited a deposit that predated the
open, nextReceiveIndex advanced past it and the celebration flashed for ~2s until
the post-scan baseline caught up. Leave receiveSeenIndex null until that final
baseline for fresh opens (matching the documented intent); the != null guard then
suppresses the flash. Same-session refreshes still use the persisted ack.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
| |
Hal stands on its own, so the data-source descriptions shouldn't name coinos:
the Electrum description now says "Point it at your own server … no REST" and the
block-explorer one drops "nothing is sent to coinos".
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
| |
The mempool parenthetical is jargon for non-technical users; the status line now
reuses the plain `pending` string. Drop the now-unused pendingInMempool key.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
All pending txs share blockTime 0, so _sortTxs's blockTime comparator returned 0
for every pending pair and they kept array (scan/arrival-append) order — so the
most recently received tx sat at the bottom of the pending group instead of the
top. Order pending txs by firstSeen descending (the timestamp we already record
when a tx is first seen unconfirmed); confirmed txs still sort by block time.
Also sort on cache restore so the order is right immediately, not only after the
first refresh.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
detect
After a socket drop the in-flight _rpcCall requests were never rejected (only
stopRealtime did that), so dead calls held every _rpcPump slot until they timed
out — stalling the post-reconnect refresh by ~10s even though the new socket and
its pushes were already live. Now reject pending calls in ws.onclose and in
_reconnectNow (which nulls onclose), so the pump frees instantly and the on-open
refreshLive runs right away.
Also tighten the half-open watchdog: ping every 10s and recycle the socket after
21s of silence (two unanswered pings) instead of 45s, so a silently-dead
connection — no onclose, no online/visibility event — resumes pushing in ~20s
instead of ~45s. Verified via CDP: force-closing the live socket reconnects in
~0.6s and the next deposit pushes in ~0.4s (UI ~1.2s).
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
The recovery-phrase section of the per-wallet settings page now shows an Import
seed action for watch-only wallets, with the load-seed card inline. The load-seed
flow takes an account id (defaulting to the active wallet), so it can upgrade a
specific watch-only wallet — validating the entered seed against that wallet's
xpub before making it spendable.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
The global Settings tab no longer shows the recovery phrase / public key — those
live only on each wallet's settings page now (the watch-only 'load seed' upgrade
stays in the global tab since it targets the active wallet). On the per-wallet
page, recovery phrase moves to the top and auto-logout to the bottom. Removes the
now-dead pubkeyCard/autoLockCard. Lowercases 'THIS' in the auto-logout copy.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
The accounts list now shows a settings cog (instead of a rename pencil) that
opens a per-wallet settings page: edit name, set auto-logout (moved here from the
global settings tab), reveal the recovery phrase, and show the public key (zpub)
— all read from the account itself, so it works for any wallet, not just the
active one. Room for more per-wallet settings later.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
| |
The network card is now just the network picker. Each network's endpoints
(Electrum server + block explorer) live solely in the Data source card, whose
options change per network and are stored per network (so switching networks
remembers each one's choice). Removes the duplicate regtest Esplora/WS fields.
Adds mutinynet (signet — testnet address format, explorer at mutinynet.com).
Per-network defaults: mainnet → coinos Electrum, testnet/mutinynet → explorer,
regtest → local Fulcrum. Fixes tx-explorer links to use each network's web base
(no double /testnet).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
| |
The data-source picker is now just Electrum vs Block explorer; coinos is the
first/default entry in the Electrum server list (our own Fulcrum), with public
servers as failover. Drops the standalone 'coinos' mode and the retired watcher
shim. Old 'coinos' selections migrate to electrum.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
| |
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
Flip COINOS_ELECTRUM on: the default 'coinos' mode is now a full Electrum backend
served same-origin at wss://halwallet.app/electrum (nginx -> Fulcrum on cs, synced
+ using bitcoind hashblock ZMQ), with the public Electrum servers as automatic
failover. Replaces the explorer-REST-data + coinos-watcher-push setup — one
connection to our own node now serves both data and instant notifications.
Verified the endpoint end-to-end through Cloudflare (server.version + get_balance).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
_rpcId could go non-numeric, so ++ produced NaN and requests serialized with
"id":null. _handleRpc matches responses with `msg.id != null`, so every
data-call response was dropped → the call timed out → _reconcileHeld skipped
the address → confirmations never reflected (until an unrelated full refresh).
Coerce to a number on every send. Verified via CDP: a mined deposit now flips
pending→confirmed in ~1s instead of stalling.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
Regtest now talks to a local Fulcrum over its native Electrum WebSocket for
both chain data and realtime push, instead of esplora REST + a separate watcher.
This matches prod (Fulcrum) and gives ~2-3x lower latency than the previous
electrs polling. getBackend()/electrumCandidates() route regtest to the
Electrum backend at the configured Fulcrum WS (default ws://localhost:50003);
the wallet's realtime path is ungated for regtest. ElectrumApi already covers
every call (utxos, history, fees, broadcast), incl. the swap feature.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
On regtest there's no realtime push (coinos watcher is mainnet-only), so the UI
only updated on the 5–10s poll — a funded tx took a while to appear and a
just-mined block stayed "pending" until the next reconcile. electrs speaks the
Electrum protocol the watcher already understands, but only over TCP; route it
through a small WS<->TCP bridge (see coinos-server/electrum-ws) so the wallet
subscribes scripthashes and reconciles instantly on each notification. Data
still comes from esplora; this only adds the push channel. Configurable in
Settings (default ws://localhost:50003); falls back to polling if unreachable.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
New `regtest` network (bech32 `bcrt`, testnet version bytes) selectable in
Settings, pointed at a configurable local Esplora (default http://localhost:3000).
Adds getNetwork/setNetwork + getRegtestEsplora persistence, a regtest branch in
resolveHosts, mainnet-only gating for the realtime watcher + Electrum backend,
and a Network selector card. Account loading reads the active network.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
The light frontier poll walks past already-used addresses, and _reconcileHeld
refreshed held-coin balances but not the history tx summaries — so a
pending->confirmed transition only showed via the realtime WebSocket push.
Backends without that push (custom electrs/esplora, regtest) left the History
row stuck on "pending" even after the tx confirmed. Re-fetch and update tx
summaries for changed held addresses during reconcile.
Co-Authored-By: Claude Opus 4.8 <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
The Electrum data path fired every request at once, so a scan burst dozens of
calls at a rate-limited public server, which then dropped some (the timeouts).
Add a concurrency cap (4 in flight; Electrum pipelines, so it stays fast) with
excess queued — mirrors the Esplora scheduler's intent. Verified a full scan via
the public jochen server completes in ~4.5s with peak concurrency 4, no timeouts.
The throttle queue is drained on disconnect/stop alongside in-flight calls.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
Two Electrum-backend issues:
1. Stale balance after a send made on another device: _reconcileHeld set each
address's balance from get_balance/address-stats, where a confirmed coin being
spent by an unconfirmed tx STILL counts as confirmed (with a compensating
negative unconfirmed). So a device that didn't make the send kept showing the
spent coin's value. Now the entry balance is derived from the actual unspent
set (listunspent, which excludes spent coins) — verified a spent coin clears.
2. Per-address rescan failing with 'electrum timeout: blockchain.scripthash.
get_balance': public Electrum servers can drop a response or the socket can
flap mid-call. _rpcCall now retries a couple of times on a fresh id (12s each)
before giving up.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
| |
On the Electrum backend the post-send rescan is many round-trips, so the balance
lagged a few seconds. Now a successful broadcast immediately applies the tx
locally (applySentTx): drop the spent coins, credit change as pending, add a
pending history row, recompute the balance, and emit — so the UI reflects the
send instantly. The realtime watcher / backstop poll reconciles and fills in the
confirmation once the explorer has indexed it (no immediate rescan, so a
not-yet-indexed tx can't briefly revert the optimistic state). Verified the
balance/utxo/history math.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
| |
The Esplora broadcast cleared its abort timer right after fetch() resolved, so
the subsequent res.text() body read had no timeout — a stalled response body
hung the whole broadcast (and the send spinner) indefinitely, with the tx never
reaching the network. Keep the abort timer active through the body read, and add
a hard 30s outer timeout in the send handler so a wedged broadcast always surfaces
as 'timed out — try again' instead of spinning forever. (The silent-payment tx
itself is valid — verified structure + BIP143 signature over the real outputs.)
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
| |
broadcast() set the success result but kept ui.busy=true and didn't render until
after awaiting wallet.scan(), so the 'Sign & broadcast' button spun for the whole
post-send rescan (slow under rate-limiting / on the Electrum backend) — looking
stuck even though the tx had already broadcast. Now it shows the success screen
the instant the broadcast resolves and refreshes balances in the background.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
| |
The ✕ on a wallet now opens a confirmation screen warning it's removed from this
device (keep its recovery phrase; other wallets unaffected) instead of deleting
immediately.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
- goHome: when a wallet is open, the logo goes to its Receive page (its tabs)
instead of the create/import screen — so it's always a way back to your wallet.
Only with no wallet open does it show create/import.
- Paste buttons: a clipboard 'Paste' icon on the send address field and the
import (seed/key/xpub) and 'load seed to spend' fields, filling them from the
clipboard. Hidden where the Clipboard read API isn't available.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
| |
A vault exists → Accounts screen shows Change password: enter the current
password, then a new one (with confirm; leave blank to remove it). It decrypts
the actual vault and re-encrypts it with the new password, so wallets not loaded
in the current session are never dropped. Keeps the in-memory password in sync
when the vault is already unlocked. Verified the re-encrypt round-trip
(old rejected, new works, blank works).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
The logout timer is now an account setting (stored per account in the session and
the durable directory), not a global one, and it removes only that wallet from
the device — its session entry, directory entry, cached state (xpub + seed keys),
and its vault entry — leaving other wallets untouched.
- wipeAccount(id) surgically removes one wallet; the active one falls back to the
next account (or the unlock screen).
- Background-away timestamp drives per-account evaluation on resume/boot; an armed
timer fires for the soonest-due wallet so a blurred-but-visible window still
signs out on time. Overdue saved wallets are removed from the vault when it's
unlocked (the only point we can re-encrypt it).
- New cacheKeyFor() export lets app code target one wallet's cache keys exactly
(verified against the wallet's seed/xpub/watch keys).
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
| |
With a logout timer set, signing out now removes everything from the device
including the password-protected vault — nothing survives, so the recovery
phrase is required to return. Updated the setting copy to say so.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|
| |
|
|
|
|
|
|
| |
A vault saved with no password auto-unlocks on open, which would undo the
sign-out. When a logout timer fires (or a boot is overdue), remove it too —
only a password-protected vault survives.
Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
|