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 /tools | |
| 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 thatHEADmaster
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 'tools')
| -rw-r--r-- | tools/ark-offline-init.test.js | 22 |
1 files changed, 22 insertions, 0 deletions
diff --git a/tools/ark-offline-init.test.js b/tools/ark-offline-init.test.js new file mode 100644 index 0000000..922682d --- /dev/null +++ b/tools/ark-offline-init.test.js @@ -0,0 +1,22 @@ +// bun test tools/ark-offline-init.test.js — the Ark server gone: with the +// server's last published info in hand the manager still opens (coins read, +// exits can start); without it, init fails as before. +import { test, expect, mock } from 'bun:test'; +import * as proto from '../src/ark/proto.js'; +mock.module('../src/ark/proto.js', () => ({ ...proto, + getArkInfo: async () => { throw new Error('fetch failed'); }, + handshake: async () => { throw new Error('fetch failed'); }, +})); +const { ArkManager } = await import('../src/ark/manager.js'); +const serverPubkey = '02' + 'ab'.repeat(32); +const hint = { serverPubkey, vtxoExpiryDelta: 8640, vtxoExitDelta: 144, refreshFees: { baseFeeSat: 300, ppmExpiryTable: [] }, offboardFees: { baseFeeSat: 0, fixedAdditionalVb: 0, ppmExpiryTable: [] }, lnSendFees: {}, lnReceiveFees: {} }; +const mk = (infoHint) => new ArkManager({ account: null, storage: { load: () => ({ v: 1, serverPubkey, vtxos: [], actions: [], movements: [], scheduled: [] }), save() {} }, arkUrl: 'http://x', esploraUrl: 'http://y', network: 'mainnet', infoHint }); +test('with cached info the manager opens offline', async () => { + const m = await mk(hint).init(); + expect(m.offline).toBe(true); + expect(m.info.refreshFees.baseFeeSat).toBe(300); + expect(Buffer.from(m.serverPub).toString('hex')).toBe(serverPubkey); +}); +test('without cached info the old failure stands', async () => { + await expect(mk(null).init()).rejects.toThrow('fetch failed'); +}); |
