diff options
| author | Adam Soltys <[email protected]> | 2026-08-01 08:54:59 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-08-01 08:54:59 -0700 |
| commit | 0953013271fd9fbc857d3da94a5d65662423b806 (patch) | |
| tree | e7a62d6f7cde91d66d6088061f76dbf240b7a91c /src/ark/manager.js | |
| parent | 93f167e074e1f6b0fd831f7f2f3b42fc172ef26c (diff) | |
| download | coinosv3-0953013271fd9fbc857d3da94a5d65662423b806.tar.gz coinosv3-0953013271fd9fbc857d3da94a5d65662423b806.zip | |
Keep Ark state per ASP, not just per wallet
Switching providers showed the previous server's balance and tried to resume
its in-flight board ("1 deposit confirming" against a server that had never
heard of it). A vtxo is only meaningful against the ASP that cosigned it, so
state must be scoped to both the wallet and the server.
- ark state keys gain a namespace derived from the ASP endpoint, so switching
providers switches state and switching back restores it
- state is stamped with the server pubkey; on connect a mismatch is discarded
rather than displayed. This also self-corrects the one-time adoption of
pre-namespacing state, which can only guess which ASP it belonged to
- mergeArkStates refuses to fuse two servers' states, and the nostr sync
snapshot carries (and filters on) the ASP it came from, so a device on a
different provider can't inject foreign vtxos
Nothing is deleted: each ASP's state lives under its own key, and the legacy
key is left in place for whichever server rightfully claims it.
Co-Authored-By: Claude Fable 5 <[email protected]>
Diffstat (limited to 'src/ark/manager.js')
| -rw-r--r-- | src/ark/manager.js | 14 |
1 files changed, 14 insertions, 0 deletions
diff --git a/src/ark/manager.js b/src/ark/manager.js index fc6262d..4814a26 100644 --- a/src/ark/manager.js +++ b/src/ark/manager.js @@ -54,6 +54,7 @@ import { validateVtxo, VtxoValidationError } from './validate.js'; const EMPTY_STATE = () => ({ v: 1, + serverPubkey: null, // which ASP this state belongs to (guarded in init) mailboxCheckpoint: 0, nextKeyIndex: 1, // 0 is the receive-address key vtxos: [], // { id, bytes, keyIndex, amountSat, expiryHeight, state } @@ -101,6 +102,19 @@ export class ArkManager { const hs = await handshake(this.arkUrl).catch(() => null); this.psa = hs?.psa; this.serverPub = hex.decode(this.info.serverPubkey); + + // A vtxo is only meaningful against the server that cosigned it. State + // carried over from a different ASP (a provider switch, or a snapshot + // adopted from the pre-namespacing key) would show phantom balance and + // try to resume actions this server has never heard of — so drop it. + // Nothing is lost: the other ASP's state lives under its own key. + if (this.state.serverPubkey && this.state.serverPubkey !== this.info.serverPubkey) { + this.state = EMPTY_STATE(); + } + if (!this.state.serverPubkey) { + this.state.serverPubkey = this.info.serverPubkey; + this._save(); + } return this; } |
