Namehold v0.4.0
Added
-
System tray / menu-bar presence — Namehold now lives in the system tray
so it keeps running (local hsd node + background sync daemon alive) when the
main window is closed. The tray menu offers Open Namehold, a live node
status label with a Start/Stop node toggle, a Sync in background
checkbox, and Quit. A new System Tray section in Settings adds two
toggles: Close to tray (default ON — closing the window hides it instead
of quitting; click the tray icon or use Open to restore) and Launch at
login (registers the app to auto-start, viatauri-plugin-autostart:
LaunchAgent on macOS, Run key on Windows,.desktopon Linux). The tray
icon reflects node state with three variants (normal / syncing / stopped),
rendered as a macOS template image so it adapts to light/dark menu bars. A
3-second reconciliation ticker keeps the tray in sync with changes made
outside it (frontend actions, hsd autostart, sync transitions). New Tauri
commands:is_close_to_tray_enabled,set_close_to_tray_enabled. New
settings keys:close_to_tray,launch_at_login. -
Recover lost bids from any hsd wallet — if you reinstall, seed-restore,
or import a bid from another hsd-compatible wallet, Namehold can recover the
bid value without you remembering the exact amount. The Name Actions modal
shows a Recover bid panel during the REVEAL phase with two options:
enter the amount if you remember it, or click Auto-recover (brute-force)
to sweep candidate values. Recovery uses only the account xpub (public) —
never needs your passphrase — and works because the nonce derivation is the
hsd standard, not Namehold-specific. Typical bids under 100 HNS recover in
seconds. See docs/RECOVER_LOST_BIDS.md for the
full guide. -
Background HSD Sync Daemon — a separate Rust binary (
namehold-syncd) that
syncs wallet profiles (UTXOs, name states, transactions) from the local hsd node
every 60 seconds, even when the app is closed. Controlled by a Settings checkbox
"Sync in background" (default ON). When enabled, hsd stays running after app
exit; the next launch adopts it. A cross-process DB lock table (sync_locks)
coordinates the app's manual Sync and the daemon via heartbeats (10s) and
stale-lock takeover (30s) to prevent concurrent writes. Crash recovery: the app
respawns the daemon on startup if the toggle is ON and the daemon is dead.
Bundled as a Tauri sidecar (externalBin). -
New DB migration
021_sync_locks.sql— creates thesync_lockstable for
cross-process sync coordination. -
SPV (Simplified Payment Verification) mode — an opt-in lightweight alternative
to the full node mode. SPV downloads only block headers (~几十MB vs ~15GB),
enabling fast first launch and minimal disk usage. Balance and name data come from
the explorer; sending is blocked in SPV mode (read-only). Controlled via a
"Node mode" dropdown in Settings → Connections (default: Full node). -
Explorer failover — all explorer HTTP requests now support automatic failover
to a configurable fallback URL. Configured via "Explorer fallback URL" in Settings. -
SPV UI indicators — StatusStrip shows "Explorer (SPV)" when in SPV mode to
explain why reads come from the explorer. -
SPV-aware write capability — SPV mode shows a clear "SPV mode cannot send
transactions" message instead of the generic "node not address-indexed" error. -
TLD Management P1 — Batch operations — renew, reveal, redeem, or finalize
multiple names in one transaction. Multi-select checkboxes on the Owned Names
table with a batch action bar ("Renew Selected" / "Reveal Selected" /
"Redeem Selected" / "Finalize Selected"). Each action opens a
BatchConfirmModalshowing the count and estimated fee with a collapsible
name list before signing + broadcasting. -
TLD Management P2 — Watchlist — track names you don't own for monitoring.
New "Watchlist" page in the sidebar with add/remove, tags (comma-separated),
bulk state fetch viaget_watchlist_status, CSV import/export (name,tags, notes,added_at,state,expiry), and an "Add to Watchlist" toggle in both
NameActionsModalandNameInfoModal. Database migrations
022_watchlist.sql(base table) and024_watchlist_tags.sql(addstags
column). -
TLD Management P3 — Atomic paid name swaps — atomic finalize-with-payment
covenant: the buyer finalizes a TRANSFER and pays the seller in the same
transaction, so no party can renege after the lockup expires. Buyer side:
"Buy with payment" button on names in TRANSFER state. Seller side: "Sell
with payment" flow with saved offer tracking (023_paid_swap_offers.sql)
and a verify-onlyclaim_paid_transfercommand that inspects the
broadcast tx before marking an offer paid.
Changed
-
Removed the Portfolio page and the "Show Portfolio in the sidebar"
setting. The hiddenadvanced_mode-gated Portfolio workspace (Inventory,
Batches, Renewals, DNS tabs) and its/portfolioroute have been removed
entirely, along with theadvanced_modesetting key. The sidebar no longer
has any advanced-mode gating. -
MIT LICENSE — repo now carries an explicit MIT license file.
-
get_resourceTauri command — returns combined name info + DNS resource
records from the local hsd node with graceful degradation to the explorer for
name state. Currently backend-only (no frontend consumer after the DNS page
removal in a later commit). -
Watchlist v2 — richer columns + background alerts. The Watchlist table
now shows three additional columns pulled from the live name info: a
Countdown to the next phase transition (e.g. "Bidding closes in 42
blocks (~7h)"), the Highest bid so far, and Expires (days-until-
expire, colour-graded like the Renewals view). Names owned by the active
wallet profile get an inline Owned badge next to the name. Combined
with a new opt-in Watchlist notifications section in Settings, the
background sync daemon (namehold-syncd) polls each watched name every
60s, diffs against the last-seen snapshot in a newwatched_name_states
cache table, and fires OS notifications on: entry into BIDDING, a
previously CLOSED name becoming available again, bidding-soon lead
time (default 144 blocks / ~1 day), and a configurable global
highest-bid threshold crossing (in HNS). Adaptive polling skips names
whose next transition is > 300 blocks out when the state was refreshed
within the last 5 minutes. The daemon is the sole notifier — the in-app
scanner still owns reveal/renewal deadlines for names you've bid on or own,
so there's no double-fire. Alerts fire even when the Namehold app is closed
(as long as background sync is enabled). New Tauri command:
get_watched_states(read-only, hydrates the columns without RPC on first
page open — currently unwired on the frontend; columns hydrate via
read_name_info). New settings keys:watchlist_notify_enabled,
watchlist_notify_bidding_soon_lead_blocks,
watchlist_notify_highest_bid_threshold_hns. New DB migration:
025_watched_name_states.sql. New crate:notify-rust(cross-platform
OS notifications, no Tauri AppHandle required). -
Unified input/button sizing.
InputandSelectnow accept an
inputSizeprop ("sm" | "md", default"md") that shares the exact
padding + text-size tokens withButton'ssizeprop, so a control and the
button beside it render at identical heights. AllButtonvariants now carry
a (transparent) 1px border so bordered inputs and borderless buttons line up
to the pixel. Replaced ad-hoc raw<input>/<select>elements across the
Auctions, Activity, Namebase dashboard/import, wallet name filter, DNS
records editor, and the DataTable search box with the sharedInput/
Selectcomponents. Fixes the visible ~10px height gap between the
add-name/look-up inputs and their adjacent buttons. -
Inline node lifecycle actions. The StatusStrip node pill now opens a
popover menu with Start node / Stop node / Re-sync chain actions
(plus an "Open Settings" escape hatch), replacing the old Settings link. The
WalletView "needs node sync" callout has an inline Start node button
with an "Open Settings" fallback on failure. The update-installed banner
shows a Relaunch now button instead of directing users to Settings.
New reusablePopovercomponent (src/components/ui/Popover.tsx).
Fixed
- macOS notification sender identity — OS notifications from the
background sync daemon (namehold-syncd) now attribute to Namehold
instead of "Terminal" / Finder / a generic sender. Because the daemon runs
unbundled (no TauriAppHandle), it now claims the Namehold bundle ID via a
Once-guardedensure_notify_identity()before emitting; the Tauri app
pre-empts the same identity before the notification plugin initializes. A
new Debug Notifications panel in Settings (debug builds only) fires each
notification path on demand for verification, backed by the
#[cfg(debug_assertions)]simulate_notificationTauri command. - TldInventory bulk Transfer/Finalize — bulk actions on N selected names
now actually operate on all N, not just the first. Transfer loops N single
transactions (per-name recipient safety); Finalize uses the batch draft
command for a single atomic transaction. (Historical: the Portfolio/
TldInventory workspace this fixed is removed in this same release.) - Layout badge color inversion — the wallet capability badge now renders
CAN SEND in green (safe) and READ-ONLY in neutral gray, matching intuitive
traffic-light semantics (previously CAN SEND was red). - Sync UI view jumping — automatic sync (every 60s) no longer expands the
full sync status panel. Auto-sync shows "Syncing…" on the button with a
spinner; the full progress panel only appears for manual Sync. - Stale-data banner suppressed when node is live — the "Couldn't verify
urgent auction tasks — data may be stale." banner no longer appears during
transient query hiccups while the node is synced; it only shows when the
node is actually offline. - Unicode/IDN name lookup — the "Get a TLD" input now accepts Unicode
characters (e.g.сбер,münchen) and encodes them to ACE (Punycode) at
lookup time, instead of silently stripping non-ASCII input. Addedtr46
UTS-46 processing library andsrc/lib/idnEncode.tsmodule.
Removed
- Dead migration UI —
SyncVerificationandMigrationAssistant
components (plus their test) and thecompare_inventory_with_provider
backend command have been removed. These were scaffolding for a one-time
Namebase migration flow that is no longer needed.
CI / tooling
- sccache + mold linker + debuginfo thinning — CI cold-compile speedup
via distributed compilation caching (sccache), themoldlinker for
faster linking, and stripped debuginfo in CI builds. - Parallel rust-lint + rust-test jobs, nextest adoption — lint and test
run concurrently;cargo-nextestreplacescargo testfor per-test
parallelism and structured output. - Fast/full lane split — PR pushes run a fast lane (subset of tests);
pushes tomainrun the full suite. Configured vianextest.toml. - sccache resilience — graceful degradation when the GHA cache backend
is unreachable; CI continues uncached rather than failing. - Argon2id test-mode cost reduction —
cfg(test)drops KDF from 256 MiB
to 8 MiB, cutting vault-related tests from ~50s to <0.25s each. - Per-process temp DB paths — fixes nextest parallelism flakes where
concurrent test processes collided on the same SQLite file.