@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.
@@ -30,6 +30,175 @@ var __toESM = (mod2, isNodeMode, target) => (target = mod2 != null ? __create(__
30
30
  ));
31
31
  var __toCommonJS = (mod2) => __copyProps(__defProp({}, "__esModule", { value: true }), mod2);
32
32
 
33
+ // constants.ts
34
+ function getAddressId(directAddress) {
35
+ let hash = directAddress;
36
+ if (hash.startsWith("DIRECT://")) {
37
+ hash = hash.slice(9);
38
+ } else if (hash.startsWith("DIRECT:")) {
39
+ hash = hash.slice(7);
40
+ }
41
+ const first = hash.slice(0, 6).toLowerCase();
42
+ const last = hash.slice(-6).toLowerCase();
43
+ return `DIRECT_${first}_${last}`;
44
+ }
45
+ 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;
46
+ var init_constants = __esm({
47
+ "constants.ts"() {
48
+ "use strict";
49
+ DEFAULT_ENCRYPTION_KEY = "sphere-default-key";
50
+ STORAGE_KEYS_GLOBAL = {
51
+ /** Encrypted BIP39 mnemonic */
52
+ MNEMONIC: "mnemonic",
53
+ /** Encrypted master private key */
54
+ MASTER_KEY: "master_key",
55
+ /** BIP32 chain code */
56
+ CHAIN_CODE: "chain_code",
57
+ /** HD derivation path (full path like m/44'/0'/0'/0/0) */
58
+ DERIVATION_PATH: "derivation_path",
59
+ /** Base derivation path (like m/44'/0'/0' without chain/index) */
60
+ BASE_PATH: "base_path",
61
+ /** Derivation mode: bip32, wif_hmac, legacy_hmac */
62
+ DERIVATION_MODE: "derivation_mode",
63
+ /** Wallet source: mnemonic, file, unknown */
64
+ WALLET_SOURCE: "wallet_source",
65
+ /** Wallet existence flag */
66
+ WALLET_EXISTS: "wallet_exists",
67
+ /** Current active address index */
68
+ CURRENT_ADDRESS_INDEX: "current_address_index",
69
+ /** Nametag cache per address (separate from tracked addresses registry) */
70
+ ADDRESS_NAMETAGS: "address_nametags",
71
+ /** Active addresses registry (JSON: TrackedAddressesStorage) */
72
+ TRACKED_ADDRESSES: "tracked_addresses",
73
+ /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
74
+ LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
75
+ /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
76
+ GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
77
+ /** Cached token registry JSON (fetched from remote) */
78
+ TOKEN_REGISTRY_CACHE: "token_registry_cache",
79
+ /** Timestamp of last token registry cache update (ms since epoch) */
80
+ TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
81
+ /** Cached price data JSON (from CoinGecko or other provider) */
82
+ PRICE_CACHE: "price_cache",
83
+ /** Timestamp of last price cache update (ms since epoch) */
84
+ PRICE_CACHE_TS: "price_cache_ts"
85
+ };
86
+ STORAGE_KEYS_ADDRESS = {
87
+ /** Pending transfers for this address */
88
+ PENDING_TRANSFERS: "pending_transfers",
89
+ /** Transfer outbox for this address */
90
+ OUTBOX: "outbox",
91
+ /** Conversations for this address */
92
+ CONVERSATIONS: "conversations",
93
+ /** Messages for this address */
94
+ MESSAGES: "messages",
95
+ /** Transaction history for this address */
96
+ TRANSACTION_HISTORY: "transaction_history",
97
+ /** Pending V5 finalization tokens (unconfirmed instant split tokens) */
98
+ PENDING_V5_TOKENS: "pending_v5_tokens",
99
+ /** Group chat: joined groups for this address */
100
+ GROUP_CHAT_GROUPS: "group_chat_groups",
101
+ /** Group chat: messages for this address */
102
+ GROUP_CHAT_MESSAGES: "group_chat_messages",
103
+ /** Group chat: members for this address */
104
+ GROUP_CHAT_MEMBERS: "group_chat_members",
105
+ /** Group chat: processed event IDs for deduplication */
106
+ GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events"
107
+ };
108
+ STORAGE_KEYS = {
109
+ ...STORAGE_KEYS_GLOBAL,
110
+ ...STORAGE_KEYS_ADDRESS
111
+ };
112
+ DEFAULT_NOSTR_RELAYS = [
113
+ "wss://relay.unicity.network",
114
+ "wss://relay.damus.io",
115
+ "wss://nos.lol",
116
+ "wss://relay.nostr.band"
117
+ ];
118
+ NIP29_KINDS = {
119
+ /** Chat message sent to group */
120
+ CHAT_MESSAGE: 9,
121
+ /** Thread root message */
122
+ THREAD_ROOT: 11,
123
+ /** Thread reply message */
124
+ THREAD_REPLY: 12,
125
+ /** User join request */
126
+ JOIN_REQUEST: 9021,
127
+ /** User leave request */
128
+ LEAVE_REQUEST: 9022,
129
+ /** Admin: add/update user */
130
+ PUT_USER: 9e3,
131
+ /** Admin: remove user */
132
+ REMOVE_USER: 9001,
133
+ /** Admin: edit group metadata */
134
+ EDIT_METADATA: 9002,
135
+ /** Admin: delete event */
136
+ DELETE_EVENT: 9005,
137
+ /** Admin: create group */
138
+ CREATE_GROUP: 9007,
139
+ /** Admin: delete group */
140
+ DELETE_GROUP: 9008,
141
+ /** Admin: create invite code */
142
+ CREATE_INVITE: 9009,
143
+ /** Relay-signed group metadata */
144
+ GROUP_METADATA: 39e3,
145
+ /** Relay-signed group admins */
146
+ GROUP_ADMINS: 39001,
147
+ /** Relay-signed group members */
148
+ GROUP_MEMBERS: 39002,
149
+ /** Relay-signed group roles */
150
+ GROUP_ROLES: 39003
151
+ };
152
+ DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
153
+ DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
154
+ TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
155
+ DEFAULT_IPFS_GATEWAYS = [
156
+ "https://unicity-ipfs1.dyndns.org"
157
+ ];
158
+ DEFAULT_BASE_PATH = "m/44'/0'/0'";
159
+ DEFAULT_DERIVATION_PATH = `${DEFAULT_BASE_PATH}/0/0`;
160
+ DEFAULT_ELECTRUM_URL = "wss://fulcrum.unicity.network:50004";
161
+ TEST_ELECTRUM_URL = "wss://fulcrum.unicity.network:50004";
162
+ TOKEN_REGISTRY_URL = "https://raw.githubusercontent.com/unicitynetwork/unicity-ids/refs/heads/main/unicity-ids.testnet.json";
163
+ TOKEN_REGISTRY_REFRESH_INTERVAL = 36e5;
164
+ TEST_NOSTR_RELAYS = [
165
+ "wss://nostr-relay.testnet.unicity.network"
166
+ ];
167
+ DEFAULT_GROUP_RELAYS = [
168
+ "wss://sphere-relay.unicity.network"
169
+ ];
170
+ NETWORKS = {
171
+ mainnet: {
172
+ name: "Mainnet",
173
+ aggregatorUrl: DEFAULT_AGGREGATOR_URL,
174
+ nostrRelays: DEFAULT_NOSTR_RELAYS,
175
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
176
+ electrumUrl: DEFAULT_ELECTRUM_URL,
177
+ groupRelays: DEFAULT_GROUP_RELAYS,
178
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
179
+ },
180
+ testnet: {
181
+ name: "Testnet",
182
+ aggregatorUrl: TEST_AGGREGATOR_URL,
183
+ nostrRelays: TEST_NOSTR_RELAYS,
184
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
185
+ electrumUrl: TEST_ELECTRUM_URL,
186
+ groupRelays: DEFAULT_GROUP_RELAYS,
187
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
188
+ },
189
+ dev: {
190
+ name: "Development",
191
+ aggregatorUrl: DEV_AGGREGATOR_URL,
192
+ nostrRelays: TEST_NOSTR_RELAYS,
193
+ ipfsGateways: DEFAULT_IPFS_GATEWAYS,
194
+ electrumUrl: TEST_ELECTRUM_URL,
195
+ groupRelays: DEFAULT_GROUP_RELAYS,
196
+ tokenRegistryUrl: TOKEN_REGISTRY_URL
197
+ }
198
+ };
199
+ }
200
+ });
201
+
33
202
  // core/bech32.ts
34
203
  function convertBits(data, fromBits, toBits, pad) {
35
204
  let acc = 0;
@@ -447,7 +616,8 @@ var init_network = __esm({
447
616
  "l1/network.ts"() {
448
617
  "use strict";
449
618
  init_addressToScriptHash();
450
- DEFAULT_ENDPOINT = "wss://fulcrum.unicity.network:50004";
619
+ init_constants();
620
+ DEFAULT_ENDPOINT = DEFAULT_ELECTRUM_URL;
451
621
  ws = null;
452
622
  isConnected = false;
453
623
  isConnecting = false;
@@ -472,7 +642,7 @@ var core_exports = {};
472
642
  __export(core_exports, {
473
643
  CHARSET: () => CHARSET,
474
644
  CurrencyUtils: () => CurrencyUtils,
475
- DEFAULT_DERIVATION_PATH: () => DEFAULT_DERIVATION_PATH,
645
+ DEFAULT_DERIVATION_PATH: () => DEFAULT_DERIVATION_PATH2,
476
646
  DEFAULT_TOKEN_DECIMALS: () => DEFAULT_TOKEN_DECIMALS,
477
647
  Sphere: () => Sphere,
478
648
  base58Decode: () => base58Decode,
@@ -495,6 +665,7 @@ __export(core_exports, {
495
665
  deriveChildKey: () => deriveChildKey,
496
666
  deriveKeyAtPath: () => deriveKeyAtPath,
497
667
  deserializeEncrypted: () => deserializeEncrypted,
668
+ discoverAddressesImpl: () => discoverAddressesImpl,
498
669
  doubleSha256: () => doubleSha256,
499
670
  ec: () => ec,
500
671
  encodeBech32: () => encodeBech32,
@@ -544,6 +715,9 @@ __export(core_exports, {
544
715
  });
545
716
  module.exports = __toCommonJS(core_exports);
546
717
 
718
+ // modules/payments/L1PaymentsModule.ts
719
+ init_constants();
720
+
547
721
  // l1/index.ts
548
722
  init_bech32();
549
723
  init_addressToScriptHash();
@@ -557,7 +731,7 @@ var ec = new import_elliptic.default.ec("secp256k1");
557
731
  var CURVE_ORDER = BigInt(
558
732
  "0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141"
559
733
  );
560
- var DEFAULT_DERIVATION_PATH = "m/44'/0'/0'";
734
+ var DEFAULT_DERIVATION_PATH2 = "m/44'/0'/0'";
561
735
  function generateMnemonic2(strength = 128) {
562
736
  return bip39.generateMnemonic(strength);
563
737
  }
@@ -1578,7 +1752,7 @@ var L1PaymentsModule = class {
1578
1752
  _transport;
1579
1753
  constructor(config) {
1580
1754
  this._config = {
1581
- electrumUrl: config?.electrumUrl ?? "wss://fulcrum.unicity.network:50004",
1755
+ electrumUrl: config?.electrumUrl ?? DEFAULT_ELECTRUM_URL,
1582
1756
  network: config?.network ?? "mainnet",
1583
1757
  defaultFeeRate: config?.defaultFeeRate ?? 10,
1584
1758
  enableVesting: config?.enableVesting ?? true
@@ -2415,168 +2589,8 @@ var NametagMinter = class {
2415
2589
  }
2416
2590
  };
2417
2591
 
2418
- // constants.ts
2419
- var DEFAULT_ENCRYPTION_KEY = "sphere-default-key";
2420
- var STORAGE_KEYS_GLOBAL = {
2421
- /** Encrypted BIP39 mnemonic */
2422
- MNEMONIC: "mnemonic",
2423
- /** Encrypted master private key */
2424
- MASTER_KEY: "master_key",
2425
- /** BIP32 chain code */
2426
- CHAIN_CODE: "chain_code",
2427
- /** HD derivation path (full path like m/44'/0'/0'/0/0) */
2428
- DERIVATION_PATH: "derivation_path",
2429
- /** Base derivation path (like m/44'/0'/0' without chain/index) */
2430
- BASE_PATH: "base_path",
2431
- /** Derivation mode: bip32, wif_hmac, legacy_hmac */
2432
- DERIVATION_MODE: "derivation_mode",
2433
- /** Wallet source: mnemonic, file, unknown */
2434
- WALLET_SOURCE: "wallet_source",
2435
- /** Wallet existence flag */
2436
- WALLET_EXISTS: "wallet_exists",
2437
- /** Current active address index */
2438
- CURRENT_ADDRESS_INDEX: "current_address_index",
2439
- /** Nametag cache per address (separate from tracked addresses registry) */
2440
- ADDRESS_NAMETAGS: "address_nametags",
2441
- /** Active addresses registry (JSON: TrackedAddressesStorage) */
2442
- TRACKED_ADDRESSES: "tracked_addresses",
2443
- /** Last processed Nostr wallet event timestamp (unix seconds), keyed per pubkey */
2444
- LAST_WALLET_EVENT_TS: "last_wallet_event_ts",
2445
- /** Group chat: last used relay URL (stale data detection) — global, same relay for all addresses */
2446
- GROUP_CHAT_RELAY_URL: "group_chat_relay_url",
2447
- /** Cached token registry JSON (fetched from remote) */
2448
- TOKEN_REGISTRY_CACHE: "token_registry_cache",
2449
- /** Timestamp of last token registry cache update (ms since epoch) */
2450
- TOKEN_REGISTRY_CACHE_TS: "token_registry_cache_ts",
2451
- /** Cached price data JSON (from CoinGecko or other provider) */
2452
- PRICE_CACHE: "price_cache",
2453
- /** Timestamp of last price cache update (ms since epoch) */
2454
- PRICE_CACHE_TS: "price_cache_ts"
2455
- };
2456
- var STORAGE_KEYS_ADDRESS = {
2457
- /** Pending transfers for this address */
2458
- PENDING_TRANSFERS: "pending_transfers",
2459
- /** Transfer outbox for this address */
2460
- OUTBOX: "outbox",
2461
- /** Conversations for this address */
2462
- CONVERSATIONS: "conversations",
2463
- /** Messages for this address */
2464
- MESSAGES: "messages",
2465
- /** Transaction history for this address */
2466
- TRANSACTION_HISTORY: "transaction_history",
2467
- /** Pending V5 finalization tokens (unconfirmed instant split tokens) */
2468
- PENDING_V5_TOKENS: "pending_v5_tokens",
2469
- /** Group chat: joined groups for this address */
2470
- GROUP_CHAT_GROUPS: "group_chat_groups",
2471
- /** Group chat: messages for this address */
2472
- GROUP_CHAT_MESSAGES: "group_chat_messages",
2473
- /** Group chat: members for this address */
2474
- GROUP_CHAT_MEMBERS: "group_chat_members",
2475
- /** Group chat: processed event IDs for deduplication */
2476
- GROUP_CHAT_PROCESSED_EVENTS: "group_chat_processed_events"
2477
- };
2478
- var STORAGE_KEYS = {
2479
- ...STORAGE_KEYS_GLOBAL,
2480
- ...STORAGE_KEYS_ADDRESS
2481
- };
2482
- function getAddressId(directAddress) {
2483
- let hash = directAddress;
2484
- if (hash.startsWith("DIRECT://")) {
2485
- hash = hash.slice(9);
2486
- } else if (hash.startsWith("DIRECT:")) {
2487
- hash = hash.slice(7);
2488
- }
2489
- const first = hash.slice(0, 6).toLowerCase();
2490
- const last = hash.slice(-6).toLowerCase();
2491
- return `DIRECT_${first}_${last}`;
2492
- }
2493
- var DEFAULT_NOSTR_RELAYS = [
2494
- "wss://relay.unicity.network",
2495
- "wss://relay.damus.io",
2496
- "wss://nos.lol",
2497
- "wss://relay.nostr.band"
2498
- ];
2499
- var NIP29_KINDS = {
2500
- /** Chat message sent to group */
2501
- CHAT_MESSAGE: 9,
2502
- /** Thread root message */
2503
- THREAD_ROOT: 11,
2504
- /** Thread reply message */
2505
- THREAD_REPLY: 12,
2506
- /** User join request */
2507
- JOIN_REQUEST: 9021,
2508
- /** User leave request */
2509
- LEAVE_REQUEST: 9022,
2510
- /** Admin: add/update user */
2511
- PUT_USER: 9e3,
2512
- /** Admin: remove user */
2513
- REMOVE_USER: 9001,
2514
- /** Admin: edit group metadata */
2515
- EDIT_METADATA: 9002,
2516
- /** Admin: delete event */
2517
- DELETE_EVENT: 9005,
2518
- /** Admin: create group */
2519
- CREATE_GROUP: 9007,
2520
- /** Admin: delete group */
2521
- DELETE_GROUP: 9008,
2522
- /** Admin: create invite code */
2523
- CREATE_INVITE: 9009,
2524
- /** Relay-signed group metadata */
2525
- GROUP_METADATA: 39e3,
2526
- /** Relay-signed group admins */
2527
- GROUP_ADMINS: 39001,
2528
- /** Relay-signed group members */
2529
- GROUP_MEMBERS: 39002,
2530
- /** Relay-signed group roles */
2531
- GROUP_ROLES: 39003
2532
- };
2533
- var DEFAULT_AGGREGATOR_URL = "https://aggregator.unicity.network/rpc";
2534
- var DEV_AGGREGATOR_URL = "https://dev-aggregator.dyndns.org/rpc";
2535
- var TEST_AGGREGATOR_URL = "https://goggregator-test.unicity.network";
2536
- var DEFAULT_IPFS_GATEWAYS = [
2537
- "https://unicity-ipfs1.dyndns.org"
2538
- ];
2539
- var DEFAULT_BASE_PATH = "m/44'/0'/0'";
2540
- var DEFAULT_DERIVATION_PATH2 = `${DEFAULT_BASE_PATH}/0/0`;
2541
- var DEFAULT_ELECTRUM_URL = "wss://fulcrum.alpha.unicity.network:50004";
2542
- var TEST_ELECTRUM_URL = "wss://fulcrum.alpha.testnet.unicity.network:50004";
2543
- var TOKEN_REGISTRY_URL = "https://raw.githubusercontent.com/unicitynetwork/unicity-ids/refs/heads/main/unicity-ids.testnet.json";
2544
- var TOKEN_REGISTRY_REFRESH_INTERVAL = 36e5;
2545
- var TEST_NOSTR_RELAYS = [
2546
- "wss://nostr-relay.testnet.unicity.network"
2547
- ];
2548
- var DEFAULT_GROUP_RELAYS = [
2549
- "wss://sphere-relay.unicity.network"
2550
- ];
2551
- var NETWORKS = {
2552
- mainnet: {
2553
- name: "Mainnet",
2554
- aggregatorUrl: DEFAULT_AGGREGATOR_URL,
2555
- nostrRelays: DEFAULT_NOSTR_RELAYS,
2556
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2557
- electrumUrl: DEFAULT_ELECTRUM_URL,
2558
- groupRelays: DEFAULT_GROUP_RELAYS,
2559
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2560
- },
2561
- testnet: {
2562
- name: "Testnet",
2563
- aggregatorUrl: TEST_AGGREGATOR_URL,
2564
- nostrRelays: TEST_NOSTR_RELAYS,
2565
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2566
- electrumUrl: TEST_ELECTRUM_URL,
2567
- groupRelays: DEFAULT_GROUP_RELAYS,
2568
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2569
- },
2570
- dev: {
2571
- name: "Development",
2572
- aggregatorUrl: DEV_AGGREGATOR_URL,
2573
- nostrRelays: TEST_NOSTR_RELAYS,
2574
- ipfsGateways: DEFAULT_IPFS_GATEWAYS,
2575
- electrumUrl: TEST_ELECTRUM_URL,
2576
- groupRelays: DEFAULT_GROUP_RELAYS,
2577
- tokenRegistryUrl: TOKEN_REGISTRY_URL
2578
- }
2579
- };
2592
+ // modules/payments/PaymentsModule.ts
2593
+ init_constants();
2580
2594
 
2581
2595
  // types/txf.ts
2582
2596
  var ARCHIVED_PREFIX = "archived-";
@@ -2618,6 +2632,7 @@ function parseForkedKey(key) {
2618
2632
  }
2619
2633
 
2620
2634
  // registry/TokenRegistry.ts
2635
+ init_constants();
2621
2636
  var FETCH_TIMEOUT_MS = 1e4;
2622
2637
  var TokenRegistry = class _TokenRegistry {
2623
2638
  static instance = null;
@@ -7430,6 +7445,7 @@ var import_HashAlgorithm6 = require("@unicitylabs/state-transition-sdk/lib/hash/
7430
7445
  var import_UnmaskedPredicate6 = require("@unicitylabs/state-transition-sdk/lib/predicate/embedded/UnmaskedPredicate");
7431
7446
 
7432
7447
  // modules/communications/CommunicationsModule.ts
7448
+ init_constants();
7433
7449
  var CommunicationsModule = class {
7434
7450
  config;
7435
7451
  deps = null;
@@ -7905,6 +7921,7 @@ function createCommunicationsModule(config) {
7905
7921
 
7906
7922
  // modules/groupchat/GroupChatModule.ts
7907
7923
  var import_nostr_js_sdk2 = require("@unicitylabs/nostr-js-sdk");
7924
+ init_constants();
7908
7925
 
7909
7926
  // modules/groupchat/types.ts
7910
7927
  var GroupRole = {
@@ -11749,6 +11766,9 @@ function createMarketModule(config) {
11749
11766
  return new MarketModule(config);
11750
11767
  }
11751
11768
 
11769
+ // core/Sphere.ts
11770
+ init_constants();
11771
+
11752
11772
  // core/encryption.ts
11753
11773
  var import_crypto_js6 = __toESM(require("crypto-js"), 1);
11754
11774
  var DEFAULT_ITERATIONS = 1e5;
@@ -11937,6 +11957,72 @@ async function scanAddressesImpl(deriveAddress, options = {}) {
11937
11957
  };
11938
11958
  }
11939
11959
 
11960
+ // core/discover.ts
11961
+ async function discoverAddressesImpl(deriveTransportPubkey, batchResolve, options = {}) {
11962
+ const maxAddresses = options.maxAddresses ?? 50;
11963
+ const gapLimit = options.gapLimit ?? 20;
11964
+ const batchSize = options.batchSize ?? 20;
11965
+ const { onProgress, signal } = options;
11966
+ const discovered = /* @__PURE__ */ new Map();
11967
+ let consecutiveEmpty = 0;
11968
+ let scanned = 0;
11969
+ const totalBatches = Math.ceil(maxAddresses / batchSize);
11970
+ for (let batchStart = 0; batchStart < maxAddresses; batchStart += batchSize) {
11971
+ if (signal?.aborted) break;
11972
+ if (consecutiveEmpty >= gapLimit) break;
11973
+ const batchEnd = Math.min(batchStart + batchSize, maxAddresses);
11974
+ const batchIndices = [];
11975
+ const pubkeyToIndex = /* @__PURE__ */ new Map();
11976
+ const pubkeyToInfo = /* @__PURE__ */ new Map();
11977
+ for (let i = batchStart; i < batchEnd; i++) {
11978
+ const info = deriveTransportPubkey(i);
11979
+ batchIndices.push(i);
11980
+ pubkeyToIndex.set(info.transportPubkey, i);
11981
+ pubkeyToInfo.set(info.transportPubkey, info);
11982
+ }
11983
+ const batchPubkeys = Array.from(pubkeyToIndex.keys());
11984
+ onProgress?.({
11985
+ currentBatch: Math.floor(batchStart / batchSize) + 1,
11986
+ totalBatches,
11987
+ discoveredCount: discovered.size,
11988
+ currentGap: consecutiveEmpty,
11989
+ phase: "transport"
11990
+ });
11991
+ const peerInfos = await batchResolve(batchPubkeys);
11992
+ const foundInBatch = /* @__PURE__ */ new Set();
11993
+ for (const peer of peerInfos) {
11994
+ const index = pubkeyToIndex.get(peer.transportPubkey);
11995
+ if (index !== void 0) {
11996
+ foundInBatch.add(index);
11997
+ const derived = pubkeyToInfo.get(peer.transportPubkey);
11998
+ discovered.set(index, {
11999
+ index,
12000
+ l1Address: peer.l1Address || derived.l1Address,
12001
+ directAddress: peer.directAddress || derived.directAddress,
12002
+ chainPubkey: peer.chainPubkey || derived.chainPubkey,
12003
+ nametag: peer.nametag,
12004
+ l1Balance: 0,
12005
+ source: "transport"
12006
+ });
12007
+ }
12008
+ }
12009
+ for (const idx of batchIndices) {
12010
+ scanned++;
12011
+ if (foundInBatch.has(idx)) {
12012
+ consecutiveEmpty = 0;
12013
+ } else {
12014
+ consecutiveEmpty++;
12015
+ if (consecutiveEmpty >= gapLimit) break;
12016
+ }
12017
+ }
12018
+ }
12019
+ return {
12020
+ addresses: Array.from(discovered.values()).sort((a, b) => a.index - b.index),
12021
+ scannedCount: scanned,
12022
+ aborted: signal?.aborted ?? false
12023
+ };
12024
+ }
12025
+
11940
12026
  // core/Sphere.ts
11941
12027
  init_network();
11942
12028
 
@@ -12759,7 +12845,9 @@ var Sphere = class _Sphere {
12759
12845
  price: options.price,
12760
12846
  groupChat,
12761
12847
  market,
12762
- password: options.password
12848
+ password: options.password,
12849
+ discoverAddresses: options.discoverAddresses,
12850
+ onProgress: options.onProgress
12763
12851
  });
12764
12852
  return { sphere: sphere2, created: false };
12765
12853
  }
@@ -12787,7 +12875,9 @@ var Sphere = class _Sphere {
12787
12875
  price: options.price,
12788
12876
  groupChat,
12789
12877
  market,
12790
- password: options.password
12878
+ password: options.password,
12879
+ discoverAddresses: options.discoverAddresses,
12880
+ onProgress: options.onProgress
12791
12881
  });
12792
12882
  return { sphere, created: true, generatedMnemonic };
12793
12883
  }
@@ -12848,6 +12938,7 @@ var Sphere = class _Sphere {
12848
12938
  if (await _Sphere.exists(options.storage)) {
12849
12939
  throw new Error("Wallet already exists. Use Sphere.load() or Sphere.clear() first.");
12850
12940
  }
12941
+ const progress = options.onProgress;
12851
12942
  if (!options.storage.isConnected()) {
12852
12943
  await options.storage.connect();
12853
12944
  }
@@ -12865,20 +12956,39 @@ var Sphere = class _Sphere {
12865
12956
  marketConfig
12866
12957
  );
12867
12958
  sphere._password = options.password ?? null;
12959
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12868
12960
  await sphere.storeMnemonic(options.mnemonic, options.derivationPath);
12869
12961
  await sphere.initializeIdentityFromMnemonic(options.mnemonic, options.derivationPath);
12962
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12870
12963
  await sphere.initializeProviders();
12871
12964
  await sphere.initializeModules();
12965
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12872
12966
  await sphere.finalizeWalletCreation();
12873
12967
  sphere._initialized = true;
12874
12968
  _Sphere.instance = sphere;
12875
12969
  await sphere.ensureAddressTracked(0);
12876
12970
  if (options.nametag) {
12971
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
12877
12972
  await sphere.registerNametag(options.nametag);
12878
12973
  } else {
12974
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12879
12975
  await sphere.recoverNametagFromTransport();
12976
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12880
12977
  await sphere.syncIdentityWithTransport();
12881
12978
  }
12979
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
12980
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
12981
+ try {
12982
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
12983
+ const result = await sphere.discoverAddresses(discoverOpts);
12984
+ if (result.addresses.length > 0) {
12985
+ console.log(`[Sphere.create] Address discovery: found ${result.addresses.length} address(es)`);
12986
+ }
12987
+ } catch (err) {
12988
+ console.warn("[Sphere.create] Address discovery failed (non-fatal):", err);
12989
+ }
12990
+ }
12991
+ progress?.({ step: "complete", message: "Wallet created" });
12882
12992
  return sphere;
12883
12993
  }
12884
12994
  /**
@@ -12888,6 +12998,7 @@ var Sphere = class _Sphere {
12888
12998
  if (!await _Sphere.exists(options.storage)) {
12889
12999
  throw new Error("No wallet found. Use Sphere.create() to create a new wallet.");
12890
13000
  }
13001
+ const progress = options.onProgress;
12891
13002
  _Sphere.configureTokenRegistry(options.storage, options.network);
12892
13003
  const groupChatConfig = _Sphere.resolveGroupChatConfig(options.groupChat, options.network);
12893
13004
  const marketConfig = _Sphere.resolveMarketConfig(options.market);
@@ -12905,13 +13016,17 @@ var Sphere = class _Sphere {
12905
13016
  if (!options.storage.isConnected()) {
12906
13017
  await options.storage.connect();
12907
13018
  }
13019
+ progress?.({ step: "storing_keys", message: "Loading wallet keys..." });
12908
13020
  await sphere.loadIdentityFromStorage();
13021
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12909
13022
  await sphere.initializeProviders();
12910
13023
  await sphere.initializeModules();
13024
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12911
13025
  await sphere.syncIdentityWithTransport();
12912
13026
  sphere._initialized = true;
12913
13027
  _Sphere.instance = sphere;
12914
13028
  if (sphere._identity?.nametag && !sphere._payments.hasNametag()) {
13029
+ progress?.({ step: "registering_nametag", message: "Restoring nametag token..." });
12915
13030
  console.log(`[Sphere] Nametag @${sphere._identity.nametag} has no token, attempting to mint...`);
12916
13031
  try {
12917
13032
  const result = await sphere.mintNametag(sphere._identity.nametag);
@@ -12924,6 +13039,19 @@ var Sphere = class _Sphere {
12924
13039
  console.warn(`[Sphere] Nametag token mint failed:`, err);
12925
13040
  }
12926
13041
  }
13042
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses && sphere._masterKey) {
13043
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
13044
+ try {
13045
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
13046
+ const result = await sphere.discoverAddresses(discoverOpts);
13047
+ if (result.addresses.length > 0) {
13048
+ console.log(`[Sphere.load] Address discovery: found ${result.addresses.length} address(es)`);
13049
+ }
13050
+ } catch (err) {
13051
+ console.warn("[Sphere.load] Address discovery failed (non-fatal):", err);
13052
+ }
13053
+ }
13054
+ progress?.({ step: "complete", message: "Wallet loaded" });
12927
13055
  return sphere;
12928
13056
  }
12929
13057
  /**
@@ -12933,9 +13061,11 @@ var Sphere = class _Sphere {
12933
13061
  if (!options.mnemonic && !options.masterKey) {
12934
13062
  throw new Error("Either mnemonic or masterKey is required");
12935
13063
  }
13064
+ const progress = options.onProgress;
12936
13065
  console.log("[Sphere.import] Starting import...");
12937
13066
  const needsClear = _Sphere.instance !== null || await _Sphere.exists(options.storage);
12938
13067
  if (needsClear) {
13068
+ progress?.({ step: "clearing", message: "Clearing previous wallet data..." });
12939
13069
  console.log("[Sphere.import] Clearing existing wallet data...");
12940
13070
  await _Sphere.clear({ storage: options.storage, tokenStorage: options.tokenStorage });
12941
13071
  console.log("[Sphere.import] Clear done");
@@ -12960,6 +13090,7 @@ var Sphere = class _Sphere {
12960
13090
  marketConfig
12961
13091
  );
12962
13092
  sphere._password = options.password ?? null;
13093
+ progress?.({ step: "storing_keys", message: "Storing wallet keys..." });
12963
13094
  if (options.mnemonic) {
12964
13095
  if (!_Sphere.validateMnemonic(options.mnemonic)) {
12965
13096
  throw new Error("Invalid mnemonic");
@@ -12984,17 +13115,21 @@ var Sphere = class _Sphere {
12984
13115
  options.derivationPath
12985
13116
  );
12986
13117
  }
13118
+ progress?.({ step: "initializing", message: "Initializing wallet..." });
12987
13119
  console.log("[Sphere.import] Initializing providers...");
12988
13120
  await sphere.initializeProviders();
12989
13121
  console.log("[Sphere.import] Providers initialized. Initializing modules...");
12990
13122
  await sphere.initializeModules();
12991
13123
  console.log("[Sphere.import] Modules initialized");
12992
13124
  if (!options.nametag) {
13125
+ progress?.({ step: "recovering_nametag", message: "Recovering nametag..." });
12993
13126
  console.log("[Sphere.import] Recovering nametag from transport...");
12994
13127
  await sphere.recoverNametagFromTransport();
12995
13128
  console.log("[Sphere.import] Nametag recovery done");
13129
+ progress?.({ step: "syncing_identity", message: "Publishing identity..." });
12996
13130
  await sphere.syncIdentityWithTransport();
12997
13131
  }
13132
+ progress?.({ step: "finalizing", message: "Finalizing wallet..." });
12998
13133
  console.log("[Sphere.import] Finalizing wallet creation...");
12999
13134
  await sphere.finalizeWalletCreation();
13000
13135
  sphere._initialized = true;
@@ -13002,10 +13137,12 @@ var Sphere = class _Sphere {
13002
13137
  console.log("[Sphere.import] Tracking address 0...");
13003
13138
  await sphere.ensureAddressTracked(0);
13004
13139
  if (options.nametag) {
13140
+ progress?.({ step: "registering_nametag", message: "Registering nametag..." });
13005
13141
  console.log("[Sphere.import] Registering nametag...");
13006
13142
  await sphere.registerNametag(options.nametag);
13007
13143
  }
13008
13144
  if (sphere._tokenStorageProviders.size > 0) {
13145
+ progress?.({ step: "syncing_tokens", message: "Syncing tokens..." });
13009
13146
  try {
13010
13147
  const syncResult = await sphere._payments.sync();
13011
13148
  console.log(`[Sphere.import] Auto-sync: +${syncResult.added} -${syncResult.removed}`);
@@ -13013,6 +13150,19 @@ var Sphere = class _Sphere {
13013
13150
  console.warn("[Sphere.import] Auto-sync failed (non-fatal):", err);
13014
13151
  }
13015
13152
  }
13153
+ if (options.discoverAddresses !== false && sphere._transport.discoverAddresses) {
13154
+ progress?.({ step: "discovering_addresses", message: "Discovering addresses..." });
13155
+ try {
13156
+ const discoverOpts = typeof options.discoverAddresses === "object" ? { ...options.discoverAddresses, autoTrack: options.discoverAddresses.autoTrack ?? true } : { autoTrack: true };
13157
+ const result = await sphere.discoverAddresses(discoverOpts);
13158
+ if (result.addresses.length > 0) {
13159
+ console.log(`[Sphere.import] Address discovery: found ${result.addresses.length} address(es)`);
13160
+ }
13161
+ } catch (err) {
13162
+ console.warn("[Sphere.import] Address discovery failed (non-fatal):", err);
13163
+ }
13164
+ }
13165
+ progress?.({ step: "complete", message: "Import complete" });
13016
13166
  console.log("[Sphere.import] Import complete");
13017
13167
  return sphere;
13018
13168
  }
@@ -13881,6 +14031,23 @@ var Sphere = class _Sphere {
13881
14031
  await provider.initialize();
13882
14032
  }
13883
14033
  await this.reinitializeModulesForNewAddress();
14034
+ this.emitEvent("identity:changed", {
14035
+ l1Address: this._identity.l1Address,
14036
+ directAddress: this._identity.directAddress,
14037
+ chainPubkey: this._identity.chainPubkey,
14038
+ nametag: this._identity.nametag,
14039
+ addressIndex: index
14040
+ });
14041
+ console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
14042
+ this.postSwitchSync(index, newNametag).catch((err) => {
14043
+ console.warn(`[Sphere] Post-switch sync failed for address ${index}:`, err);
14044
+ });
14045
+ }
14046
+ /**
14047
+ * Background transport sync and nametag operations after address switch.
14048
+ * Runs after switchToAddress returns so L1/L3 queries can start immediately.
14049
+ */
14050
+ async postSwitchSync(index, newNametag) {
13884
14051
  if (!newNametag) {
13885
14052
  await this.syncIdentityWithTransport();
13886
14053
  }
@@ -13903,7 +14070,7 @@ var Sphere = class _Sphere {
13903
14070
  nametag: newNametag,
13904
14071
  addressIndex: index
13905
14072
  });
13906
- } else if (this._identity.nametag && !this._payments.hasNametag()) {
14073
+ } else if (this._identity?.nametag && !this._payments.hasNametag()) {
13907
14074
  console.log(`[Sphere] Nametag @${this._identity.nametag} has no token after switch, minting...`);
13908
14075
  try {
13909
14076
  const result = await this.mintNametag(this._identity.nametag);
@@ -13916,14 +14083,6 @@ var Sphere = class _Sphere {
13916
14083
  console.warn(`[Sphere] Nametag token mint failed after switch:`, err);
13917
14084
  }
13918
14085
  }
13919
- this.emitEvent("identity:changed", {
13920
- l1Address: this._identity.l1Address,
13921
- directAddress: this._identity.directAddress,
13922
- chainPubkey: this._identity.chainPubkey,
13923
- nametag: this._identity.nametag,
13924
- addressIndex: index
13925
- });
13926
- console.log(`[Sphere] Switched to address ${index}:`, this._identity.l1Address);
13927
14086
  }
13928
14087
  /**
13929
14088
  * Re-initialize modules after address switch
@@ -14130,6 +14289,98 @@ var Sphere = class _Sphere {
14130
14289
  await this.persistTrackedAddresses();
14131
14290
  await this.persistAddressNametags();
14132
14291
  }
14292
+ /**
14293
+ * Discover previously used HD addresses.
14294
+ *
14295
+ * Primary: queries Nostr relay for identity binding events (fast, single batch query).
14296
+ * Secondary: runs L1 balance scan to find legacy addresses with no binding event.
14297
+ *
14298
+ * @example
14299
+ * ```ts
14300
+ * const result = await sphere.discoverAddresses();
14301
+ * console.log(`Found ${result.addresses.length} addresses`);
14302
+ *
14303
+ * // With auto-tracking
14304
+ * await sphere.discoverAddresses({ autoTrack: true });
14305
+ * ```
14306
+ */
14307
+ async discoverAddresses(options = {}) {
14308
+ this.ensureReady();
14309
+ if (!this._masterKey) {
14310
+ throw new Error("Address discovery requires HD master key");
14311
+ }
14312
+ if (!this._transport.discoverAddresses) {
14313
+ throw new Error("Transport provider does not support address discovery");
14314
+ }
14315
+ const includeL1Scan = options.includeL1Scan ?? true;
14316
+ const transportResult = await discoverAddressesImpl(
14317
+ (index) => {
14318
+ const addrInfo = this._deriveAddressInternal(index, false);
14319
+ return {
14320
+ transportPubkey: addrInfo.publicKey.slice(2),
14321
+ // x-only 32 bytes
14322
+ chainPubkey: addrInfo.publicKey,
14323
+ l1Address: addrInfo.address,
14324
+ directAddress: ""
14325
+ // not needed for discovery query
14326
+ };
14327
+ },
14328
+ (pubkeys) => this._transport.discoverAddresses(pubkeys),
14329
+ options
14330
+ );
14331
+ if (includeL1Scan) {
14332
+ try {
14333
+ const l1Result = await this.scanAddresses({
14334
+ maxAddresses: options.maxAddresses,
14335
+ gapLimit: options.gapLimit,
14336
+ signal: options.signal,
14337
+ onProgress: options.onProgress ? (p) => options.onProgress({
14338
+ currentBatch: 0,
14339
+ totalBatches: 0,
14340
+ discoveredCount: p.foundCount,
14341
+ currentGap: p.currentGap,
14342
+ phase: "l1"
14343
+ }) : void 0
14344
+ });
14345
+ for (const l1Addr of l1Result.addresses) {
14346
+ if (l1Addr.isChange) continue;
14347
+ const existing = transportResult.addresses.find((a) => a.index === l1Addr.index);
14348
+ if (existing) {
14349
+ existing.l1Balance = l1Addr.balance;
14350
+ existing.source = "both";
14351
+ if (!existing.nametag && l1Addr.nametag) {
14352
+ existing.nametag = l1Addr.nametag;
14353
+ }
14354
+ } else {
14355
+ const addrInfo = this._deriveAddressInternal(l1Addr.index, false);
14356
+ transportResult.addresses.push({
14357
+ index: l1Addr.index,
14358
+ l1Address: l1Addr.address,
14359
+ directAddress: "",
14360
+ chainPubkey: addrInfo.publicKey,
14361
+ nametag: l1Addr.nametag,
14362
+ l1Balance: l1Addr.balance,
14363
+ source: "l1"
14364
+ });
14365
+ }
14366
+ }
14367
+ transportResult.addresses.sort((a, b) => a.index - b.index);
14368
+ } catch (err) {
14369
+ console.warn("[Sphere] L1 scan failed during discovery (non-fatal):", err);
14370
+ }
14371
+ }
14372
+ if (options.autoTrack && transportResult.addresses.length > 0) {
14373
+ await this.trackScannedAddresses(
14374
+ transportResult.addresses.map((a) => ({
14375
+ index: a.index,
14376
+ // Preserve existing hidden state; default to false for newly discovered
14377
+ hidden: this._trackedAddresses.get(a.index)?.hidden ?? false,
14378
+ nametag: a.nametag
14379
+ }))
14380
+ );
14381
+ }
14382
+ return transportResult;
14383
+ }
14133
14384
  // ===========================================================================
14134
14385
  // Public Methods - Status
14135
14386
  // ===========================================================================
@@ -14701,6 +14952,17 @@ var Sphere = class _Sphere {
14701
14952
  return;
14702
14953
  }
14703
14954
  }
14955
+ const needsUpdate = !existing.directAddress || !existing.l1Address || !existing.chainPubkey || this._identity?.nametag && !existing.nametag;
14956
+ if (needsUpdate) {
14957
+ console.log("[Sphere] Existing binding incomplete, re-publishing with full data");
14958
+ await this._transport.publishIdentityBinding(
14959
+ this._identity.chainPubkey,
14960
+ this._identity.l1Address,
14961
+ this._identity.directAddress || "",
14962
+ this._identity?.nametag || existing.nametag || void 0
14963
+ );
14964
+ return;
14965
+ }
14704
14966
  console.log("[Sphere] Existing binding found, skipping re-publish");
14705
14967
  return;
14706
14968
  }
@@ -15194,6 +15456,7 @@ var CurrencyUtils = {
15194
15456
  init_bech32();
15195
15457
 
15196
15458
  // core/network-health.ts
15459
+ init_constants();
15197
15460
  var DEFAULT_TIMEOUT_MS = 5e3;
15198
15461
  async function checkNetworkHealth(network = "testnet", options) {
15199
15462
  const timeoutMs = options?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
@@ -15405,6 +15668,7 @@ async function runCustomCheck(name, checkFn, timeoutMs) {
15405
15668
  deriveChildKey,
15406
15669
  deriveKeyAtPath,
15407
15670
  deserializeEncrypted,
15671
+ discoverAddressesImpl,
15408
15672
  doubleSha256,
15409
15673
  ec,
15410
15674
  encodeBech32,