Repository navigation
DPNS departure tracking is session-scoped, so username ownership and marketplace departure classification cannot both stay correct #5019
Description
Expected Behavior
When a wallet-owned identity loses a DPNS name (sold, transferred or deleted outside the wallet), the local owned-name list drops it, and the marketplace sweep still classifies the departure (sale / transfer / deletion, history, sale-triggered balance refresh). This holds across restarts and failed sweep passes. A stale snapshot from the previous owner never changes the new owner's state.
Current Behavior
The DPNS marketplace sweep discovers departures only from ManagedIdentity.dpns_names and the session-scoped dpns_name_states (departure_candidates, sync_dpns_marketplace). dpns_name_states starts empty on every load (manager/load.rs). The owned-name list is therefore both the current-ownership record and the only durable departure trigger, and no choice for username fetches keeps both correct:
- Prune on a complete username fetch. Ownership is right, but a label pruned before the next sweep loses its only trigger. An in-memory pending-departure queue was tried in fix(sdk): keep the chosen DPNS name across wallet sync #4978 (78b0e0e); it does not survive a restart or a failed resolution.
- Keep labels for wallet-owned identities (fix(sdk): keep the chosen DPNS name across wallet sync #4978 as merged,
apply_fetched_dpns_names). Departures stay with the sweep, but:- A complete
refresh_dpns_names()(loading.rs) with an empty result leaves the departed name in the list while marketplace sync is not running (DpnsSyncManageris not auto-started), and later snapshots keep advertising it as owned. - After an external A→B transfer, B's username sync rebinds the name row to B. Any later snapshot of A (for example a balance refresh) still carries the name, so the Swift persister rebinds the row back to A and clears B's
mainDpnsName(rebind branch). The erased selection cannot be reconstructed.
- A complete
Possible Solution
Separate the two concerns:
- Departure work becomes durable. Persist pending departures alongside the ownership snapshot, e.g. a changeset /
IdentityEntryfield carried through FFI and restored on load. The sweep acknowledges an entry only after its reconciliation is durably applied, and keeps failed entries for later passes without blocking others. - Username fetches prune freely once departures are durable. A complete fetch then updates current ownership for wallet-owned identities too, and stale snapshots stop carrying departed names.
- Rebinds become reversible. Clear another identity's selection only on confirmed departure evidence, not on a snapshot rebind; otherwise keep the selection and let read-time ownership (
ownedMainDpnsName) hide it.
Steps to Reproduce (for bugs)
Found by code review of #4978 (review at c8ce2d8), not reproduced on a network. The review's scenarios:
- Wallet-owned identity holds
alice;aliceleaves it externally; callrefresh_dpns_names()with marketplace sync not started.dpns_namesstill containsalice. - Identities A and B in one wallet;
alicetransfers A→B externally; B's username sync runs; the user selectsalicefor B; a balance refresh for A emits a snapshot. The row rebinds to A and B's selection is cleared.
Context
Follow-up to #4978 (chosen DPNS name lost on every relaunch, support ticket 32382). The ticket's scenario is fixed and verified there. This issue covers ownership and departure edge cases the review surfaced, which need a durable departure store rather than another trade-off inside that PR.
Your Environment
platform v4.3-dev with #4978 (c8ce2d8b24), rs-platform-wallet + swift-sdk; testnet.
Activity