aboutsummaryrefslogtreecommitdiffstats
path: root/src/features
diff options
context:
space:
mode:
Diffstat (limited to 'src/features')
-rw-r--r--src/features/ark.js35
1 files changed, 28 insertions, 7 deletions
diff --git a/src/features/ark.js b/src/features/ark.js
index 27dd871..b5c2cd9 100644
--- a/src/features/ark.js
+++ b/src/features/ark.js
@@ -46,15 +46,35 @@ export function installArkWallet(wallet) {
_arkKey(url) { return this._cacheKey() + ':ark:' + this._arkNs(url); },
_arkLegacyKey() { return this._cacheKey() + ':ark'; },
loadArkState(url) {
+ // NB deliberately no fallback to the legacy key: the UI renders from
+ // this before any server is contacted, so returning another ASP's state
+ // here is exactly how you get a phantom balance. Pre-namespacing state
+ // is claimed via adoptArkState() once we know who cosigned it.
try {
const cur = localStorage.getItem(this._arkKey(url));
- if (cur) return JSON.parse(cur);
- // One-time adoption of pre-namespacing state. The manager verifies the
- // server pubkey on connect and discards it if it belongs elsewhere,
- // so a wrong guess here is self-correcting; the legacy key is left in
- // place so the rightful ASP can still claim it.
- const legacy = localStorage.getItem(this._arkLegacyKey());
- return legacy ? JSON.parse(legacy) : null;
+ return cur ? JSON.parse(cur) : null;
+ } catch { return null; }
+ },
+ // Offer up pre-namespacing state, but only to the ASP that actually
+ // cosigned it. Its owner is read from the state's own stamp, or failing
+ // that decoded straight out of a vtxo — the vtxo wire format carries the
+ // server pubkey, so this needs no network call and cannot guess wrong.
+ adoptArkState(serverPubkey, url) {
+ try {
+ const raw = localStorage.getItem(this._arkLegacyKey());
+ if (!raw) return null;
+ const st = JSON.parse(raw);
+ let owner = st.serverPubkey || null;
+ if (!owner) {
+ const v = (st.vtxos || []).find((x) => x.bytes);
+ if (v) { try { owner = decodeVtxo(hex.decode(v.bytes)).serverPubkey; } catch {} }
+ }
+ if (owner && owner !== serverPubkey) return null; // belongs to another ASP
+ if (!owner) return null; // can't prove ownership: leave it
+ st.serverPubkey = owner;
+ this.saveArkState(st, url);
+ localStorage.removeItem(this._arkLegacyKey()); // now safely namespaced
+ return st;
} catch { return null; }
},
saveArkState(state, url) {
@@ -218,6 +238,7 @@ export function arkFeature(ctx) {
account: wallet.account(),
storage: {
load: () => wallet.loadArkState(cfg.ark),
+ adopt: (serverPubkey) => wallet.adoptArkState(serverPubkey, cfg.ark),
// merge-on-save: the MANAGER is authoritative for the state of the
// vtxos it tracks (its reconcile/spends must persist), so its state
// is the first arg and wins; storage only contributes vtxos the