diff options
| author | Adam Soltys <[email protected]> | 2026-10-22 23:55:09 -0700 |
|---|---|---|
| committer | Adam Soltys <[email protected]> | 2026-10-22 23:55:09 -0700 |
| commit | c143b7dbe900df9a644bb67b87a92fd208e1ee74 (patch) | |
| tree | ac759084137091e795f788fa7c35a71e2d6e098c /src/ark/manager.js | |
| parent | a89bce97319d5860da8d581ff41cdace9acbb077 (diff) | |
| download | coinosv3-c143b7dbe900df9a644bb67b87a92fd208e1ee74.tar.gz coinosv3-c143b7dbe900df9a644bb67b87a92fd208e1ee74.zip | |
The wallet opens on the Ark server's last published info when the server is gone, and a unilateral exit needs only that
Adam, 2026-10-23: the app must stay navigable and able to exit if Coinos disappears. The shell already was (the worker precaches every chunk; verified with every coinos host unresolvable: boot, wallet creation, Savings address, Send all work, and Electrum fails over to public servers). The Ark side was not: connectArk's init asked the server for its info and threw, so the Manage page's Exit stayed disabled and doArkExit waited on a connect that could never finish.
ArkManager takes infoHint (the btc-wallet-arkinfo cache the app keeps per server): when GetArkInfo fails and a hint exists, init proceeds on it with `offline` set; the server key, fee tables and lifetimes are in it, and an exit needs the chain (esplora, not Coinos) rather than the server. doArkExit uses the initialized manager and waits on init alone, not on the Nostr snapshot gate the full connect also waits for (its relays may be gone too). tools/ark-offline-init.test.js.
Co-Authored-By: Claude Fable 5.1 <[email protected]>
Diffstat (limited to 'src/ark/manager.js')
| -rw-r--r-- | src/ark/manager.js | 20 |
1 files changed, 18 insertions, 2 deletions
diff --git a/src/ark/manager.js b/src/ark/manager.js index df199af..33bac55 100644 --- a/src/ark/manager.js +++ b/src/ark/manager.js @@ -208,8 +208,12 @@ export function renewPolicy(tier, network) { } export class ArkManager { - constructor({ account, storage, arkUrl, esploraUrl, network = 'regtest', onUpdate, lnQuoteUrl, statusHint, honorsExpired = false }) { + constructor({ account, storage, arkUrl, esploraUrl, network = 'regtest', onUpdate, lnQuoteUrl, statusHint, honorsExpired = false, infoHint = null }) { this.account = account; // HDKey node; ark keys derived beneath it + // The server's last published info, kept by the app: lets the wallet open + // when the server can't be reached (see init) + this.infoHint = infoHint || null; + this.offline = false; // the server cosigns spends of a coin past its timelock (coinos): such a // coin stays money here — spendable, receivable — just not exitable this.honorsExpired = !!honorsExpired; @@ -275,7 +279,19 @@ export class ArkManager { seen.add(m.vtxoId); return true; }); - this.info = await getArkInfo(this.arkUrl); + try { + this.info = await getArkInfo(this.arkUrl); + this.offline = false; + } catch (e) { + // The server is unreachable. With its last published info in hand the + // wallet still opens on its own records: coins read, a unilateral exit + // can start (that needs the chain, not the server), and anything that + // does need the server fails when it asks. Without that info there is + // no server key to check anything against — then it really is closed. + if (!this.infoHint) throw e; + this.info = this.infoHint; + this.offline = true; + } const hs = await handshake(this.arkUrl).catch(() => null); this.psa = hs?.psa; this.serverPub = hex.decode(this.info.serverPubkey); |
