Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
67 commits
Select commit Hold shift + click to select a range
302b05f
fix(identity): show spendable balance, not total, on funding screens
lklimek Jul 8, 2026
819f27c
docs(wallets): document deferred non-remember-unlock registration gap
lklimek Jul 8, 2026
2f36ed1
refactor(wallets): tidy wallet-backend caches and trim dead surface
lklimek Jul 8, 2026
d864397
Merge branch 'fix/r2-w9' — Wave 9: wallet-backend caches & nits
lklimek Jul 8, 2026
b072970
refactor(context): consolidate identity_db kv access, errors, and vot…
lklimek Jul 8, 2026
0cebdc0
Merge branch 'fix/r2-w6' — Wave 6: identity_db + scheduled votes
lklimek Jul 8, 2026
08a1a9f
refactor(ui): delete dead UI surface and dedup icon loaders
lklimek Jul 8, 2026
33fb75e
Merge branch 'fix/r2-w20' — Wave 20: dead UI surface deletion
lklimek Jul 8, 2026
6f13a25
refactor(wallet_backend): dedup funds paths and harden error typing (…
lklimek Jul 8, 2026
c657aeb
Merge branch 'fix/r2-w2' — Wave 2: wallet-backend funds paths & error…
lklimek Jul 8, 2026
f1494a2
refactor(wallet): scope test-only single-key signing helpers to tests
lklimek Jul 8, 2026
8474757
refactor(wallet): dedup secret decrypt, bincode framing, prompt meta …
lklimek Jul 8, 2026
ed6580f
refactor(wallet-backend): dedup KV/sidecar layer
lklimek Jul 8, 2026
584c1dc
refactor(dashpay): typed errors + move derivation to model/ (Wave 13)
lklimek Jul 8, 2026
842b46e
refactor(wallets): single-source fee/amount/dpns and drop dead send s…
lklimek Jul 8, 2026
2ead530
refactor(dashpay): unify avatar pipeline, profile validation, delete …
lklimek Jul 8, 2026
0ec637f
Merge branch 'fix/r2-w8' — Wave 8: wallet-backend KV/sidecar dedup
lklimek Jul 8, 2026
834dc55
refactor(tokens): honest fees, shared token executor, grouped contrac…
lklimek Jul 8, 2026
a64cf2c
refactor(backend): typed contract recovery + document mutation helper
lklimek Jul 8, 2026
bf01fff
Merge branch 'fix/r2-w1' — Wave 1: secret access & signing surface
lklimek Jul 8, 2026
180a214
refactor(model): enforce model-layer purity and tidy MCP tool boundary
lklimek Jul 8, 2026
d616018
Merge branch 'fix/r2-w3' — Wave 3: backend contracts/documents/tokens
lklimek Jul 8, 2026
b409df6
refactor(app): collapse boot/reconcilers, fold context_provider, drop…
lklimek Jul 8, 2026
dbbb192
Merge branch 'fix/r2-w4' — Wave 4: amount/fee/unified-send single-sou…
lklimek Jul 8, 2026
02e8e6e
Merge branch 'fix/r2-w13' — Wave 13: DashPay backend typed errors + d…
lklimek Jul 8, 2026
9ab7d85
Merge branch 'fix/r2-w17' — Wave 17: DashPay UI
lklimek Jul 8, 2026
19ac684
Merge branch 'fix/r2-w15' — Wave 15: model-layer purity + MCP tools
lklimek Jul 8, 2026
7885ffd
fix(backend_task): update stale proof_log_item import after Wave 15 r…
lklimek Jul 8, 2026
38af70a
Merge branch 'fix/r2-w12' — Wave 12: app.rs/boot/feature flags/contex…
lklimek Jul 8, 2026
d7873d2
refactor(context): tidy contract_token_db — typed encode error, dedup…
lklimek Jul 8, 2026
bab96be
Merge branch 'fix/r2-w7' — Wave 7: context/contract_token_db.rs
lklimek Jul 8, 2026
9a60134
refactor(backend_task): consolidate error.rs and replace message-as-p…
lklimek Jul 8, 2026
184472d
refactor(context): consolidate wallet_lifecycle orchestration (Wave 11)
lklimek Jul 8, 2026
e089261
refactor(identities): consolidate funding-method chooser + preserve e…
lklimek Jul 8, 2026
1eddaa5
Merge branch 'fix/r2-w5' — Wave 5: identity funding screens + PR-869 …
lklimek Jul 8, 2026
c529550
Merge branch 'fix/r2-w11' — Wave 11: wallet_lifecycle.rs orchestration
lklimek Jul 8, 2026
5900627
Merge branch 'fix/r2-w14' — Wave 14: error.rs consolidation + typed m…
lklimek Jul 8, 2026
10f7a0f
refactor(context): remove write-only Core-RPC health plumbing (CODE-016)
lklimek Jul 8, 2026
b1b5c9d
fix(context): make settings updaters atomic, drop dead shims (CODE-02…
lklimek Jul 8, 2026
e89fd68
refactor(context): extract shared platform-address seeding loop (CODE…
lklimek Jul 8, 2026
9027547
refactor(context): name DPNS contest-duration constants (CODE-040)
lklimek Jul 8, 2026
e3c3a99
refactor: small context/kv one-liner cleanups (CODE-045)
lklimek Jul 8, 2026
e2c5876
Merge branch 'fix/r2-w10' — Wave 10: settings / connection-status / c…
lklimek Jul 8, 2026
60fd161
refactor(ui): Wave 19 — dedup UI component surface
lklimek Jul 8, 2026
f35046a
refactor(wallet): Wave 16 — wallet model internals
lklimek Jul 8, 2026
fa11602
Merge branch 'fix/r2-w19' — Wave 19: UI components dedup
lklimek Jul 8, 2026
39de7f2
Merge branch 'fix/r2-w16' — Wave 16: wallet model internals
lklimek Jul 8, 2026
0ccf1c9
refactor(wallet): fold shielded screens into unified send screen (COD…
lklimek Jul 8, 2026
36da999
refactor(tokens): Wave 18 — unify token action screens + dedup rules …
lklimek Jul 8, 2026
7c7ad3f
Merge branch 'fix/r2-w18' — Wave 18: tokens UI dedup
lklimek Jul 8, 2026
a49c1de
fix(wallet): address QA findings on shielded send-flow fold
lklimek Jul 8, 2026
4104827
Merge branch 'fix/r2-code098' — CODE-098: fold shielded screens into …
lklimek Jul 8, 2026
4dc8380
docs(comments): Wave 21 — comment/narration hygiene sweep
lklimek Jul 8, 2026
20fb1ab
Merge branch 'fix/r2-w21' — Wave 21: comment/narration hygiene sweep …
lklimek Jul 8, 2026
1fd13b6
docs(changelog): add round-2 audit user-facing changes
lklimek Jul 8, 2026
12ff20e
fix(identity): confine hero card gradient to card bounds
lklimek Jul 9, 2026
a44a684
refactor(errors): replace stringly-typed error variants with typed so…
lklimek Jul 9, 2026
f6120bf
docs(contested-names): point contract-not-found TODOs at issue #875
lklimek Jul 9, 2026
dc6a36f
fix(wallet): unify lock-poison recovery, route single-key I/O through…
lklimek Jul 9, 2026
847a3a6
fix(address): centralize network-prefix validation in model/ and gate…
lklimek Jul 9, 2026
d8db185
refactor(wallet): add AppContext::wallet_arc helper; log skipped corr…
lklimek Jul 9, 2026
7eea2a3
fix: replace panicking unwrap/expect in production paths with error p…
lklimek Jul 9, 2026
2aa822b
chore: remove ephemeral review-IDs, tombstones, speculative dead_code…
lklimek Jul 9, 2026
9f0fede
docs(database): restore the upstream-ownership note in get_wallets
lklimek Jul 9, 2026
ecd9cfa
refactor(context): split wallet_lifecycle god-file into responsibilit…
lklimek Jul 9, 2026
ae618f5
fix(identity): flat hero card — drop the gradient for the theme surface
lklimek Jul 9, 2026
8efc7bc
fix: update legacy-table allow-list for relocated wallet_lifecycle te…
lklimek Jul 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,16 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
separate "fund directly from a specific transaction output" path was removed so
there is a single, double-spend-safe funding flow.

- **DashPay profile no longer requires a display name**: you can save your profile
with the display name left blank; only the length limits on name, bio, and
avatar URL are still enforced.

- **Shield, Send Privately, and Unshield are now one screen**: each of these
actions opens the same Send screen, already set up for what you clicked, instead
of a separate dedicated screen per action. The steps and options are unchanged,
including pasting a raw shielded address in hex form — there are just fewer
screens to navigate between.

### Known Limitations

- **Single-key wallets — send and balance refresh not available**: importing a
Expand Down Expand Up @@ -148,3 +158,14 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/).
stay on screen until you dismiss them yourself. Routine notices (a
successful action, a validation hint, an in-progress status) still clear
automatically as before.
- Choosing a funding method on the identity registration or top-up screen and
then switching wallets no longer silently discards your choice and reverts
to the default funding method.
- The top-up screen's automatic wallet selection no longer pre-selects a
wallet whose spendable balance is too small or currently locked to actually
cover the top-up, which would then be immediately rejected.
- The "My Tokens" tab no longer gets stuck on a loading spinner when you have
no identities yet; it now shows the expected empty state.
- Two settings changes made in quick succession could occasionally cause one
of them to be silently lost. Saving settings is now a single atomic step,
so no change is dropped.
4 changes: 2 additions & 2 deletions CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -271,7 +271,7 @@ Screens hold `Arc<AppContext>` and manage their own UI state.

### ConnectionStatus (single source of truth for connection health)

`ConnectionStatus` (`src/context/connection_status.rs`) is the **single source of truth** for all high-level connection health state — RPC, ZMQ, SPV, and DAPI. For connection health (status, peer counts, errors, overall state), always read from `ConnectionStatus`, not directly from `SpvManager` or other subsystems.
`ConnectionStatus` (`src/context/connection_status.rs`) is the **single source of truth** for all high-level connection health state — SPV and DAPI. For connection health (status, peer counts, errors, overall state), always read from `ConnectionStatus`, not directly from `SpvManager` or other subsystems.

SPV status is **push-based**: `SpvManager` event handlers write directly to `ConnectionStatus` atomics (status, peer count, errors) as events arrive. The UI frame loop calls `refresh_state()` to recompute `overall_state` from these atomics, but does not poll SPV for health. This means `ConnectionStatus` is up-to-date in both GUI and headless/test contexts. Detailed SPV sync progress (heights, phase summaries used by tooltips) may still be read directly from `SpvManager.status()` until that progress reporting is migrated into `ConnectionStatus`.

Expand Down Expand Up @@ -327,4 +327,4 @@ Single SQLite connection wrapped in `Mutex<Connection>`. Schema initialized in `

Linux (x86_64/aarch64), Windows (x86_64), macOS (x86_64/aarch64 with code signing)

Requires protoc v25.2+ for protocol buffer compilation. Different ZMQ libraries for Windows (`zeromq`) vs Unix (`zmq`).
Requires protoc v25.2+ for protocol buffer compilation.
11 changes: 2 additions & 9 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,12 @@ native-dialog = "0.9.0"
raw-cpuid = "11.5.0"

[features]
default = ["identity-hub"]
default = []
testing = []
bench = []
mcp = ["dep:rmcp", "rmcp/server", "rmcp/macros", "rmcp/transport-streamable-http-server", "dep:axum", "dep:subtle"]
cli = ["dep:rmcp", "rmcp/server", "rmcp/macros", "rmcp/client", "rmcp/transport-io", "rmcp/transport-streamable-http-client-reqwest", "dep:clap", "dep:clap_complete"]
headless = ["cli", "mcp"]
# New unified Identities hub UI section (four-tab: Home/Contacts/Activity/Settings).
# Default-enabled. Disable to get a smaller compile surface when iterating on legacy
# Identities / Dashpay screens only.
identity-hub = []
# Unified Activity timeline aggregator. Off by default — the aggregator backend does
# not exist yet; when off, the Activity tab renders a gated "coming soon" message.
identity-hub-activity-feed = ["identity-hub"]

[dev-dependencies]
egui_kittest = { version = "0.35.0", features = ["eframe"] }
Expand Down Expand Up @@ -155,7 +148,7 @@ debug = "line-tables-only"

[lints.rust.unexpected_cfgs]
level = "warn"
check-cfg = ["cfg(tokio_unstable)", "cfg(feature, values(\"testing\", \"bench\", \"mcp\", \"cli\", \"headless\", \"identity-hub\", \"identity-hub-activity-feed\"))"]
check-cfg = ["cfg(tokio_unstable)", "cfg(feature, values(\"testing\", \"bench\", \"mcp\", \"cli\", \"headless\"))"]


[lints.clippy]
Expand Down
58 changes: 58 additions & 0 deletions docs/ai-design/2026-07-08-secret-decrypt-dedup/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Secret-decrypt dedup (audit R2, Wave 1 — CODE-003)

**Date:** 2026-07-08
**Scope:** `model/wallet/encryption.rs`, `wallet_backend/{secret_access,single_key_entry}.rs`

## Decision: local dedup (route a), NOT the upstream per-secret migration (route b)

CODE-003 flagged the AES-256-GCM decrypt sequence (derive Argon2 key → init cipher
→ checked-nonce → decrypt) as copy-pasted across three readers:

- `wallet_backend/secret_access.rs::decrypt_hd_seed` — HD-seed migration reader
- `wallet_backend/single_key_entry.rs::SingleKeyEntry::decrypt` — imported single-key reader
- `model/wallet/encryption.rs::ClosedKeyItem::decrypt_seed` — deprecated `src/database` seed store

The triage rationale proposed adopting the upstream platform per-secret encryption
(XChaCha20-Poly1305 Tier-2 via `SecretStore::set_secret`/`get_secret`, already wired
in `secret_seam.rs` as `put_secret_protected`/`get_secret_protected`) and deleting the
local code.

**We did NOT do that, deliberately.** Those three AES-GCM decrypts are the **legacy
migration reader** for wallet secrets already written to users' disks in DET's own
AES-GCM envelope format. Two authoritative module docs establish this:

- `secret_seam.rs` module doc: *"The only remaining legacy decrypt (for not-yet-migrated
AES-GCM secrets) lives in the legacy reader."*
- `wallet_seed_store.rs` module doc: the `envelope.v1` row *"is retained DECODE-ONLY as a
migration reader … rewritten to the raw label on the first load/unlock and then deleted."*

The Tier-2 primitive already exists and the lazy legacy→Tier-2 re-wrap already runs in
`secret_access::decrypt_jit`. Route (b) is therefore a **data migration** whose write side
is already built — the readers must stay until every user's on-disk secret has been
re-wrapped. Deleting them would lock users out of existing wallets.

## What was done (route a)

Extracted one crate-private `decrypt_message(ciphertext, salt, nonce, password, site)`
in `model/wallet/encryption.rs`, returning `Zeroizing<Vec<u8>>` and a two-variant
`DecryptError` (`WrongPassword` = AEAD auth failure; `Malformed` = structural/corrupt).
All three readers route through it, mapping the two variants to their existing domain
errors. Behavior is preserved exactly (same `TaskError` mapping for wrong-password vs
corrupt-blob; same length validation at each caller). Structural diagnostics are logged
once inside the helper with a `site` field.

## Consequence for Wave 16 CODE-087

**CODE-087 still applies, unchanged.** It targets the `(Vec<u8>, Vec<u8>, Vec<u8>)` triple
returned by `encrypt_message` (+ its `type_complexity` allows) in
`model/wallet/encryption.rs`. Route (a) keeps `encryption.rs` and `encrypt_message`
exactly as-is, so the named-struct cleanup CODE-087 asks for is neither resolved nor
mooted by this change — schedule it as originally planned.

## If route (b) is ever scheduled

It is a standalone migration task, not a dedup: extend the existing lazy re-wrap so the
`ClosedKeyItem` (deprecated `src/database`) path is also migrated, confirm all three
legacy formats have a re-wrap path, keep the readers until telemetry/versioning shows no
un-migrated secrets remain, then delete the readers and `encryption.rs` together. Route (a)
does not block route (b).
Loading
Loading