diff options
| author | Adam Soltys <[email protected]> | 2026-08-01 09:09:18 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-01 09:09:18 -0700 |
| commit | 4f7cfb911a12c2447a9cd18a83f0e806912db964 (patch) | |
| tree | e30fde19ba79ff611c92c1d731995ba903b9bae1 /src/features | |
| parent | 38662483c170029b1a397f5a47cd49311012324f (diff) | |
| download | coinosv3-4f7cfb911a12c2447a9cd18a83f0e806912db964.tar.gz coinosv3-4f7cfb911a12c2447a9cd18a83f0e806912db964.zip | |
Stop the nostr sync snapshot from importing another ASP's coins
The phantom balance came back through the sync path. Snapshots published by
older builds carry no ASP tag, so the tag check passed them, and with the
local namespace empty the merge returned the snapshot wholesale — writing
second.tech's vtxos straight into the coinos namespace, where the manager
then stamped them as coinos'.
Two fixes, both grounded in the fact that a vtxo names its own cosigner:
- the sync path derives the snapshot's true owner from its vtxos and parks it
under that owner instead of merging when it isn't provably ours
- ArkManager.init drops any state whose coins were cosigned by a different
server, whatever the stamp claims. Stamps are something we wrote; the vtxo
bytes are evidence.
Found by tracing localStorage reads in the live tab: the namespaced key was
being *created* during load, which pointed at the merge rather than at
storage keying.
Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/features')
| -rw-r--r-- | src/features/ark.js | 17 |
1 files changed, 15 insertions, 2 deletions
diff --git a/src/features/ark.js b/src/features/ark.js index fd8fbaf..56ffc4c 100644 --- a/src/features/ark.js +++ b/src/features/ark.js @@ -207,9 +207,22 @@ export function arkFeature(ctx) { if (!d.arkState) return; const cfg = getArkConfig(); if (!cfg) return; - // only merge a snapshot from the same ASP — another server's vtxos are - // not ours to show (older snapshots carry no tag; accept those) if (d.arkServer && d.arkServer !== wallet._arkNs(cfg.ark)) return; + // A snapshot from an older build carries no tag, so the tag alone can't + // be trusted — ask the vtxos who cosigned them. If they belong to a + // different ASP (or we can't yet prove they belong to this one), park + // the snapshot under its real owner instead of merging it in. Merging + // blind is exactly how another server's balance appears here. + const owner = d.arkState.serverPubkey || wallet._arkVtxoOwner(d.arkState); + const mine = (ark && ark.info && ark.info.serverPubkey) + || (wallet.loadArkState(cfg.ark) || {}).serverPubkey || null; + if (owner && owner !== mine) { + try { + localStorage.setItem(wallet._arkHoldKey(owner), + JSON.stringify({ ...d.arkState, serverPubkey: owner })); + } catch {} + return; + } const local = wallet.loadArkState(cfg.ark); const merged = mergeArkStates(local, d.arkState); wallet.saveArkState(merged, cfg.ark); |
