aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/sync.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-07-04 22:21:12 -0700
committerAdam Soltys <[email protected]>2026-07-04 22:21:12 -0700
commit086bcf33d532f61505a0bc19e8f2d1f08392acce (patch)
treee30d3adeb9adb70029abb7d932ab7bd28a96d010 /src/features/sync.js
parent0f96ea2500a311ab77a9fed3b10ab928370a6b0d (diff)
downloadcoinosv3-086bcf33d532f61505a0bc19e8f2d1f08392acce.tar.gz
coinosv3-086bcf33d532f61505a0bc19e8f2d1f08392acce.zip
Per-network nostr sync + honest balance loading state
One shared d-tag let a network switch apply the mainnet snapshot to a signet wallet (the flash of wrong balance) and clobber mainnet state on the relays. Each network now syncs its own replaceable event (mainnet keeps the legacy bare tag), snapshots carry netName, and a foreign-net snapshot is never applied. The balance card spins until cache, Nostr, or a scan has populated this network once — 'scanning' alone missed the cache/Nostr window after wallet.load(). Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/features/sync.js')
-rw-r--r--src/features/sync.js11
1 files changed, 9 insertions, 2 deletions
diff --git a/src/features/sync.js b/src/features/sync.js
index 8cbd9f3..41d772e 100644
--- a/src/features/sync.js
+++ b/src/features/sync.js
@@ -3,7 +3,7 @@
// (used e.g. to DM locked-gift claim codes). Installed onto the core wallet;
// a build without sync ships none of it and never talks to a relay.
-import { NostrSync, getSyncConfig, setSyncConfig, npubOf } from '../nostr.js';
+import { NostrSync, getSyncConfig, setSyncConfig, npubOf, syncDtag } from '../nostr.js';
import { t } from '../i18n.js';
export function installSyncWallet(wallet) {
@@ -28,6 +28,7 @@ export function installSyncWallet(wallet) {
const sync = getSyncConfig();
if (this.offline || !sync.enabled) return false;
this.nostr.setRelays(sync.relays);
+ this.nostr.setDtag(syncDtag(this.netName));
let remote;
try {
remote = await this.nostr.fetch();
@@ -35,6 +36,9 @@ export function installSyncWallet(wallet) {
return false;
}
if (!remote) return false;
+ // A snapshot for another network must never apply here (events published
+ // before per-network d-tags all live under the mainnet tag).
+ if (remote.netName && remote.netName !== this.netName) return false;
if ((remote.savedAt || 0) > (this._savedAt || 0)) {
this._applySnapshot(remote);
this.saveCache(); // mirror into localStorage
@@ -57,8 +61,11 @@ export function installSyncWallet(wallet) {
const sync = getSyncConfig();
if (wallet.offline || !sync.enabled) return;
wallet.nostr.setRelays(sync.relays);
+ // bind the d-tag now: the debounced publish must keep this snapshot's
+ // network even if the wallet switches networks before the timer fires
+ const dtag = syncDtag(wallet.netName);
clearTimeout(wallet._nostrPubTimer);
- wallet._nostrPubTimer = setTimeout(() => wallet.nostr.publish(snap), 2500);
+ wallet._nostrPubTimer = setTimeout(() => wallet.nostr.publish(snap, dtag), 2500);
});
wallet.registerRealtimeHook({ stop: () => clearTimeout(wallet._nostrPubTimer) });
}