aboutsummaryrefslogtreecommitdiffstats
path: root/src/features/ark.js
diff options
context:
space:
mode:
authorAdam Soltys <[email protected]>2026-09-22 11:24:34 -0700
committerAdam Soltys <[email protected]>2026-09-22 11:24:34 -0700
commit229746922fbd566ef9014845c2111c5044ac91fa (patch)
tree074d800cef61ce3c75bdfd7731828d8ad2f0280d /src/features/ark.js
parentff0038baed91f79722c3a3ac71651cdd1fc145e8 (diff)
downloadcoinosv3-229746922fbd566ef9014845c2111c5044ac91fa.tar.gz
coinosv3-229746922fbd566ef9014845c2111c5044ac91fa.zip
Ark: receives waiting with another server are claimed; notifications belong to the identity.
Once per session the wallet visits every other Ark server it holds state with — its own manager, a receive rescan, a sync to claim — and says what arrived and where; the coins wait there until a switch back. The stored notification list remembers which identity fetched it, so another identity on the same wallet starts empty instead of reading the previous one's. Co-Authored-By: Claude Fable 5.1 <[email protected]> Claude-Session: https://claude.ai/code/session_01Tmfg8k5f3TbNJS34qiqHAp
Diffstat (limited to 'src/features/ark.js')
-rw-r--r--src/features/ark.js39
1 files changed, 38 insertions, 1 deletions
diff --git a/src/features/ark.js b/src/features/ark.js
index 2b81a1e..ab7f28d 100644
--- a/src/features/ark.js
+++ b/src/features/ark.js
@@ -417,6 +417,7 @@ export function arkFeature(ctx) {
// the next connect's first tick re-decides for the wallet now open.
arkRenewWarn = null;
arkAutoRefreshAt = 0;
+ rescuedServers = false;
}
function arkAvailable() {
@@ -443,7 +444,7 @@ export function arkFeature(ctx) {
store.open().then(() => { ctx.forgetAmountAnim && ctx.forgetAmountAnim(); render(); initArk(); }).catch(() => {});
return;
}
- if (arkAvailable() && arkWanted()) { lastAutoInit = Date.now(); connectArk().catch(() => {}); }
+ if (arkAvailable() && arkWanted()) { lastAutoInit = Date.now(); connectArk().then(() => rescueOtherServers()).catch(() => {}); }
}
// Automatic re-inits (a synced snapshot arriving) must not restart a
@@ -452,6 +453,42 @@ export function arkFeature(ctx) {
// card's "connecting" indicator flickers on every snapshot. User-driven
// calls to initArk() stay immediate.
let lastAutoInit = 0;
+ // A payment can land with a server this wallet is NOT connected to: an
+ // invoice minted for its coinos name by the background answerer before a
+ // switch, or by another device still on the old server. Once per session,
+ // every other server this wallet holds state with gets a short visit — its
+ // own manager, a receive rescan, a sync to claim — and a toast says what
+ // arrived and where. The coins stay with that server until a switch back.
+ let rescuedServers = false;
+ async function rescueOtherServers() {
+ if (rescuedServers || wallet.watchOnly) return;
+ rescuedServers = true;
+ const cur = getArkConfig();
+ if (!cur) return;
+ for (const p of arkPresets(getNetwork())) {
+ if (!p.ark || p.ark === cur.ark || p.id === 'custom' || p.id === 'off') continue;
+ if (!wallet.loadArkState(p.ark)) continue; // never used that server
+ try {
+ const mgr = new ArkManager({
+ account: wallet.account(),
+ storage: {
+ load: () => wallet.loadArkState(p.ark),
+ adopt: (serverPubkey) => wallet.adoptArkState(serverPubkey, p.ark),
+ save: (s) => { wallet.saveArkState(mergeArkStates(s, wallet.loadArkState(p.ark)), p.ark); },
+ },
+ arkUrl: p.ark, esploraUrl: p.esplora, network: getNetwork(),
+ });
+ await mgr.init();
+ const done = () => (mgr.state.movements || []).filter((m) => m.type === 'ln-receive' && m.status === 'complete');
+ const before = done().length;
+ await mgr.sync(); // rescans receives and drives the claims
+ await new Promise((r) => setTimeout(r, 2500));
+ await mgr.sync(); // a claim takes more than one step
+ const got = done().slice(before).reduce((n, m) => n + (m.amountSat || 0), 0);
+ if (got > 0) toast(t('arkOtherServerReceipt', { amount: fmtSats(got), server: p.label.replace(/ \(.*\)$/, '') }), 9000);
+ } catch (e) { console.warn('ark: rescue on ' + p.ark + ' failed', e); }
+ }
+ }
function maybeInitArk() {
if (ark || arkConnectPromise) return;
if (Date.now() - lastAutoInit < 20000) return;