@unicitylabs/sphere-sdk 0.4.7 → 0.4.8

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;
@@ -430,7 +599,8 @@ var init_network = __esm({
430
599
  "l1/network.ts"() {
431
600
  "use strict";
432
601
  init_addressToScriptHash();
433
- DEFAULT_ENDPOINT = "wss://fulcrum.unicity.network:50004";
602
+ init_constants();
603
+ DEFAULT_ENDPOINT = DEFAULT_ELECTRUM_URL;
434
604
  ws = null;
435
605
  isConnected = false;
436
606
  isConnecting = false;
@@ -450,6 +620,9 @@ var init_network = __esm({
450
620
  }
451
621
  });
452
622
 
623
+ // modules/payments/L1PaymentsModule.ts
624
+ init_constants();
625
+
453
626
  // l1/index.ts
454
627
  init_bech32();
455
628
  init_addressToScriptHash();
@@ -463,7 +636,7 @@ var ec = new elliptic.ec("secp256k1");
463
636
  var CURVE_ORDER = BigInt(
464
637
  "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
465
638
  );
466
- var DEFAULT_DERIVATION_PATH = "m/44'/0'/0'";
639
+ var DEFAULT_DERIVATION_PATH2 = "m/44'/0'/0'";
467
640
  function generateMnemonic2(strength = 128) {
468
641
  return bip39.generateMnemonic(strength);
469
642
  }
@@ -1484,7 +1657,7 @@ var L1PaymentsModule = class {
1484
1657
  _transport;
1485
1658
  constructor(config) {
1486
1659
  this._config = {
1487
- electrumUrl: config?.electrumUrl ?? "wss://fulcrum.unicity.network:50004",
1660
+ electrumUrl: config?.electrumUrl ?? DEFAULT_ELECTRUM_URL,
1488
1661
  network: config?.network ?? "mainnet",
1489
1662
  defaultFeeRate: config?.defaultFeeRate ?? 10,
1490
1663
  enableVesting: config?.enableVesting ?? true
@@ -2321,168 +2494,8 @@ var NametagMinter = class {
2321
2494
  }
2322
2495
  };
2323
2496
 
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
- };
2497
+ // modules/payments/PaymentsModule.ts
2498
+ init_constants();
2486
2499
 
2487
2500
  // types/txf.ts
2488
2501
  var ARCHIVED_PREFIX = "archived-";
@@ -2524,6 +2537,7 @@ function parseForkedKey(key) {
2524
2537
  }
2525
2538
 
2526
2539
  // registry/TokenRegistry.ts
2540
+ init_constants();
2527
2541
  var FETCH_TIMEOUT_MS = 1e4;
2528
2542
  var TokenRegistry = class _TokenRegistry {
2529
2543
  static instance = null;
@@ -7336,6 +7350,7 @@ import { HashAlgorithm as HashAlgorithm6 } from "@unicitylabs/state-transition-s
7336
7350
  import { UnmaskedPredicate as UnmaskedPredicate6 } from "@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate";
7337
7351
 
7338
7352
  // modules/communications/CommunicationsModule.ts
7353
+ init_constants();
7339
7354
  var CommunicationsModule = class {
7340
7355
  config;
7341
7356
  deps = null;
@@ -7810,6 +7825,7 @@ function createCommunicationsModule(config) {
7810
7825
  }
7811
7826
 
7812
7827
  // modules/groupchat/GroupChatModule.ts
7828
+ init_constants();
7813
7829
  import {
7814
7830
  NostrClient,
7815
7831
  NostrKeyManager,
@@ -11659,6 +11675,9 @@ function createMarketModule(config) {
11659
11675
  return new MarketModule(config);
11660
11676
  }
11661
11677
 
11678
+ // core/Sphere.ts
11679
+ init_constants();
11680
+
11662
11681
  // core/encryption.ts
11663
11682
  import CryptoJS6 from "crypto-js";
11664
11683
  var DEFAULT_ITERATIONS = 1e5;
@@ -11847,6 +11866,72 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
11847
11866
  };
11848
11867
  }
11849
11868
 
11869
+ // core/discover.ts
11870
+ async function discoverAddressesImpl(deriveTransportPubkey, batchResolve, options = {}) {
11871
+ const maxAddresses = options.maxAddresses ?? 50;
11872
+ const gapLimit = options.gapLimit ?? 20;
11873
+ const batchSize = options.batchSize ?? 20;
11874
+ const { onProgress, signal } = options;
11875
+ const discovered = /* @__PURE__ */ new Map();
11876
+ let consecutiveEmpty = 0;
11877
+ let scanned = 0;
11878
+ const totalBatches = Math.ceil(maxAddresses / batchSize);
11879
+ for (let batchStart = 0; batchStart < maxAddresses; batchStart += batchSize) {
11880
+ if (signal?.aborted) break;
11881
+ if (consecutiveEmpty >= gapLimit) break;
11882
+ const batchEnd = Math.min(batchStart + batchSize, maxAddresses);
11883
+ const batchIndices = [];
11884
+ const pubkeyToIndex = /* @__PURE__ */ new Map();
11885
+ const pubkeyToInfo = /* @__PURE__ */ new Map();
11886
+ for (let i = batchStart; i < batchEnd; i++) {
11887
+ const info = deriveTransportPubkey(i);
11888
+ batchIndices.push(i);
11889
+ pubkeyToIndex.set(info.transportPubkey, i);
11890
+ pubkeyToInfo.set(info.transportPubkey, info);
11891
+ }
11892
+ const batchPubkeys = Array.from(pubkeyToIndex.keys());
11893
+ onProgress?.({
11894
+ currentBatch: Math.floor(batchStart / batchSize) + 1,
11895
+ totalBatches,
11896
+ discoveredCount: discovered.size,
11897
+ currentGap: consecutiveEmpty,
11898
+ phase: "transport"
11899
+ });
11900
+ const peerInfos = await batchResolve(batchPubkeys);
11901
+ const foundInBatch = /* @__PURE__ */ new Set();
11902
+ for (const peer of peerInfos) {
11903
+ const index = pubkeyToIndex.get(peer.transportPubkey);
11904
+ if (index !== void 0) {
11905
+ foundInBatch.add(index);
11906
+ const derived = pubkeyToInfo.get(peer.transportPubkey);
11907
+ discovered.set(index, {
11908
+ index,
11909
+ l1Address: peer.l1Address || derived.l1Address,
11910
+ directAddress: peer.directAddress || derived.directAddress,
11911
+ chainPubkey: peer.chainPubkey || derived.chainPubkey,
11912
+ nametag: peer.nametag,
11913
+ l1Balance: 0,
11914
+ source: "transport"
11915
+ });
11916
+ }
11917
+ }
11918
+ for (const idx of batchIndices) {
11919
+ scanned++;
11920
+ if (foundInBatch.has(idx)) {
11921
+ consecutiveEmpty = 0;
11922
+ } else {
11923
+ consecutiveEmpty++;
11924
+ if (consecutiveEmpty >= gapLimit) break;
11925
+ }
11926
+ }
11927
+ }
11928
+ return {
11929
+ addresses: Array.from(discovered.values()).sort((a, b) => a.index - b.index),
11930
+ scannedCount: scanned,
11931
+ aborted: signal?.aborted ?? false
11932
+ };
11933
+ }
11934
+
11850
11935
  // core/Sphere.ts
11851
11936
  init_network();
11852
11937
 
@@ -12669,7 +12754,9 @@ var Sphere = class _Sphere {
12669
12754
  price: options.price,
12670
12755
  groupChat,
12671
12756
  market,
12672
- password: options.password
12757
+ password: options.password,
12758
+ discoverAddresses: options.discoverAddresses,
12759
+ onProgress: options.onProgress
12673
12760
  });
12674
12761
  return { sphere: sphere2, created: false };
12675
12762
  }
@@ -12697,7 +12784,9 @@ var Sphere = class _Sphere {
12697
12784
  price: options.price,
12698
12785
  groupChat,
12699
12786
  market,
12700
- password: options.password
12787
+ password: options.password,
12788
+ discoverAddresses: options.discoverAddresses,
12789
+ onProgress: options.onProgress
12701
12790
  });
12702
12791
  return { sphere, created: true, generatedMnemonic };
12703
12792
  }
@@ -12758,6 +12847,7 @@ var Sphere = class _Sphere {
12758
12847
  if (await _Sphere.exists(options.storage)) {
12759
12848
  throw new Error("Wallet already exists. Use Sphere.load() or Sphere.clear() first.");
12760
12849
  }
12850
+ const progress = options.onProgress;
12761
12851
  if (!options.storage.isConnected()) {
12762
12852
  await options.storage.connect();
12763
12853
  }
@@ -12775,20 +12865,39 @@ var Sphere = class _Sphere {
12775
12865
  marketConfig
12776
12866
  );
12777
12867
  sphere._password = options.password ?? null;
12868
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12778
12869
  await sphere.storeMnemonic(options.mnemonic, options.derivationPath);
12779
12870
  await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
12871
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12780
12872
  await sphere.initializeProviders();
12781
12873
  await sphere.initializeModules();
12874
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12782
12875
  await sphere.finalizeWalletCreation();
12783
12876
  sphere._initialized = true;
12784
12877
  _Sphere.instance = sphere;
12785
12878
  await sphere.ensureAddressTracked(0);
12786
12879
  if (options.nametag) {
12880
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
12787
12881
  await sphere.registerNametag(options.nametag);
12788
12882
  } else {
12883
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12789
12884
  await sphere.recoverNametagFromTransport();
12885
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12790
12886
  await sphere.syncIdentityWithTransport();
12791
12887
  }
12888
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
12889
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
12890
+ try {
12891
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
12892
+ const result = await sphere.discoverAddresses(discoverOpts);
12893
+ if (result.addresses.length > 0) {
12894
+ console.log(`[Sphere.create] Address discovery: found ${result.addresses.length} address(es)`);
12895
+ }
12896
+ } catch (err) {
12897
+ console.warn("[Sphere.create] Address discovery failed (non-fatal):", err);
12898
+ }
12899
+ }
12900
+ progress?.({ step: "complete", message: "Wallet created" });
12792
12901
  return sphere;
12793
12902
  }
12794
12903
  /**
@@ -12798,6 +12907,7 @@ var Sphere = class _Sphere {
12798
12907
  if (!await _Sphere.exists(options.storage)) {
12799
12908
  throw new Error("No wallet found. Use Sphere.create() to create a new wallet.");
12800
12909
  }
12910
+ const progress = options.onProgress;
12801
12911
  _Sphere.configureTokenRegistry(options.storage, options.network);
12802
12912
  const groupChatConfig = _Sphere.resolveGroupChatConfig(options.groupChat, options.network);
12803
12913
  const marketConfig = _Sphere.resolveMarketConfig(options.market);
@@ -12815,13 +12925,17 @@ var Sphere = class _Sphere {
12815
12925
  if (!options.storage.isConnected()) {
12816
12926
  await options.storage.connect();
12817
12927
  }
12928
+ progress?.({ step: "storing_keys", message: "Loading wallet keys..." });
12818
12929
  await sphere.loadIdentityFromStorage();
12930
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12819
12931
  await sphere.initializeProviders();
12820
12932
  await sphere.initializeModules();
12933
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12821
12934
  await sphere.syncIdentityWithTransport();
12822
12935
  sphere._initialized = true;
12823
12936
  _Sphere.instance = sphere;
12824
12937
  if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
12938
+ progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
12825
12939
  console.log(`[Sphere] Nametag @${sphere._identity.nametag} has no token, attempting to mint...`);
12826
12940
  try {
12827
12941
  const result = await sphere.mintNametag(sphere._identity.nametag);
@@ -12834,6 +12948,19 @@ var Sphere = class _Sphere {
12834
12948
  console.warn(`[Sphere] Nametag token mint failed:`, err);
12835
12949
  }
12836
12950
  }
12951
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
12952
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
12953
+ try {
12954
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
12955
+ const result = await sphere.discoverAddresses(discoverOpts);
12956
+ if (result.addresses.length > 0) {
12957
+ console.log(`[Sphere.load] Address discovery: found ${result.addresses.length} address(es)`);
12958
+ }
12959
+ } catch (err) {
12960
+ console.warn("[Sphere.load] Address discovery failed (non-fatal):", err);
12961
+ }
12962
+ }
12963
+ progress?.({ step: "complete", message: "Wallet loaded" });
12837
12964
  return sphere;
12838
12965
  }
12839
12966
  /**
@@ -12843,9 +12970,11 @@ var Sphere = class _Sphere {
12843
12970
  if (!options.mnemonic && !options.masterKey) {
12844
12971
  throw new Error("Either mnemonic or masterKey is required");
12845
12972
  }
12973
+ const progress = options.onProgress;
12846
12974
  console.log("[Sphere.import] Starting import...");
12847
12975
  const needsClear = _Sphere.instance !== null || await _Sphere.exists(options.storage);
12848
12976
  if (needsClear) {
12977
+ progress?.({ step: "clearing", message: "Clearing previous wallet data..." });
12849
12978
  console.log("[Sphere.import] Clearing existing wallet data...");
12850
12979
  await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
12851
12980
  console.log("[Sphere.import] Clear done");
@@ -12870,6 +12999,7 @@ var Sphere = class _Sphere {
12870
12999
  marketConfig
12871
13000
  );
12872
13001
  sphere._password = options.password ?? null;
13002
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12873
13003
  if (options.mnemonic) {
12874
13004
  if (!_Sphere.validateMnemonic(options.mnemonic)) {
12875
13005
  throw new Error("Invalid mnemonic");
@@ -12894,17 +13024,21 @@ var Sphere = class _Sphere {
12894
13024
  options.derivationPath
12895
13025
  );
12896
13026
  }
13027
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12897
13028
  console.log("[Sphere.import] Initializing providers...");
12898
13029
  await sphere.initializeProviders();
12899
13030
  console.log("[Sphere.import] Providers initialized. Initializing modules...");
12900
13031
  await sphere.initializeModules();
12901
13032
  console.log("[Sphere.import] Modules initialized");
12902
13033
  if (!options.nametag) {
13034
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12903
13035
  console.log("[Sphere.import] Recovering nametag from transport...");
12904
13036
  await sphere.recoverNametagFromTransport();
12905
13037
  console.log("[Sphere.import] Nametag recovery done");
13038
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12906
13039
  await sphere.syncIdentityWithTransport();
12907
13040
  }
13041
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12908
13042
  console.log("[Sphere.import] Finalizing wallet creation...");
12909
13043
  await sphere.finalizeWalletCreation();
12910
13044
  sphere._initialized = true;
@@ -12912,10 +13046,12 @@ var Sphere = class _Sphere {
12912
13046
  console.log("[Sphere.import] Tracking address 0...");
12913
13047
  await sphere.ensureAddressTracked(0);
12914
13048
  if (options.nametag) {
13049
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
12915
13050
  console.log("[Sphere.import] Registering nametag...");
12916
13051
  await sphere.registerNametag(options.nametag);
12917
13052
  }
12918
13053
  if (sphere._tokenStorageProviders.size > 0) {
13054
+ progress?.({ step: "syncing_tokens", message: "Syncing tokens..." });
12919
13055
  try {
12920
13056
  const syncResult = await sphere._payments.sync();
12921
13057
  console.log(`[Sphere.import] Auto-sync: +${syncResult.added} -${syncResult.removed}`);
@@ -12923,6 +13059,19 @@ var Sphere = class _Sphere {
12923
13059
  console.warn("[Sphere.import] Auto-sync failed (non-fatal):", err);
12924
13060
  }
12925
13061
  }
13062
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
13063
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
13064
+ try {
13065
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
13066
+ const result = await sphere.discoverAddresses(discoverOpts);
13067
+ if (result.addresses.length > 0) {
13068
+ console.log(`[Sphere.import] Address discovery: found ${result.addresses.length} address(es)`);
13069
+ }
13070
+ } catch (err) {
13071
+ console.warn("[Sphere.import] Address discovery failed (non-fatal):", err);
13072
+ }
13073
+ }
13074
+ progress?.({ step: "complete", message: "Import complete" });
12926
13075
  console.log("[Sphere.import] Import complete");
12927
13076
  return sphere;
12928
13077
  }
@@ -13791,6 +13940,23 @@ var Sphere = class _Sphere {
13791
13940
  await provider.initialize();
13792
13941
  }
13793
13942
  await this.reinitializeModulesForNewAddress();
13943
+ this.emitEvent("identity:changed", {
13944
+ l1Address: this._identity.l1Address,
13945
+ directAddress: this._identity.directAddress,
13946
+ chainPubkey: this._identity.chainPubkey,
13947
+ nametag: this._identity.nametag,
13948
+ addressIndex: index
13949
+ });
13950
+ console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
13951
+ this.postSwitchSync(index, newNametag).catch((err) => {
13952
+ console.warn(`[Sphere] Post-switch sync failed for address ${index}:`, err);
13953
+ });
13954
+ }
13955
+ /**
13956
+ * Background transport sync and nametag operations after address switch.
13957
+ * Runs after switchToAddress returns so L1/L3 queries can start immediately.
13958
+ */
13959
+ async postSwitchSync(index, newNametag) {
13794
13960
  if (!newNametag) {
13795
13961
  await this.syncIdentityWithTransport();
13796
13962
  }
@@ -13813,7 +13979,7 @@ var Sphere = class _Sphere {
13813
13979
  nametag: newNametag,
13814
13980
  addressIndex: index
13815
13981
  });
13816
- } else if (this._identity.nametag && !this._payments.hasNametag()) {
13982
+ } else if (this._identity?.nametag && !this._payments.hasNametag()) {
13817
13983
  console.log(`[Sphere] Nametag @${this._identity.nametag} has no token after switch, minting...`);
13818
13984
  try {
13819
13985
  const result = await this.mintNametag(this._identity.nametag);
@@ -13826,14 +13992,6 @@ var Sphere = class _Sphere {
13826
13992
  console.warn(`[Sphere] Nametag token mint failed after switch:`, err);
13827
13993
  }
13828
13994
  }
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
13995
  }
13838
13996
  /**
13839
13997
  * Re-initialize modules after address switch
@@ -14040,6 +14198,98 @@ var Sphere = class _Sphere {
14040
14198
  await this.persistTrackedAddresses();
14041
14199
  await this.persistAddressNametags();
14042
14200
  }
14201
+ /**
14202
+ * Discover previously used HD addresses.
14203
+ *
14204
+ * Primary: queries Nostr relay for identity binding events (fast, single batch query).
14205
+ * Secondary: runs L1 balance scan to find legacy addresses with no binding event.
14206
+ *
14207
+ * @example
14208
+ * ```ts
14209
+ * const result = await sphere.discoverAddresses();
14210
+ * console.log(`Found ${result.addresses.length} addresses`);
14211
+ *
14212
+ * // With auto-tracking
14213
+ * await sphere.discoverAddresses({ autoTrack: true });
14214
+ * ```
14215
+ */
14216
+ async discoverAddresses(options = {}) {
14217
+ this.ensureReady();
14218
+ if (!this._masterKey) {
14219
+ throw new Error("Address discovery requires HD master key");
14220
+ }
14221
+ if (!this._transport.discoverAddresses) {
14222
+ throw new Error("Transport provider does not support address discovery");
14223
+ }
14224
+ const includeL1Scan = options.includeL1Scan ?? true;
14225
+ const transportResult = await discoverAddressesImpl(
14226
+ (index) => {
14227
+ const addrInfo = this._deriveAddressInternal(index, false);
14228
+ return {
14229
+ transportPubkey: addrInfo.publicKey.slice(2),
14230
+ // x-only 32 bytes
14231
+ chainPubkey: addrInfo.publicKey,
14232
+ l1Address: addrInfo.address,
14233
+ directAddress: ""
14234
+ // not needed for discovery query
14235
+ };
14236
+ },
14237
+ (pubkeys) => this._transport.discoverAddresses(pubkeys),
14238
+ options
14239
+ );
14240
+ if (includeL1Scan) {
14241
+ try {
14242
+ const l1Result = await this.scanAddresses({
14243
+ maxAddresses: options.maxAddresses,
14244
+ gapLimit: options.gapLimit,
14245
+ signal: options.signal,
14246
+ onProgress: options.onProgress ? (p) => options.onProgress({
14247
+ currentBatch: 0,
14248
+ totalBatches: 0,
14249
+ discoveredCount: p.foundCount,
14250
+ currentGap: p.currentGap,
14251
+ phase: "l1"
14252
+ }) : void 0
14253
+ });
14254
+ for (const l1Addr of l1Result.addresses) {
14255
+ if (l1Addr.isChange) continue;
14256
+ const existing = transportResult.addresses.find((a) => a.index === l1Addr.index);
14257
+ if (existing) {
14258
+ existing.l1Balance = l1Addr.balance;
14259
+ existing.source = "both";
14260
+ if (!existing.nametag && l1Addr.nametag) {
14261
+ existing.nametag = l1Addr.nametag;
14262
+ }
14263
+ } else {
14264
+ const addrInfo = this._deriveAddressInternal(l1Addr.index, false);
14265
+ transportResult.addresses.push({
14266
+ index: l1Addr.index,
14267
+ l1Address: l1Addr.address,
14268
+ directAddress: "",
14269
+ chainPubkey: addrInfo.publicKey,
14270
+ nametag: l1Addr.nametag,
14271
+ l1Balance: l1Addr.balance,
14272
+ source: "l1"
14273
+ });
14274
+ }
14275
+ }
14276
+ transportResult.addresses.sort((a, b) => a.index - b.index);
14277
+ } catch (err) {
14278
+ console.warn("[Sphere] L1 scan failed during discovery (non-fatal):", err);
14279
+ }
14280
+ }
14281
+ if (options.autoTrack && transportResult.addresses.length > 0) {
14282
+ await this.trackScannedAddresses(
14283
+ transportResult.addresses.map((a) => ({
14284
+ index: a.index,
14285
+ // Preserve existing hidden state; default to false for newly discovered
14286
+ hidden: this._trackedAddresses.get(a.index)?.hidden ?? false,
14287
+ nametag: a.nametag
14288
+ }))
14289
+ );
14290
+ }
14291
+ return transportResult;
14292
+ }
14043
14293
  // ===========================================================================
14044
14294
  // Public Methods - Status
14045
14295
  // ===========================================================================
@@ -14611,6 +14861,17 @@ var Sphere = class _Sphere {
14611
14861
  return;
14612
14862
  }
14613
14863
  }
14864
+ const needsUpdate = !existing.directAddress || !existing.l1Address || !existing.chainPubkey || this._identity?.nametag && !existing.nametag;
14865
+ if (needsUpdate) {
14866
+ console.log("[Sphere] Existing binding incomplete, re-publishing with full data");
14867
+ await this._transport.publishIdentityBinding(
14868
+ this._identity.chainPubkey,
14869
+ this._identity.l1Address,
14870
+ this._identity.directAddress || "",
14871
+ this._identity?.nametag || existing.nametag || void 0
14872
+ );
14873
+ return;
14874
+ }
14614
14875
  console.log("[Sphere] Existing binding found, skipping re-publish");
14615
14876
  return;
14616
14877
  }
@@ -15104,6 +15365,7 @@ var CurrencyUtils = {
15104
15365
  init_bech32();
15105
15366
 
15106
15367
  // core/network-health.ts
15368
+ init_constants();
15107
15369
  var DEFAULT_TIMEOUT_MS = 5e3;
15108
15370
  async function checkNetworkHealth(network = "testnet", options) {
15109
15371
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -15291,7 +15553,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
15291
15553
  export {
15292
15554
  CHARSET,
15293
15555
  CurrencyUtils,
15294
- DEFAULT_DERIVATION_PATH,
15556
+ DEFAULT_DERIVATION_PATH2 as DEFAULT_DERIVATION_PATH,
15295
15557
  DEFAULT_TOKEN_DECIMALS,
15296
15558
  Sphere,
15297
15559
  base58Decode,
@@ -15314,6 +15576,7 @@ export {
15314
15576
  deriveChildKey,
15315
15577
  deriveKeyAtPath,
15316
15578
  deserializeEncrypted,
15579
+ discoverAddressesImpl,
15317
15580
  doubleSha256,
15318
15581
  ec,
15319
15582
  encodeBech32,