@unicitylabs/sphere-sdk 0.4.7 → 0.4.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -14,6 +14,175 @@ var __export = (target, all) => {
14
14
  __defProp(target, name, { get: all[name], enumerable: true });
15
15
  };
16
16
 
17
+ // constants.ts
18
+ function getAddressId(directAddress) {
19
+ let hash = directAddress;
20
+ if (hash.startsWith("DIRECT://")) {
21
+ hash = hash.slice(9);
22
+ } else if (hash.startsWith("DIRECT:")) {
23
+ hash = hash.slice(7);
24
+ }
25
+ const first = hash.slice(0, 6).toLowerCase();
26
+ const last = hash.slice(-6).toLowerCase();
27
+ return `DIRECT_${first}_${last}`;
28
+ }
29
+ var DEFAULT_ENCRYPTION_KEY, STORAGE_KEYS_GLOBAL, STORAGE_KEYS_ADDRESS, STORAGE_KEYS, DEFAULT_NOSTR_RELAYS, NIP29_KINDS, DEFAULT_AGGREGATOR_URL, DEV_AGGREGATOR_URL, TEST_AGGREGATOR_URL, DEFAULT_IPFS_GATEWAYS, DEFAULT_BASE_PATH, DEFAULT_DERIVATION_PATH, DEFAULT_ELECTRUM_URL, TEST_ELECTRUM_URL, TOKEN_REGISTRY_URL, TOKEN_REGISTRY_REFRESH_INTERVAL, TEST_NOSTR_RELAYS, DEFAULT_GROUP_RELAYS, NETWORKS;
30
+ var init_constants = __esm({
31
+ "constants.ts"() {
32
+ "use strict";
33
+ DEFAULT_ENCRYPTION_KEY = "sphere-default-key";
34
+ STORAGE_KEYS_GLOBAL = {
35
+ /** Encrypted BIP39 mnemonic */
36
+ MNEMONIC: "mnemonic",
37
+ /** Encrypted master private key */
38
+ MASTER_KEY: "master_key",
39
+ /** BIP32 chain code */
40
+ CHAIN_CODE: "chain_code",
41
+ /** HD derivation path (full path like m/44'/0'/0'/0/0) */
42
+ DERIVATION_PATH: "derivation_path",
43
+ /** Base derivation path (like m/44'/0'/0' without chain/index) */
44
+ BASE_PATH: "base_path",
45
+ /** Derivation mode: bip32, wif_hmac, legacy_hmac */
46
+ DERIVATION_MODE: "derivation_mode",
47
+ /** Wallet source: mnemonic, file, unknown */
48
+ WALLET_SOURCE: "wallet_source",
49
+ /** Wallet existence flag */
50
+ WALLET_EXISTS: "wallet_exists",
51
+ /** Current active address index */
52
+ CURRENT_ADDRESS_INDEX: "current_address_index",
53
+ /** Nametag cache per address (separate from tracked addresses registry) */
54
+ ADDRESS_NAMETAGS: "address_nametags",
55
+ /** Active addresses registry (JSON: TrackedAddressesStorage) */
56
+ TRACKED_ADDRESSES: "tracked_addresses",
57
+ /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
58
+ LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
59
+ /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
60
+ GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
61
+ /** Cached token registry JSON (fetched from remote) */
62
+ TOKEN_REGISTRY_CACHE: "token_registry_cache",
63
+ /** Timestamp of last token registry cache update (ms since epoch) */
64
+ TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
65
+ /** Cached price data JSON (from CoinGecko or other provider) */
66
+ PRICE_CACHE: "price_cache",
67
+ /** Timestamp of last price cache update (ms since epoch) */
68
+ PRICE_CACHE_TS: "price_cache_ts"
69
+ };
70
+ STORAGE_KEYS_ADDRESS = {
71
+ /** Pending transfers for this address */
72
+ PENDING_TRANSFERS: "pending_transfers",
73
+ /** Transfer outbox for this address */
74
+ OUTBOX: "outbox",
75
+ /** Conversations for this address */
76
+ CONVERSATIONS: "conversations",
77
+ /** Messages for this address */
78
+ MESSAGES: "messages",
79
+ /** Transaction history for this address */
80
+ TRANSACTION_HISTORY: "transaction_history",
81
+ /** Pending V5 finalization tokens (unconfirmed instant split tokens) */
82
+ PENDING_V5_TOKENS: "pending_v5_tokens",
83
+ /** Group chat: joined groups for this address */
84
+ GROUP_CHAT_GROUPS: "group_chat_groups",
85
+ /** Group chat: messages for this address */
86
+ GROUP_CHAT_MESSAGES: "group_chat_messages",
87
+ /** Group chat: members for this address */
88
+ GROUP_CHAT_MEMBERS: "group_chat_members",
89
+ /** Group chat: processed event IDs for deduplication */
90
+ GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events"
91
+ };
92
+ STORAGE_KEYS = {
93
+ ...STORAGE_KEYS_GLOBAL,
94
+ ...STORAGE_KEYS_ADDRESS
95
+ };
96
+ DEFAULT_NOSTR_RELAYS = [
97
+ "wss://relay.unicity.network",
98
+ "wss://relay.damus.io",
99
+ "wss://nos.lol",
100
+ "wss://relay.nostr.band"
101
+ ];
102
+ NIP29_KINDS = {
103
+ /** Chat message sent to group */
104
+ CHAT_MESSAGE: 9,
105
+ /** Thread root message */
106
+ THREAD_ROOT: 11,
107
+ /** Thread reply message */
108
+ THREAD_REPLY: 12,
109
+ /** User join request */
110
+ JOIN_REQUEST: 9021,
111
+ /** User leave request */
112
+ LEAVE_REQUEST: 9022,
113
+ /** Admin: add/update user */
114
+ PUT_USER: 9e3,
115
+ /** Admin: remove user */
116
+ REMOVE_USER: 9001,
117
+ /** Admin: edit group metadata */
118
+ EDIT_METADATA: 9002,
119
+ /** Admin: delete event */
120
+ DELETE_EVENT: 9005,
121
+ /** Admin: create group */
122
+ CREATE_GROUP: 9007,
123
+ /** Admin: delete group */
124
+ DELETE_GROUP: 9008,
125
+ /** Admin: create invite code */
126
+ CREATE_INVITE: 9009,
127
+ /** Relay-signed group metadata */
128
+ GROUP_METADATA: 39e3,
129
+ /** Relay-signed group admins */
130
+ GROUP_ADMINS: 39001,
131
+ /** Relay-signed group members */
132
+ GROUP_MEMBERS: 39002,
133
+ /** Relay-signed group roles */
134
+ GROUP_ROLES: 39003
135
+ };
136
+ DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
137
+ DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
138
+ TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
139
+ DEFAULT_IPFS_GATEWAYS = [
140
+ "https://unicity-ipfs1.dyndns.org"
141
+ ];
142
+ DEFAULT_BASE_PATH = "m/44'/0'/0'";
143
+ DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
144
+ DEFAULT_ELECTRUM_URL = "wss://fulcrum.unicity.network:50004";
145
+ TEST_ELECTRUM_URL = "wss://fulcrum.unicity.network:50004";
146
+ TOKEN_REGISTRY_URL = "https://raw.githubusercontent.com/unicitynetwork/unicity-ids/refs/heads/main/unicity-ids.testnet.json";
147
+ TOKEN_REGISTRY_REFRESH_INTERVAL = 36e5;
148
+ TEST_NOSTR_RELAYS = [
149
+ "wss://nostr-relay.testnet.unicity.network"
150
+ ];
151
+ DEFAULT_GROUP_RELAYS = [
152
+ "wss://sphere-relay.unicity.network"
153
+ ];
154
+ NETWORKS = {
155
+ mainnet: {
156
+ name: "Mainnet",
157
+ aggregatorUrl: DEFAULT_AGGREGATOR_URL,
158
+ nostrRelays: DEFAULT_NOSTR_RELAYS,
159
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
160
+ electrumUrl: DEFAULT_ELECTRUM_URL,
161
+ groupRelays: DEFAULT_GROUP_RELAYS,
162
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
163
+ },
164
+ testnet: {
165
+ name: "Testnet",
166
+ aggregatorUrl: TEST_AGGREGATOR_URL,
167
+ nostrRelays: TEST_NOSTR_RELAYS,
168
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
169
+ electrumUrl: TEST_ELECTRUM_URL,
170
+ groupRelays: DEFAULT_GROUP_RELAYS,
171
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
172
+ },
173
+ dev: {
174
+ name: "Development",
175
+ aggregatorUrl: DEV_AGGREGATOR_URL,
176
+ nostrRelays: TEST_NOSTR_RELAYS,
177
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
178
+ electrumUrl: TEST_ELECTRUM_URL,
179
+ groupRelays: DEFAULT_GROUP_RELAYS,
180
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
181
+ }
182
+ };
183
+ }
184
+ });
185
+
17
186
  // core/bech32.ts
18
187
  function convertBits(data, fromBits, toBits, pad) {
19
188
  let acc = 0;
@@ -424,13 +593,16 @@ function disconnect() {
424
593
  if (cb.timeoutId) clearTimeout(cb.timeoutId);
425
594
  });
426
595
  connectionCallbacks.length = 0;
596
+ blockSubscribers.length = 0;
597
+ lastBlockHeader = null;
427
598
  }
428
599
  var DEFAULT_ENDPOINT, ws, isConnected, isConnecting, requestId, intentionalClose, reconnectAttempts, isBlockSubscribed, lastBlockHeader, pending, blockSubscribers, connectionCallbacks, MAX_RECONNECT_ATTEMPTS, BASE_DELAY, MAX_DELAY, RPC_TIMEOUT, CONNECTION_TIMEOUT;
429
600
  var init_network = __esm({
430
601
  "l1/network.ts"() {
431
602
  "use strict";
432
603
  init_addressToScriptHash();
433
- DEFAULT_ENDPOINT = "wss://fulcrum.unicity.network:50004";
604
+ init_constants();
605
+ DEFAULT_ENDPOINT = DEFAULT_ELECTRUM_URL;
434
606
  ws = null;
435
607
  isConnected = false;
436
608
  isConnecting = false;
@@ -450,6 +622,9 @@ var init_network = __esm({
450
622
  }
451
623
  });
452
624
 
625
+ // modules/payments/L1PaymentsModule.ts
626
+ init_constants();
627
+
453
628
  // l1/index.ts
454
629
  init_bech32();
455
630
  init_addressToScriptHash();
@@ -463,7 +638,7 @@ var ec = new elliptic.ec("secp256k1");
463
638
  var CURVE_ORDER = BigInt(
464
639
  "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
465
640
  );
466
- var DEFAULT_DERIVATION_PATH = "m/44'/0'/0'";
641
+ var DEFAULT_DERIVATION_PATH2 = "m/44'/0'/0'";
467
642
  function generateMnemonic2(strength = 128) {
468
643
  return bip39.generateMnemonic(strength);
469
644
  }
@@ -1484,7 +1659,7 @@ var L1PaymentsModule = class {
1484
1659
  _transport;
1485
1660
  constructor(config) {
1486
1661
  this._config = {
1487
- electrumUrl: config?.electrumUrl ?? "wss://fulcrum.unicity.network:50004",
1662
+ electrumUrl: config?.electrumUrl ?? DEFAULT_ELECTRUM_URL,
1488
1663
  network: config?.network ?? "mainnet",
1489
1664
  defaultFeeRate: config?.defaultFeeRate ?? 10,
1490
1665
  enableVesting: config?.enableVesting ?? true
@@ -2321,168 +2496,8 @@ var NametagMinter = class {
2321
2496
  }
2322
2497
  };
2323
2498
 
2324
- // constants.ts
2325
- var DEFAULT_ENCRYPTION_KEY = "sphere-default-key";
2326
- var STORAGE_KEYS_GLOBAL = {
2327
- /** Encrypted BIP39 mnemonic */
2328
- MNEMONIC: "mnemonic",
2329
- /** Encrypted master private key */
2330
- MASTER_KEY: "master_key",
2331
- /** BIP32 chain code */
2332
- CHAIN_CODE: "chain_code",
2333
- /** HD derivation path (full path like m/44'/0'/0'/0/0) */
2334
- DERIVATION_PATH: "derivation_path",
2335
- /** Base derivation path (like m/44'/0'/0' without chain/index) */
2336
- BASE_PATH: "base_path",
2337
- /** Derivation mode: bip32, wif_hmac, legacy_hmac */
2338
- DERIVATION_MODE: "derivation_mode",
2339
- /** Wallet source: mnemonic, file, unknown */
2340
- WALLET_SOURCE: "wallet_source",
2341
- /** Wallet existence flag */
2342
- WALLET_EXISTS: "wallet_exists",
2343
- /** Current active address index */
2344
- CURRENT_ADDRESS_INDEX: "current_address_index",
2345
- /** Nametag cache per address (separate from tracked addresses registry) */
2346
- ADDRESS_NAMETAGS: "address_nametags",
2347
- /** Active addresses registry (JSON: TrackedAddressesStorage) */
2348
- TRACKED_ADDRESSES: "tracked_addresses",
2349
- /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
2350
- LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
2351
- /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
2352
- GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
2353
- /** Cached token registry JSON (fetched from remote) */
2354
- TOKEN_REGISTRY_CACHE: "token_registry_cache",
2355
- /** Timestamp of last token registry cache update (ms since epoch) */
2356
- TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
2357
- /** Cached price data JSON (from CoinGecko or other provider) */
2358
- PRICE_CACHE: "price_cache",
2359
- /** Timestamp of last price cache update (ms since epoch) */
2360
- PRICE_CACHE_TS: "price_cache_ts"
2361
- };
2362
- var STORAGE_KEYS_ADDRESS = {
2363
- /** Pending transfers for this address */
2364
- PENDING_TRANSFERS: "pending_transfers",
2365
- /** Transfer outbox for this address */
2366
- OUTBOX: "outbox",
2367
- /** Conversations for this address */
2368
- CONVERSATIONS: "conversations",
2369
- /** Messages for this address */
2370
- MESSAGES: "messages",
2371
- /** Transaction history for this address */
2372
- TRANSACTION_HISTORY: "transaction_history",
2373
- /** Pending V5 finalization tokens (unconfirmed instant split tokens) */
2374
- PENDING_V5_TOKENS: "pending_v5_tokens",
2375
- /** Group chat: joined groups for this address */
2376
- GROUP_CHAT_GROUPS: "group_chat_groups",
2377
- /** Group chat: messages for this address */
2378
- GROUP_CHAT_MESSAGES: "group_chat_messages",
2379
- /** Group chat: members for this address */
2380
- GROUP_CHAT_MEMBERS: "group_chat_members",
2381
- /** Group chat: processed event IDs for deduplication */
2382
- GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events"
2383
- };
2384
- var STORAGE_KEYS = {
2385
- ...STORAGE_KEYS_GLOBAL,
2386
- ...STORAGE_KEYS_ADDRESS
2387
- };
2388
- function getAddressId(directAddress) {
2389
- let hash = directAddress;
2390
- if (hash.startsWith("DIRECT://")) {
2391
- hash = hash.slice(9);
2392
- } else if (hash.startsWith("DIRECT:")) {
2393
- hash = hash.slice(7);
2394
- }
2395
- const first = hash.slice(0, 6).toLowerCase();
2396
- const last = hash.slice(-6).toLowerCase();
2397
- return `DIRECT_${first}_${last}`;
2398
- }
2399
- var DEFAULT_NOSTR_RELAYS = [
2400
- "wss://relay.unicity.network",
2401
- "wss://relay.damus.io",
2402
- "wss://nos.lol",
2403
- "wss://relay.nostr.band"
2404
- ];
2405
- var NIP29_KINDS = {
2406
- /** Chat message sent to group */
2407
- CHAT_MESSAGE: 9,
2408
- /** Thread root message */
2409
- THREAD_ROOT: 11,
2410
- /** Thread reply message */
2411
- THREAD_REPLY: 12,
2412
- /** User join request */
2413
- JOIN_REQUEST: 9021,
2414
- /** User leave request */
2415
- LEAVE_REQUEST: 9022,
2416
- /** Admin: add/update user */
2417
- PUT_USER: 9e3,
2418
- /** Admin: remove user */
2419
- REMOVE_USER: 9001,
2420
- /** Admin: edit group metadata */
2421
- EDIT_METADATA: 9002,
2422
- /** Admin: delete event */
2423
- DELETE_EVENT: 9005,
2424
- /** Admin: create group */
2425
- CREATE_GROUP: 9007,
2426
- /** Admin: delete group */
2427
- DELETE_GROUP: 9008,
2428
- /** Admin: create invite code */
2429
- CREATE_INVITE: 9009,
2430
- /** Relay-signed group metadata */
2431
- GROUP_METADATA: 39e3,
2432
- /** Relay-signed group admins */
2433
- GROUP_ADMINS: 39001,
2434
- /** Relay-signed group members */
2435
- GROUP_MEMBERS: 39002,
2436
- /** Relay-signed group roles */
2437
- GROUP_ROLES: 39003
2438
- };
2439
- var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
2440
- var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
2441
- var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
2442
- var DEFAULT_IPFS_GATEWAYS = [
2443
- "https://unicity-ipfs1.dyndns.org"
2444
- ];
2445
- var DEFAULT_BASE_PATH = "m/44'/0'/0'";
2446
- var DEFAULT_DERIVATION_PATH2 = `${DEFAULT_BASE_PATH}/0/0`;
2447
- var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
2448
- var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
2449
- var TOKEN_REGISTRY_URL = "https://raw.githubusercontent.com/unicitynetwork/unicity-ids/refs/heads/main/unicity-ids.testnet.json";
2450
- var TOKEN_REGISTRY_REFRESH_INTERVAL = 36e5;
2451
- var TEST_NOSTR_RELAYS = [
2452
- "wss://nostr-relay.testnet.unicity.network"
2453
- ];
2454
- var DEFAULT_GROUP_RELAYS = [
2455
- "wss://sphere-relay.unicity.network"
2456
- ];
2457
- var NETWORKS = {
2458
- mainnet: {
2459
- name: "Mainnet",
2460
- aggregatorUrl: DEFAULT_AGGREGATOR_URL,
2461
- nostrRelays: DEFAULT_NOSTR_RELAYS,
2462
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2463
- electrumUrl: DEFAULT_ELECTRUM_URL,
2464
- groupRelays: DEFAULT_GROUP_RELAYS,
2465
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2466
- },
2467
- testnet: {
2468
- name: "Testnet",
2469
- aggregatorUrl: TEST_AGGREGATOR_URL,
2470
- nostrRelays: TEST_NOSTR_RELAYS,
2471
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2472
- electrumUrl: TEST_ELECTRUM_URL,
2473
- groupRelays: DEFAULT_GROUP_RELAYS,
2474
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2475
- },
2476
- dev: {
2477
- name: "Development",
2478
- aggregatorUrl: DEV_AGGREGATOR_URL,
2479
- nostrRelays: TEST_NOSTR_RELAYS,
2480
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2481
- electrumUrl: TEST_ELECTRUM_URL,
2482
- groupRelays: DEFAULT_GROUP_RELAYS,
2483
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2484
- }
2485
- };
2499
+ // modules/payments/PaymentsModule.ts
2500
+ init_constants();
2486
2501
 
2487
2502
  // types/txf.ts
2488
2503
  var ARCHIVED_PREFIX = "archived-";
@@ -2524,6 +2539,7 @@ function parseForkedKey(key) {
2524
2539
  }
2525
2540
 
2526
2541
  // registry/TokenRegistry.ts
2542
+ init_constants();
2527
2543
  var FETCH_TIMEOUT_MS = 1e4;
2528
2544
  var TokenRegistry = class _TokenRegistry {
2529
2545
  static instance = null;
@@ -7336,6 +7352,7 @@ import { HashAlgorithm as HashAlgorithm6 } from "@unicitylabs/state-transition-s
7336
7352
  import { UnmaskedPredicate as UnmaskedPredicate6 } from "@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate";
7337
7353
 
7338
7354
  // modules/communications/CommunicationsModule.ts
7355
+ init_constants();
7339
7356
  var CommunicationsModule = class {
7340
7357
  config;
7341
7358
  deps = null;
@@ -7810,6 +7827,7 @@ function createCommunicationsModule(config) {
7810
7827
  }
7811
7828
 
7812
7829
  // modules/groupchat/GroupChatModule.ts
7830
+ init_constants();
7813
7831
  import {
7814
7832
  NostrClient,
7815
7833
  NostrKeyManager,
@@ -11659,6 +11677,9 @@ function createMarketModule(config) {
11659
11677
  return new MarketModule(config);
11660
11678
  }
11661
11679
 
11680
+ // core/Sphere.ts
11681
+ init_constants();
11682
+
11662
11683
  // core/encryption.ts
11663
11684
  import CryptoJS6 from "crypto-js";
11664
11685
  var DEFAULT_ITERATIONS = 1e5;
@@ -11847,6 +11868,72 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
11847
11868
  };
11848
11869
  }
11849
11870
 
11871
+ // core/discover.ts
11872
+ async function discoverAddressesImpl(deriveTransportPubkey, batchResolve, options = {}) {
11873
+ const maxAddresses = options.maxAddresses ?? 50;
11874
+ const gapLimit = options.gapLimit ?? 20;
11875
+ const batchSize = options.batchSize ?? 20;
11876
+ const { onProgress, signal } = options;
11877
+ const discovered = /* @__PURE__ */ new Map();
11878
+ let consecutiveEmpty = 0;
11879
+ let scanned = 0;
11880
+ const totalBatches = Math.ceil(maxAddresses / batchSize);
11881
+ for (let batchStart = 0; batchStart < maxAddresses; batchStart += batchSize) {
11882
+ if (signal?.aborted) break;
11883
+ if (consecutiveEmpty >= gapLimit) break;
11884
+ const batchEnd = Math.min(batchStart + batchSize, maxAddresses);
11885
+ const batchIndices = [];
11886
+ const pubkeyToIndex = /* @__PURE__ */ new Map();
11887
+ const pubkeyToInfo = /* @__PURE__ */ new Map();
11888
+ for (let i = batchStart; i < batchEnd; i++) {
11889
+ const info = deriveTransportPubkey(i);
11890
+ batchIndices.push(i);
11891
+ pubkeyToIndex.set(info.transportPubkey, i);
11892
+ pubkeyToInfo.set(info.transportPubkey, info);
11893
+ }
11894
+ const batchPubkeys = Array.from(pubkeyToIndex.keys());
11895
+ onProgress?.({
11896
+ currentBatch: Math.floor(batchStart / batchSize) + 1,
11897
+ totalBatches,
11898
+ discoveredCount: discovered.size,
11899
+ currentGap: consecutiveEmpty,
11900
+ phase: "transport"
11901
+ });
11902
+ const peerInfos = await batchResolve(batchPubkeys);
11903
+ const foundInBatch = /* @__PURE__ */ new Set();
11904
+ for (const peer of peerInfos) {
11905
+ const index = pubkeyToIndex.get(peer.transportPubkey);
11906
+ if (index !== void 0) {
11907
+ foundInBatch.add(index);
11908
+ const derived = pubkeyToInfo.get(peer.transportPubkey);
11909
+ discovered.set(index, {
11910
+ index,
11911
+ l1Address: peer.l1Address || derived.l1Address,
11912
+ directAddress: peer.directAddress || derived.directAddress,
11913
+ chainPubkey: peer.chainPubkey || derived.chainPubkey,
11914
+ nametag: peer.nametag,
11915
+ l1Balance: 0,
11916
+ source: "transport"
11917
+ });
11918
+ }
11919
+ }
11920
+ for (const idx of batchIndices) {
11921
+ scanned++;
11922
+ if (foundInBatch.has(idx)) {
11923
+ consecutiveEmpty = 0;
11924
+ } else {
11925
+ consecutiveEmpty++;
11926
+ if (consecutiveEmpty >= gapLimit) break;
11927
+ }
11928
+ }
11929
+ }
11930
+ return {
11931
+ addresses: Array.from(discovered.values()).sort((a, b) => a.index - b.index),
11932
+ scannedCount: scanned,
11933
+ aborted: signal?.aborted ?? false
11934
+ };
11935
+ }
11936
+
11850
11937
  // core/Sphere.ts
11851
11938
  init_network();
11852
11939
 
@@ -12669,7 +12756,9 @@ var Sphere = class _Sphere {
12669
12756
  price: options.price,
12670
12757
  groupChat,
12671
12758
  market,
12672
- password: options.password
12759
+ password: options.password,
12760
+ discoverAddresses: options.discoverAddresses,
12761
+ onProgress: options.onProgress
12673
12762
  });
12674
12763
  return { sphere: sphere2, created: false };
12675
12764
  }
@@ -12697,7 +12786,9 @@ var Sphere = class _Sphere {
12697
12786
  price: options.price,
12698
12787
  groupChat,
12699
12788
  market,
12700
- password: options.password
12789
+ password: options.password,
12790
+ discoverAddresses: options.discoverAddresses,
12791
+ onProgress: options.onProgress
12701
12792
  });
12702
12793
  return { sphere, created: true, generatedMnemonic };
12703
12794
  }
@@ -12758,6 +12849,7 @@ var Sphere = class _Sphere {
12758
12849
  if (await _Sphere.exists(options.storage)) {
12759
12850
  throw new Error("Wallet already exists. Use Sphere.load() or Sphere.clear() first.");
12760
12851
  }
12852
+ const progress = options.onProgress;
12761
12853
  if (!options.storage.isConnected()) {
12762
12854
  await options.storage.connect();
12763
12855
  }
@@ -12775,20 +12867,39 @@ var Sphere = class _Sphere {
12775
12867
  marketConfig
12776
12868
  );
12777
12869
  sphere._password = options.password ?? null;
12870
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12778
12871
  await sphere.storeMnemonic(options.mnemonic, options.derivationPath);
12779
12872
  await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
12873
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12780
12874
  await sphere.initializeProviders();
12781
12875
  await sphere.initializeModules();
12876
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12782
12877
  await sphere.finalizeWalletCreation();
12783
12878
  sphere._initialized = true;
12784
12879
  _Sphere.instance = sphere;
12785
12880
  await sphere.ensureAddressTracked(0);
12786
12881
  if (options.nametag) {
12882
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
12787
12883
  await sphere.registerNametag(options.nametag);
12788
12884
  } else {
12885
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12789
12886
  await sphere.recoverNametagFromTransport();
12887
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12790
12888
  await sphere.syncIdentityWithTransport();
12791
12889
  }
12890
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
12891
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
12892
+ try {
12893
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
12894
+ const result = await sphere.discoverAddresses(discoverOpts);
12895
+ if (result.addresses.length > 0) {
12896
+ console.log(`[Sphere.create] Address discovery: found ${result.addresses.length} address(es)`);
12897
+ }
12898
+ } catch (err) {
12899
+ console.warn("[Sphere.create] Address discovery failed (non-fatal):", err);
12900
+ }
12901
+ }
12902
+ progress?.({ step: "complete", message: "Wallet created" });
12792
12903
  return sphere;
12793
12904
  }
12794
12905
  /**
@@ -12798,6 +12909,7 @@ var Sphere = class _Sphere {
12798
12909
  if (!await _Sphere.exists(options.storage)) {
12799
12910
  throw new Error("No wallet found. Use Sphere.create() to create a new wallet.");
12800
12911
  }
12912
+ const progress = options.onProgress;
12801
12913
  _Sphere.configureTokenRegistry(options.storage, options.network);
12802
12914
  const groupChatConfig = _Sphere.resolveGroupChatConfig(options.groupChat, options.network);
12803
12915
  const marketConfig = _Sphere.resolveMarketConfig(options.market);
@@ -12815,13 +12927,17 @@ var Sphere = class _Sphere {
12815
12927
  if (!options.storage.isConnected()) {
12816
12928
  await options.storage.connect();
12817
12929
  }
12930
+ progress?.({ step: "storing_keys", message: "Loading wallet keys..." });
12818
12931
  await sphere.loadIdentityFromStorage();
12932
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12819
12933
  await sphere.initializeProviders();
12820
12934
  await sphere.initializeModules();
12935
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12821
12936
  await sphere.syncIdentityWithTransport();
12822
12937
  sphere._initialized = true;
12823
12938
  _Sphere.instance = sphere;
12824
12939
  if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
12940
+ progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
12825
12941
  console.log(`[Sphere] Nametag @${sphere._identity.nametag} has no token, attempting to mint...`);
12826
12942
  try {
12827
12943
  const result = await sphere.mintNametag(sphere._identity.nametag);
@@ -12834,6 +12950,19 @@ var Sphere = class _Sphere {
12834
12950
  console.warn(`[Sphere] Nametag token mint failed:`, err);
12835
12951
  }
12836
12952
  }
12953
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
12954
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
12955
+ try {
12956
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
12957
+ const result = await sphere.discoverAddresses(discoverOpts);
12958
+ if (result.addresses.length > 0) {
12959
+ console.log(`[Sphere.load] Address discovery: found ${result.addresses.length} address(es)`);
12960
+ }
12961
+ } catch (err) {
12962
+ console.warn("[Sphere.load] Address discovery failed (non-fatal):", err);
12963
+ }
12964
+ }
12965
+ progress?.({ step: "complete", message: "Wallet loaded" });
12837
12966
  return sphere;
12838
12967
  }
12839
12968
  /**
@@ -12843,9 +12972,11 @@ var Sphere = class _Sphere {
12843
12972
  if (!options.mnemonic && !options.masterKey) {
12844
12973
  throw new Error("Either mnemonic or masterKey is required");
12845
12974
  }
12975
+ const progress = options.onProgress;
12846
12976
  console.log("[Sphere.import] Starting import...");
12847
12977
  const needsClear = _Sphere.instance !== null || await _Sphere.exists(options.storage);
12848
12978
  if (needsClear) {
12979
+ progress?.({ step: "clearing", message: "Clearing previous wallet data..." });
12849
12980
  console.log("[Sphere.import] Clearing existing wallet data...");
12850
12981
  await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
12851
12982
  console.log("[Sphere.import] Clear done");
@@ -12870,6 +13001,7 @@ var Sphere = class _Sphere {
12870
13001
  marketConfig
12871
13002
  );
12872
13003
  sphere._password = options.password ?? null;
13004
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12873
13005
  if (options.mnemonic) {
12874
13006
  if (!_Sphere.validateMnemonic(options.mnemonic)) {
12875
13007
  throw new Error("Invalid mnemonic");
@@ -12894,17 +13026,21 @@ var Sphere = class _Sphere {
12894
13026
  options.derivationPath
12895
13027
  );
12896
13028
  }
13029
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12897
13030
  console.log("[Sphere.import] Initializing providers...");
12898
13031
  await sphere.initializeProviders();
12899
13032
  console.log("[Sphere.import] Providers initialized. Initializing modules...");
12900
13033
  await sphere.initializeModules();
12901
13034
  console.log("[Sphere.import] Modules initialized");
12902
13035
  if (!options.nametag) {
13036
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12903
13037
  console.log("[Sphere.import] Recovering nametag from transport...");
12904
13038
  await sphere.recoverNametagFromTransport();
12905
13039
  console.log("[Sphere.import] Nametag recovery done");
13040
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12906
13041
  await sphere.syncIdentityWithTransport();
12907
13042
  }
13043
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12908
13044
  console.log("[Sphere.import] Finalizing wallet creation...");
12909
13045
  await sphere.finalizeWalletCreation();
12910
13046
  sphere._initialized = true;
@@ -12912,10 +13048,12 @@ var Sphere = class _Sphere {
12912
13048
  console.log("[Sphere.import] Tracking address 0...");
12913
13049
  await sphere.ensureAddressTracked(0);
12914
13050
  if (options.nametag) {
13051
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
12915
13052
  console.log("[Sphere.import] Registering nametag...");
12916
13053
  await sphere.registerNametag(options.nametag);
12917
13054
  }
12918
13055
  if (sphere._tokenStorageProviders.size > 0) {
13056
+ progress?.({ step: "syncing_tokens", message: "Syncing tokens..." });
12919
13057
  try {
12920
13058
  const syncResult = await sphere._payments.sync();
12921
13059
  console.log(`[Sphere.import] Auto-sync: +${syncResult.added} -${syncResult.removed}`);
@@ -12923,6 +13061,19 @@ var Sphere = class _Sphere {
12923
13061
  console.warn("[Sphere.import] Auto-sync failed (non-fatal):", err);
12924
13062
  }
12925
13063
  }
13064
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
13065
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
13066
+ try {
13067
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
13068
+ const result = await sphere.discoverAddresses(discoverOpts);
13069
+ if (result.addresses.length > 0) {
13070
+ console.log(`[Sphere.import] Address discovery: found ${result.addresses.length} address(es)`);
13071
+ }
13072
+ } catch (err) {
13073
+ console.warn("[Sphere.import] Address discovery failed (non-fatal):", err);
13074
+ }
13075
+ }
13076
+ progress?.({ step: "complete", message: "Import complete" });
12926
13077
  console.log("[Sphere.import] Import complete");
12927
13078
  return sphere;
12928
13079
  }
@@ -13791,6 +13942,23 @@ var Sphere = class _Sphere {
13791
13942
  await provider.initialize();
13792
13943
  }
13793
13944
  await this.reinitializeModulesForNewAddress();
13945
+ this.emitEvent("identity:changed", {
13946
+ l1Address: this._identity.l1Address,
13947
+ directAddress: this._identity.directAddress,
13948
+ chainPubkey: this._identity.chainPubkey,
13949
+ nametag: this._identity.nametag,
13950
+ addressIndex: index
13951
+ });
13952
+ console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
13953
+ this.postSwitchSync(index, newNametag).catch((err) => {
13954
+ console.warn(`[Sphere] Post-switch sync failed for address ${index}:`, err);
13955
+ });
13956
+ }
13957
+ /**
13958
+ * Background transport sync and nametag operations after address switch.
13959
+ * Runs after switchToAddress returns so L1/L3 queries can start immediately.
13960
+ */
13961
+ async postSwitchSync(index, newNametag) {
13794
13962
  if (!newNametag) {
13795
13963
  await this.syncIdentityWithTransport();
13796
13964
  }
@@ -13813,7 +13981,7 @@ var Sphere = class _Sphere {
13813
13981
  nametag: newNametag,
13814
13982
  addressIndex: index
13815
13983
  });
13816
- } else if (this._identity.nametag && !this._payments.hasNametag()) {
13984
+ } else if (this._identity?.nametag && !this._payments.hasNametag()) {
13817
13985
  console.log(`[Sphere] Nametag @${this._identity.nametag} has no token after switch, minting...`);
13818
13986
  try {
13819
13987
  const result = await this.mintNametag(this._identity.nametag);
@@ -13826,14 +13994,6 @@ var Sphere = class _Sphere {
13826
13994
  console.warn(`[Sphere] Nametag token mint failed after switch:`, err);
13827
13995
  }
13828
13996
  }
13829
- this.emitEvent("identity:changed", {
13830
- l1Address: this._identity.l1Address,
13831
- directAddress: this._identity.directAddress,
13832
- chainPubkey: this._identity.chainPubkey,
13833
- nametag: this._identity.nametag,
13834
- addressIndex: index
13835
- });
13836
- console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
13837
13997
  }
13838
13998
  /**
13839
13999
  * Re-initialize modules after address switch
@@ -14040,6 +14200,98 @@ var Sphere = class _Sphere {
14040
14200
  await this.persistTrackedAddresses();
14041
14201
  await this.persistAddressNametags();
14042
14202
  }
14203
+ /**
14204
+ * Discover previously used HD addresses.
14205
+ *
14206
+ * Primary: queries Nostr relay for identity binding events (fast, single batch query).
14207
+ * Secondary: runs L1 balance scan to find legacy addresses with no binding event.
14208
+ *
14209
+ * @example
14210
+ * ```ts
14211
+ * const result = await sphere.discoverAddresses();
14212
+ * console.log(`Found ${result.addresses.length} addresses`);
14213
+ *
14214
+ * // With auto-tracking
14215
+ * await sphere.discoverAddresses({ autoTrack: true });
14216
+ * ```
14217
+ */
14218
+ async discoverAddresses(options = {}) {
14219
+ this.ensureReady();
14220
+ if (!this._masterKey) {
14221
+ throw new Error("Address discovery requires HD master key");
14222
+ }
14223
+ if (!this._transport.discoverAddresses) {
14224
+ throw new Error("Transport provider does not support address discovery");
14225
+ }
14226
+ const includeL1Scan = options.includeL1Scan ?? true;
14227
+ const transportResult = await discoverAddressesImpl(
14228
+ (index) => {
14229
+ const addrInfo = this._deriveAddressInternal(index, false);
14230
+ return {
14231
+ transportPubkey: addrInfo.publicKey.slice(2),
14232
+ // x-only 32 bytes
14233
+ chainPubkey: addrInfo.publicKey,
14234
+ l1Address: addrInfo.address,
14235
+ directAddress: ""
14236
+ // not needed for discovery query
14237
+ };
14238
+ },
14239
+ (pubkeys) => this._transport.discoverAddresses(pubkeys),
14240
+ options
14241
+ );
14242
+ if (includeL1Scan) {
14243
+ try {
14244
+ const l1Result = await this.scanAddresses({
14245
+ maxAddresses: options.maxAddresses,
14246
+ gapLimit: options.gapLimit,
14247
+ signal: options.signal,
14248
+ onProgress: options.onProgress ? (p) => options.onProgress({
14249
+ currentBatch: 0,
14250
+ totalBatches: 0,
14251
+ discoveredCount: p.foundCount,
14252
+ currentGap: p.currentGap,
14253
+ phase: "l1"
14254
+ }) : void 0
14255
+ });
14256
+ for (const l1Addr of l1Result.addresses) {
14257
+ if (l1Addr.isChange) continue;
14258
+ const existing = transportResult.addresses.find((a) => a.index === l1Addr.index);
14259
+ if (existing) {
14260
+ existing.l1Balance = l1Addr.balance;
14261
+ existing.source = "both";
14262
+ if (!existing.nametag && l1Addr.nametag) {
14263
+ existing.nametag = l1Addr.nametag;
14264
+ }
14265
+ } else {
14266
+ const addrInfo = this._deriveAddressInternal(l1Addr.index, false);
14267
+ transportResult.addresses.push({
14268
+ index: l1Addr.index,
14269
+ l1Address: l1Addr.address,
14270
+ directAddress: "",
14271
+ chainPubkey: addrInfo.publicKey,
14272
+ nametag: l1Addr.nametag,
14273
+ l1Balance: l1Addr.balance,
14274
+ source: "l1"
14275
+ });
14276
+ }
14277
+ }
14278
+ transportResult.addresses.sort((a, b) => a.index - b.index);
14279
+ } catch (err) {
14280
+ console.warn("[Sphere] L1 scan failed during discovery (non-fatal):", err);
14281
+ }
14282
+ }
14283
+ if (options.autoTrack && transportResult.addresses.length > 0) {
14284
+ await this.trackScannedAddresses(
14285
+ transportResult.addresses.map((a) => ({
14286
+ index: a.index,
14287
+ // Preserve existing hidden state; default to false for newly discovered
14288
+ hidden: this._trackedAddresses.get(a.index)?.hidden ?? false,
14289
+ nametag: a.nametag
14290
+ }))
14291
+ );
14292
+ }
14293
+ return transportResult;
14294
+ }
14043
14295
  // ===========================================================================
14044
14296
  // Public Methods - Status
14045
14297
  // ===========================================================================
@@ -14611,6 +14863,17 @@ var Sphere = class _Sphere {
14611
14863
  return;
14612
14864
  }
14613
14865
  }
14866
+ const needsUpdate = !existing.directAddress || !existing.l1Address || !existing.chainPubkey || this._identity?.nametag && !existing.nametag;
14867
+ if (needsUpdate) {
14868
+ console.log("[Sphere] Existing binding incomplete, re-publishing with full data");
14869
+ await this._transport.publishIdentityBinding(
14870
+ this._identity.chainPubkey,
14871
+ this._identity.l1Address,
14872
+ this._identity.directAddress || "",
14873
+ this._identity?.nametag || existing.nametag || void 0
14874
+ );
14875
+ return;
14876
+ }
14614
14877
  console.log("[Sphere] Existing binding found, skipping re-publish");
14615
14878
  return;
14616
14879
  }
@@ -15104,6 +15367,7 @@ var CurrencyUtils = {
15104
15367
  init_bech32();
15105
15368
 
15106
15369
  // core/network-health.ts
15370
+ init_constants();
15107
15371
  var DEFAULT_TIMEOUT_MS = 5e3;
15108
15372
  async function checkNetworkHealth(network = "testnet", options) {
15109
15373
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -15291,7 +15555,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
15291
15555
  export {
15292
15556
  CHARSET,
15293
15557
  CurrencyUtils,
15294
- DEFAULT_DERIVATION_PATH,
15558
+ DEFAULT_DERIVATION_PATH2 as DEFAULT_DERIVATION_PATH,
15295
15559
  DEFAULT_TOKEN_DECIMALS,
15296
15560
  Sphere,
15297
15561
  base58Decode,
@@ -15314,6 +15578,7 @@ export {
15314
15578
  deriveChildKey,
15315
15579
  deriveKeyAtPath,
15316
15580
  deserializeEncrypted,
15581
+ discoverAddressesImpl,
15317
15582
  doubleSha256,
15318
15583
  ec,
15319
15584
  encodeBech32,